@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
package/README.md
CHANGED
|
@@ -674,7 +674,7 @@ skills/ # Public skill contracts and local OSS skills
|
|
|
674
674
|
|---|---|---|
|
|
675
675
|
| Catalog skills | 86 | `SKILLS.length` (`src/lib/registry-data/`) |
|
|
676
676
|
| Categories | 17 | `CATEGORIES` (`src/lib/registry-types.ts`) |
|
|
677
|
-
| MCP tools |
|
|
677
|
+
| MCP tools | 68 | `tools/list` against a live `buildServer()` |
|
|
678
678
|
|
|
679
679
|
Every number in this table is re-derived from the source tree on each test run by
|
|
680
680
|
`src/lib/readme-derived-counts.test.ts`, so a drifted figure fails a test rather
|
|
@@ -933,3 +933,198 @@ through a tool remains a separate follow-up.
|
|
|
933
933
|
If enrollment reports that key issuance was attempted but not confirmed, inspect
|
|
934
934
|
the selected profile and workspace keys before retrying. A lost response can
|
|
935
935
|
still have created a server key; the CLI does not retry issuance automatically.
|
|
936
|
+
|
|
937
|
+
### Leave a workspace
|
|
938
|
+
|
|
939
|
+
Use the exact membership ID and observed role from fresh `workspace list` output.
|
|
940
|
+
Leaving requires deliberate confirmation and a fresh verification code:
|
|
941
|
+
|
|
942
|
+
```sh
|
|
943
|
+
HASNA_PROFILE=team-b skills workspace leave <membership-id> --expected-role member --email you@example.com --code-stdin --confirm --json
|
|
944
|
+
```
|
|
945
|
+
|
|
946
|
+
The selected profile must authenticate the same membership. Without a named
|
|
947
|
+
profile, supply `--user-id <user-id>` from discovery; this also supports viewers
|
|
948
|
+
who cannot create API keys. The server refuses stale roles, the last active
|
|
949
|
+
owner, and leaving your last available workspace. It decides authority atomically.
|
|
950
|
+
|
|
951
|
+
The SDK offers `RemoteSkillsAuthClient.leaveWorkspace(email, code,
|
|
952
|
+
{ userId, membershipId }, { expectedRole, confirm: true })`; an existing interactive
|
|
953
|
+
session can use `RemoteSkillsClient.leaveWorkspace(context, input)`. MCP exposes
|
|
954
|
+
`leave_workspace` with those same explicit IDs, role, confirmation and fresh code.
|
|
955
|
+
All surfaces call the same HTTP method once. API keys cannot authorize the leave.
|
|
956
|
+
|
|
957
|
+
Success returns `{ organizationId, membershipId, removed: true,
|
|
958
|
+
signInRequired: true }`. Sign in again to an available workspace afterwards.
|
|
959
|
+
Saved credentials and unrelated profiles remain unchanged; credentials for the
|
|
960
|
+
left membership no longer grant access. A lost or invalid response raises
|
|
961
|
+
`RemoteWorkspaceLeaveUnconfirmedError`: inspect available memberships before any
|
|
962
|
+
new action. Never automatically retry or substitute another membership ID.
|
|
963
|
+
|
|
964
|
+
|
|
965
|
+
## Workspace invitations
|
|
966
|
+
|
|
967
|
+
The SDK, CLI and MCP use the same invitation operations on your configured API.
|
|
968
|
+
A compatible hosted service must enable invitation delivery. Every operation
|
|
969
|
+
requires fresh verification bound to your observed user ID and current membership
|
|
970
|
+
ID; any named profile must match. Owners can invite all roles; admins manage only
|
|
971
|
+
member/viewer invitations. The server enforces current authority and verified
|
|
972
|
+
recipient email. Existing accounts with no available membership still need the
|
|
973
|
+
separate invitation recovery flow; these commands do not bypass ordinary login.
|
|
974
|
+
|
|
975
|
+
Use `skills workspace list` to observe the account and membership IDs. The
|
|
976
|
+
`workspace invitations` commands are `list`, `get <invitation-id>`, `issue`,
|
|
977
|
+
`resend <invitation-id>`, `revoke <invitation-id>` and `accept <invitation-id>`.
|
|
978
|
+
Each requires `--email`, `--user-id` and `--membership-id`. Mutations also require
|
|
979
|
+
`--confirm`. `list --after <nextCursor>` reads one additional page, at most 50
|
|
980
|
+
invitations; it never automatically traverses the account.
|
|
981
|
+
|
|
982
|
+
For `issue`, supply `--recipient`, `--role` and your own
|
|
983
|
+
`--idempotency-key <uuid>`. `resend` requires that key and
|
|
984
|
+
`--expected-generation`; `revoke` requires `--expected-generation`. Save the
|
|
985
|
+
request key with its original nonsecret context and parameters before issuing or
|
|
986
|
+
resending. A lost response is not proof of failure: read current invitations or
|
|
987
|
+
reconcile with exactly the same key and original parameters. Never replace the
|
|
988
|
+
key to retry an uncertain action. No command retries or rewrites saved profiles.
|
|
989
|
+
|
|
990
|
+
Read, issue, resend and revoke can read a previously requested six-digit code via
|
|
991
|
+
`--code-stdin`. Otherwise an interactive terminal requests a code and masks input.
|
|
992
|
+
Acceptance takes its invitation ID as the argument and reads the fresh code on
|
|
993
|
+
stdin line one and the 43-character invitation token on line two with
|
|
994
|
+
`--secrets-stdin`. Interactive acceptance masks both inputs. Do not put either
|
|
995
|
+
secret in arguments, environment variables, shell history, scripts or profiles.
|
|
996
|
+
Obtain both from your inbox and pass them through your terminal or an approved
|
|
997
|
+
secret-input mechanism. JSON/noninteractive acceptance requires `--secrets-stdin`.
|
|
998
|
+
|
|
999
|
+
Acceptance returns the joined organization and membership IDs. It does not change
|
|
1000
|
+
the current workspace, default home, saved keys or profiles. Inspect your workspace
|
|
1001
|
+
list and deliberately select a membership afterward. A delivery state of
|
|
1002
|
+
`provider_accepted` means the provider accepted the request, not that it reached
|
|
1003
|
+
an inbox.
|
|
1004
|
+
|
|
1005
|
+
Both SDK entrypoints export `RemoteSkillsClient` methods
|
|
1006
|
+
`listWorkspaceInvitations(context, options?)`,
|
|
1007
|
+
`getWorkspaceInvitation(context, invitationId)`,
|
|
1008
|
+
`issueWorkspaceInvitation(context, input)`,
|
|
1009
|
+
`resendWorkspaceInvitation(context, invitationId, input)`,
|
|
1010
|
+
`revokeWorkspaceInvitation(context, invitationId, input)` and
|
|
1011
|
+
`acceptWorkspaceInvitation(context, invitationId, { token, confirm: true })`.
|
|
1012
|
+
The corresponding `RemoteSkillsAuthClient` methods prepend `email, code` to those
|
|
1013
|
+
arguments for fresh verification. `context` is `{ userId, membershipId }`.
|
|
1014
|
+
Issue input is `{ email, role, idempotencyKey, confirm: true }`; resend is
|
|
1015
|
+
`{ expectedGeneration, idempotencyKey, confirm: true }`; revoke is
|
|
1016
|
+
`{ expectedGeneration, confirm: true }`. Tokens and temporary sessions are never
|
|
1017
|
+
returned in invitation projections or persisted by these methods.
|
|
1018
|
+
|
|
1019
|
+
MCP exposes `list_workspace_invitations`, `get_workspace_invitation`,
|
|
1020
|
+
`issue_workspace_invitation`, `resend_workspace_invitation`,
|
|
1021
|
+
`revoke_workspace_invitation` and `accept_workspace_invitation`. Supply explicit
|
|
1022
|
+
`userId`, `membershipId`, `email` and fresh `code` in each tool request. Issue uses
|
|
1023
|
+
`recipient` for the invitation email; acceptance's `token` travels only in the
|
|
1024
|
+
MCP request. Treat the host's request history as sensitive; the tools never echo
|
|
1025
|
+
that token or save it in a profile. Other mutation fields match the SDK.
|
|
1026
|
+
|
|
1027
|
+
Known server refusals are fixed `RemoteWorkspaceInvitationError` codes.
|
|
1028
|
+
`WorkspaceInvitationInputError` rejects invalid inputs before authentication.
|
|
1029
|
+
`RemoteWorkspaceInvitationReadError` refuses malformed, cross-workspace or
|
|
1030
|
+
unbounded results. `RemoteWorkspaceInvitationUnconfirmedError` requires explicit
|
|
1031
|
+
reconciliation of a mutation; it never triggers automatic replay. These adapters
|
|
1032
|
+
require service and real recipient acceptance testing before invitations can be
|
|
1033
|
+
offered as a live product capability.
|
|
1034
|
+
|
|
1035
|
+
### Content identity without extraction
|
|
1036
|
+
|
|
1037
|
+
`computeContentHashFromEntries` and `verifyContentHashFromEntries` are available
|
|
1038
|
+
from the root package and `@hasna/skills/sdk`. They consume regular-file entries
|
|
1039
|
+
such as the result of `inspectSkillBundle`, revalidate their shape and paths, and
|
|
1040
|
+
copy their bytes before yielding. Neither function reads a directory, extracts
|
|
1041
|
+
files, changes the supplied entries, or authorizes code execution.
|
|
1042
|
+
|
|
1043
|
+
```ts
|
|
1044
|
+
import { inspectSkillBundle, computeContentHashFromEntries,
|
|
1045
|
+
verifyContentHashFromEntries, revisionIdOf } from "@hasna/skills/sdk";
|
|
1046
|
+
|
|
1047
|
+
const inspected = await inspectSkillBundle(uploadBytes, { signal });
|
|
1048
|
+
const contentHash = await computeContentHashFromEntries(inspected.entries, { signal });
|
|
1049
|
+
const verification = await verifyContentHashFromEntries(inspected.entries, { signal });
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
Verification reads `provenance.content_hash` from the same captured `skill.json`;
|
|
1053
|
+
it cannot accept a second manifest in place of those bytes. Manifest field
|
|
1054
|
+
validation remains a separate operation. `revisionIdOf` and `RevisionContent`
|
|
1055
|
+
expose the existing revision identity, whose optional fields default to null and
|
|
1056
|
+
whose published tag order matters. An archive SHA, canonical content hash and
|
|
1057
|
+
published revision ID describe different identities and are not interchangeable.
|
|
1058
|
+
|
|
1059
|
+
The entry functions preserve the directory hash's coverage, LF normalization,
|
|
1060
|
+
binary handling, manifest self-hash removal, ordering and serialization. The
|
|
1061
|
+
archive packer has a different exclusion policy; hashing inspected entries does
|
|
1062
|
+
not add excluded files back into an archive. Existing directory functions remain
|
|
1063
|
+
synchronous and retain their previous behavior.
|
|
1064
|
+
|
|
1065
|
+
`CONTENT_HASH_LIMITS` caps the entry count at 1,024, raw and normalized content
|
|
1066
|
+
at 64 MiB, each raw/normalized file at 16 MiB, paths at 100 UTF-8 bytes, and the root
|
|
1067
|
+
manifest at 16 KiB with nesting depth 64. The deadline is five seconds. Callers may lower
|
|
1068
|
+
these limits through `ContentHashOptions`; zero and values above the ceilings
|
|
1069
|
+
are refused. Excluded entries still count toward raw limits and path-collision
|
|
1070
|
+
checks. Paths must be canonical and distinct under NFC/case folding; shared
|
|
1071
|
+
buffers and accessor-backed entry fields are refused. This validates ordinary
|
|
1072
|
+
untrusted byte entries, not arbitrary JavaScript proxies or hostile host code.
|
|
1073
|
+
`ContentHashInputError` reports fixed invalid-input, limit, abort or timeout codes
|
|
1074
|
+
without including file contents or paths in its messages.
|
|
1075
|
+
|
|
1076
|
+
## Invitation email recovery
|
|
1077
|
+
|
|
1078
|
+
An existing account with no usable membership can explicitly recover access by
|
|
1079
|
+
accepting an invitation with its secret and a fresh recovery code. This separate
|
|
1080
|
+
flow creates no session, key, workspace, default pointer or credit grant. New
|
|
1081
|
+
accounts use ordinary signup. A compatible service must enable email recovery.
|
|
1082
|
+
|
|
1083
|
+
Set `HASNA_SKILLS_API_URL` (or `SKILLS_API_URL`) explicitly for recovery. If both
|
|
1084
|
+
are set, they must name the same API. Recovery never consults a keychain or saved
|
|
1085
|
+
key to choose its server. It preserves all profiles and never treats cached
|
|
1086
|
+
identity metadata as proof.
|
|
1087
|
+
|
|
1088
|
+
Generate and retain a challenge UUID **before** the first request. Keep it with
|
|
1089
|
+
the same invitation ID and server, without storing the token or code. Run
|
|
1090
|
+
`skills workspace invitations email-challenge <invitation-id>
|
|
1091
|
+
--challenge-id <your-uuid> --confirm` to enter the invitation token through a
|
|
1092
|
+
masked prompt, or add `--token-stdin` for exactly one secret input line.
|
|
1093
|
+
The eligibility-neutral result does not confirm that a code was sent or delivered.
|
|
1094
|
+
A reused challenge ID never requests a replacement code automatically.
|
|
1095
|
+
|
|
1096
|
+
After receiving the recovery code, run
|
|
1097
|
+
`skills workspace invitations email-accept <invitation-id>
|
|
1098
|
+
--challenge-id <same-uuid> --confirm`. Interactive entry masks the token and code;
|
|
1099
|
+
`--secrets-stdin` reads the recovery code on line one and the invitation token on
|
|
1100
|
+
line two. JSON use requires the corresponding stdin option. Never put proof in
|
|
1101
|
+
arguments, environment variables, URLs, scripts or shell history.
|
|
1102
|
+
|
|
1103
|
+
Acceptance returns `accepted: true`, `changed: true`, `signInRequired: true` and
|
|
1104
|
+
the organization/membership IDs. Use fresh ordinary sign-in afterward. If the
|
|
1105
|
+
acceptance response is lost, sign in to inspect available memberships before any
|
|
1106
|
+
further action; never retry acceptance automatically. If necessary, deliberately
|
|
1107
|
+
request a new recovery challenge. An uncertain challenge response requires
|
|
1108
|
+
retaining its original ID and checking your inbox, without automatic rotation.
|
|
1109
|
+
|
|
1110
|
+
Both SDK entrypoints expose `RemoteSkillsAuthClient` methods
|
|
1111
|
+
`requestInvitationEmailChallenge({ invitationId, token, challengeId, confirm: true })`
|
|
1112
|
+
and `acceptInvitationEmailChallenge({ invitationId, token, challengeId, code,
|
|
1113
|
+
confirm: true })`. Both send one anonymous POST to the captured API origin and
|
|
1114
|
+
return bounded, validated projections. `InvitationEmailInputError` rejects invalid
|
|
1115
|
+
input, `RemoteInvitationEmailError` exposes fixed service refusal codes, and
|
|
1116
|
+
`RemoteInvitationEmailUnconfirmedError` requires explicit reconciliation. No
|
|
1117
|
+
cookie, Authorization header, credential resolution, login or profile write is
|
|
1118
|
+
part of these methods.
|
|
1119
|
+
|
|
1120
|
+
For an agent host without a key, start
|
|
1121
|
+
`skills-mcp --invitation-recovery --stdio` with an explicit API URL. This mode
|
|
1122
|
+
exposes only `request_invitation_email_challenge` and
|
|
1123
|
+
`accept_invitation_email_challenge`, with the same SDK input fields. It rejects
|
|
1124
|
+
other startup flags, HTTP mode and local mode. The ordinary MCP startup and data
|
|
1125
|
+
access gates remain in effect outside this mode. Treat host request history as
|
|
1126
|
+
sensitive: tokens and codes appear only in the MCP input body and are never
|
|
1127
|
+
returned or saved by the tools.
|
|
1128
|
+
|
|
1129
|
+
These clients still require deployed configuration and controlled real recipient
|
|
1130
|
+
email acceptance before recovery can be offered as a live product capability.
|