@hasna/skills 0.5.1 → 0.5.3
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 +196 -1
- package/bin/index.js +1339 -619
- package/bin/mcp.js +28222 -26875
- package/bin/migrate.js +172 -1
- package/bin/server.js +187 -1
- package/bin/worker.js +225 -40
- package/dist/cli/commands/invitation-recovery.d.ts +2 -0
- package/dist/cli/commands/invitation-verification.d.ts +8 -0
- package/dist/cli/commands/workspace-invitations.d.ts +2 -0
- package/dist/cli/commands/workspace-leave.d.ts +2 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +1075 -163
- package/dist/lib/invitation-customer-action.d.ts +14 -0
- package/dist/lib/invitation-recovery-target.d.ts +5 -0
- package/dist/lib/remote-auth.d.ts +15 -0
- package/dist/lib/remote-client.d.ts +15 -0
- package/dist/lib/remote-invitation-recovery.d.ts +62 -0
- package/dist/lib/remote-invitations.d.ts +128 -0
- package/dist/lib/remote-workspace-leave.d.ts +52 -0
- package/dist/lib/skill-bundle.d.ts +54 -1
- package/dist/lib/skill-entry-path.d.ts +6 -0
- package/dist/lib/skill-hash.d.ts +33 -0
- package/dist/mcp/index.d.ts +0 -1
- package/dist/mcp/invitation-recovery.d.ts +2 -0
- package/dist/mcp/remote-invitation-tools.d.ts +2 -0
- package/dist/sdk/index.d.ts +5 -0
- package/dist/sdk/index.js +1020 -103
- package/dist/sdk/registry.d.ts +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RemoteSkillsAuthClient } from "./remote-auth.js";
|
|
2
|
+
import { type RemoteWorkspaceContext } from "./remote-workspace-selection.js";
|
|
3
|
+
import { type InvitationAction, type InvitationInputs, type InvitationResults } from "./remote-invitations.js";
|
|
4
|
+
/** A saved profile constrains explicit input; it never silently supplies another target. */
|
|
5
|
+
export declare function invitationProfileContext(userId: string, membershipId: string, profile?: RemoteWorkspaceContext): Readonly<{
|
|
6
|
+
userId: string;
|
|
7
|
+
membershipId: string;
|
|
8
|
+
}>;
|
|
9
|
+
/** Surface adapters share this dispatch; the remote client owns validation and transport. */
|
|
10
|
+
export declare function invokeFreshInvitation<A extends InvitationAction>(client: RemoteSkillsAuthClient, email: string, code: string, context: RemoteWorkspaceContext, action: A, input: InvitationInputs[A]): Promise<InvitationResults[A]>;
|
|
11
|
+
export declare function invitationCustomerError(error: unknown): {
|
|
12
|
+
code: string;
|
|
13
|
+
error: string;
|
|
14
|
+
};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { type RequestInvitationEmailChallenge, type AcceptInvitationEmailChallenge } from "./remote-invitation-recovery.js";
|
|
2
|
+
import { type ListRemoteWorkspaceInvitations, type IssueRemoteWorkspaceInvitation, type ResendRemoteWorkspaceInvitation, type RevokeRemoteWorkspaceInvitation, type AcceptRemoteWorkspaceInvitation } from "./remote-invitations.js";
|
|
3
|
+
import { type LeaveRemoteWorkspace } from "./remote-workspace-leave.js";
|
|
1
4
|
import { type RemoteWorkspaceContext, type RemoteWorkspaceSession, type RemoteAccountWorkspaceDiscovery } from "./remote-workspace-selection.js";
|
|
2
5
|
import { type RemoteWorkspaceMembersOptions } from "./remote-workspace.js";
|
|
3
6
|
import { type SetRemoteWorkspaceMemberRole, type RemoveRemoteWorkspaceMember } from "./remote-workspace.js";
|
|
@@ -20,6 +23,8 @@ export declare class HostedApiError extends Error {
|
|
|
20
23
|
export declare class RemoteSkillsAuthClient {
|
|
21
24
|
readonly apiOrigin: string;
|
|
22
25
|
constructor(apiUrl: string);
|
|
26
|
+
requestInvitationEmailChallenge(input: RequestInvitationEmailChallenge): Promise<import("./remote-invitation-recovery.js").RemoteInvitationEmailChallenge>;
|
|
27
|
+
acceptInvitationEmailChallenge(input: AcceptInvitationEmailChallenge): Promise<import("./remote-invitation-recovery.js").RemoteInvitationEmailAcceptance>;
|
|
23
28
|
requestCode(email: string): Promise<any>;
|
|
24
29
|
verifyCode(email: string, code: string): Promise<any>;
|
|
25
30
|
startDevice(): Promise<any>;
|
|
@@ -30,6 +35,14 @@ export declare class RemoteSkillsAuthClient {
|
|
|
30
35
|
/** Contains a secret session token. Selection never creates or stores an API key. */
|
|
31
36
|
switchWorkspace(email: string, code: string, context: RemoteWorkspaceContext): Promise<RemoteWorkspaceSession>;
|
|
32
37
|
private workspaceLogin;
|
|
38
|
+
listWorkspaceInvitations(email: string, code: string, context: RemoteWorkspaceContext, options?: ListRemoteWorkspaceInvitations): Promise<import("./remote-invitations.js").RemoteWorkspaceInvitationsPage>;
|
|
39
|
+
getWorkspaceInvitation(email: string, code: string, context: RemoteWorkspaceContext, invitationId: string): Promise<{
|
|
40
|
+
invitation: import("./remote-invitations.js").RemoteWorkspaceInvitation;
|
|
41
|
+
}>;
|
|
42
|
+
issueWorkspaceInvitation(email: string, code: string, context: RemoteWorkspaceContext, input: IssueRemoteWorkspaceInvitation): Promise<import("./remote-invitations.js").RemoteWorkspaceInvitationResult>;
|
|
43
|
+
resendWorkspaceInvitation(email: string, code: string, context: RemoteWorkspaceContext, invitationId: string, input: ResendRemoteWorkspaceInvitation): Promise<import("./remote-invitations.js").RemoteWorkspaceInvitationResult>;
|
|
44
|
+
revokeWorkspaceInvitation(email: string, code: string, context: RemoteWorkspaceContext, invitationId: string, input: RevokeRemoteWorkspaceInvitation): Promise<import("./remote-invitations.js").RemoteWorkspaceInvitationResult>;
|
|
45
|
+
acceptWorkspaceInvitation(email: string, code: string, context: RemoteWorkspaceContext, invitationId: string, input: AcceptRemoteWorkspaceInvitation): Promise<import("./remote-invitations.js").RemoteWorkspaceInvitationAcceptance>;
|
|
33
46
|
createApiKey(email: string, code: string, name: string, scopes?: string[], context?: RemoteWorkspaceContext): Promise<{
|
|
34
47
|
[field: string]: unknown;
|
|
35
48
|
key: string;
|
|
@@ -46,6 +59,8 @@ export declare class RemoteSkillsAuthClient {
|
|
|
46
59
|
/** Fresh owner/admin session; explicit context survives default-workspace OTP selection. */
|
|
47
60
|
listWorkspaceMembers(email: string, code: string, options?: RemoteWorkspaceMembersOptions, context?: RemoteWorkspaceContext): Promise<import("./remote-workspace.js").RemoteWorkspaceMembersPage>;
|
|
48
61
|
setWorkspaceMemberRole(email: string, code: string, membershipId: string, input: SetRemoteWorkspaceMemberRole, context?: RemoteWorkspaceContext): Promise<import("./remote-workspace.js").RemoteWorkspaceMemberRoleResult>;
|
|
62
|
+
/** Fresh verification binds the exact observed incarnation before a single confirmed leave. */
|
|
63
|
+
leaveWorkspace(email: string, code: string, context: RemoteWorkspaceContext, input: LeaveRemoteWorkspace): Promise<import("./remote-workspace-leave.js").RemoteWorkspaceLeaveResult>;
|
|
49
64
|
removeWorkspaceMember(email: string, code: string, membershipId: string, input: RemoveRemoteWorkspaceMember, context?: RemoteWorkspaceContext): Promise<import("./remote-workspace.js").RemoteWorkspaceMemberRemovalResult>;
|
|
50
65
|
/** Common auth transport used by CLI login, preserving the selected instance through awaits. */
|
|
51
66
|
request(path: string, options?: RequestInit): Promise<any>;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type ListRemoteWorkspaceInvitations, type IssueRemoteWorkspaceInvitation, type ResendRemoteWorkspaceInvitation, type RevokeRemoteWorkspaceInvitation, type AcceptRemoteWorkspaceInvitation } from "./remote-invitations.js";
|
|
2
|
+
import { type LeaveRemoteWorkspace, type RemoteWorkspaceLeaveResult } from "./remote-workspace-leave.js";
|
|
1
3
|
import { type RemoteWorkspaceContext, type RemoteAccountWorkspaces, type RemoteWorkspaceSession, type RemoteWorkspaceSelectionErrorCode } from "./remote-workspace-selection.js";
|
|
2
4
|
import { type RemoteWorkspaceMembersOptions, type RemoteWorkspaceMembersPage } from "./remote-workspace.js";
|
|
3
5
|
import { type RemoteWorkspaceMemberErrorCode, type SetRemoteWorkspaceMemberRole, type RemoveRemoteWorkspaceMember, type RemoteWorkspaceMemberRoleResult, type RemoteWorkspaceMemberRemovalResult } from "./remote-workspace.js";
|
|
@@ -145,6 +147,19 @@ export declare class RemoteSkillsClient {
|
|
|
145
147
|
/** Removes only this incarnation. A successful tombstone replay is returned unchanged. */
|
|
146
148
|
removeWorkspaceMember(membershipId: string, input: RemoveRemoteWorkspaceMember): Promise<RemoteWorkspaceMemberRemovalResult>;
|
|
147
149
|
private requestWorkspaceMember;
|
|
150
|
+
/** Leave only the explicitly confirmed current incarnation, once. No credential writes or retries. */
|
|
151
|
+
leaveWorkspace(context: RemoteWorkspaceContext, input: LeaveRemoteWorkspace): Promise<RemoteWorkspaceLeaveResult>;
|
|
152
|
+
listWorkspaceInvitations(context: RemoteWorkspaceContext, options?: ListRemoteWorkspaceInvitations): Promise<import("./remote-invitations.js").RemoteWorkspaceInvitationsPage>;
|
|
153
|
+
getWorkspaceInvitation(context: RemoteWorkspaceContext, invitationId: string): Promise<{
|
|
154
|
+
invitation: import("./remote-invitations.js").RemoteWorkspaceInvitation;
|
|
155
|
+
}>;
|
|
156
|
+
issueWorkspaceInvitation(context: RemoteWorkspaceContext, input: IssueRemoteWorkspaceInvitation): Promise<import("./remote-invitations.js").RemoteWorkspaceInvitationResult>;
|
|
157
|
+
resendWorkspaceInvitation(context: RemoteWorkspaceContext, invitationId: string, input: ResendRemoteWorkspaceInvitation): Promise<import("./remote-invitations.js").RemoteWorkspaceInvitationResult>;
|
|
158
|
+
revokeWorkspaceInvitation(context: RemoteWorkspaceContext, invitationId: string, input: RevokeRemoteWorkspaceInvitation): Promise<import("./remote-invitations.js").RemoteWorkspaceInvitationResult>;
|
|
159
|
+
acceptWorkspaceInvitation(context: RemoteWorkspaceContext, invitationId: string, input: AcceptRemoteWorkspaceInvitation): Promise<import("./remote-invitations.js").RemoteWorkspaceInvitationAcceptance>;
|
|
160
|
+
/** One bounded operation, bound to the observed current incarnation. No retries,
|
|
161
|
+
* key/session persistence or post-acceptance selection of another workspace. */
|
|
162
|
+
private requestWorkspaceInvitation;
|
|
148
163
|
listApiKeys(): Promise<Record<string, unknown>[]>;
|
|
149
164
|
createApiKey(name: string, scopes?: string[]): Promise<{
|
|
150
165
|
key: string;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export type RequestInvitationEmailChallenge = Readonly<{
|
|
2
|
+
invitationId: string;
|
|
3
|
+
token: string;
|
|
4
|
+
challengeId: string;
|
|
5
|
+
confirm: true;
|
|
6
|
+
}>;
|
|
7
|
+
export type AcceptInvitationEmailChallenge = RequestInvitationEmailChallenge & Readonly<{
|
|
8
|
+
code: string;
|
|
9
|
+
}>;
|
|
10
|
+
export type RemoteInvitationEmailChallenge = {
|
|
11
|
+
challengeId: string;
|
|
12
|
+
message: string;
|
|
13
|
+
expiresIn: 600;
|
|
14
|
+
};
|
|
15
|
+
export type RemoteInvitationEmailAcceptance = {
|
|
16
|
+
organizationId: string;
|
|
17
|
+
membershipId: string;
|
|
18
|
+
accepted: true;
|
|
19
|
+
changed: true;
|
|
20
|
+
signInRequired: true;
|
|
21
|
+
};
|
|
22
|
+
export declare class InvitationEmailInputError extends Error {
|
|
23
|
+
readonly code = "INVITATION_EMAIL_INPUT_INVALID";
|
|
24
|
+
constructor();
|
|
25
|
+
}
|
|
26
|
+
declare const refusals: {
|
|
27
|
+
readonly INVALID_REQUEST: readonly [400, "Invitation recovery parameters were refused."];
|
|
28
|
+
readonly ORIGIN_REQUIRED: readonly [403, "Invitation recovery requires the configured site origin."];
|
|
29
|
+
readonly INVITATION_PROOF_UNAVAILABLE: readonly [401, "Invitation proof is unavailable. Sign in or explicitly request another recovery code."];
|
|
30
|
+
readonly RATE_LIMITED: readonly [429, "Invitation verification is rate limited. Wait before another deliberate action."];
|
|
31
|
+
readonly INVITATION_BUSY: readonly [503, "Invitation is busy. Sign in to check membership before another deliberate action."];
|
|
32
|
+
readonly INVITATION_DELIVERY_UNAVAILABLE: readonly [503, "Invitation recovery is unavailable on this service."];
|
|
33
|
+
};
|
|
34
|
+
export type RemoteInvitationEmailErrorCode = keyof typeof refusals;
|
|
35
|
+
export declare class RemoteInvitationEmailError extends Error {
|
|
36
|
+
readonly code: RemoteInvitationEmailErrorCode;
|
|
37
|
+
readonly status: number;
|
|
38
|
+
constructor(code: RemoteInvitationEmailErrorCode);
|
|
39
|
+
}
|
|
40
|
+
export declare class RemoteInvitationEmailUnconfirmedError extends Error {
|
|
41
|
+
readonly action: "challenge" | "accept";
|
|
42
|
+
readonly code = "INVITATION_EMAIL_UNCONFIRMED";
|
|
43
|
+
constructor(action: "challenge" | "accept");
|
|
44
|
+
}
|
|
45
|
+
export declare function invitationEmailIds(invitationId: unknown, challengeId: unknown): {
|
|
46
|
+
invitationId: string;
|
|
47
|
+
challengeId: string;
|
|
48
|
+
};
|
|
49
|
+
export declare function invitationEmailInput<A extends "challenge" | "accept">(action: A, input: A extends "accept" ? AcceptInvitationEmailChallenge : RequestInvitationEmailChallenge): {
|
|
50
|
+
code?: string | undefined;
|
|
51
|
+
token: string;
|
|
52
|
+
confirm: true;
|
|
53
|
+
invitationId: string;
|
|
54
|
+
challengeId: string;
|
|
55
|
+
};
|
|
56
|
+
/** Explicit anonymous protocol: no auth resolver, headers, session creation or persistence. */
|
|
57
|
+
export declare function requestInvitationEmail<A extends "challenge" | "accept">(origin: string, action: A, input: A extends "accept" ? AcceptInvitationEmailChallenge : RequestInvitationEmailChallenge): Promise<A extends "accept" ? RemoteInvitationEmailAcceptance : RemoteInvitationEmailChallenge>;
|
|
58
|
+
export declare function invitationEmailCustomerError(error: unknown): {
|
|
59
|
+
code: string;
|
|
60
|
+
error: string;
|
|
61
|
+
};
|
|
62
|
+
export {};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { RemoteCustomerRole } from "./remote-profile.js";
|
|
2
|
+
export type RemoteWorkspaceInvitation = {
|
|
3
|
+
id: string;
|
|
4
|
+
organizationId: string;
|
|
5
|
+
email: string;
|
|
6
|
+
role: RemoteCustomerRole;
|
|
7
|
+
generation: number;
|
|
8
|
+
status: "pending" | "expired" | "accepted" | "revoked";
|
|
9
|
+
expiresAt: string;
|
|
10
|
+
createdAt: string;
|
|
11
|
+
delivery: {
|
|
12
|
+
state: "queued" | "sending" | "uncertain" | "provider_accepted" | "failed" | "cancelled";
|
|
13
|
+
attempts: number;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export type RemoteWorkspaceInvitationsPage = {
|
|
17
|
+
organizationId: string;
|
|
18
|
+
invitations: RemoteWorkspaceInvitation[];
|
|
19
|
+
nextCursor: string | null;
|
|
20
|
+
};
|
|
21
|
+
export type RemoteWorkspaceInvitationResult = {
|
|
22
|
+
invitation: RemoteWorkspaceInvitation;
|
|
23
|
+
changed: boolean;
|
|
24
|
+
};
|
|
25
|
+
export type RemoteWorkspaceInvitationAcceptance = {
|
|
26
|
+
organizationId: string;
|
|
27
|
+
membershipId: string;
|
|
28
|
+
accepted: true;
|
|
29
|
+
changed: boolean;
|
|
30
|
+
};
|
|
31
|
+
export type ListRemoteWorkspaceInvitations = Readonly<{
|
|
32
|
+
after?: string;
|
|
33
|
+
}>;
|
|
34
|
+
export type IssueRemoteWorkspaceInvitation = Readonly<{
|
|
35
|
+
email: string;
|
|
36
|
+
role: RemoteCustomerRole;
|
|
37
|
+
idempotencyKey: string;
|
|
38
|
+
confirm: true;
|
|
39
|
+
}>;
|
|
40
|
+
export type ResendRemoteWorkspaceInvitation = Readonly<{
|
|
41
|
+
expectedGeneration: number;
|
|
42
|
+
idempotencyKey: string;
|
|
43
|
+
confirm: true;
|
|
44
|
+
}>;
|
|
45
|
+
export type RevokeRemoteWorkspaceInvitation = Readonly<{
|
|
46
|
+
expectedGeneration: number;
|
|
47
|
+
confirm: true;
|
|
48
|
+
}>;
|
|
49
|
+
/** Secret input, never returned or persisted by the client. Acceptance does not select the new membership. */
|
|
50
|
+
export type AcceptRemoteWorkspaceInvitation = Readonly<{
|
|
51
|
+
token: string;
|
|
52
|
+
confirm: true;
|
|
53
|
+
}>;
|
|
54
|
+
export declare class WorkspaceInvitationInputError extends Error {
|
|
55
|
+
readonly code = "INVITATION_INPUT_INVALID";
|
|
56
|
+
constructor();
|
|
57
|
+
}
|
|
58
|
+
export declare const invitationFailures: {
|
|
59
|
+
readonly INVALID_REQUEST: readonly [400, "Invitation parameters were refused."];
|
|
60
|
+
readonly ACCOUNT_UNAVAILABLE: readonly [403, "Account is unavailable."];
|
|
61
|
+
readonly INTERACTIVE_SESSION_REQUIRED: readonly [403, "Fresh interactive sign-in is required."];
|
|
62
|
+
readonly WORKSPACE_ADMIN_REQUIRED: readonly [403, "A current workspace owner or admin is required."];
|
|
63
|
+
readonly INVITATION_FORBIDDEN: readonly [403, "Your current role cannot manage this invitation."];
|
|
64
|
+
readonly INVITATION_UNAVAILABLE: readonly [404, "Invitation is unavailable for this account."];
|
|
65
|
+
readonly INVITATION_CHANGED: readonly [409, "Invitation changed. Read its current generation before another action."];
|
|
66
|
+
readonly INVITATION_EXISTS: readonly [409, "A pending invitation already exists. Read current invitations."];
|
|
67
|
+
readonly ALREADY_MEMBER: readonly [409, "An active membership already exists. An invitation cannot change its role."];
|
|
68
|
+
readonly IDEMPOTENCY_CONFLICT: readonly [409, "This request key was used for different invitation parameters. Reconcile the original request."];
|
|
69
|
+
readonly INVITATION_LIMIT: readonly [429, "Invitation limit reached. Wait before issuing or resending."];
|
|
70
|
+
readonly INVITATION_BUSY: readonly [503, "Invitation is busy. Read its state before another action."];
|
|
71
|
+
readonly INVITATION_DELIVERY_UNAVAILABLE: readonly [503, "Invitation email delivery is unavailable."];
|
|
72
|
+
};
|
|
73
|
+
export type RemoteWorkspaceInvitationErrorCode = keyof typeof invitationFailures;
|
|
74
|
+
export declare class RemoteWorkspaceInvitationError extends Error {
|
|
75
|
+
readonly code: RemoteWorkspaceInvitationErrorCode;
|
|
76
|
+
readonly status: number;
|
|
77
|
+
constructor(code: RemoteWorkspaceInvitationErrorCode);
|
|
78
|
+
}
|
|
79
|
+
export declare class RemoteWorkspaceInvitationUnconfirmedError extends Error {
|
|
80
|
+
readonly code = "INVITATION_UNCONFIRMED";
|
|
81
|
+
constructor();
|
|
82
|
+
}
|
|
83
|
+
export declare class RemoteWorkspaceInvitationReadError extends Error {
|
|
84
|
+
readonly code = "INVITATION_READ_FAILED";
|
|
85
|
+
constructor();
|
|
86
|
+
}
|
|
87
|
+
export declare function invitationFailure(value: unknown, status: number): "INVALID_REQUEST" | "ACCOUNT_UNAVAILABLE" | "INTERACTIVE_SESSION_REQUIRED" | "WORKSPACE_ADMIN_REQUIRED" | "INVITATION_FORBIDDEN" | "INVITATION_UNAVAILABLE" | "INVITATION_CHANGED" | "INVITATION_EXISTS" | "ALREADY_MEMBER" | "IDEMPOTENCY_CONFLICT" | "INVITATION_LIMIT" | "INVITATION_BUSY" | "INVITATION_DELIVERY_UNAVAILABLE" | null;
|
|
88
|
+
export type InvitationAction = "list" | "get" | "issue" | "resend" | "revoke" | "accept";
|
|
89
|
+
export type InvitationInputs = {
|
|
90
|
+
list: ListRemoteWorkspaceInvitations;
|
|
91
|
+
get: Readonly<{
|
|
92
|
+
invitationId: string;
|
|
93
|
+
}>;
|
|
94
|
+
issue: IssueRemoteWorkspaceInvitation;
|
|
95
|
+
resend: ResendRemoteWorkspaceInvitation & Readonly<{
|
|
96
|
+
invitationId: string;
|
|
97
|
+
}>;
|
|
98
|
+
revoke: RevokeRemoteWorkspaceInvitation & Readonly<{
|
|
99
|
+
invitationId: string;
|
|
100
|
+
}>;
|
|
101
|
+
accept: AcceptRemoteWorkspaceInvitation & Readonly<{
|
|
102
|
+
invitationId: string;
|
|
103
|
+
}>;
|
|
104
|
+
};
|
|
105
|
+
export type InvitationResults = {
|
|
106
|
+
list: RemoteWorkspaceInvitationsPage;
|
|
107
|
+
get: {
|
|
108
|
+
invitation: RemoteWorkspaceInvitation;
|
|
109
|
+
};
|
|
110
|
+
issue: RemoteWorkspaceInvitationResult;
|
|
111
|
+
resend: RemoteWorkspaceInvitationResult;
|
|
112
|
+
revoke: RemoteWorkspaceInvitationResult;
|
|
113
|
+
accept: RemoteWorkspaceInvitationAcceptance;
|
|
114
|
+
};
|
|
115
|
+
export declare function invitationId(value: unknown): string;
|
|
116
|
+
/** Capture and validate all caller values before authentication or other awaits. */
|
|
117
|
+
export declare function invitationInput<A extends InvitationAction>(action: A, input: InvitationInputs[A]): InvitationInputs[A];
|
|
118
|
+
export declare function invitationRequest<A extends InvitationAction>(action: A, input: InvitationInputs[A]): {
|
|
119
|
+
path: string;
|
|
120
|
+
method: string;
|
|
121
|
+
body?: undefined;
|
|
122
|
+
} | {
|
|
123
|
+
path: string;
|
|
124
|
+
method: string;
|
|
125
|
+
body: string;
|
|
126
|
+
};
|
|
127
|
+
/** Project only validated contract fields; never surface arbitrary response metadata. */
|
|
128
|
+
export declare function parseInvitationResult<A extends InvitationAction>(action: A, value: unknown, input: InvitationInputs[A], organizationId: string): InvitationResults[A];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type RemoteWorkspaceContext } from "./remote-workspace-selection.js";
|
|
2
|
+
import type { RemoteCustomerRole } from "./remote-profile.js";
|
|
3
|
+
export type LeaveRemoteWorkspace = Readonly<{
|
|
4
|
+
expectedRole: RemoteCustomerRole;
|
|
5
|
+
confirm: true;
|
|
6
|
+
}>;
|
|
7
|
+
export type RemoteWorkspaceLeaveResult = {
|
|
8
|
+
organizationId: string;
|
|
9
|
+
membershipId: string;
|
|
10
|
+
removed: true;
|
|
11
|
+
signInRequired: true;
|
|
12
|
+
};
|
|
13
|
+
export declare class WorkspaceLeaveInputError extends Error {
|
|
14
|
+
constructor();
|
|
15
|
+
}
|
|
16
|
+
export declare function workspaceLeaveInput(context: RemoteWorkspaceContext, input: LeaveRemoteWorkspace): {
|
|
17
|
+
context: Readonly<{
|
|
18
|
+
userId: string;
|
|
19
|
+
membershipId: string;
|
|
20
|
+
}>;
|
|
21
|
+
input: {
|
|
22
|
+
expectedRole: RemoteCustomerRole;
|
|
23
|
+
confirm: true;
|
|
24
|
+
};
|
|
25
|
+
body: {
|
|
26
|
+
membershipId: string;
|
|
27
|
+
expectedRole: RemoteCustomerRole;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export declare const workspaceLeaveFailures: {
|
|
31
|
+
readonly INVALID_REQUEST: readonly [400, "Provide the exact current membership and expected role."];
|
|
32
|
+
readonly ACCOUNT_UNAVAILABLE: readonly [403, "Account is unavailable."];
|
|
33
|
+
readonly INTERACTIVE_SESSION_REQUIRED: readonly [403, "Fresh interactive sign-in is required to leave a workspace."];
|
|
34
|
+
readonly MEMBERSHIP_ROLE_CHANGED: readonly [409, "Your role changed. Sign in and inspect the workspace before leaving."];
|
|
35
|
+
readonly LAST_OWNER_REQUIRED: readonly [409, "The workspace must retain another active owner."];
|
|
36
|
+
readonly LAST_WORKSPACE_REQUIRED: readonly [409, "Another available workspace is required before leaving."];
|
|
37
|
+
readonly MEMBERSHIP_BUSY: readonly [503, "Membership is busy. Inspect the workspace before another leave action."];
|
|
38
|
+
};
|
|
39
|
+
export type RemoteWorkspaceLeaveErrorCode = keyof typeof workspaceLeaveFailures;
|
|
40
|
+
export declare class RemoteWorkspaceLeaveError extends Error {
|
|
41
|
+
readonly code: RemoteWorkspaceLeaveErrorCode;
|
|
42
|
+
readonly status: number;
|
|
43
|
+
constructor(code: RemoteWorkspaceLeaveErrorCode);
|
|
44
|
+
}
|
|
45
|
+
export declare class RemoteWorkspaceLeaveUnconfirmedError extends Error {
|
|
46
|
+
readonly code = "WORKSPACE_LEAVE_UNCONFIRMED";
|
|
47
|
+
constructor();
|
|
48
|
+
}
|
|
49
|
+
export declare function workspaceLeaveFailure(value: unknown, status: number): RemoteWorkspaceLeaveErrorCode | null;
|
|
50
|
+
export declare function parseWorkspaceLeaveResult(value: unknown, membershipId: string, organizationId: string): RemoteWorkspaceLeaveResult;
|
|
51
|
+
/** A configured profile may constrain an explicit leave, never retarget it. */
|
|
52
|
+
export declare function workspaceLeaveProfileContext(membershipId: string, userId: string | undefined, profile?: RemoteWorkspaceContext): RemoteWorkspaceContext;
|
|
@@ -33,5 +33,58 @@ export declare function sha256Hex(bytes: Uint8Array): string;
|
|
|
33
33
|
/** Collect the files a bundle would contain, in archive order. */
|
|
34
34
|
export declare function collectSkillBundleEntries(dir: string): SkillBundleEntry[];
|
|
35
35
|
export declare function packSkillBundle(dir: string, options?: PackSkillBundleOptions): PackedSkillBundle;
|
|
36
|
-
/**
|
|
36
|
+
/** Legacy synchronous reader for trusted inputs. Unbounded; use inspectSkillBundle for uploads. */
|
|
37
37
|
export declare function unpackSkillBundle(bundle: Uint8Array): SkillBundleEntry[];
|
|
38
|
+
/** Hard ceilings. Callers may tighten these limits, never disable or raise them. */
|
|
39
|
+
export interface SkillBundleInspectionLimits {
|
|
40
|
+
compressedBytes: number;
|
|
41
|
+
decompressedBytes: number;
|
|
42
|
+
entries: number;
|
|
43
|
+
fileBytes: number;
|
|
44
|
+
pathBytes: number;
|
|
45
|
+
timeoutMs: number;
|
|
46
|
+
}
|
|
47
|
+
export declare const SKILL_BUNDLE_INSPECTION_LIMITS: Readonly<SkillBundleInspectionLimits>;
|
|
48
|
+
export interface InspectSkillBundleOptions {
|
|
49
|
+
limits?: Partial<SkillBundleInspectionLimits>;
|
|
50
|
+
signal?: AbortSignal;
|
|
51
|
+
}
|
|
52
|
+
export interface InspectedSkillBundle {
|
|
53
|
+
/** Each body has its own buffer. No path has been written or executed. */
|
|
54
|
+
entries: SkillBundleEntry[];
|
|
55
|
+
/** Hash of the complete owned compressed snapshot, not of extracted files. */
|
|
56
|
+
sha256: string;
|
|
57
|
+
compressedByteSize: number;
|
|
58
|
+
/** Includes headers, body padding, terminators and trailing zero padding. */
|
|
59
|
+
decompressedByteSize: number;
|
|
60
|
+
unpackedByteSize: number;
|
|
61
|
+
fileCount: number;
|
|
62
|
+
}
|
|
63
|
+
export type SkillBundleInspectionErrorCode = "BUNDLE_INVALID" | "BUNDLE_LIMIT" | "BUNDLE_ABORTED" | "BUNDLE_TIMEOUT";
|
|
64
|
+
export declare class SkillBundleInspectionError extends Error {
|
|
65
|
+
readonly code: SkillBundleInspectionErrorCode;
|
|
66
|
+
constructor(code: SkillBundleInspectionErrorCode, message: string);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Inspect a bounded gzipped ustar bundle without filesystem writes or execution.
|
|
70
|
+
* Resolves only after the entire gzip stream and tar structure validate. Returned
|
|
71
|
+
* entries are NOT permission to execute code or safely extract through existing
|
|
72
|
+
* filesystem symlinks; consumers still own storage, authorization and isolation.
|
|
73
|
+
*
|
|
74
|
+
* Only regular files, canonical relative slash paths (100 UTF-8 bytes maximum),
|
|
75
|
+
* no prefix/extension/link records, and modes without special bits are supported.
|
|
76
|
+
* Paths are unique under NFC + lowercase and cannot collide with a file ancestor.
|
|
77
|
+
* Noncanonical dot/empty/backslash segments are refused, not silently rewritten.
|
|
78
|
+
* Two zero tar blocks are required, followed only by complete zero padding blocks.
|
|
79
|
+
* Gzip members are decoded as one stream: an empty extra member is harmless, but
|
|
80
|
+
* a second nonempty archive after the tar terminator is rejected.
|
|
81
|
+
*
|
|
82
|
+
* The decoder has bounded stream buffers; decompressed bytes are counted before
|
|
83
|
+
* parsing or retaining each chunk, so expansion is stopped during decompression.
|
|
84
|
+
* Memory is bounded by the compressed snapshot, accepted file bodies, and stream
|
|
85
|
+
* buffers. The deadline covers copying, hashing, decoding and parsing, with both
|
|
86
|
+
* a timer and monotonic checks. Decoding yields to timers every 256 KiB so Bun's
|
|
87
|
+
* stream microtasks cannot starve a caller's scheduled abort. No partial entries
|
|
88
|
+
* escape on any failure.
|
|
89
|
+
*/
|
|
90
|
+
export declare function inspectSkillBundle(bundle: Uint8Array, options?: InspectSkillBundleOptions): Promise<InspectedSkillBundle>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Internal shared path policy for ordinary in-memory regular-file entries. */
|
|
2
|
+
export declare class SkillEntryPaths {
|
|
3
|
+
private readonly files;
|
|
4
|
+
private readonly directories;
|
|
5
|
+
add(path: string, maxBytes: number, invalid: (message: string) => never, limit: () => never): void;
|
|
6
|
+
}
|
package/dist/lib/skill-hash.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PortableSkillManifest } from "./portable-skills-types.js";
|
|
2
|
+
import type { SkillBundleEntry } from "./skill-bundle.js";
|
|
2
3
|
/**
|
|
3
4
|
* Canonical content hashing for the hasna.skill.v1 portable bundle.
|
|
4
5
|
*
|
|
@@ -49,6 +50,38 @@ export interface ContentHashVerification {
|
|
|
49
50
|
/** The recomputed hash over the current bundle. */
|
|
50
51
|
computedHash?: string;
|
|
51
52
|
}
|
|
53
|
+
export interface ContentHashLimits {
|
|
54
|
+
entries: number;
|
|
55
|
+
rawBytes: number;
|
|
56
|
+
normalizedBytes: number;
|
|
57
|
+
fileBytes: number;
|
|
58
|
+
normalizedFileBytes: number;
|
|
59
|
+
pathBytes: number;
|
|
60
|
+
manifestBytes: number;
|
|
61
|
+
manifestDepth: number;
|
|
62
|
+
timeoutMs: number;
|
|
63
|
+
}
|
|
64
|
+
/** Hard ceilings for the entry API. Callers may tighten these, never disable them. */
|
|
65
|
+
export declare const CONTENT_HASH_LIMITS: Readonly<ContentHashLimits>;
|
|
66
|
+
export interface ContentHashOptions {
|
|
67
|
+
limits?: Partial<ContentHashLimits>;
|
|
68
|
+
signal?: AbortSignal;
|
|
69
|
+
}
|
|
70
|
+
export type ContentHashInputErrorCode = "CONTENT_HASH_INVALID" | "CONTENT_HASH_LIMIT" | "CONTENT_HASH_ABORTED" | "CONTENT_HASH_TIMEOUT";
|
|
71
|
+
export declare class ContentHashInputError extends Error {
|
|
72
|
+
readonly code: ContentHashInputErrorCode;
|
|
73
|
+
constructor(code: ContentHashInputErrorCode, message: string);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Hash bounded ordinary regular-file entries without filesystem access or extraction.
|
|
77
|
+
* Entries are revalidated and copied, even if supplied by inspectSkillBundle. This is
|
|
78
|
+
* content identity, not manifest validity, permission to execute, or a JS sandbox.
|
|
79
|
+
* Text uses the directory oracle's nonfatal UTF-8/LF normalization. Excluded paths
|
|
80
|
+
* still count toward input limits and collision checks. Inputs are never mutated.
|
|
81
|
+
*/
|
|
82
|
+
export declare function computeContentHashFromEntries(entries: readonly SkillBundleEntry[], options?: ContentHashOptions): Promise<string>;
|
|
83
|
+
/** Verify only the declaration in the same owned skill.json, never a second manifest. */
|
|
84
|
+
export declare function verifyContentHashFromEntries(entries: readonly SkillBundleEntry[], options?: ContentHashOptions): Promise<ContentHashVerification>;
|
|
52
85
|
/**
|
|
53
86
|
* Verify a skill folder's declared content_hash against the recomputed
|
|
54
87
|
* canonical hash of the current bundle. A missing declaration or a mismatch
|
package/dist/mcp/index.d.ts
CHANGED
package/dist/sdk/index.d.ts
CHANGED
|
@@ -40,3 +40,8 @@ export type { RemoteCustomerRole, RemoteCustomerProfile, RemoteCurrentWorkspace,
|
|
|
40
40
|
export type { RemoteWorkspaceContext, RemoteAccountWorkspace, RemoteAccountWorkspaces, RemoteWorkspaceIdentity, RemoteWorkspaceSession, RemoteAccountWorkspaceDiscovery, RemoteWorkspaceSelectionErrorCode } from "../lib/remote-workspace-selection.js";
|
|
41
41
|
export { WorkspaceContextInputError, WorkspaceIdentityMismatchError } from "../lib/remote-workspace-selection.js";
|
|
42
42
|
export { RemoteWorkspaceSelectionError } from "../lib/remote-client.js";
|
|
43
|
+
export type { LeaveRemoteWorkspace, RemoteWorkspaceLeaveResult, RemoteWorkspaceLeaveErrorCode } from "../lib/remote-workspace-leave.js";
|
|
44
|
+
export { WorkspaceLeaveInputError, RemoteWorkspaceLeaveError, RemoteWorkspaceLeaveUnconfirmedError } from "../lib/remote-workspace-leave.js";
|
|
45
|
+
export type { RemoteWorkspaceInvitation, RemoteWorkspaceInvitationsPage, RemoteWorkspaceInvitationResult, RemoteWorkspaceInvitationAcceptance, ListRemoteWorkspaceInvitations, IssueRemoteWorkspaceInvitation, ResendRemoteWorkspaceInvitation, RevokeRemoteWorkspaceInvitation, AcceptRemoteWorkspaceInvitation, RemoteWorkspaceInvitationErrorCode } from "../lib/remote-invitations.js";
|
|
46
|
+
export { WorkspaceInvitationInputError, RemoteWorkspaceInvitationError, RemoteWorkspaceInvitationUnconfirmedError, RemoteWorkspaceInvitationReadError } from "../lib/remote-invitations.js";
|
|
47
|
+
export { InvitationEmailInputError, RemoteInvitationEmailError, RemoteInvitationEmailUnconfirmedError, type RequestInvitationEmailChallenge, type AcceptInvitationEmailChallenge, type RemoteInvitationEmailChallenge, type RemoteInvitationEmailAcceptance, type RemoteInvitationEmailErrorCode } from "../lib/remote-invitation-recovery.js";
|