agent-relay 11.8.0 → 11.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -3
- package/dist/cli/agent-relay-mcp.d.ts.map +1 -1
- package/dist/cli/agent-relay-mcp.js +61 -1
- package/dist/cli/agent-relay-mcp.js.map +1 -1
- package/dist/cli/bootstrap.d.ts.map +1 -1
- package/dist/cli/bootstrap.js +2 -0
- package/dist/cli/bootstrap.js.map +1 -1
- package/dist/cli/commands/fleet-agent.d.ts +22 -5
- package/dist/cli/commands/fleet-agent.d.ts.map +1 -1
- package/dist/cli/commands/fleet-agent.js +0 -0
- package/dist/cli/commands/fleet-agent.js.map +1 -1
- package/dist/cli/commands/fleet.d.ts +3 -0
- package/dist/cli/commands/fleet.d.ts.map +1 -1
- package/dist/cli/commands/fleet.js +230 -55
- package/dist/cli/commands/fleet.js.map +1 -1
- package/dist/cli/commands/observer.d.ts +28 -0
- package/dist/cli/commands/observer.d.ts.map +1 -0
- package/dist/cli/commands/observer.js +182 -0
- package/dist/cli/commands/observer.js.map +1 -0
- package/dist/cli/lib/observer-url.d.ts +32 -0
- package/dist/cli/lib/observer-url.d.ts.map +1 -0
- package/dist/cli/lib/observer-url.js +61 -0
- package/dist/cli/lib/observer-url.js.map +1 -0
- package/dist/index.cjs +48 -1
- package/package.json +9 -9
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agent-relay observer` — mint a scoped, read-only observer link.
|
|
3
|
+
*
|
|
4
|
+
* The engine rejects a workspace key (`rk_live_`) on the realtime endpoint, and
|
|
5
|
+
* a workspace key is an administrative credential that has no business in a URL
|
|
6
|
+
* or a terminal transcript. This command mints a scoped `ot_live_` token instead
|
|
7
|
+
* and prints the observer URL built from it, so "let a human follow along" is a
|
|
8
|
+
* single command rather than a hand-rolled API call.
|
|
9
|
+
*/
|
|
10
|
+
import { InvalidArgumentError } from 'commander';
|
|
11
|
+
import { createObserverToken, listObserverTokens, revokeObserverToken, } from '@agent-relay/sdk';
|
|
12
|
+
import { DEFAULT_OBSERVER_EXPIRES, DEFAULT_OBSERVER_URL, observerUrl, resolveObserverBaseUrl, } from '../lib/observer-url.js';
|
|
13
|
+
import { printJson, runSdk, withSdkDefaults } from '../lib/sdk-command.js';
|
|
14
|
+
import { resolveBaseUrl, resolveWorkspaceKey } from '../lib/sdk-client.js';
|
|
15
|
+
const MAX_CHANNEL_FILTERS = 50;
|
|
16
|
+
function withObserverDefaults(overrides = {}) {
|
|
17
|
+
return {
|
|
18
|
+
...withSdkDefaults(overrides),
|
|
19
|
+
createObserverToken,
|
|
20
|
+
listObserverTokens,
|
|
21
|
+
revokeObserverToken,
|
|
22
|
+
now: () => Date.now(),
|
|
23
|
+
randomSuffix: () => Math.random().toString(36).slice(2, 10),
|
|
24
|
+
...overrides,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Parse a `30m` / `24h` / `7d` duration into milliseconds. Bare digits are
|
|
29
|
+
* rejected rather than guessed at — `--expires 24` is far more likely to mean
|
|
30
|
+
* hours than milliseconds, and silently picking either would be wrong.
|
|
31
|
+
*/
|
|
32
|
+
export function parseDuration(value) {
|
|
33
|
+
const match = /^(\d+)([mhd])$/.exec(value.trim());
|
|
34
|
+
if (!match) {
|
|
35
|
+
throw new InvalidArgumentError('Expected a duration like 30m, 24h, or 7d.');
|
|
36
|
+
}
|
|
37
|
+
const amount = Number(match[1]);
|
|
38
|
+
if (amount <= 0) {
|
|
39
|
+
throw new InvalidArgumentError('Expected a positive duration.');
|
|
40
|
+
}
|
|
41
|
+
const unitMs = { m: 60_000, h: 3_600_000, d: 86_400_000 }[match[2]];
|
|
42
|
+
const total = amount * unitMs;
|
|
43
|
+
// The engine caps nothing here, but a token outliving the workspace is a
|
|
44
|
+
// liability rather than a convenience.
|
|
45
|
+
if (total > 90 * 86_400_000) {
|
|
46
|
+
throw new InvalidArgumentError('Expected a duration of 90d or less.');
|
|
47
|
+
}
|
|
48
|
+
return total;
|
|
49
|
+
}
|
|
50
|
+
function parseChannels(value) {
|
|
51
|
+
const names = value
|
|
52
|
+
.split(',')
|
|
53
|
+
.map((name) => name.trim().replace(/^#/, ''))
|
|
54
|
+
.filter(Boolean);
|
|
55
|
+
if (names.length === 0) {
|
|
56
|
+
throw new InvalidArgumentError('Expected at least one channel name.');
|
|
57
|
+
}
|
|
58
|
+
// Collapse duplicates before enforcing the cap: `--channels a,a,a` is one
|
|
59
|
+
// filter, and rejecting it for exceeding a limit it never reaches would be
|
|
60
|
+
// surprising.
|
|
61
|
+
const unique = [...new Set(names)];
|
|
62
|
+
if (unique.length > MAX_CHANNEL_FILTERS) {
|
|
63
|
+
throw new InvalidArgumentError(`Expected at most ${MAX_CHANNEL_FILTERS} channel names.`);
|
|
64
|
+
}
|
|
65
|
+
return unique;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Credentials shared by every observer subcommand. `baseUrl` is spread rather
|
|
69
|
+
* than passed as `undefined` because the SDK options treat an explicit
|
|
70
|
+
* `undefined` and an absent key differently.
|
|
71
|
+
*/
|
|
72
|
+
function connection(options) {
|
|
73
|
+
const baseUrl = resolveBaseUrl({ baseUrl: options.baseUrl });
|
|
74
|
+
return {
|
|
75
|
+
workspaceKey: resolveWorkspaceKey({
|
|
76
|
+
workspaceKey: options.workspaceKey,
|
|
77
|
+
}),
|
|
78
|
+
...(baseUrl ? { baseUrl } : {}),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function describeToken(token) {
|
|
82
|
+
return {
|
|
83
|
+
id: token.id,
|
|
84
|
+
name: token.name,
|
|
85
|
+
status: token.status,
|
|
86
|
+
expiresAt: token.expiresAt,
|
|
87
|
+
createdAt: token.createdAt,
|
|
88
|
+
...(token.lastUsedAt === undefined ? {} : { lastUsedAt: token.lastUsedAt }),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export function registerObserverCommands(program, overrides = {}) {
|
|
92
|
+
const deps = withObserverDefaults(overrides);
|
|
93
|
+
const env = process.env;
|
|
94
|
+
const group = program
|
|
95
|
+
.command('observer')
|
|
96
|
+
.description('Mint a read-only observer link so a human can follow this workspace');
|
|
97
|
+
group
|
|
98
|
+
.option('--workspace-key <key>', 'Workspace key (defaults to RELAY_WORKSPACE_KEY or the active workspace)')
|
|
99
|
+
.option('--base-url <url>', 'Override the engine API base URL (defaults to RELAY_BASE_URL)')
|
|
100
|
+
.option('--observer-url <url>', `Observer dashboard URL (defaults to ${DEFAULT_OBSERVER_URL})`)
|
|
101
|
+
.option('--name <name>', 'Token name (defaults to a generated unique name)')
|
|
102
|
+
.option('--channels <names>', 'Restrict to a comma-separated list of channels', parseChannels)
|
|
103
|
+
.option('--include-dms', 'Include agent DM traffic (excluded by default)')
|
|
104
|
+
.option('--expires <duration>', `Token lifetime, e.g. 30m, 24h, 7d (default ${DEFAULT_OBSERVER_EXPIRES})`, parseDuration)
|
|
105
|
+
.option('--json', 'Output the token metadata and URL as JSON')
|
|
106
|
+
.action(async (options) => {
|
|
107
|
+
await runSdk(deps, async () => {
|
|
108
|
+
const lifetimeMs = options.expires ?? parseDuration(DEFAULT_OBSERVER_EXPIRES);
|
|
109
|
+
const name = options.name?.trim() || `observer-cli-${deps.randomSuffix()}`;
|
|
110
|
+
// Resolve the dashboard URL BEFORE minting. A bad `--observer-url` or
|
|
111
|
+
// `RELAY_OBSERVER_URL` would otherwise mint a live 24-hour token and
|
|
112
|
+
// then throw before printing it, leaving an active credential the
|
|
113
|
+
// caller never saw.
|
|
114
|
+
const observerBase = resolveObserverBaseUrl(options.observerUrl, env);
|
|
115
|
+
const token = await deps.createObserverToken({
|
|
116
|
+
...connection(options),
|
|
117
|
+
name,
|
|
118
|
+
description: 'Minted by `agent-relay observer` for read-only follow-along',
|
|
119
|
+
filters: {
|
|
120
|
+
includeDms: options.includeDms === true,
|
|
121
|
+
...(options.channels ? { channelNames: options.channels } : {}),
|
|
122
|
+
},
|
|
123
|
+
expiresAt: new Date(deps.now() + lifetimeMs).toISOString(),
|
|
124
|
+
});
|
|
125
|
+
if (!token.token) {
|
|
126
|
+
throw new Error('Observer token created, but the response did not include token material.');
|
|
127
|
+
}
|
|
128
|
+
const url = observerUrl(observerBase, token.token);
|
|
129
|
+
if (options.json) {
|
|
130
|
+
printJson(deps, { ...describeToken(token), url });
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
deps.log(url);
|
|
134
|
+
deps.log('');
|
|
135
|
+
deps.log(`Read-only. Expires ${token.expiresAt ?? 'never'}.`);
|
|
136
|
+
deps.log(options.includeDms === true ? 'Includes agent DMs.' : 'Channels only — agent DMs are excluded.');
|
|
137
|
+
deps.log(`Revoke with: agent-relay observer revoke ${token.id}`);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
group
|
|
141
|
+
.command('list')
|
|
142
|
+
.description('List observer tokens for this workspace (token material is never shown)')
|
|
143
|
+
.option('--workspace-key <key>', 'Workspace key (defaults to RELAY_WORKSPACE_KEY or the active workspace)')
|
|
144
|
+
.option('--base-url <url>', 'Override the engine API base URL')
|
|
145
|
+
.option('--json', 'Output as JSON')
|
|
146
|
+
.action(async (_options, command) => {
|
|
147
|
+
// The parent `observer` group declares the same flag names, and Commander
|
|
148
|
+
// resolves a repeated option onto the ancestor that declared it first — so
|
|
149
|
+
// the local opts object here is empty and `--json` / `--workspace-key`
|
|
150
|
+
// would be silently dropped. Read the merged view instead.
|
|
151
|
+
const options = command.optsWithGlobals();
|
|
152
|
+
await runSdk(deps, async () => {
|
|
153
|
+
const tokens = await deps.listObserverTokens(connection(options));
|
|
154
|
+
if (options.json) {
|
|
155
|
+
printJson(deps, tokens.map(describeToken));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (tokens.length === 0) {
|
|
159
|
+
deps.log('No observer tokens.');
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
for (const token of tokens) {
|
|
163
|
+
deps.log(`${token.id} ${token.status} expires ${token.expiresAt ?? 'never'} ${token.name}`);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
group
|
|
168
|
+
.command('revoke')
|
|
169
|
+
.description('Revoke an observer token by id')
|
|
170
|
+
.argument('<id>', 'Observer token id')
|
|
171
|
+
.option('--workspace-key <key>', 'Workspace key (defaults to RELAY_WORKSPACE_KEY or the active workspace)')
|
|
172
|
+
.option('--base-url <url>', 'Override the engine API base URL')
|
|
173
|
+
.action(async (id, _options, command) => {
|
|
174
|
+
// See the note on `observer list` — read merged options, not local ones.
|
|
175
|
+
const options = command.optsWithGlobals();
|
|
176
|
+
await runSdk(deps, async () => {
|
|
177
|
+
await deps.revokeObserverToken({ ...connection(options), id });
|
|
178
|
+
deps.log(`Revoked ${id}.`);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=observer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observer.js","sourceRoot":"","sources":["../../../src/cli/commands/observer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observer dashboard URL construction, shared by the `observer` command group
|
|
3
|
+
* and the `get_observer_url` MCP tool so both produce identical links.
|
|
4
|
+
*
|
|
5
|
+
* The credential rides in the `?key=` query string because that is what the
|
|
6
|
+
* observer dashboard reads. That is precisely why the value must always be a
|
|
7
|
+
* scoped, read-only `ot_live_` token and never a workspace key: query strings
|
|
8
|
+
* land in browser history, referrer headers, and proxy logs.
|
|
9
|
+
*/
|
|
10
|
+
/** Where the hosted observer dashboard lives. */
|
|
11
|
+
export declare const DEFAULT_OBSERVER_URL = "https://agentrelay.com/observer";
|
|
12
|
+
/** Default token lifetime for a link meant to be pasted into chat. */
|
|
13
|
+
export declare const DEFAULT_OBSERVER_EXPIRES = "24h";
|
|
14
|
+
/**
|
|
15
|
+
* Resolve the observer dashboard base URL: explicit flag, then
|
|
16
|
+
* `RELAY_OBSERVER_URL` (for self-hosted or staging dashboards), then the
|
|
17
|
+
* hosted default.
|
|
18
|
+
*
|
|
19
|
+
* @param explicit - Value passed on the command line, if any
|
|
20
|
+
* @param env - Environment to read `RELAY_OBSERVER_URL` from
|
|
21
|
+
* @returns A validated absolute URL
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveObserverBaseUrl(explicit: string | undefined, env?: NodeJS.ProcessEnv): string;
|
|
24
|
+
/**
|
|
25
|
+
* Build the observer URL for a token.
|
|
26
|
+
*
|
|
27
|
+
* @param baseUrl - Observer dashboard base URL
|
|
28
|
+
* @param token - Scoped `ot_live_` observer token
|
|
29
|
+
* @returns The full observer URL
|
|
30
|
+
*/
|
|
31
|
+
export declare function observerUrl(baseUrl: string, token: string): string;
|
|
32
|
+
//# sourceMappingURL=observer-url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observer-url.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/observer-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,iDAAiD;AACjD,eAAO,MAAM,oBAAoB,oCAAoC,CAAC;AAEtE,sEAAsE;AACtE,eAAO,MAAM,wBAAwB,QAAQ,CAAC;AAE9C;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAmBR;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CASlE"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observer dashboard URL construction, shared by the `observer` command group
|
|
3
|
+
* and the `get_observer_url` MCP tool so both produce identical links.
|
|
4
|
+
*
|
|
5
|
+
* The credential rides in the `?key=` query string because that is what the
|
|
6
|
+
* observer dashboard reads. That is precisely why the value must always be a
|
|
7
|
+
* scoped, read-only `ot_live_` token and never a workspace key: query strings
|
|
8
|
+
* land in browser history, referrer headers, and proxy logs.
|
|
9
|
+
*/
|
|
10
|
+
/** Where the hosted observer dashboard lives. */
|
|
11
|
+
export const DEFAULT_OBSERVER_URL = 'https://agentrelay.com/observer';
|
|
12
|
+
/** Default token lifetime for a link meant to be pasted into chat. */
|
|
13
|
+
export const DEFAULT_OBSERVER_EXPIRES = '24h';
|
|
14
|
+
/**
|
|
15
|
+
* Resolve the observer dashboard base URL: explicit flag, then
|
|
16
|
+
* `RELAY_OBSERVER_URL` (for self-hosted or staging dashboards), then the
|
|
17
|
+
* hosted default.
|
|
18
|
+
*
|
|
19
|
+
* @param explicit - Value passed on the command line, if any
|
|
20
|
+
* @param env - Environment to read `RELAY_OBSERVER_URL` from
|
|
21
|
+
* @returns A validated absolute URL
|
|
22
|
+
*/
|
|
23
|
+
export function resolveObserverBaseUrl(explicit, env = process.env) {
|
|
24
|
+
const value = explicit?.trim() || env.RELAY_OBSERVER_URL?.trim() || DEFAULT_OBSERVER_URL;
|
|
25
|
+
let parsed;
|
|
26
|
+
try {
|
|
27
|
+
// Fail here rather than emitting a malformed link the caller only discovers
|
|
28
|
+
// after pasting it somewhere public.
|
|
29
|
+
parsed = new URL(value);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
throw new Error(`Invalid observer URL: ${value}`);
|
|
33
|
+
}
|
|
34
|
+
// The token is appended to this URL's query string, so the scheme decides
|
|
35
|
+
// where a live credential ends up. `new URL` happily accepts `data:`,
|
|
36
|
+
// `javascript:`, and arbitrary custom schemes; restrict to the two that
|
|
37
|
+
// actually address an observer dashboard so a bad `RELAY_OBSERVER_URL`
|
|
38
|
+
// cannot turn the generated link into a token-exfiltration vector.
|
|
39
|
+
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
|
|
40
|
+
throw new Error(`Observer URL must be http or https: ${value}`);
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Build the observer URL for a token.
|
|
46
|
+
*
|
|
47
|
+
* @param baseUrl - Observer dashboard base URL
|
|
48
|
+
* @param token - Scoped `ot_live_` observer token
|
|
49
|
+
* @returns The full observer URL
|
|
50
|
+
*/
|
|
51
|
+
export function observerUrl(baseUrl, token) {
|
|
52
|
+
if (!token.startsWith('ot_live_')) {
|
|
53
|
+
// A workspace key in this position would be an administrative credential in
|
|
54
|
+
// a shareable URL — the exact failure this command exists to prevent.
|
|
55
|
+
throw new Error('Observer URLs require a scoped observer token (ot_live_...).');
|
|
56
|
+
}
|
|
57
|
+
const url = new URL(baseUrl);
|
|
58
|
+
url.searchParams.set('key', token);
|
|
59
|
+
return url.toString();
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=observer-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observer-url.js","sourceRoot":"","sources":["../../../src/cli/lib/observer-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,iDAAiD;AACjD,MAAM,CAAC,MAAM,oBAAoB,GAAG,iCAAiC,CAAC;AAEtE,sEAAsE;AACtE,MAAM,CAAC,MAAM,wBAAwB,GAAG,KAAK,CAAC;AAE9C;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAA4B,EAC5B,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,KAAK,GAAG,QAAQ,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,IAAI,oBAAoB,CAAC;IACzF,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,4EAA4E;QAC5E,qCAAqC;QACrC,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,EAAE,CAAC,CAAC;IACpD,CAAC;IACD,0EAA0E;IAC1E,sEAAsE;IACtE,wEAAwE;IACxE,uEAAuE;IACvE,mEAAmE;IACnE,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,uCAAuC,KAAK,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,KAAa;IACxD,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,4EAA4E;QAC5E,sEAAsE;QACtE,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACnC,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC"}
|
package/dist/index.cjs
CHANGED
|
@@ -182,6 +182,7 @@ __export(index_exports, {
|
|
|
182
182
|
MessageReadPredicate: () => MessageReadPredicate,
|
|
183
183
|
OBSERVABILITY_UNAVAILABLE: () => OBSERVABILITY_UNAVAILABLE,
|
|
184
184
|
RELAYCAST_SDK_VERSION: () => RELAYCAST_SDK_VERSION,
|
|
185
|
+
RELAY_OBSERVER_SCOPES: () => RELAY_OBSERVER_SCOPES,
|
|
185
186
|
RELAY_SERVICE_FAILURE_MESSAGE: () => RELAY_SERVICE_FAILURE_MESSAGE,
|
|
186
187
|
RelayCapabilityError: () => RelayCapabilityError,
|
|
187
188
|
RelayError: () => RelayError,
|
|
@@ -214,6 +215,7 @@ __export(index_exports, {
|
|
|
214
215
|
createLogger: () => createLogger,
|
|
215
216
|
createNotifyHandler: () => createNotifyHandler,
|
|
216
217
|
createObserverEventSource: () => createObserverEventSource,
|
|
218
|
+
createObserverToken: () => createObserverToken,
|
|
217
219
|
createRealtimeClient: () => createRealtimeClient,
|
|
218
220
|
createRequestEnvelope: () => createRequestEnvelope,
|
|
219
221
|
createRequestHandler: () => createRequestHandler,
|
|
@@ -246,6 +248,7 @@ __export(index_exports, {
|
|
|
246
248
|
isPlaceholderTargetFast: () => isPlaceholderTargetFast,
|
|
247
249
|
isSpawnOrReleaseCommandFast: () => isSpawnOrReleaseCommandFast,
|
|
248
250
|
isValidAgentName: () => isValidAgentName,
|
|
251
|
+
listObserverTokens: () => listObserverTokens,
|
|
249
252
|
logAndTraceError: () => logAndTraceError,
|
|
250
253
|
logRelayHandlerError: () => logRelayHandlerError,
|
|
251
254
|
mapModelToCli: () => mapModelToCli,
|
|
@@ -280,6 +283,7 @@ __export(index_exports, {
|
|
|
280
283
|
resolveAgentName: () => resolveAgentName,
|
|
281
284
|
resolveAgentToken: () => resolveAgentToken,
|
|
282
285
|
resolveCommand: () => resolveCommand,
|
|
286
|
+
revokeObserverToken: () => revokeObserverToken,
|
|
283
287
|
routerLog: () => routerLog,
|
|
284
288
|
safeRelayErrorMessage: () => safeRelayErrorMessage,
|
|
285
289
|
stripAnsiFast: () => stripAnsiFast,
|
|
@@ -295,7 +299,7 @@ __export(index_exports, {
|
|
|
295
299
|
module.exports = __toCommonJS(index_exports);
|
|
296
300
|
|
|
297
301
|
// ../../node_modules/@relaycast/sdk/dist/version.js
|
|
298
|
-
var SDK_VERSION = "8.1.
|
|
302
|
+
var SDK_VERSION = "8.1.3";
|
|
299
303
|
|
|
300
304
|
// ../../node_modules/zod/v4/classic/external.js
|
|
301
305
|
var external_exports = {};
|
|
@@ -21453,6 +21457,45 @@ var RelaycastMessagingClient = class {
|
|
|
21453
21457
|
|
|
21454
21458
|
// ../sdk/dist/messaging/thin-client.js
|
|
21455
21459
|
var RELAYCAST_SDK_VERSION = SDK_VERSION;
|
|
21460
|
+
var RELAY_OBSERVER_SCOPES = [
|
|
21461
|
+
"stream:read",
|
|
21462
|
+
"messages:read",
|
|
21463
|
+
"threads:read",
|
|
21464
|
+
"dms:read",
|
|
21465
|
+
"channels:read",
|
|
21466
|
+
"search:read",
|
|
21467
|
+
"agents:read",
|
|
21468
|
+
"nodes:read",
|
|
21469
|
+
"deliveries:read",
|
|
21470
|
+
"activity:read",
|
|
21471
|
+
"files:read",
|
|
21472
|
+
"reactions:read"
|
|
21473
|
+
];
|
|
21474
|
+
function observerTokenClient(workspaceKey, options) {
|
|
21475
|
+
return new RelayCast(clientConfig(workspaceKey, options));
|
|
21476
|
+
}
|
|
21477
|
+
async function createObserverToken(options) {
|
|
21478
|
+
const client = observerTokenClient(options.workspaceKey, options);
|
|
21479
|
+
return client.observerTokens.create({
|
|
21480
|
+
name: options.name,
|
|
21481
|
+
...options.description === void 0 ? {} : { description: options.description },
|
|
21482
|
+
scopes: [...options.scopes ?? RELAY_OBSERVER_SCOPES],
|
|
21483
|
+
// `include_dms` defaults to false server-side, but send it explicitly so the
|
|
21484
|
+
// token's stored filters record the decision rather than an absence.
|
|
21485
|
+
filters: {
|
|
21486
|
+
includeDms: options.filters?.includeDms === true,
|
|
21487
|
+
...options.filters?.channelNames?.length ? { channelNames: options.filters.channelNames } : {},
|
|
21488
|
+
...options.filters?.agentIds?.length ? { agentIds: options.filters.agentIds } : {}
|
|
21489
|
+
},
|
|
21490
|
+
...options.expiresAt === void 0 ? {} : { expiresAt: options.expiresAt }
|
|
21491
|
+
});
|
|
21492
|
+
}
|
|
21493
|
+
async function listObserverTokens(options) {
|
|
21494
|
+
return observerTokenClient(options.workspaceKey, options).observerTokens.list();
|
|
21495
|
+
}
|
|
21496
|
+
async function revokeObserverToken(options) {
|
|
21497
|
+
await observerTokenClient(options.workspaceKey, options).observerTokens.revoke(options.id);
|
|
21498
|
+
}
|
|
21456
21499
|
function pickTelemetryOverrides(options) {
|
|
21457
21500
|
return {
|
|
21458
21501
|
...options.originActor === void 0 ? {} : { originActor: options.originActor },
|
|
@@ -24140,6 +24183,7 @@ function generateRequestId(prefix = "") {
|
|
|
24140
24183
|
MessageReadPredicate,
|
|
24141
24184
|
OBSERVABILITY_UNAVAILABLE,
|
|
24142
24185
|
RELAYCAST_SDK_VERSION,
|
|
24186
|
+
RELAY_OBSERVER_SCOPES,
|
|
24143
24187
|
RELAY_SERVICE_FAILURE_MESSAGE,
|
|
24144
24188
|
RelayCapabilityError,
|
|
24145
24189
|
RelayError,
|
|
@@ -24172,6 +24216,7 @@ function generateRequestId(prefix = "") {
|
|
|
24172
24216
|
createLogger,
|
|
24173
24217
|
createNotifyHandler,
|
|
24174
24218
|
createObserverEventSource,
|
|
24219
|
+
createObserverToken,
|
|
24175
24220
|
createRealtimeClient,
|
|
24176
24221
|
createRequestEnvelope,
|
|
24177
24222
|
createRequestHandler,
|
|
@@ -24204,6 +24249,7 @@ function generateRequestId(prefix = "") {
|
|
|
24204
24249
|
isPlaceholderTargetFast,
|
|
24205
24250
|
isSpawnOrReleaseCommandFast,
|
|
24206
24251
|
isValidAgentName,
|
|
24252
|
+
listObserverTokens,
|
|
24207
24253
|
logAndTraceError,
|
|
24208
24254
|
logRelayHandlerError,
|
|
24209
24255
|
mapModelToCli,
|
|
@@ -24238,6 +24284,7 @@ function generateRequestId(prefix = "") {
|
|
|
24238
24284
|
resolveAgentName,
|
|
24239
24285
|
resolveAgentToken,
|
|
24240
24286
|
resolveCommand,
|
|
24287
|
+
revokeObserverToken,
|
|
24241
24288
|
routerLog,
|
|
24242
24289
|
safeRelayErrorMessage,
|
|
24243
24290
|
stripAnsiFast,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-relay",
|
|
3
|
-
"version": "11.8.
|
|
3
|
+
"version": "11.8.1",
|
|
4
4
|
"description": "Real-time agent-to-agent communication system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
"pack:validate": "npm pack --dry-run"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@agent-relay/cloud": "11.8.
|
|
47
|
-
"@agent-relay/config": "11.8.
|
|
48
|
-
"@agent-relay/fleet": "11.8.
|
|
49
|
-
"@agent-relay/harness-driver": "11.8.
|
|
50
|
-
"@agent-relay/harnesses": "11.8.
|
|
51
|
-
"@agent-relay/sdk": "11.8.
|
|
52
|
-
"@agent-relay/session": "11.8.
|
|
53
|
-
"@agent-relay/utils": "11.8.
|
|
46
|
+
"@agent-relay/cloud": "11.8.1",
|
|
47
|
+
"@agent-relay/config": "11.8.1",
|
|
48
|
+
"@agent-relay/fleet": "11.8.1",
|
|
49
|
+
"@agent-relay/harness-driver": "11.8.1",
|
|
50
|
+
"@agent-relay/harnesses": "11.8.1",
|
|
51
|
+
"@agent-relay/sdk": "11.8.1",
|
|
52
|
+
"@agent-relay/session": "11.8.1",
|
|
53
|
+
"@agent-relay/utils": "11.8.1",
|
|
54
54
|
"@modelcontextprotocol/sdk": "^1.23.0",
|
|
55
55
|
"@relayfile/client": "^0.10.27",
|
|
56
56
|
"@relayflows/cli": "1.0.1",
|