@hasna/skills 0.4.0 → 0.5.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.
Files changed (48) hide show
  1. package/README.md +220 -5
  2. package/bin/index.js +7747 -5645
  3. package/bin/mcp.js +1493 -431
  4. package/bin/migrate.js +148 -40
  5. package/bin/server.js +53 -83
  6. package/bin/worker.js +41 -73
  7. package/dist/admin-contract.d.ts +37 -19
  8. package/dist/admin-contract.js +1 -1
  9. package/dist/cli/cli.test-utils.d.ts +10 -8
  10. package/dist/cli/commands/customer-profile.d.ts +2 -0
  11. package/dist/cli/commands/customer-verification.d.ts +5 -0
  12. package/dist/cli/commands/tool-primitives.d.ts +1 -1
  13. package/dist/cli/commands/workspace-member-mutations.d.ts +2 -0
  14. package/dist/cli/commands/workspace-members.d.ts +2 -0
  15. package/dist/cli/commands/workspace-selection.d.ts +11 -0
  16. package/dist/cli/env-assignment.d.ts +9 -0
  17. package/dist/index.d.ts +8 -2
  18. package/dist/index.js +841 -167
  19. package/dist/lib/agent-sync.d.ts +13 -8
  20. package/dist/lib/api-url.d.ts +4 -3
  21. package/dist/lib/app-home.d.ts +0 -1
  22. package/dist/lib/client-types.d.ts +75 -0
  23. package/dist/lib/credential-state.d.ts +12 -0
  24. package/dist/lib/fleet-credentials.d.ts +41 -15
  25. package/dist/lib/home-adoption.d.ts +2 -0
  26. package/dist/lib/home-census.d.ts +3 -1
  27. package/dist/lib/local-opt-in.d.ts +24 -0
  28. package/dist/lib/portable-skills-files.d.ts +6 -2
  29. package/dist/lib/read-access.d.ts +83 -0
  30. package/dist/lib/remote-auth.d.ts +23 -3
  31. package/dist/lib/remote-client.d.ts +45 -5
  32. package/dist/lib/remote-profile.d.ts +26 -0
  33. package/dist/lib/remote-registry.d.ts +7 -3
  34. package/dist/lib/remote-workspace-selection.d.ts +58 -0
  35. package/dist/lib/remote-workspace.d.ts +76 -0
  36. package/dist/lib/skillinfo.d.ts +1 -1
  37. package/dist/lib/workspace-profile.d.ts +49 -0
  38. package/dist/mcp/helpers.d.ts +22 -0
  39. package/dist/mcp/index.d.ts +16 -0
  40. package/dist/sdk/governance-store.d.ts +1 -0
  41. package/dist/sdk/index.d.ts +8 -2
  42. package/dist/sdk/index.js +1312 -297
  43. package/dist/sdk/outputs.d.ts +0 -11
  44. package/dist/sdk/runs.d.ts +1 -1
  45. package/dist/storage.js +6 -40
  46. package/docs/skill-standard.md +30 -2
  47. package/package.json +6 -4
  48. package/dist/lib/instance-credentials-race.fixture.d.ts +0 -1
@@ -1,14 +1,3 @@
1
- /**
2
- * Outputs governance: default-private visibility, pre-persistence redaction,
3
- * hard size limits, finite TTLs, and immutable deletion receipts.
4
- *
5
- * The writer is the one gate every artifact passes at write time: visibility is
6
- * stamped from the governance default, redaction runs BEFORE the bytes are
7
- * stored, the per-output and per-run-total caps are checked before the row is
8
- * written, and expiresAt is computed from the configured TTL. The expiry sweep
9
- * is the retention half: artifacts whose expiresAt is in the past are deleted
10
- * (row + object) and every deletion lands one append-only receipt.
11
- */
12
1
  import type { ArtifactBody, ObjectStore } from "./storage.js";
13
2
  import type { GovernanceStore, LifecycleReceipt } from "./governance-store.js";
14
3
  import { type OutputGovernanceConfig } from "./governance.js";
@@ -11,7 +11,7 @@
11
11
  * `FOR UPDATE SKIP LOCKED`, SQLite `BEGIN IMMEDIATE` plus a conditional claim) — no
12
12
  * business logic is duplicated here.
13
13
  */
14
- import { z } from "zod";
14
+ import { z } from "zod/v3";
15
15
  import { REMOTE_SKILL_RUN_CONTRACT_VERSION, normalizeRemoteSkillRunContract, type RemoteSkillRunContract } from "../lib/remote-run-contract.js";
16
16
  import type { ApiPrincipal, CreateRunInput, ServerRunRecord, ServerRunStatus, SkillsProductStore } from "../server/types.js";
17
17
  import type { OfflineGate } from "./offline.js";
package/dist/storage.js CHANGED
@@ -119,12 +119,7 @@ import { homedir } from "os";
119
119
  import { join, resolve } from "path";
120
120
  import { homedir as pathsResolverHomedir } from "os";
121
121
  import { join as pathsResolverJoin } from "path";
122
- var PATHS_RESOLVER_KIND_ENV = {
123
- config: "HASNA_CONFIG_HOME",
124
- data: "HASNA_DATA_HOME",
125
- state: "HASNA_STATE_HOME",
126
- cache: "HASNA_CACHE_HOME"
127
- };
122
+ var PATHS_RESOLVER_DATA_ENV = "HASNA_DATA_HOME";
128
123
  var PATHS_RESOLVER_APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
129
124
  function pathsResolverAssertApp(app) {
130
125
  if (typeof app !== "string" || app.length === 0) {
@@ -134,48 +129,19 @@ function pathsResolverAssertApp(app) {
134
129
  throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
135
130
  }
136
131
  }
137
- function pathsResolverAssertKind(kind) {
138
- if (!Object.keys(PATHS_RESOLVER_KIND_ENV).includes(kind)) {
139
- throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV).join(", ")}`);
140
- }
141
- }
142
- function pathsResolverBaseDir(kind, options) {
143
- pathsResolverAssertKind(kind);
132
+ function pathsResolverDataBaseDir(options) {
144
133
  const env = options.env ?? process.env;
145
- const override = env[PATHS_RESOLVER_KIND_ENV[kind]];
134
+ const override = env[PATHS_RESOLVER_DATA_ENV];
146
135
  if (typeof override === "string" && override.length > 0)
147
136
  return override;
148
137
  const home = options.home ?? pathsResolverHomedir();
149
138
  const platform = options.platform ?? process.platform;
150
- if (platform === "darwin") {
151
- switch (kind) {
152
- case "config":
153
- case "data":
154
- return pathsResolverJoin(home, "Library", "Application Support", "Hasna");
155
- case "cache":
156
- return pathsResolverJoin(home, "Library", "Caches", "Hasna");
157
- case "state":
158
- return pathsResolverJoin(home, "Library", "Logs", "Hasna");
159
- }
160
- }
161
- switch (kind) {
162
- case "config":
163
- return pathsResolverJoin(home, ".config", "hasna");
164
- case "data":
165
- return pathsResolverJoin(home, ".local", "share", "hasna");
166
- case "state":
167
- return pathsResolverJoin(home, ".local", "state", "hasna");
168
- case "cache":
169
- return pathsResolverJoin(home, ".cache", "hasna");
170
- }
139
+ return platform === "darwin" ? pathsResolverJoin(home, "Library", "Application Support", "Hasna") : pathsResolverJoin(home, ".local", "share", "hasna");
171
140
  }
172
- function pathsResolverResolve(kind, options) {
141
+ function dataDir(options) {
173
142
  pathsResolverAssertApp(options.app);
174
143
  const appSegment = options.internal === true ? pathsResolverJoin("internal", options.app) : options.app;
175
- return pathsResolverJoin(pathsResolverBaseDir(kind, options), appSegment);
176
- }
177
- function dataDir(options) {
178
- return pathsResolverResolve("data", options);
144
+ return pathsResolverJoin(pathsResolverDataBaseDir(options), appSegment);
179
145
  }
180
146
  var DATA_DIR_ENV = "HASNA_SKILLS_DIR";
181
147
  var HASNA_SKILLS_HOME_ENV = "HASNA_SKILLS_HOME";
@@ -298,6 +298,7 @@ them alone by design. Adoption is the migration mode for that population:
298
298
  ```bash
299
299
  skills sync --adopt # dry-run: hash unmarked home skills vs the corpus
300
300
  skills sync --adopt --apply # write markers for exact matches; ledger the rest
301
+ skills sync my-skill --adopt --for codex --source ./skills --apply
301
302
  ```
302
303
 
303
304
  Each unmarked home skill's `SKILL.md` is hashed (line endings normalized,
@@ -312,6 +313,26 @@ Each unmarked home skill's `SKILL.md` is hashed (line endings normalized,
312
313
  Every written marker is listed in a rollback record under
313
314
  `~/.hasna/skills/rollback/`. Nothing is ever deleted by adoption.
314
315
 
316
+ ### Managed home ownership
317
+
318
+ Ordinary sync updates an existing directory only when its regular
319
+ `.hasna-skills.json` sidecar contains `managedBy: "@hasna/skills"`. Missing,
320
+ foreign or malformed markers leave the directory unmanaged. A directory with
321
+ `SKILL.md` can still be explicitly replaced using `skills sync --force`;
322
+ an unmanaged directory without `SKILL.md` is always preserved. Preview mode
323
+ uses the same ownership decision and writes nothing.
324
+
325
+ The library's `removeManagedAgentSkill` and `removeSkillForAgent` follow the same
326
+ exact-owner check, including project and global agent installs. They return
327
+ `false` and preserve a directory without valid Skills ownership; neither has a
328
+ force override.
329
+
330
+ Remote tombstones also preserve directories without exact Skills ownership.
331
+ Registry reconciliation accepts a marker's baseline hash and version only when
332
+ that same marker names the Skills owner. Foreign or invalid markers cannot choose
333
+ which divergent copy wins; the existing conflict policy and explicit overrides
334
+ still apply.
335
+
315
336
  ### Home drift census
316
337
 
317
338
  ```bash
@@ -324,5 +345,12 @@ Compares each existing agent home against the canonical corpus and lists
324
345
  candidates, not drift. `skills diff <name>` and `skills outdated` use the same
325
346
  home-vs-canonical comparison; the pinned-skill version comparison remains as a
326
347
  subset. `skills sync --prune [--apply]` removes only marked-and-stray dirs,
327
- recording each removal in the rollback store before it happens.
328
-
348
+ recording each removal in the rollback store before it happens. Adoption and
349
+ prune honor `--source` (then `$SKILLS_SOURCE`, then the installed cache), `--for`
350
+ and optional skill names. Names are normalized and must exist in the selected
351
+ corpus or selected agent homes; a stale prune target need not exist in the corpus.
352
+ Invalid selections fail before any apply write. Prune requires the marker
353
+ `managedBy` to be exactly `@hasna/skills`; another tool's marker never grants
354
+ deletion authority. Adoption also leaves every already-marked directory alone.
355
+ Rollback records contain identities, hashes and markers, not backups of removed
356
+ file content.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,6 +32,7 @@
32
32
  "files": [
33
33
  "dist/",
34
34
  "!dist/**/*.test.d.ts",
35
+ "!dist/**/*.fixture.d.ts",
35
36
  "!dist/test-preload.d.ts",
36
37
  "!dist/platform",
37
38
  "bin/",
@@ -57,8 +58,9 @@
57
58
  "migrate": "bun run ./src/server/migrate.ts",
58
59
  "typecheck": "tsc --noEmit",
59
60
  "verify:release": "bun run scripts/release-guard.ts",
61
+ "verify:consumer-types": "bun run scripts/consumer-types.ts",
60
62
  "prepare": "bun run build:js",
61
- "prepack": "bun run build && bun run verify:release",
63
+ "prepack": "bun run build && bun run verify:release && bun run verify:consumer-types",
62
64
  "prepublishOnly": "bun run typecheck && bun run test"
63
65
  },
64
66
  "keywords": [
@@ -80,6 +82,7 @@
80
82
  "author": "Hasna",
81
83
  "license": "Apache-2.0",
82
84
  "devDependencies": {
85
+ "@hasna/contracts": "1.0.2",
83
86
  "@types/bun": "1.3.14",
84
87
  "@types/node": "25.2.3",
85
88
  "@types/react": "^18.2.0",
@@ -91,8 +94,7 @@
91
94
  "dependencies": {
92
95
  "@aws-sdk/client-ecs": "^3.1079.0",
93
96
  "@aws-sdk/client-s3": "^3.1079.0",
94
- "@hasna/contracts": "1.0.1",
95
- "@hasna/events": "0.1.16",
97
+ "@hasna/events": "0.1.18",
96
98
  "@modelcontextprotocol/sdk": "^1.26.0",
97
99
  "chalk": "^5.3.0",
98
100
  "commander": "^12.1.0",
@@ -1 +0,0 @@
1
- export {};