teamclaws 1.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.
package/dist/http.js ADDED
@@ -0,0 +1,107 @@
1
+ import { DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_RESPONSE_LIMIT_BYTES, MAX_ERROR_MESSAGE_LENGTH, } from "./constants.js";
2
+ import { TeamClawsError } from "./errors.js";
3
+ import { isObject } from "./validation.js";
4
+ export async function requestJson(fetcher, url, options = {}) {
5
+ const timeout = AbortSignal.timeout(options.timeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS);
6
+ const signal = options.signal
7
+ ? AbortSignal.any([timeout, options.signal])
8
+ : timeout;
9
+ const headers = new Headers({
10
+ Accept: "application/json",
11
+ ...options.headers,
12
+ });
13
+ let body;
14
+ if (options.form) {
15
+ headers.set("Content-Type", "application/x-www-form-urlencoded");
16
+ body = options.form.toString();
17
+ }
18
+ else if (options.body !== undefined) {
19
+ headers.set("Content-Type", "application/json");
20
+ body = JSON.stringify(options.body);
21
+ }
22
+ let response;
23
+ try {
24
+ response = await fetcher(url, {
25
+ method: options.method ?? "GET",
26
+ headers,
27
+ ...(body === undefined ? {} : { body }),
28
+ redirect: "error",
29
+ signal,
30
+ });
31
+ }
32
+ catch (error) {
33
+ if (signal.aborted) {
34
+ throw new TeamClawsError("network_timeout", "TeamClaws did not respond in time.", {
35
+ retryable: true,
36
+ exitCode: 5,
37
+ });
38
+ }
39
+ void error;
40
+ throw new TeamClawsError("network_error", "TeamClaws could not be reached securely.", {
41
+ retryable: true,
42
+ exitCode: 5,
43
+ });
44
+ }
45
+ const contentLength = Number(response.headers.get("content-length") ?? 0);
46
+ const limit = options.responseLimitBytes ?? DEFAULT_RESPONSE_LIMIT_BYTES;
47
+ if (contentLength > limit) {
48
+ throw new TeamClawsError("response_too_large", "TeamClaws returned an oversized response.", {
49
+ exitCode: 9,
50
+ });
51
+ }
52
+ const contentType = response.headers
53
+ .get("content-type")
54
+ ?.split(";", 1)[0]
55
+ ?.trim();
56
+ if (contentType !== "application/json") {
57
+ throw new TeamClawsError("invalid_response", "TeamClaws returned a non-JSON response.", {
58
+ exitCode: 9,
59
+ });
60
+ }
61
+ const text = await response.text();
62
+ if (Buffer.byteLength(text, "utf8") > limit) {
63
+ throw new TeamClawsError("response_too_large", "TeamClaws returned an oversized response.", {
64
+ exitCode: 9,
65
+ });
66
+ }
67
+ let parsed;
68
+ try {
69
+ parsed = JSON.parse(text);
70
+ }
71
+ catch {
72
+ throw new TeamClawsError("invalid_response", "TeamClaws returned invalid JSON.", { exitCode: 9 });
73
+ }
74
+ return { status: response.status, headers: response.headers, body: parsed };
75
+ }
76
+ export function errorFromResponse(response, fallbackCode) {
77
+ if (!isObject(response.body)) {
78
+ return new TeamClawsError(fallbackCode, "TeamClaws rejected the request.", {
79
+ retryable: response.status >= 500,
80
+ exitCode: response.status === 401 ? 3 : 5,
81
+ });
82
+ }
83
+ const protocolError = isObject(response.body.error)
84
+ ? response.body.error
85
+ : response.body;
86
+ const code = safeProtocolString(protocolError.code, fallbackCode, 80);
87
+ const message = safeProtocolString(protocolError.message ?? protocolError.error, "TeamClaws rejected the request.", MAX_ERROR_MESSAGE_LENGTH);
88
+ const retryable = protocolError.retryable === true;
89
+ const retryAfter = Number(protocolError.retry_after_seconds);
90
+ return new TeamClawsError(code, message, {
91
+ retryable,
92
+ ...(Number.isInteger(retryAfter) && retryAfter > 0 && retryAfter <= 86_400
93
+ ? { retryAfterSeconds: retryAfter }
94
+ : {}),
95
+ exitCode: response.status === 401 ? 3 : response.status === 429 ? 5 : 1,
96
+ });
97
+ }
98
+ function safeProtocolString(value, fallback, maxLength) {
99
+ if (typeof value !== "string" ||
100
+ value.length === 0 ||
101
+ value.length > maxLength)
102
+ return fallback;
103
+ if ([...value].some((character) => character.charCodeAt(0) < 0x20))
104
+ return fallback;
105
+ return value;
106
+ }
107
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
package/dist/output.js ADDED
@@ -0,0 +1,298 @@
1
+ import { OUTPUT_SCHEMA_VERSION } from "./constants.js";
2
+ export class Output {
3
+ json;
4
+ stdout;
5
+ stderr;
6
+ constructor(json, stdout = process.stdout, stderr = process.stderr) {
7
+ this.json = json;
8
+ this.stdout = stdout;
9
+ this.stderr = stderr;
10
+ }
11
+ loginBrowser(url) {
12
+ this.event({
13
+ schema_version: OUTPUT_SCHEMA_VERSION,
14
+ event: "login_browser_required",
15
+ url,
16
+ });
17
+ if (!this.json)
18
+ this.stdout.write(`${url}\n`);
19
+ }
20
+ pairingBrowser(url, userCode, agentAction) {
21
+ const event = {
22
+ schema_version: OUTPUT_SCHEMA_VERSION,
23
+ event: "pairing_browser_required",
24
+ url,
25
+ user_code: userCode,
26
+ };
27
+ if (agentAction)
28
+ event.agent_action = agentAction;
29
+ this.event(event);
30
+ if (!this.json) {
31
+ if (agentAction) {
32
+ this.stdout.write(agentAction.message_markdown);
33
+ if (!agentAction.message_markdown.endsWith("\n")) {
34
+ this.stdout.write("\n");
35
+ }
36
+ }
37
+ else {
38
+ this.stdout.write(`Approve pairing in your browser:\n${url}\nPairing code: ${userCode}\n`);
39
+ }
40
+ }
41
+ }
42
+ loginComplete(user) {
43
+ this.event({
44
+ schema_version: OUTPUT_SCHEMA_VERSION,
45
+ event: "login_complete",
46
+ status: "success",
47
+ user,
48
+ });
49
+ if (!this.json)
50
+ this.stdout.write(`Signed in to TeamClaws as ${user.display_name} (${user.email}).\n`);
51
+ }
52
+ authStatus(status, user, expiresAt) {
53
+ const event = {
54
+ schema_version: OUTPUT_SCHEMA_VERSION,
55
+ event: "auth_status",
56
+ status,
57
+ };
58
+ if (user)
59
+ event.user = user;
60
+ if (expiresAt)
61
+ event.expires_at = expiresAt;
62
+ this.event(event);
63
+ if (!this.json) {
64
+ this.stdout.write(status === "signed_in" && user
65
+ ? `Signed in as ${user.display_name} (${user.email}).\n`
66
+ : "Not signed in to TeamClaws.\n");
67
+ }
68
+ }
69
+ logoutComplete(remoteConfirmed) {
70
+ this.event({
71
+ schema_version: OUTPUT_SCHEMA_VERSION,
72
+ event: "logout_complete",
73
+ status: remoteConfirmed ? "success" : "local_only_warning",
74
+ });
75
+ if (!this.json) {
76
+ this.stdout.write(remoteConfirmed
77
+ ? "Signed out from TeamClaws on this computer.\n"
78
+ : "Signed out on this computer. TeamClaws could not confirm remote revocation.\n");
79
+ }
80
+ }
81
+ servers(servers) {
82
+ this.event({
83
+ schema_version: OUTPUT_SCHEMA_VERSION,
84
+ event: "servers_list",
85
+ status: "success",
86
+ servers,
87
+ });
88
+ if (!this.json) {
89
+ if (servers.length === 0) {
90
+ this.stdout.write("No pairing-ready TeamClaws workspaces are available.\n");
91
+ return;
92
+ }
93
+ servers.forEach((server, index) => {
94
+ this.stdout.write(`${index + 1}. ${server.alias} — ${server.server_id} — ${server.workspace_url}\n`);
95
+ });
96
+ }
97
+ }
98
+ pairingComplete(serverId, origin, displayName, externalChatHandoff, capabilities, generatedAt) {
99
+ const workspace = {
100
+ server_id: serverId,
101
+ origin,
102
+ display_name: displayName,
103
+ };
104
+ const event = {
105
+ schema_version: OUTPUT_SCHEMA_VERSION,
106
+ event: "pairing_complete",
107
+ status: "success",
108
+ workspace,
109
+ };
110
+ if (externalChatHandoff)
111
+ event.external_chat_handoff = externalChatHandoff;
112
+ if (capabilities !== undefined) {
113
+ event.external_chat_capabilities = capabilities;
114
+ event.external_chat_capabilities_generated_at = generatedAt ?? null;
115
+ }
116
+ this.event(event);
117
+ if (!this.json) {
118
+ this.stdout.write(`Paired ${displayName} (${origin}).\n`);
119
+ if (capabilities)
120
+ this.renderInventory(capabilities, generatedAt);
121
+ else
122
+ this.stdout.write("Capabilities unavailable; use chat capabilities to refresh.\n");
123
+ }
124
+ }
125
+ pairingStatus(status, workspace) {
126
+ const event = {
127
+ schema_version: OUTPUT_SCHEMA_VERSION,
128
+ event: "pairing_status",
129
+ status,
130
+ };
131
+ if (workspace)
132
+ event.workspace = workspace;
133
+ this.event(event);
134
+ if (this.json)
135
+ return;
136
+ if (status === "paired" && workspace) {
137
+ this.stdout.write(`Paired with ${workspace.origin}.\n`);
138
+ return;
139
+ }
140
+ if (status === "credential_rejected" && workspace) {
141
+ this.stdout.write(`Saved pairing rejected by ${workspace.origin}.\n`);
142
+ return;
143
+ }
144
+ if (status === "unreachable" && workspace) {
145
+ this.stdout.write(`Could not verify pairing with ${workspace.origin} within five seconds.\n`);
146
+ return;
147
+ }
148
+ if (status === "unreachable") {
149
+ this.stdout.write("Could not safely verify the selected pairing.\n");
150
+ return;
151
+ }
152
+ this.stdout.write("Not paired with the selected workspace.\n");
153
+ }
154
+ capabilityInventory(workspace, capabilities) {
155
+ this.event({
156
+ schema_version: OUTPUT_SCHEMA_VERSION,
157
+ event: "chat_capabilities",
158
+ status: "success",
159
+ source: "refresh",
160
+ workspace,
161
+ external_chat_capabilities: capabilities,
162
+ });
163
+ if (!this.json)
164
+ this.renderInventory(capabilities, undefined, true);
165
+ }
166
+ renderInventory(capabilities, generatedAt, checkRecommendation = false) {
167
+ if (!capabilities.providers.some((provider) => provider.models.length > 0)) {
168
+ this.stdout.write("No provider/model is currently available.\n");
169
+ }
170
+ for (const provider of capabilities.providers) {
171
+ for (const model of provider.models) {
172
+ this.stdout.write(`${provider.id}/${model.id} — reasoning: ${model.supported_reasoning_levels.join(", ") || "none"}; fast: ${model.fast_mode_available && capabilities.policy.allow_fast_mode ? "available" : "unavailable"}\n`);
173
+ }
174
+ }
175
+ const recommendation = capabilities.recommended_selection;
176
+ const model = capabilities.providers
177
+ .find((provider) => provider.id === recommendation?.provider_key)
178
+ ?.models.find((item) => item.id === recommendation?.model_name);
179
+ const usable = recommendation &&
180
+ model &&
181
+ (!recommendation.reasoning_effort ||
182
+ model.supported_reasoning_levels.includes(recommendation.reasoning_effort)) &&
183
+ (!recommendation.fast_mode ||
184
+ (model.fast_mode_available && capabilities.policy.allow_fast_mode));
185
+ this.stdout.write(checkRecommendation && !usable
186
+ ? "No usable recommendation.\n"
187
+ : recommendation
188
+ ? `Recommended: ${recommendation.provider_key}/${recommendation.model_name}.\n`
189
+ : "No recommended provider/model.\n");
190
+ this.stdout.write(generatedAt
191
+ ? `Snapshot generated: ${generatedAt}.\n`
192
+ : "Generation time is not supplied by the capabilities endpoint.\n");
193
+ }
194
+ chatCapabilities(selection) {
195
+ this.externalChatEvent("capabilities_resolved", {
196
+ provider_key: selection.provider_key,
197
+ model_name: selection.model_name,
198
+ reasoning_effort: selection.reasoning_effort,
199
+ fast_mode_effective: selection.fast_mode,
200
+ });
201
+ if (!this.json)
202
+ this.stdout.write(`Using ${selection.provider_key}/${selection.model_name}.\n`);
203
+ }
204
+ chatSessionCreated(sessionId, requestId, status, ownerUrl) {
205
+ this.externalChatEvent("session_created", {
206
+ session_id: sessionId,
207
+ request_id: requestId,
208
+ status,
209
+ owner_conversation_url: ownerUrl,
210
+ });
211
+ if (!this.json)
212
+ this.stdout.write(`Created external chat session ${sessionId}.\n`);
213
+ }
214
+ chatRequestStatus(sessionId, requestId, status, revision) {
215
+ this.externalChatEvent("request_status_changed", {
216
+ session_id: sessionId,
217
+ request_id: requestId,
218
+ status,
219
+ revision,
220
+ });
221
+ if (!this.json)
222
+ this.stdout.write(`Request status: ${status}.\n`);
223
+ }
224
+ chatApprovalRequired(sessionId, requestId, ownerUrl) {
225
+ this.externalChatEvent("approval_required", {
226
+ session_id: sessionId,
227
+ request_id: requestId,
228
+ status: "awaiting_approval",
229
+ owner_conversation_url: ownerUrl,
230
+ });
231
+ if (!this.json)
232
+ this.stdout.write(`Owner approval required in TCChat: ${ownerUrl}\n`);
233
+ }
234
+ chatAssistantMessage(sessionId, requestId, messageId, body, provider, model) {
235
+ this.externalChatEvent("assistant_message", {
236
+ session_id: sessionId,
237
+ request_id: requestId,
238
+ message_id: messageId,
239
+ body_text: body,
240
+ provider_key: provider,
241
+ model_name: model,
242
+ });
243
+ if (!this.json)
244
+ this.stdout.write(`${body}\n`);
245
+ }
246
+ chatRequestSucceeded(sessionId, requestId, responseCount, ownerUrl) {
247
+ this.externalChatEvent("request_succeeded", {
248
+ session_id: sessionId,
249
+ request_id: requestId,
250
+ status: "succeeded",
251
+ response_count: responseCount,
252
+ owner_conversation_url: ownerUrl,
253
+ });
254
+ if (!this.json)
255
+ this.stdout.write(`Open this conversation in TCChat: ${ownerUrl}\n`);
256
+ }
257
+ chatRequestFailed(sessionId, requestId, status, code, detail, ownerUrl) {
258
+ this.externalChatEvent("request_failed", {
259
+ session_id: sessionId,
260
+ request_id: requestId,
261
+ status,
262
+ error_code: code,
263
+ error_detail: detail,
264
+ owner_conversation_url: ownerUrl,
265
+ });
266
+ if (!this.json)
267
+ this.stderr.write(`Error: ${detail}\n`);
268
+ }
269
+ error(error) {
270
+ const event = {
271
+ schema_version: OUTPUT_SCHEMA_VERSION,
272
+ event: "error",
273
+ status: "error",
274
+ code: error.code,
275
+ message: error.message,
276
+ retryable: error.retryable,
277
+ };
278
+ if (error.retryAfterSeconds !== undefined) {
279
+ event.retry_after_seconds = error.retryAfterSeconds;
280
+ }
281
+ if (this.json)
282
+ this.stdout.write(`${JSON.stringify(event)}\n`);
283
+ else
284
+ this.stderr.write(`Error: ${error.message}\n`);
285
+ }
286
+ event(event) {
287
+ if (this.json)
288
+ this.stdout.write(`${JSON.stringify(event)}\n`);
289
+ }
290
+ externalChatEvent(event, facts) {
291
+ this.event({
292
+ schema_version: OUTPUT_SCHEMA_VERSION,
293
+ event,
294
+ ...facts,
295
+ });
296
+ }
297
+ }
298
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,245 @@
1
+ import { parseCapabilityInventory } from "./external-chat.js";
2
+ import { TeamClawsError } from "./errors.js";
3
+ import { PAIRING_STATUS_TIMEOUT_MS } from "./constants.js";
4
+ import { errorFromResponse, requestJson, } from "./http.js";
5
+ import { directTargetUrl, isObject, parsePairingCredential, parseVerifiedDevice, parseVerifiedWorkspace, requireInteger, } from "./validation.js";
6
+ import { openExternalBrowser } from "./browser.js";
7
+ export class PairingClient {
8
+ fetcher;
9
+ store;
10
+ output;
11
+ openBrowser;
12
+ now;
13
+ wait;
14
+ constructor(options) {
15
+ this.fetcher = options.fetcher ?? fetch;
16
+ this.store = options.store;
17
+ this.output = options.output;
18
+ this.openBrowser = options.openBrowser ?? openExternalBrowser;
19
+ this.now = options.now ?? Date.now;
20
+ this.wait = options.wait ?? waitFor;
21
+ }
22
+ async status(target, signal) {
23
+ let credential;
24
+ try {
25
+ credential = await this.store.findWorkspace(target);
26
+ }
27
+ catch {
28
+ this.output.pairingStatus("unreachable");
29
+ return "unreachable";
30
+ }
31
+ if (!credential) {
32
+ this.output.pairingStatus("not_paired");
33
+ return "not_paired";
34
+ }
35
+ const workspace = {
36
+ server_id: credential.server_id,
37
+ origin: credential.origin,
38
+ display_name: credential.display_name,
39
+ };
40
+ try {
41
+ const response = await requestJson(this.fetcher, `${credential.origin}/teamclaws-admin/api/device-pairings/me/`, {
42
+ headers: {
43
+ Authorization: `Bearer ${credential.device_id}:${credential.device_token}`,
44
+ },
45
+ timeoutMs: PAIRING_STATUS_TIMEOUT_MS,
46
+ ...(signal ? { signal } : {}),
47
+ });
48
+ if (response.status === 401 || response.status === 403) {
49
+ this.output.pairingStatus("credential_rejected", workspace);
50
+ return "credential_rejected";
51
+ }
52
+ if (response.status < 200 || response.status >= 300) {
53
+ this.output.pairingStatus("unreachable", workspace);
54
+ return "unreachable";
55
+ }
56
+ const displayName = parseVerifiedDevice(response.body, credential.device_id);
57
+ this.output.pairingStatus("paired", {
58
+ ...workspace,
59
+ display_name: displayName,
60
+ });
61
+ return "paired";
62
+ }
63
+ catch (error) {
64
+ if (signal?.aborted)
65
+ throw error;
66
+ this.output.pairingStatus("unreachable", workspace);
67
+ return "unreachable";
68
+ }
69
+ }
70
+ async complete(pending, deviceName, noOpen, signal) {
71
+ this.output.pairingBrowser(pending.verification_uri_complete, pending.user_code, pending.agent_action);
72
+ if (!noOpen)
73
+ await this.openBrowser(pending.verification_uri_complete);
74
+ let credential;
75
+ try {
76
+ credential = await this.poll(pending, signal);
77
+ const initial = {
78
+ version: 1,
79
+ server_id: pending.server_id,
80
+ origin: pending.target.origin,
81
+ display_name: deviceName,
82
+ device_id: credential.device_id,
83
+ device_token: credential.device_token,
84
+ created_at: new Date(this.now()).toISOString(),
85
+ };
86
+ await this.store.writeWorkspace(initial);
87
+ try {
88
+ const stored = await this.store.readWorkspace(pending.server_id);
89
+ if (!stored)
90
+ throw verificationError();
91
+ const verification = await this.verify(pending, stored, signal);
92
+ const verified = {
93
+ ...stored,
94
+ display_name: verification.display_name,
95
+ };
96
+ await this.store.writeWorkspace(verified);
97
+ let snapshot;
98
+ let generatedAt;
99
+ if (Object.hasOwn(credential, "external_chat_capabilities")) {
100
+ snapshot = null;
101
+ generatedAt = null;
102
+ try {
103
+ const timestamp = credential.external_chat_capabilities_generated_at;
104
+ if (typeof timestamp === "string" &&
105
+ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|\+00:00)$/.test(timestamp) &&
106
+ Number.isFinite(Date.parse(timestamp))) {
107
+ snapshot = parseCapabilityInventory(credential.external_chat_capabilities);
108
+ generatedAt = timestamp;
109
+ }
110
+ }
111
+ catch {
112
+ // Optional inventory must not invalidate a successfully verified credential.
113
+ }
114
+ }
115
+ this.output.pairingComplete(pending.server_id, pending.target.origin, verification.display_name, verification.external_chat_handoff, snapshot, generatedAt);
116
+ }
117
+ catch (error) {
118
+ await this.store.removeWorkspace(pending.server_id);
119
+ throw error;
120
+ }
121
+ }
122
+ catch (error) {
123
+ if (signal?.aborted) {
124
+ await this.cancel(pending).catch(() => undefined);
125
+ throw new TeamClawsError("cancelled", "Pairing was cancelled.", {
126
+ exitCode: 8,
127
+ });
128
+ }
129
+ throw error;
130
+ }
131
+ finally {
132
+ credential = undefined;
133
+ void credential;
134
+ }
135
+ }
136
+ async poll(pending, signal) {
137
+ const deadline = this.now() + pending.expires_in * 1_000;
138
+ let intervalSeconds = pending.interval;
139
+ const pollUrl = directTargetUrl(pending.target, pending.target.token_poll_path);
140
+ while (this.now() < deadline) {
141
+ if (signal?.aborted)
142
+ throw new TeamClawsError("cancelled", "Pairing was cancelled.");
143
+ const response = await requestJson(this.fetcher, pollUrl, {
144
+ method: "POST",
145
+ body: { device_code: pending.device_code },
146
+ ...(signal ? { signal } : {}),
147
+ });
148
+ if (response.status >= 200 && response.status < 300) {
149
+ if (response.status === 202) {
150
+ intervalSeconds = pendingInterval(response, intervalSeconds);
151
+ await this.wait(intervalSeconds * 1_000, signal);
152
+ continue;
153
+ }
154
+ return parsePairingCredential(response.body);
155
+ }
156
+ if (response.status === 429) {
157
+ intervalSeconds = slowDownInterval(response, intervalSeconds);
158
+ await this.wait(intervalSeconds * 1_000, signal);
159
+ continue;
160
+ }
161
+ const protocolError = errorFromResponse(response, "pairing_failed");
162
+ throw mapPairingError(protocolError);
163
+ }
164
+ throw new TeamClawsError("pairing_expired", "The pairing request expired.", { exitCode: 7 });
165
+ }
166
+ async cancel(pending) {
167
+ const response = await requestJson(this.fetcher, directTargetUrl(pending.target, pending.target.cancellation_path), {
168
+ method: "POST",
169
+ body: { device_code: pending.device_code },
170
+ timeoutMs: 5_000,
171
+ });
172
+ if (response.status < 200 || response.status >= 300)
173
+ throw errorFromResponse(response, "cancel_failed");
174
+ }
175
+ async verify(pending, credential, signal) {
176
+ const response = await requestJson(this.fetcher, directTargetUrl(pending.target, pending.target.credential_verification_path), {
177
+ headers: {
178
+ Authorization: `Bearer ${credential.device_id}:${credential.device_token}`,
179
+ },
180
+ ...(signal ? { signal } : {}),
181
+ });
182
+ if (response.status < 200 || response.status >= 300)
183
+ throw verificationError();
184
+ return parseVerifiedWorkspace(response.body, credential.device_id, credential.origin);
185
+ }
186
+ }
187
+ function pendingInterval(response, fallback) {
188
+ if (!isObject(response.body) ||
189
+ response.body.status !== "authorization_pending") {
190
+ throw new TeamClawsError("invalid_response", "The workspace returned an invalid pending response.", {
191
+ exitCode: 9,
192
+ });
193
+ }
194
+ return requireInteger(response.body.interval ?? fallback, "polling interval", 1, 60);
195
+ }
196
+ function slowDownInterval(response, current) {
197
+ const header = Number(response.headers.get("retry-after"));
198
+ if (Number.isInteger(header) && header > 0 && header <= 300)
199
+ return header;
200
+ if (isObject(response.body)) {
201
+ const seconds = Number(response.body.retry_after_seconds);
202
+ if (Number.isInteger(seconds) && seconds > 0 && seconds <= 300)
203
+ return seconds;
204
+ }
205
+ return Math.min(current + 5, 60);
206
+ }
207
+ function mapPairingError(error) {
208
+ if (["denied", "authorization_denied", "pairing_denied"].includes(error.code)) {
209
+ return new TeamClawsError("pairing_denied", "The workspace owner denied pairing.", { exitCode: 6 });
210
+ }
211
+ if (["expired", "pairing_expired"].includes(error.code)) {
212
+ return new TeamClawsError("pairing_expired", "The pairing request expired.", { exitCode: 7 });
213
+ }
214
+ if (["cancelled", "canceled", "pairing_cancelled"].includes(error.code)) {
215
+ return new TeamClawsError("pairing_cancelled", "The pairing request was cancelled.", { exitCode: 8 });
216
+ }
217
+ return error;
218
+ }
219
+ function verificationError() {
220
+ return new TeamClawsError("credential_verification_failed", "The workspace credential could not be verified and was not retained.", { exitCode: 9 });
221
+ }
222
+ async function waitFor(milliseconds, signal) {
223
+ await new Promise((resolve, reject) => {
224
+ if (signal?.aborted) {
225
+ reject(new TeamClawsError("cancelled", "Pairing was cancelled.", {
226
+ exitCode: 8,
227
+ }));
228
+ return;
229
+ }
230
+ const finish = () => {
231
+ signal?.removeEventListener("abort", abort);
232
+ resolve();
233
+ };
234
+ const timer = setTimeout(finish, milliseconds);
235
+ const abort = () => {
236
+ clearTimeout(timer);
237
+ signal?.removeEventListener("abort", abort);
238
+ reject(new TeamClawsError("cancelled", "Pairing was cancelled.", {
239
+ exitCode: 8,
240
+ }));
241
+ };
242
+ signal?.addEventListener("abort", abort, { once: true });
243
+ });
244
+ }
245
+ //# sourceMappingURL=pairing.js.map