@caplets/core 0.26.0 → 0.26.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/dist/native.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as nativeCapletPromptGuidance, F as nativeCodeModeToolName, M as nativeCapletToolName, N as nativeCapletsSystemGuidance, P as nativeCodeModeToolId, h as createSdkRemoteCapletsClient, j as nativeCapletToolDescription, m as RemoteNativeCapletsService, t as createNativeCapletsService, v as resolveNativeCapletsServiceOptions } from "./service-rvZ7z6FI.js";
1
+ import { A as nativeCapletPromptGuidance, F as nativeCodeModeToolName, M as nativeCapletToolName, N as nativeCapletsSystemGuidance, P as nativeCodeModeToolId, h as createSdkRemoteCapletsClient, j as nativeCapletToolDescription, m as RemoteNativeCapletsService, t as createNativeCapletsService, v as resolveNativeCapletsServiceOptions } from "./service-aBIn4nrw.js";
2
2
  import { generatedToolInputJsonSchema, generatedToolInputSchema } from "./generated-tool-input-schema.js";
3
3
  //#region src/native/process-cleanup.ts
4
4
  function registerNativeCapletsProcessCleanup(service, options = {}) {
@@ -1,5 +1,5 @@
1
1
  import { CapletsError } from "../errors";
2
- export declare const PROJECT_BINDING_ERROR_CODES: readonly ["cloud_auth_required", "cloud_auth_expired", "cloud_auth_revoked", "workspace_selection_required", "workspace_switch_required", "workspace_forbidden", "project_binding_forbidden", "endpoint_unavailable", "websocket_upgrade_required", "sync_required", "sync_failed", "sync_size_limit_exceeded", "lease_conflict", "lease_expired", "policy_denied", "usage_limit_reached", "billing_required", "subscription_past_due", "email_verification_required", "remote_credentials_required", "remote_auth_failed"];
2
+ export declare const PROJECT_BINDING_ERROR_CODES: readonly ["cloud_auth_required", "cloud_auth_expired", "cloud_auth_revoked", "workspace_selection_required", "workspace_switch_required", "workspace_forbidden", "project_binding_forbidden", "endpoint_unavailable", "websocket_upgrade_required", "sync_required", "sync_failed", "sync_size_limit_exceeded", "lease_conflict", "lease_expired", "policy_denied", "usage_limit_reached", "billing_required", "subscription_past_due", "email_verification_required", "remote_credentials_required", "remote_credentials_revoked", "remote_auth_failed"];
3
3
  export type ProjectBindingErrorCode = (typeof PROJECT_BINDING_ERROR_CODES)[number];
4
4
  export type ProjectBindingRecovery = {
5
5
  code: ProjectBindingErrorCode;
@@ -16,6 +16,7 @@ export type CloudProfileLookup = {
16
16
  };
17
17
  export type SaveSelfHostedProfileInput = {
18
18
  hostUrl: string;
19
+ hostIdentity?: string | undefined;
19
20
  clientId: string;
20
21
  clientLabel?: string | undefined;
21
22
  credentials: RemoteProfileCredential;
@@ -23,6 +24,7 @@ export type SaveSelfHostedProfileInput = {
23
24
  };
24
25
  export type SelfHostedProfileLookup = {
25
26
  hostUrl: string;
27
+ hostIdentity?: string | undefined;
26
28
  };
27
29
  export type RefreshSelfHostedProfileInput = SelfHostedProfileLookup & {
28
30
  needsRefresh: (credential: RemoteProfileCredential) => boolean;
@@ -16,6 +16,7 @@ export type RemoteProfileCredential = {
16
16
  export type RemoteProfileStatusInput = {
17
17
  kind: RemoteProfileKind;
18
18
  hostUrl: string;
19
+ hostIdentity?: string | undefined;
19
20
  key?: string | undefined;
20
21
  workspaceId?: string | undefined;
21
22
  workspaceSlug?: string | undefined;
@@ -31,6 +32,7 @@ export type RemoteProfileStatus = {
31
32
  kind: RemoteProfileKind;
32
33
  key: string;
33
34
  hostUrl: string;
35
+ hostIdentity?: string | undefined;
34
36
  workspaceId?: string | undefined;
35
37
  workspaceSlug?: string | undefined;
36
38
  clientId?: string | undefined;
@@ -1,4 +1,5 @@
1
- import type { IssuedRemoteClientCredentials, RemoteClientStatus, ValidatedRemoteClient } from "./server-credentials";
1
+ import { type VaultEncryptedRecord } from "../vault/crypto";
2
+ import type { IssuedRemoteClientCredentials, RemoteClientStatus, RemotePendingLoginStatus, RemotePendingLoginState, ValidatedRemoteClient } from "./server-credentials";
2
3
  export type RemoteServerCredentialStoreOptions = {
3
4
  dir: string;
4
5
  };
@@ -25,6 +26,29 @@ export type RefreshClientCredentialsInput = {
25
26
  refreshToken: string;
26
27
  now?: Date | undefined;
27
28
  };
29
+ export type CreatePendingLoginInput = {
30
+ hostUrl: string;
31
+ hostIdentity?: string | undefined;
32
+ clientLabel?: string | undefined;
33
+ clientFingerprint?: string | undefined;
34
+ sourceHint?: string | undefined;
35
+ now?: Date | undefined;
36
+ };
37
+ export type PendingLoginPossessionInput = {
38
+ flowId: string;
39
+ pendingCompletionSecret: string;
40
+ now?: Date | undefined;
41
+ };
42
+ export type RefreshPendingLoginInput = PendingLoginPossessionInput & {
43
+ pendingRefreshSecret: string;
44
+ };
45
+ export type ApprovePendingLoginInput = {
46
+ operatorCode: string;
47
+ now?: Date | undefined;
48
+ };
49
+ export type CompletePendingLoginInput = PendingLoginPossessionInput & {
50
+ hostUrl: string;
51
+ };
28
52
  type StoredPairingCode = {
29
53
  codeId: string;
30
54
  hostUrl: string;
@@ -49,18 +73,91 @@ type StoredRemoteClient = {
49
73
  lastUsedAt?: string | undefined;
50
74
  revokedAt?: string | undefined;
51
75
  };
76
+ type PendingLoginStatus = RemotePendingLoginState;
77
+ type StoredPendingLogin = {
78
+ flowId: string;
79
+ hostUrl: string;
80
+ hostIdentity?: string | undefined;
81
+ operatorCodeHash: string;
82
+ pendingRefreshHash: string;
83
+ supersededPendingRefreshHashes: SupersededRefreshToken[];
84
+ pendingRefreshReplay?: PendingRefreshReplay | undefined;
85
+ pendingCompletionHash: string;
86
+ completionReplay?: CompletionReplay | undefined;
87
+ clientLabel: string;
88
+ clientFingerprint?: string | undefined;
89
+ sourceHint?: string | undefined;
90
+ createdAt: string;
91
+ codeExpiresAt: string;
92
+ flowExpiresAt: string;
93
+ status: PendingLoginStatus;
94
+ operatorCodeFingerprint?: string | undefined;
95
+ approvedAt?: string | undefined;
96
+ deniedAt?: string | undefined;
97
+ cancelledAt?: string | undefined;
98
+ exchangedAt?: string | undefined;
99
+ };
52
100
  type SupersededRefreshToken = {
53
101
  hash: string;
54
102
  supersededAt: string;
55
103
  };
104
+ type PendingRefreshReplay = {
105
+ refreshHash: string;
106
+ expiresAt: string;
107
+ encryptedResponse: VaultEncryptedRecord;
108
+ };
109
+ type CompletionReplay = {
110
+ expiresAt: string;
111
+ encryptedCredentials: VaultEncryptedRecord;
112
+ };
56
113
  type RemoteServerCredentialState = {
57
114
  version: 1;
58
115
  pairingCodes: StoredPairingCode[];
116
+ pendingLogins: StoredPendingLogin[];
59
117
  clients: StoredRemoteClient[];
60
118
  };
61
119
  export declare class RemoteServerCredentialStore {
62
120
  readonly dir: string;
63
121
  constructor(options: RemoteServerCredentialStoreOptions);
122
+ createPendingLogin(input: CreatePendingLoginInput): {
123
+ flowId: string;
124
+ operatorCode: string;
125
+ operatorCodeFingerprint: string;
126
+ pendingRefreshSecret: string;
127
+ pendingCompletionSecret: string;
128
+ codeExpiresAt: string;
129
+ flowExpiresAt: string;
130
+ intervalSeconds: number;
131
+ };
132
+ pollPendingLogin(input: PendingLoginPossessionInput): {
133
+ flowId: string;
134
+ status: PendingLoginStatus;
135
+ };
136
+ refreshPendingLogin(input: RefreshPendingLoginInput): {
137
+ flowId: string;
138
+ operatorCode: string;
139
+ operatorCodeFingerprint: string;
140
+ pendingRefreshSecret: string;
141
+ codeExpiresAt: string;
142
+ flowExpiresAt: string;
143
+ intervalSeconds: number;
144
+ };
145
+ denyPendingLogin(input: ApprovePendingLoginInput): {
146
+ flowId: string;
147
+ status: "denied";
148
+ };
149
+ cancelPendingLogin(input: PendingLoginPossessionInput): {
150
+ flowId: string;
151
+ status: "cancelled";
152
+ };
153
+ approvePendingLogin(input: ApprovePendingLoginInput): {
154
+ flowId: string;
155
+ status: "approved";
156
+ clientLabel: string;
157
+ clientFingerprint?: string | undefined;
158
+ sourceHint?: string | undefined;
159
+ };
160
+ completePendingLogin(input: CompletePendingLoginInput): IssuedRemoteClientCredentials;
64
161
  createPairingCode(input: CreatePairingCodeInput): {
65
162
  codeId: string;
66
163
  code: string;
@@ -68,6 +165,7 @@ export declare class RemoteServerCredentialStore {
68
165
  };
69
166
  exchangePairingCode(input: ExchangePairingCodeInput): IssuedRemoteClientCredentials;
70
167
  listClients(): RemoteClientStatus[];
168
+ listPendingLogins(now?: Date): RemotePendingLoginStatus[];
71
169
  revokeClient(clientId: string, now?: Date): boolean;
72
170
  validateAccessToken(input: ValidateAccessTokenInput): ValidatedRemoteClient;
73
171
  refreshClientCredentials(input: RefreshClientCredentialsInput): IssuedRemoteClientCredentials;
@@ -80,5 +178,6 @@ export declare class RemoteServerCredentialStore {
80
178
  private acquireLock;
81
179
  private releaseLock;
82
180
  private clearStaleLock;
181
+ private pendingLoginForCompletion;
83
182
  }
84
183
  export {};
@@ -16,6 +16,24 @@ export type RemoteClientStatus = {
16
16
  lastUsedAt?: string | undefined;
17
17
  revokedAt?: string | undefined;
18
18
  };
19
+ export type RemotePendingLoginState = "pending" | "approved" | "denied" | "cancelled" | "expired" | "exchanged";
20
+ export type RemotePendingLoginStatus = {
21
+ flowId: string;
22
+ hostUrl: string;
23
+ hostIdentity?: string | undefined;
24
+ status: RemotePendingLoginState;
25
+ operatorCodeFingerprint?: string | undefined;
26
+ clientLabel: string;
27
+ clientFingerprint?: string | undefined;
28
+ sourceHint?: string | undefined;
29
+ createdAt: string;
30
+ codeExpiresAt: string;
31
+ flowExpiresAt: string;
32
+ approvedAt?: string | undefined;
33
+ deniedAt?: string | undefined;
34
+ cancelledAt?: string | undefined;
35
+ exchangedAt?: string | undefined;
36
+ };
19
37
  export type ValidatedRemoteClient = RemoteClientStatus & {
20
38
  tokenType: "Bearer";
21
39
  };
@@ -35,6 +35,11 @@ export declare function servicePaths(base: string): {
35
35
  attachInvoke: string;
36
36
  projectBindings: string;
37
37
  pairingExchange: string;
38
+ remoteLoginStart: string;
39
+ remoteLoginPoll: string;
40
+ remoteLoginRefresh: string;
41
+ remoteLoginComplete: string;
42
+ remoteLoginCancel: string;
38
43
  remoteRefresh: string;
39
44
  remoteClient: string;
40
45
  health: string;
@@ -1,5 +1,5 @@
1
1
  import { A as safeParseAsync$1, C as toJSONSchema, D as parse$3, E as $ZodType, F as NEVER, M as defineLazy, N as normalizeParams, O as parseAsync, P as $constructor, S as datetime, T as $ZodObject, _ as record, a as any, b as unknown, c as custom, d as literal, f as looseObject, g as preprocess, h as optional, i as _null, j as clone, k as safeParse$1, l as discriminatedUnion, m as object$1, o as array, p as number$1, r as _enum, s as boolean, t as ZodNumber$1, u as intersection, v as string, w as _coercedNumber, x as url, y as union } from "./schemas-BoqMu4MG.js";
2
- import { a as isAllowedHttpBaseUrl, c as validateHttpActionHeaders, d as errorResult, f as redactSecrets, i as SERVER_ID_PATTERN, n as HEADER_NAME_PATTERN, o as isAllowedRemoteUrl, p as toSafeError, r as HTTP_BASE_URL_PATTERN, s as isUrl, t as FORBIDDEN_HEADERS, u as CapletsError } from "./validation-C4tYXw6G.js";
2
+ import { a as isAllowedHttpBaseUrl, c as validateHttpActionHeaders, d as errorResult, f as redactSecrets, i as SERVER_ID_PATTERN, n as HEADER_NAME_PATTERN, o as isAllowedRemoteUrl, p as toSafeError, r as HTTP_BASE_URL_PATTERN, s as isUrl, t as FORBIDDEN_HEADERS, u as CapletsError } from "./validation-GD2x5HW1.js";
3
3
  import { generatedToolInputJsonSchema, generatedToolInputJsonSchemaForCaplet, generatedToolInputSchemaForCaplet, mcpOperations, operations } from "./generated-tool-input-schema.js";
4
4
  import { f as observedOutputShapeKey, i as observeOutputShape, r as normalizedObservableValue, t as usefulOutputSchema, u as FileObservedOutputShapeStore } from "./observed-output-shapes-DuP7mJQf.js";
5
5
  import { createRequire } from "node:module";
@@ -64028,7 +64028,7 @@ var CapletsEngine = class {
64028
64028
  }
64029
64029
  }
64030
64030
  async completeCliWords(words) {
64031
- const { completeCliWords } = await import("./completion-DaYL-XQN.js").then((n) => n.r);
64031
+ const { completeCliWords } = await import("./completion-CFOJucl5.js").then((n) => n.r);
64032
64032
  return await completeCliWords(words, {
64033
64033
  config: this.registry.config,
64034
64034
  managers: {
@@ -81700,13 +81700,16 @@ function isAuthFailure(error) {
81700
81700
  }
81701
81701
  function isPermanentRemoteCredentialsError(error) {
81702
81702
  const candidate = error;
81703
- if (candidate?.projectBindingCode === "remote_credentials_required" || candidate?.projectBindingCode === "remote_auth_failed") return true;
81703
+ if (isPermanentRemoteCredentialsCode(candidate?.projectBindingCode)) return true;
81704
81704
  if (isPlainObject(candidate?.details)) {
81705
81705
  const code = candidate.details.code;
81706
- if (code === "remote_credentials_required" || code === "remote_auth_failed") return true;
81706
+ if (isPermanentRemoteCredentialsCode(code)) return true;
81707
81707
  }
81708
81708
  return isAuthFailure(error);
81709
81709
  }
81710
+ function isPermanentRemoteCredentialsCode(code) {
81711
+ return code === "remote_credentials_required" || code === "remote_credentials_revoked" || code === "remote_auth_failed";
81712
+ }
81710
81713
  //#endregion
81711
81714
  //#region src/cloud-auth/errors.ts
81712
81715
  const SECRET_PATTERN = /(cap_access_[a-z0-9._~+/=-]+|cap_refresh_[a-z0-9._~+/=-]+|one_time_code_[a-z0-9._~+/=-]+|Bearer\s+)[^\s"]*/giu;
@@ -81869,6 +81872,7 @@ const PROJECT_BINDING_ERROR_CODES = [
81869
81872
  "subscription_past_due",
81870
81873
  "email_verification_required",
81871
81874
  "remote_credentials_required",
81875
+ "remote_credentials_revoked",
81872
81876
  "remote_auth_failed"
81873
81877
  ];
81874
81878
  var ProjectBindingError = class extends CapletsError {
@@ -81902,6 +81906,7 @@ function recoveryCommandFor(code) {
81902
81906
  case "workspace_switch_required": return "caplets remote login <cloud-url> --workspace <workspace>";
81903
81907
  case "sync_size_limit_exceeded": return "Add exclusions to .capletsignore or upgrade the workspace plan.";
81904
81908
  case "remote_credentials_required":
81909
+ case "remote_credentials_revoked":
81905
81910
  case "remote_auth_failed": return "caplets remote login <url>";
81906
81911
  case "endpoint_unavailable":
81907
81912
  case "websocket_upgrade_required": return "caplets doctor";
@@ -82079,6 +82084,7 @@ function remoteProfileStatus(input) {
82079
82084
  kind: input.kind,
82080
82085
  key,
82081
82086
  hostUrl,
82087
+ ...input.hostIdentity ? { hostIdentity: input.hostIdentity } : {},
82082
82088
  ...input.workspaceId ? { workspaceId: input.workspaceId } : {},
82083
82089
  ...input.workspaceSlug ? { workspaceSlug: input.workspaceSlug } : {},
82084
82090
  ...input.clientId ? { clientId: input.clientId } : {},
@@ -82136,7 +82142,9 @@ var FileRemoteProfileStore = class {
82136
82142
  kind: "self-hosted",
82137
82143
  hostUrl: normalizeRemoteProfileHostUrl(input.hostUrl)
82138
82144
  });
82139
- return this.statusByKey(key, false);
82145
+ const status = await this.statusByKey(key, false);
82146
+ assertHostIdentityMatches(status, input.hostIdentity);
82147
+ return status;
82140
82148
  }
82141
82149
  async logoutSelfHostedProfile(input) {
82142
82150
  return await this.withMutationLock(async () => {
@@ -82205,7 +82213,7 @@ var FileRemoteProfileStore = class {
82205
82213
  }
82206
82214
  const selected = this.readSelectedWorkspace(hostUrl);
82207
82215
  if (selected) return this.statusByKey(selected.profileKey, true);
82208
- if (this.listProfilesForHost(hostUrl).length > 0) throw new CapletsError("REQUEST_INVALID", "Cloud Remote Profile requires a selected or explicit workspace.");
82216
+ if (this.listProfilesForHost(hostUrl).length > 0) throw cloudWorkspaceAmbiguityError();
82209
82217
  return this.migrateLegacyCloudProfile(hostUrl);
82210
82218
  }
82211
82219
  async listCloudProfileStatuses(hostUrlInput) {
@@ -82233,7 +82241,7 @@ var FileRemoteProfileStore = class {
82233
82241
  let key;
82234
82242
  if (workspace) key = this.listProfilesForHost(hostUrl).find((profile) => profileMatchesWorkspace(profile, workspace))?.key;
82235
82243
  else if (selected) key = selected.profileKey;
82236
- else if (this.listProfilesForHost(hostUrl).length > 0) throw new CapletsError("REQUEST_INVALID", "Cloud Remote Profile requires a selected or explicit workspace.");
82244
+ else if (this.listProfilesForHost(hostUrl).length > 0) throw cloudWorkspaceAmbiguityError();
82237
82245
  if (!key) return false;
82238
82246
  const profile = this.readProfile(key);
82239
82247
  await this.credentials.delete(key);
@@ -82273,7 +82281,7 @@ var FileRemoteProfileStore = class {
82273
82281
  else {
82274
82282
  const selected = this.readSelectedWorkspace(hostUrl);
82275
82283
  if (selected) status = await this.statusByKey(selected.profileKey, true);
82276
- else if (this.listProfilesForHost(hostUrl).length > 0) throw new CapletsError("REQUEST_INVALID", "Cloud Remote Profile requires a selected or explicit workspace.");
82284
+ else if (this.listProfilesForHost(hostUrl).length > 0) throw cloudWorkspaceAmbiguityError();
82277
82285
  }
82278
82286
  if (!status) return void 0;
82279
82287
  const credential = await this.credentials.load(status.key);
@@ -82326,6 +82334,7 @@ var FileRemoteProfileStore = class {
82326
82334
  kind: profile.kind,
82327
82335
  key: profile.key,
82328
82336
  hostUrl: profile.hostUrl,
82337
+ hostIdentity: profile.hostIdentity,
82329
82338
  workspaceId: profile.workspaceId,
82330
82339
  workspaceSlug: profile.workspaceSlug,
82331
82340
  clientId: profile.clientId,
@@ -82346,11 +82355,13 @@ var FileRemoteProfileStore = class {
82346
82355
  });
82347
82356
  const now = (input.now ?? /* @__PURE__ */ new Date()).toISOString();
82348
82357
  const existing = this.readProfile(key);
82358
+ const hostIdentity = input.hostIdentity ?? existing?.hostIdentity;
82349
82359
  const profile = {
82350
82360
  version: 1,
82351
82361
  kind: "self-hosted",
82352
82362
  key,
82353
82363
  hostUrl,
82364
+ ...hostIdentity ? { hostIdentity } : {},
82354
82365
  clientId: input.clientId,
82355
82366
  ...input.clientLabel ? { clientLabel: input.clientLabel } : {},
82356
82367
  createdAt: existing?.createdAt ?? now,
@@ -82523,6 +82534,14 @@ function legacyCredential(credentials) {
82523
82534
  ...credentials.tokenType ? { tokenType: credentials.tokenType } : {}
82524
82535
  };
82525
82536
  }
82537
+ function assertHostIdentityMatches(status, expectedHostIdentity) {
82538
+ if (!status || !expectedHostIdentity || !status.hostIdentity) return;
82539
+ if (status.hostIdentity === expectedHostIdentity) return;
82540
+ throw new CapletsError("AUTH_FAILED", "Remote Profile belongs to a different host identity.");
82541
+ }
82542
+ function cloudWorkspaceAmbiguityError() {
82543
+ return new CapletsError("REQUEST_INVALID", "Cloud Remote Profile requires a selected or explicit workspace.", { reason: "cloud_workspace_ambiguous" });
82544
+ }
82526
82545
  function parseStoredRemoteProfile(value) {
82527
82546
  if (!isRecord$1(value)) return void 0;
82528
82547
  if (value.version !== 1) return void 0;
@@ -82535,6 +82554,7 @@ function parseStoredRemoteProfile(value) {
82535
82554
  kind: value.kind,
82536
82555
  key: value.key,
82537
82556
  hostUrl: value.hostUrl,
82557
+ ...typeof value.hostIdentity === "string" ? { hostIdentity: value.hostIdentity } : {},
82538
82558
  ...typeof value.workspaceId === "string" ? { workspaceId: value.workspaceId } : {},
82539
82559
  ...typeof value.workspaceSlug === "string" ? { workspaceSlug: value.workspaceSlug } : {},
82540
82560
  ...typeof value.clientId === "string" ? { clientId: value.clientId } : {},
@@ -82621,11 +82641,11 @@ async function resolveRemoteSelection(input = {}, env = process.env) {
82621
82641
  const explicitWorkspace = input.workspace ?? (workspaceFromRemoteUrl ? void 0 : env.CAPLETS_REMOTE_WORKSPACE);
82622
82642
  const profileWorkspace = workspaceFromRemoteUrl ?? explicitWorkspace;
82623
82643
  const normalizedRemoteUrl = normalizeRemoteProfileHostUrl(remoteUrl);
82624
- let status = await store.getCloudProfileStatus({
82644
+ let status = await getCloudProfileStatusForSelection(store, {
82625
82645
  hostUrl: normalizedRemoteUrl,
82626
82646
  workspace: profileWorkspace
82627
82647
  });
82628
- if (!status && profileWorkspace) status = await store.getCloudProfileStatus({ hostUrl: normalizedRemoteUrl });
82648
+ if (!status && profileWorkspace) status = await getCloudProfileStatusForSelection(store, { hostUrl: normalizedRemoteUrl });
82629
82649
  let credential = status ? await store.credentials.load(status.key) : void 0;
82630
82650
  if (!status || !credential?.accessToken) throw projectBindingError("cloud_auth_required");
82631
82651
  let credentials = cloudCredentialsFromRemoteProfile(status, credential);
@@ -82703,7 +82723,7 @@ async function refreshSelfHostedCredentials(remoteUrl, refreshToken, options) {
82703
82723
  }
82704
82724
  async function selfHostedRefreshError(remoteUrl, response) {
82705
82725
  const summary = await parseSelfHostedRefreshError(response);
82706
- if (response.status === 401 || summary?.code === "AUTH_FAILED") return remoteLoginRequired(remoteUrl);
82726
+ if (response.status === 401 || summary?.code === "AUTH_FAILED" || summary?.code === "REMOTE_CREDENTIALS_REVOKED") return selfHostedRefreshLooksRevoked(summary) ? remoteLoginRevoked(remoteUrl) : remoteLoginRequired(remoteUrl);
82707
82727
  if (response.status === 503 || summary?.code === "SERVER_UNAVAILABLE") return new CapletsError("SERVER_UNAVAILABLE", summary?.message ?? "Remote credential refresh is temporarily unavailable.");
82708
82728
  return new CapletsError("AUTH_REFRESH_FAILED", summary?.message ?? `Remote credential refresh failed with HTTP ${response.status}.`);
82709
82729
  }
@@ -82749,6 +82769,30 @@ function remoteLoginRequired(remoteUrl) {
82749
82769
  recoveryCommand: `caplets remote login ${normalizeRemoteProfileHostUrl(remoteUrl)}`
82750
82770
  });
82751
82771
  }
82772
+ function remoteLoginRevoked(remoteUrl) {
82773
+ const normalizedUrl = normalizeRemoteProfileHostUrl(remoteUrl);
82774
+ return new ProjectBindingError({
82775
+ code: "remote_credentials_revoked",
82776
+ message: `Remote credentials for ${normalizedUrl} were revoked or rejected. Run Remote Login again and ask the server operator to approve the pending login.`,
82777
+ recoveryCommand: `caplets remote login ${normalizedUrl}`
82778
+ });
82779
+ }
82780
+ function selfHostedRefreshLooksRevoked(summary) {
82781
+ if (summary?.code === "REMOTE_CREDENTIALS_REVOKED") return true;
82782
+ return /revoked|rejected|stale/iu.test(summary?.message ?? "");
82783
+ }
82784
+ async function getCloudProfileStatusForSelection(store, input) {
82785
+ try {
82786
+ return await store.getCloudProfileStatus(input);
82787
+ } catch (error) {
82788
+ if (isCloudWorkspaceAmbiguity(error)) throw projectBindingError("workspace_switch_required", "Cloud Remote Profile requires a selected or explicit workspace.");
82789
+ throw error;
82790
+ }
82791
+ }
82792
+ function isCloudWorkspaceAmbiguity(error) {
82793
+ const details = error instanceof CapletsError ? error.details : void 0;
82794
+ return error instanceof CapletsError && error.code === "REQUEST_INVALID" && typeof details === "object" && details !== null && !Array.isArray(details) && details.reason === "cloud_workspace_ambiguous";
82795
+ }
82752
82796
  async function parseSelfHostedRefreshCredentials(response) {
82753
82797
  const parsed = await response.json();
82754
82798
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new CapletsError("DOWNSTREAM_PROTOCOL_ERROR", "Remote refresh response must be an object.");
@@ -83547,4 +83591,4 @@ function errorMessage(error) {
83547
83591
  return error instanceof Error ? error.message : String(error);
83548
83592
  }
83549
83593
  //#endregion
83550
- export { resolveExposure as $, CallToolRequestSchema as $t, nativeCapletPromptGuidance as A, getLiteralValue as An, startOAuthFlow as At, CodeModeSessionManager as B, __exportAll as Bn, defaultStateBaseDir as Bt, resolveHostedCloudRemote as C, SetLevelRequestSchema as Cn, hasRenderableStructuredContent as Ct, isLoopbackHost as D, isJSONRPCErrorResponse as Dn, runGenericOAuthFlow as Dt, controlUrlForBase as E, isInitializeRequest as En, refreshOAuthTokenBundle as Et, nativeCodeModeToolName as F, isZ4Schema as Fn, DEFAULT_COMPLETION_CACHE_DIR as Ft, CodeModeJournalStore as G, ReadBuffer as Gt, diagnoseCodeModeTypeScript as H, resolveConfigPath as Ht, codeModeRunInputSchema as I, normalizeObjectSchema as In, DEFAULT_OBSERVED_OUTPUT_SHAPE_CACHE_DIR as It, codeModeDeclarationHash as J, assertToolsCallTaskCapability as Jt, CodeModeLogStore as K, serializeMessage as Kt, codeModeRunParamsSchema as L, objectFromShape as Ln, defaultCacheBaseDir as Lt, nativeCapletToolName as M, getParseErrorMessage as Mn, isTokenBundleExpired as Mt, nativeCapletsSystemGuidance as N, getSchemaDescription as Nn, readTokenBundle as Nt, parseServerBaseUrl as O, isJSONRPCRequest as On, runOAuthFlow as Ot, nativeCodeModeToolId as P, isSchemaOptional as Pn, DEFAULT_AUTH_DIR as Pt, CapletsEngine as Q, toJsonSchemaCompat as Qt, emptyCodeModeRunMeta as R, safeParse as Rn, defaultConfigBaseDir as Rt, resolveCapletsRemote as S, SUPPORTED_PROTOCOL_VERSIONS as Sn, loadCapletFilesFromMap as St, appendBasePath as T, assertCompleteRequestResourceTemplate as Tn, markdownStructuredContent as Tt, createCodeModeCapletsApi as U, resolveProjectCapletsRoot as Ut, QuickJsCodeModeSandbox as V, resolveCapletsRoot as Vt, listCodeModeCallableCaplets as W, resolveProjectConfigPath as Wt, generateCodeModeRunToolDescription as X, Protocol as Xt, generateCodeModeDeclarations as Y, AjvJsonSchemaValidator as Yt, minifyCodeModeDeclarationText as Z, mergeCapabilities as Zt, CapletsCloudClient as _, ListRootsResultSchema as _n, FileVaultStore as _t, CloudAuthStore as a, DEFAULT_NEGOTIATED_PROTOCOL_VERSION as an, ServerRegistry as at, isCapletsCloudUrl as b, McpError as bn, discoverCapletFiles as bt, redactedCloudAuthStatus as c, ErrorCode as cn, loadConfig as ct, projectBindingError as d, InitializedNotificationSchema as dn, loadLocalOverlayConfigWithSources as dt, CallToolResultSchema as en, decodeDirectResourceUri as et, projectBindingRecovery as f, JSONRPCMessageSchema as fn, loadProjectConfig as ft, buildProjectSyncManifest as g, ListResourcesRequestSchema as gn, vaultStoreForAuthDir as gt, createSdkRemoteCapletsClient as h, ListResourceTemplatesRequestSchema as hn, vaultResolverForAuthDir as ht, createRemoteProfileStore as i, CreateTaskResultSchema as in, handleServerTool as it, nativeCapletToolDescription as j, getObjectShape as jn, deleteTokenBundle as jt, resolveCapletsServer as k, isJSONRPCResultResponse as kn, startGenericOAuthFlow as kt, PROJECT_BINDING_ERROR_CODES as l, GetPromptRequestSchema as ln, loadConfigWithSources as lt, RemoteNativeCapletsService as m, ListPromptsRequestSchema as mn, vaultBootstrapResolver as mt, resolveRemoteSelection as n, CreateMessageResultSchema as nn, findProjectRoot as nt, cloudAuthPath as o, ElicitResultSchema as on, capabilityDescription as ot, CloudAuthClient as p, LATEST_PROTOCOL_VERSION as pn, parseConfig as pt, redactCodeModeLogText as q, assertClientRequestTaskCapability as qt, cloudCredentialsFromRemoteProfile as r, CreateMessageResultWithToolsSchema as rn, fingerprintProjectRoot as rt, migrateCredentials as s, EmptyResultSchema as sn, GoogleDiscoveryManager as st, createNativeCapletsService as t, CompleteRequestSchema as tn, directResourceUriMatchesTemplate as tt, ProjectBindingError as u, InitializeRequestSchema as un, loadGlobalConfig as ut, resolveNativeCapletsServiceOptions as v, ListToolsRequestSchema as vn, VAULT_MAX_VALUE_BYTES as vt, resolveRemoteMode as w, assertCompleteRequestPrompt as wn, markdownCallToolResultContent as wt, normalizeRemoteProfileHostUrl as x, ReadResourceRequestSchema as xn, validateCapletFile as xt, hostedCloudWorkspaceFromRemoteUrl as y, LoggingLevelSchema as yn, validateVaultKeyName as yt, runCodeMode as z, safeParseAsync as zn, defaultConfigPath as zt };
83594
+ export { resolveExposure as $, mergeCapabilities as $t, nativeCapletPromptGuidance as A, isJSONRPCRequest as An, runOAuthFlow as At, CodeModeSessionManager as B, safeParse as Bn, defaultConfigBaseDir as Bt, resolveHostedCloudRemote as C, ReadResourceRequestSchema as Cn, validateCapletFile as Ct, isLoopbackHost as D, assertCompleteRequestResourceTemplate as Dn, markdownStructuredContent as Dt, controlUrlForBase as E, assertCompleteRequestPrompt as En, markdownCallToolResultContent as Et, nativeCodeModeToolName as F, getSchemaDescription as Fn, readTokenBundle as Ft, CodeModeJournalStore as G, resolveProjectCapletsRoot as Gt, diagnoseCodeModeTypeScript as H, __exportAll as Hn, defaultStateBaseDir as Ht, codeModeRunInputSchema as I, isSchemaOptional as In, DEFAULT_AUTH_DIR as It, codeModeDeclarationHash as J, serializeMessage as Jt, CodeModeLogStore as K, resolveProjectConfigPath as Kt, codeModeRunParamsSchema as L, isZ4Schema as Ln, DEFAULT_COMPLETION_CACHE_DIR as Lt, nativeCapletToolName as M, getLiteralValue as Mn, startOAuthFlow as Mt, nativeCapletsSystemGuidance as N, getObjectShape as Nn, deleteTokenBundle as Nt, parseServerBaseUrl as O, isInitializeRequest as On, refreshOAuthTokenBundle as Ot, nativeCodeModeToolId as P, getParseErrorMessage as Pn, isTokenBundleExpired as Pt, CapletsEngine as Q, Protocol as Qt, emptyCodeModeRunMeta as R, normalizeObjectSchema as Rn, DEFAULT_OBSERVED_OUTPUT_SHAPE_CACHE_DIR as Rt, resolveCapletsRemote as S, McpError as Sn, discoverCapletFiles as St, appendBasePath as T, SetLevelRequestSchema as Tn, hasRenderableStructuredContent as Tt, createCodeModeCapletsApi as U, resolveCapletsRoot as Ut, QuickJsCodeModeSandbox as V, safeParseAsync as Vn, defaultConfigPath as Vt, listCodeModeCallableCaplets as W, resolveConfigPath as Wt, generateCodeModeRunToolDescription as X, assertToolsCallTaskCapability as Xt, generateCodeModeDeclarations as Y, assertClientRequestTaskCapability as Yt, minifyCodeModeDeclarationText as Z, AjvJsonSchemaValidator as Zt, CapletsCloudClient as _, ListResourceTemplatesRequestSchema as _n, FileVaultStore as _t, CloudAuthStore as a, CreateMessageResultWithToolsSchema as an, ServerRegistry as at, isCapletsCloudUrl as b, ListToolsRequestSchema as bn, decryptVaultValue as bt, redactedCloudAuthStatus as c, ElicitResultSchema as cn, loadConfig as ct, projectBindingError as d, GetPromptRequestSchema as dn, loadLocalOverlayConfigWithSources as dt, toJsonSchemaCompat as en, decodeDirectResourceUri as et, projectBindingRecovery as f, InitializeRequestSchema as fn, loadProjectConfig as ft, buildProjectSyncManifest as g, ListPromptsRequestSchema as gn, vaultStoreForAuthDir as gt, createSdkRemoteCapletsClient as h, LATEST_PROTOCOL_VERSION as hn, vaultResolverForAuthDir as ht, createRemoteProfileStore as i, CreateMessageResultSchema as in, handleServerTool as it, nativeCapletToolDescription as j, isJSONRPCResultResponse as jn, startGenericOAuthFlow as jt, resolveCapletsServer as k, isJSONRPCErrorResponse as kn, runGenericOAuthFlow as kt, PROJECT_BINDING_ERROR_CODES as l, EmptyResultSchema as ln, loadConfigWithSources as lt, RemoteNativeCapletsService as m, JSONRPCMessageSchema as mn, vaultBootstrapResolver as mt, resolveRemoteSelection as n, CallToolResultSchema as nn, findProjectRoot as nt, cloudAuthPath as o, CreateTaskResultSchema as on, capabilityDescription as ot, CloudAuthClient as p, InitializedNotificationSchema as pn, parseConfig as pt, redactCodeModeLogText as q, ReadBuffer as qt, cloudCredentialsFromRemoteProfile as r, CompleteRequestSchema as rn, fingerprintProjectRoot as rt, migrateCredentials as s, DEFAULT_NEGOTIATED_PROTOCOL_VERSION as sn, GoogleDiscoveryManager as st, createNativeCapletsService as t, CallToolRequestSchema as tn, directResourceUriMatchesTemplate as tt, ProjectBindingError as u, ErrorCode as un, loadGlobalConfig as ut, resolveNativeCapletsServiceOptions as v, ListResourcesRequestSchema as vn, VAULT_MAX_VALUE_BYTES as vt, resolveRemoteMode as w, SUPPORTED_PROTOCOL_VERSIONS as wn, loadCapletFilesFromMap as wt, normalizeRemoteProfileHostUrl as x, LoggingLevelSchema as xn, encryptVaultValue as xt, hostedCloudWorkspaceFromRemoteUrl as y, ListRootsResultSchema as yn, validateVaultKeyName as yt, runCodeMode as z, objectFromShape as zn, defaultCacheBaseDir as zt };
@@ -35,6 +35,7 @@ const CAPLETS_ERROR_CODES = [
35
35
  "TOOL_CALL_TIMEOUT",
36
36
  "AUTH_REQUIRED",
37
37
  "AUTH_FAILED",
38
+ "REMOTE_CREDENTIALS_REVOKED",
38
39
  "AUTH_REFRESH_FAILED",
39
40
  "DOWNSTREAM_PROTOCOL_ERROR",
40
41
  "DOWNSTREAM_TOOL_ERROR",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caplets/core",
3
- "version": "0.26.0",
3
+ "version": "0.26.1",
4
4
  "description": "Core runtime library for Caplets Code Mode and progressive disclosure gateways.",
5
5
  "keywords": [
6
6
  "caplets",