@hasna/skills 0.8.9 → 0.8.11

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.
Files changed (37) hide show
  1. package/README.md +103 -1
  2. package/bin/index.js +26509 -24016
  3. package/bin/mcp.js +596 -222
  4. package/bin/migrate.js +7 -5
  5. package/bin/server.js +12313 -73626
  6. package/bin/worker.js +7636 -60520
  7. package/dist/cli/commands/plugin-admission.d.ts +2 -0
  8. package/dist/index.d.ts +9 -2
  9. package/dist/index.js +23559 -21779
  10. package/dist/lib/agent-adapters.d.ts +1 -0
  11. package/dist/lib/agent-codex-trust.d.ts +42 -0
  12. package/dist/lib/agent-discovery.d.ts +4 -2
  13. package/dist/lib/claude-marketplace-registry.d.ts +17 -0
  14. package/dist/lib/codex-hook-rpc.d.ts +13 -0
  15. package/dist/lib/codex-hook-trust-files.d.ts +15 -0
  16. package/dist/lib/codex-hook-trust-identity.d.ts +16 -0
  17. package/dist/lib/codex-hook-trust-layout.d.ts +3 -0
  18. package/dist/lib/fleet-credentials.d.ts +18 -0
  19. package/dist/lib/hook-diagnostics.d.ts +7 -0
  20. package/dist/lib/plugin-admission.d.ts +101 -0
  21. package/dist/lib/plugin-discovery.d.ts +13 -0
  22. package/dist/lib/plugin-projection-store.d.ts +14 -0
  23. package/dist/lib/plugin-projection.d.ts +80 -0
  24. package/dist/lib/profile-client.d.ts +10 -0
  25. package/dist/lib/recurring-recovery.d.ts +2 -2
  26. package/dist/lib/recurring-surface.d.ts +1 -1
  27. package/dist/lib/remote-client.d.ts +14 -4
  28. package/dist/lib/remote-credit-checkout.d.ts +22 -0
  29. package/dist/lib/remote-customer-operations.d.ts +3 -4
  30. package/dist/lib/remote-permissions.d.ts +24 -0
  31. package/dist/lib/selection-cache.d.ts +32 -0
  32. package/dist/lib/selection-resolver.d.ts +3 -1
  33. package/dist/lib/session-reconciliation.d.ts +100 -0
  34. package/dist/sdk/index.d.ts +5 -2
  35. package/dist/sdk/index.js +18528 -78089
  36. package/docs/plugin-admission.md +221 -0
  37. package/package.json +7 -5
@@ -0,0 +1,221 @@
1
+ # Reviewed plugin admission
2
+
3
+ `skills integration plugin` prepares a plugin before a coding agent discovers
4
+ it. Projection contracts support schema versions 1 and 2; targets use schema
5
+ version 1, bindings use schema version 2, and admission plans and receipts use
6
+ schema version 3. Claude command sources use `copy` mode, certified against
7
+ Claude 2.1.274 and 2.1.276 on Linux ARM64. It removes native skill and command prompts while preserving
8
+ reviewed agents, tools, MCP, LSP, hooks and assets. Prompt hooks enforce drift;
9
+ they do not clean an already loaded plugin catalog.
10
+
11
+ All packages and migration mappings belong in the owner's private Skills
12
+ instance. The public Skills package ships this software and synthetic tests;
13
+ it contains no operational plugin catalog or skill payloads. The Skills server
14
+ can use its supported storage backend. Plugin admission does not require S3.
15
+
16
+ ## Private package contract
17
+
18
+ Publish migrated prompts through the normal versioned Skills authoring flow.
19
+ Then publish a separate instruction bundle containing `plugin-projection.json`
20
+ and the original regular-file plugin tree under `original/`. Keep its root
21
+ instruction and package metadata outside that tree. Select the integration
22
+ bundle and all its mapped payload versions in a dedicated integration profile.
23
+ These operations do not silently publish or change a selection profile.
24
+
25
+ The exported `PluginProjectionManifest` retains this strict version 1 contract:
26
+
27
+ | Field | Meaning |
28
+ | --- | --- |
29
+ | `schemaVersion`, `agent` | `1`, `"claude"` |
30
+ | `pluginId` | Exact `plugin-name@marketplace-name` |
31
+ | `upstream` | Credential-free HTTPS source, revision, version, license, and original `treeDigest` |
32
+ | `review.hooks` | `"reviewed-no-skill-injection"` |
33
+ | `review.dependencies` | `"reviewed-no-retired-payload-dependency"` |
34
+ | `payloads` | Every original skill and command prompt, with source path, kind, source digest and exact hosted target slug/version/bundle digest |
35
+
36
+ Schema version 2 also supports original manifests that omit `version`. It uses
37
+ `upstream.version: null`, requires a full lowercase 40- or 64-character Git
38
+ commit in `upstream.revision`, and still binds the complete original tree digest.
39
+ A null version refuses an original manifest with any `version` field, including
40
+ null or an empty string. A declared version must still match exactly. No vendor
41
+ version is invented or written into the projection. Claude's command-copy cache
42
+ uses a bare 12-character content hash when the manifest has no version; declared
43
+ versions retain their version-plus-hash form. Both forms require the exact
44
+ admitted producer receipt and complete file witnesses.
45
+
46
+ Version 2 requires `review.documentation`, an array containing zero or one
47
+ `{ path, sourceDigest }` entries. Only an exact root `README.md` (case-insensitive
48
+ spelling), with mode 0644 and its one-file tree digest, can be declared inert
49
+ documentation. Its original bytes may describe a retired prompt. The exception
50
+ refuses a README selected by a native component, referenced by native configuration,
51
+ or referenced by another retained text file. Other Markdown, including agents,
52
+ keeps the strict removed-file and native skill-preload checks. An undeclared README
53
+ also keeps those checks. This explicit review does not certify arbitrary dynamic
54
+ runtime behavior: dependency review must still establish that the README is not
55
+ an indirect runtime input. Version 1 gains no documentation exception.
56
+
57
+ `pluginTreeDigest(entries)` hashes sorted file witnesses: path, normalized mode,
58
+ size and SHA-256. A payload's `sourceDigest` is that function applied to its
59
+ single original file. The source is preserved byte-for-byte in the private
60
+ archive; the native projection is derived from it. Default and custom command
61
+ paths, dormant default commands, root skills and case-insensitive aliases are
62
+ covered. Custom skill trees are removed, including their support files. The
63
+ only rewritten ordinary file is the plugin manifest when its `skills` or
64
+ `commands` declarations need removal.
65
+
66
+ Overlapping ordinary components, runtime references to removed files, native agent
67
+ skill preloads, unsupported manifest fields and upstream package installation
68
+ requirements refuse admission. Review must cover indirect/dynamic dependencies
69
+ as well as the direct references checked by software. Admission never executes
70
+ an upstream shell command or installation script. Preserved plugin tools and
71
+ hooks still run under the native agent's normal trust controls when used.
72
+
73
+ ## Plan, admit and resolve
74
+
75
+ Prepare an owner-only JSON `PluginAdmissionTarget` with schema version 1,
76
+ plugin ID, exact `registrations` (user and/or canonical project paths), certified
77
+ native executable/version/digest, and the absolute Skills executable/digest.
78
+ One marketplace command serves that complete reviewed registration set.
79
+ Executable digests use `sha256:<hex>`; symlink aliases must be resolved to their
80
+ reviewed canonical file paths. No executable is invoked while planning.
81
+
82
+ ```sh
83
+ skills integration plugin plan plugin-container --selection-profile integrations --target /absolute/private/target.json
84
+ skills integration plugin admit plugin-container --selection-profile integrations --target /absolute/private/target.json --plan-digest sha256:REVIEWED_DIGEST --evidence-digest sha256:REVIEWED_EVIDENCE
85
+ skills integration plugin resolve --binding REVIEWED_BINDING_ID
86
+ ```
87
+
88
+ Plan and admit emit JSON. Review the exact plan digest, retained/removed file
89
+ witnesses, provenance and hosted payload mappings. Admit refetches the profile
90
+ and exact bundles before accepting that digest. Its owner-only immutable receipt
91
+ binds authority, workspace, profile ID, exact canonical container and mapped
92
+ payload versions/digests, source and projection digests, scope set, executable
93
+ witnesses, resolver command, authenticated owner identity, exact profile
94
+ revision, aliases and triggers. `observation` records the same freshly observed
95
+ principal and routing state. `evidenceDigest` hashes that complete authenticated
96
+ evidence snapshot, and `planDigest` hashes the admission identity including the
97
+ evidence digest. Admission requires both reviewed digests. Receipt reads validate
98
+ both hashes, strict field schemas and agreement between mapped and observed
99
+ identities. Legacy binding, plan and receipt schemas are refused rather than
100
+ upgraded implicitly. Originals remain in the
101
+ private hosted bundle; local native materializations contain only the projection.
102
+
103
+ The owner-local store is `~/.hasna/skills/plugin-admission/`: `bindings/` holds
104
+ content-addressed bindings, `receipts/<binding>/` holds approved plans, and
105
+ `objects/<binding>/<plan-digest>/` holds complete immutable projections. The
106
+ resolver freshly authenticates through normal owner credential configuration
107
+ on every call, including exact payload bundle reads. It refuses environment
108
+ authority/local-storage overrides. No `--cached`, API URL/key or local fallback
109
+ option exists. The resolver calls authenticated `whoami` before and after profile,
110
+ bundle and executable verification. The stable user/account identity and required
111
+ `owner` role must remain unchanged, and the account must equal the selected
112
+ workspace. Credential rotation remains valid because receipts never bind a raw
113
+ API-key identifier. Any profile revision, alias or trigger change requires a new
114
+ plan and explicit approval, including edits made after review. Missing
115
+ canonical selections, changed versions/digests, authority/workspace/profile
116
+ changes, revoked API access, changed package content or executable witnesses
117
+ still refuse or require renewed admission. A mapped canonical slug cannot be
118
+ replaced through an alias, even with identical content. Human plan/admit input
119
+ may use an integration alias; the resulting binding uses its canonical slug.
120
+
121
+ Re-admitting an unchanged identity and evidence returns its original receipt.
122
+ A new plan reports current principal and routing evidence. Resolver calls remain
123
+ write-free. Canonical object keys and
124
+ registration-set ordering keep binding IDs, plan digests and persisted binding
125
+ bytes stable.
126
+
127
+ Configure the private marketplace source using the receipt's exact
128
+ `sourceCommand`, `source: "command"`, `mode: "copy"` and `timeout: 30`.
129
+ On certified Linux hosts, that accepted command opens the reviewed resolver,
130
+ hashes `/proc/self/fd/9` with the absolute system SHA-256 utility, and executes
131
+ the same pinned descriptor. A pathname replacement before the open is rejected;
132
+ a replacement after hashing cannot become the executed resolver. The resolver
133
+ has a 25-second API deadline and prints exactly one absolute
134
+ directory path on success. Errors produce sanitized stderr and a nonzero exit.
135
+ Only explicit admission writes artifacts; resolve cannot publish or materialize
136
+ an unapproved revision. Concurrent admission uses a nonwaiting publication lock.
137
+ Interrupted attempts cannot expose partial directories as successful results.
138
+
139
+ Registration and activation remain explicit operations. Review the command
140
+ shown by Claude's JSON install/update response and pass its exact
141
+ `--accept-command` hash; never substitute blanket approval. Command-source
142
+ support begins at 2.1.229 and exact CLI acceptance at 2.1.271, but version 1
143
+ certifies 2.1.274 and 2.1.276. Claude invokes the source during installation and updates;
144
+ this does not imply a resolver invocation on every agent startup. This command does not upgrade Claude, register a
145
+ marketplace, change native settings, disable other plugins or restart agents.
146
+
147
+ ## Discovery transition contract
148
+
149
+ After explicit native registration, use `captureManagedPluginRegistry()` in a
150
+ reviewed discovery input. It emits a `claude-plugin-registry` source witness with
151
+ the registry path and exact admission bindings. Keep the normal full witnesses
152
+ for native settings, marketplace catalog/source configuration and other loader
153
+ inputs. Do not retain a competing whole-registry byte witness when intentionally
154
+ admitting receipt-backed transitions; unmanaged entries remain covered by the
155
+ structured registry witness itself.
156
+
157
+ Only these managed row fields can vary after validation: `version`,
158
+ `installPath`, `sourceProducerPath`, `previousProducerPaths`, `lastUpdated`.
159
+ Every current row must match its own producer receipt and exact reviewed scope.
160
+ All retained native cache versions must match approved immutable projections,
161
+ including their command files, ordinary components, paths, modes and membership.
162
+ The certified native adapter separately validates root `.in_use/<pid>` process
163
+ markers and `.orphaned_at` epoch-millisecond pruning markers. These bounded
164
+ metadata records cannot authorize content, and cannot come from the original
165
+ package. Links, unknown keys, payload files and nested directories still refuse.
166
+ Every unmanaged row and every unknown field remains in the witness. New
167
+ registrations, changed commands, cross-scope substitutions or modified caches
168
+ refuse. Old receipts and projections remain until separately reviewed retirement.
169
+
170
+ Project plugin enablement requires a full reviewed settings-file witness and
171
+ matching admitted project registration. Other project discovery overrides and
172
+ new loaders still require their dedicated review. API failure refuses an update; it does not report a
173
+ stale projection as synchronized. Claude may retain its previous installation
174
+ after a refused update, whose existing local drift checks continue to apply.
175
+
176
+ ## Marketplace registry timestamps
177
+
178
+ For an explicitly reviewed `known_marketplaces.json`,
179
+ `captureClaudeMarketplaceRegistry(path)` emits a separate
180
+ `claude-marketplace-registry` witness. It preserves every marketplace name,
181
+ source, install location and unknown value. Only a valid UTC `lastUpdated`
182
+ timestamp can vary, and only for exact rows containing `source`,
183
+ `installLocation` and `lastUpdated`, with a recognized GitHub repository or local
184
+ directory source. Rows with any extra field, including `autoUpdate`, retain
185
+ their entire contents in the digest. Registration changes still refuse.
186
+
187
+ This mode is opt-in for reviewed Claude discovery. It cannot project fields,
188
+ carry managed-plugin rules, accept an absent registry or synthesize registry
189
+ changes during hook installation. It does not replace the separate settings,
190
+ installed-plugin, marketplace catalog, loader, root or payload witnesses.
191
+ Capture requires a bounded regular file with strict UTF-8 and unambiguous JSON;
192
+ links, duplicate keys and concurrent file replacement refuse.
193
+
194
+ Existing byte witnesses retain their exact behavior. A prior hash mismatch is
195
+ not proof of a timestamp-only change: review the complete current registration
196
+ and its complementary sources before explicitly replacing an old witness.
197
+ Capturing this witness does not write a policy or approve native registration.
198
+
199
+ ## Verification and limits
200
+
201
+ Unit tests cover provenance and mapping failures, offline/revoked authorities,
202
+ timeouts, concurrent publication, symlinks/special files, cache mutation, retained
203
+ history, and exact unmanaged registry coverage. Synthetic native tests exercise
204
+ actual Claude with a disposable home and loopback mock authority in a separate
205
+ network namespace. They contact no real provider and require explicit opt-in:
206
+ `SKILLS_TEST_CLAUDE_BIN`, `SKILLS_TEST_CLAUDE_SHA256` (reviewed native executable
207
+ digest), `SKILLS_TEST_CLAUDE_VERSION` (defaults to 2.1.274), and
208
+ `SKILLS_TEST_NETWORK_ISOLATED=1`. Both versioned and versionless upstream
209
+ manifests run through install, unchanged and changed updates, refusal and drift checks. Before native execution, the test
210
+ checks the source before/after copying, complete copied digest, size and ELF
211
+ format, then atomically publishes its private executable fixture.
212
+
213
+ The initial implementation is a reviewed admission boundary, not an upstream
214
+ ingestion scheduler or a general plugin execution sandbox. MacOS runtime proof,
215
+ additional native versions and providers require their own canary evidence.
216
+ Package data is bounded to 1,024 files, 64 MiB total and 16 MiB per file. Native
217
+ cache history is bounded to 128 entries and an aggregate 256 MiB per witness.
218
+
219
+ Primary runtime references: [command sources](https://code.claude.com/docs/en/plugin-marketplaces#command-sources),
220
+ [plugin components](https://code.claude.com/docs/en/plugins-reference), and
221
+ [exact command acceptance](https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md#21271).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.8.9",
3
+ "version": "0.8.11",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -38,6 +38,7 @@
38
38
  "bin/",
39
39
  "migrations/",
40
40
  "docs/skill-standard.md",
41
+ "docs/plugin-admission.md",
41
42
  "schemas/",
42
43
  "LICENSE",
43
44
  "README.md",
@@ -61,10 +62,11 @@
61
62
  "typecheck": "tsc --noEmit",
62
63
  "verify:release": "bun run scripts/release-guard.ts",
63
64
  "verify:consumer-types": "bun run scripts/consumer-types.ts",
64
- "prepare": "bun run build:js",
65
- "prepack": "bun run build && bun run verify:release && bun run verify:consumer-types",
65
+ "prepack": "bun run verify:generated && bun run verify:release && bun run verify:consumer-types",
66
66
  "prepublishOnly": "bun run verify:producer && bun run typecheck && bun run test",
67
- "verify:producer": "bun run scripts/release-dependencies.ts"
67
+ "verify:producer": "bun run scripts/release-dependencies.ts",
68
+ "verify:generated": "HASNA_SKILLS_RELEASE_ARTIFACT_TEST=1 bun test src/lib/release-artifacts.test.ts",
69
+ "verify:consumer-credentials": "bun run scripts/consumer-credentials.ts"
68
70
  },
69
71
  "keywords": [
70
72
  "skills",
@@ -86,7 +88,6 @@
86
88
  "license": "Apache-2.0",
87
89
  "devDependencies": {
88
90
  "@hasna/contracts": "1.1.0",
89
- "@hasna/secrets": "0.4.2",
90
91
  "@types/bun": "1.3.14",
91
92
  "@types/node": "25.2.3",
92
93
  "@types/react": "^18.2.0",
@@ -99,6 +100,7 @@
99
100
  "@aws-sdk/client-ecs": "^3.1079.0",
100
101
  "@aws-sdk/client-s3": "^3.1079.0",
101
102
  "@hasna/events": "0.1.18",
103
+ "@hasna/secrets": "0.4.2",
102
104
  "@modelcontextprotocol/sdk": "^1.26.0",
103
105
  "chalk": "^5.3.0",
104
106
  "commander": "^12.1.0",