@hasna/skills 0.9.11 → 0.9.13

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.
@@ -1,4 +1,4 @@
1
- import type { ServerSkillVersion, ServerArtifact, ServerPin, ServerRunLog, ServerRunRecord, ServerSkillBundle, ServerSkillRecord } from "./types.js";
1
+ import type { ServerSkillVersion, ServerArtifact, ServerPin, ServerRunLog, ServerRunRecord, ServerSkillBundle, ServerSkillRecord, PublishedSkillSelectionState } from "./types.js";
2
2
  export declare function nowIso(): string;
3
3
  /**
4
4
  * Coerce a caller-supplied row limit to a non-negative integer.
@@ -17,6 +17,7 @@ export declare function rowToRun(row: Record<string, unknown>): ServerRunRecord;
17
17
  export declare function rowToLog(row: Record<string, unknown>): ServerRunLog;
18
18
  export declare function rowToArtifact(row: Record<string, unknown>): ServerArtifact;
19
19
  export declare function rowToSkill(row: Record<string, unknown>): ServerSkillRecord;
20
+ export declare function rowToPublishedSelectionState(row: Record<string, unknown>): PublishedSkillSelectionState;
20
21
  export declare function rowToPin(row: Record<string, unknown>): ServerPin;
21
22
  export declare function rowToSkillBundle(row: Record<string, unknown>): ServerSkillBundle;
22
23
  export declare function parseJsonObject(value: unknown): Record<string, unknown>;
@@ -15,7 +15,7 @@ import { SqliteExecutionGrantStore } from "./execution-grant-store.js";
15
15
  */
16
16
  import { Database } from "bun:sqlite";
17
17
  import { SqliteSkillSelectionStore } from "./selection-store.js";
18
- import type { ApiPrincipal, ClaimRunInput, CreateRunInput, PublishSkillInput, RunTransitionPatch, ServerArtifact, ServerPin, ServerRunLog, ServerRunRecord, ServerSkillBundle, ServerSkillVersion, ApiKeyScopeUpdateResult, OperatorScopeEnrollmentInput, OperatorScopeEnrollmentResult, OperatorScopeTargetSnapshot, ServerSkillRecord, SkillLifecyclePatch, SkillsProductStore, StoreBackendInfo, UpdateSkillPatch } from "./types.js";
18
+ import type { ApiPrincipal, ClaimRunInput, CreateRunInput, PublishSkillInput, PublishedSkillSelection, PublishedSkillSelectionState, RunTransitionPatch, ServerArtifact, ServerPin, ServerRunLog, ServerRunRecord, ServerSkillBundle, ServerSkillVersion, ApiKeyScopeUpdateResult, OperatorScopeEnrollmentInput, OperatorScopeEnrollmentResult, OperatorScopeTargetSnapshot, ServerSkillRecord, SkillLifecyclePatch, SkillsProductStore, StoreBackendInfo, UpdateSkillPatch } from "./types.js";
19
19
  export interface SqliteStoreOptions {
20
20
  /** Apply pending migrations on open. Default true - it is what makes zero-config work. */
21
21
  migrate?: boolean;
@@ -113,6 +113,7 @@ export declare class SqliteSkillsStore implements SkillsProductStore {
113
113
  getSkillBundle(principal: ApiPrincipal, sha256: string): Promise<ServerSkillBundle | null>;
114
114
  listSkillVersions(principal: ApiPrincipal, slug: string): Promise<ServerSkillVersion[]>;
115
115
  getSkillVersion(principal: ApiPrincipal, slug: string, version: string): Promise<ServerSkillVersion | null>;
116
+ getPublishedSelectionStates(principal: ApiPrincipal, selections: readonly PublishedSkillSelection[]): Promise<PublishedSkillSelectionState[]>;
116
117
  pinSkill(principal: ApiPrincipal, slug: string, metadata?: Record<string, unknown>): Promise<ServerPin>;
117
118
  unpinSkill(principal: ApiPrincipal, slug: string): Promise<boolean>;
118
119
  listPins(principal: ApiPrincipal): Promise<ServerPin[]>;
@@ -1,6 +1,6 @@
1
1
  import { MemoryExecutionGrantStore, PostgresExecutionGrantStore } from "./execution-grant-store.js";
2
2
  import { MemorySkillSelectionStore, PostgresSkillSelectionStore } from "./selection-store.js";
3
- import type { ApiPrincipal, ClaimRunInput, CreateRunInput, PublishSkillInput, RunTransitionPatch, ServerArtifact, ServerPin, ServerRunLog, ServerRunRecord, ServerSkillBundle, ServerSkillRecord, ServerSkillVersion, ApiKeyScopeUpdateResult, OperatorScopeEnrollmentInput, OperatorScopeEnrollmentResult, OperatorScopeTargetSnapshot, SkillsProductStore, StoreBackendInfo, UpdateSkillPatch } from "./types.js";
3
+ import type { ApiPrincipal, ClaimRunInput, CreateRunInput, PublishSkillInput, PublishedSkillSelection, PublishedSkillSelectionState, RunTransitionPatch, ServerArtifact, ServerPin, ServerRunLog, ServerRunRecord, ServerSkillBundle, ServerSkillRecord, ServerSkillVersion, ApiKeyScopeUpdateResult, OperatorScopeEnrollmentInput, OperatorScopeEnrollmentResult, OperatorScopeTargetSnapshot, SkillsProductStore, StoreBackendInfo, UpdateSkillPatch } from "./types.js";
4
4
  import { type SkillLifecyclePatch } from "./types.js";
5
5
  import { type SqliteStoreOptions } from "./sqlite-store.js";
6
6
  export declare function createArtifactId(): string;
@@ -79,6 +79,7 @@ export declare class MemorySkillsStore implements SkillsProductStore {
79
79
  publishSkill(input: PublishSkillInput): Promise<ServerSkillRecord>;
80
80
  listSkillVersions(principal: ApiPrincipal, slug: string): Promise<ServerSkillVersion[]>;
81
81
  getSkillVersion(principal: ApiPrincipal, slug: string, version: string): Promise<ServerSkillVersion | null>;
82
+ getPublishedSelectionStates(principal: ApiPrincipal, selections: readonly PublishedSkillSelection[]): Promise<PublishedSkillSelectionState[]>;
82
83
  listSkills(principal: ApiPrincipal): Promise<ServerSkillRecord[]>;
83
84
  getSkill(principal: ApiPrincipal, slug: string): Promise<ServerSkillRecord | null>;
84
85
  setSkillLifecycle(principal: ApiPrincipal, slug: string, patch: SkillLifecyclePatch, expectedRevisionId?: string): Promise<ServerSkillRecord | null>;
@@ -180,6 +181,7 @@ export declare class PostgresSkillsStore implements SkillsProductStore {
180
181
  getSkillBundle(principal: ApiPrincipal, sha256: string): Promise<ServerSkillBundle | null>;
181
182
  listSkillVersions(principal: ApiPrincipal, slug: string): Promise<ServerSkillVersion[]>;
182
183
  getSkillVersion(principal: ApiPrincipal, slug: string, version: string): Promise<ServerSkillVersion | null>;
184
+ getPublishedSelectionStates(principal: ApiPrincipal, selections: readonly PublishedSkillSelection[]): Promise<PublishedSkillSelectionState[]>;
183
185
  pinSkill(principal: ApiPrincipal, slug: string, metadata?: Record<string, unknown>): Promise<ServerPin>;
184
186
  unpinSkill(principal: ApiPrincipal, slug: string): Promise<boolean>;
185
187
  listPins(principal: ApiPrincipal): Promise<ServerPin[]>;
@@ -279,6 +279,17 @@ export interface ServerSkillVersion {
279
279
  publishedByUserId?: string;
280
280
  createdAt: string;
281
281
  }
282
+ /** Exact version lookup, independent of the registry's mutable current version. */
283
+ export interface PublishedSkillSelection {
284
+ slug: string;
285
+ version: string;
286
+ }
287
+ /** Metadata only: bundle availability means its tenant-owned storage row exists. */
288
+ export interface PublishedSkillSelectionState extends PublishedSkillSelection {
289
+ current: Pick<ServerSkillRecord, "lifecycle" | "tombstonedAt"> | null;
290
+ versionBundleSha256: string | null;
291
+ bundleAvailable: boolean;
292
+ }
282
293
  export interface PublishSkillInput {
283
294
  /** Internal boot-seed precondition: never revive or replace non-bundled records. */
284
295
  seedBundledOnly?: true;
@@ -441,6 +452,13 @@ export interface SkillsProductStore {
441
452
  /** Every published version of a slug, newest first (hasna/apps#1630). */
442
453
  listSkillVersions(principal: ApiPrincipal, slug: string): Promise<ServerSkillVersion[]>;
443
454
  getSkillVersion(principal: ApiPrincipal, slug: string, version: string): Promise<ServerSkillVersion | null>;
455
+ /**
456
+ * Read at most MAX_PROFILE_SELECTIONS exact selections in one database snapshot,
457
+ * scoped to the principal's org at every join. Returns one row per input in input
458
+ * order, including missing selections and duplicates. Never reads bundle bytes or
459
+ * substitutes the latest version; callers retain lifecycle/digest error policy.
460
+ */
461
+ getPublishedSelectionStates(principal: ApiPrincipal, selections: readonly PublishedSkillSelection[]): Promise<PublishedSkillSelectionState[]>;
444
462
  pinSkill(principal: ApiPrincipal, slug: string, metadata?: Record<string, unknown>): Promise<ServerPin>;
445
463
  /** False when this principal has no pin by that slug. */
446
464
  unpinSkill(principal: ApiPrincipal, slug: string): Promise<boolean>;
@@ -286,3 +286,39 @@ cache history is bounded to 128 entries and an aggregate 256 MiB per witness.
286
286
  Primary runtime references: [command sources](https://code.claude.com/docs/en/plugin-marketplaces#command-sources),
287
287
  [plugin components](https://code.claude.com/docs/en/plugins-reference), and
288
288
  [exact command acceptance](https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md#21271).
289
+
290
+ ### Explicit v2 preference reviews
291
+
292
+ `captureClaudeSettingsV2(path)` creates a `claude-settings-v2` witness. In
293
+ addition to the v1 display/model selections, it tolerates the documented
294
+ persisted effort values `low`, `medium`, `high`, and `xhigh`, both at the top
295
+ level and in known built-in model entries whose only property is `effortLevel`.
296
+ Custom model entries and entries with any other property remain fully bound.
297
+ The boolean `skipDangerousModePermissionPrompt` is Claude's saved dialog
298
+ acknowledgment; it does not select a permission mode. Permission settings,
299
+ plugins, hooks, environment, ultracode and unknown configuration remain bound.
300
+ Invalid recognized preference types are refused.
301
+
302
+ `captureClaudeMarketplaceRegistryV2(path)` creates a
303
+ `claude-marketplace-registry-v2` witness. It also recognizes a registry row with
304
+ an optional boolean `autoUpdate`. That boolean remains bound; only a strictly
305
+ validated `lastUpdated` timestamp may vary. A new source or installation path,
306
+ a changed automatic-update policy, or an unknown field still requires review.
307
+
308
+ Capture either witness through the CLI:
309
+
310
+ ```sh
311
+ skills hook witness --kind claude-settings-v2 --path /canonical/home/.claude/settings.json --json
312
+ skills hook witness --kind claude-marketplace-registry-v2 --path /canonical/home/.claude/plugins/known_marketplaces.json --json
313
+ ```
314
+
315
+ Capture does not install or authorize a review. Compare the current complete
316
+ configuration with its previous review, put the chosen witness in the reviewed
317
+ discovery inputs, and preview `skills hook install --discovery-inputs <file>`
318
+ before applying. Existing byte and v1 witnesses are never silently converted.
319
+ Runtime support for the selected witness version must be installed before
320
+ policy activation. A real hook installation is a configuration change, not a
321
+ preference: its owning installer must coordinate a guarded settings/policy
322
+ update, or it needs a fresh explicit review.
323
+
324
+ The effort schema follows [Claude's model configuration documentation](https://code.claude.com/docs/en/model-config#adjust-effort-level).
@@ -122,7 +122,7 @@ incomplete, invalid, or whose `content_hash` does not match the bundle.
122
122
  | `name` | string | Lowercase slug; matches the folder name |
123
123
  | `description` | string | What this skill does and when to use it |
124
124
  | `version` | string | Semver (e.g. `0.1.0`). Any content change requires a version bump |
125
- | `runtime` | object | The runtime contract below |
125
+ | `runtime` | object | The runtime contract below; optional for explicit `kind: instruction` |
126
126
  | `provenance` | object | Source and integrity fields; `content_hash` is required |
127
127
 
128
128
  ### Optional fields (legacy-compatible)
@@ -139,6 +139,12 @@ incomplete, invalid, or whose `content_hash` does not match the bundle.
139
139
 
140
140
  ### The runtime contract
141
141
 
142
+ An explicit `kind: instruction` manifest may omit `runtime`. Preparation keeps
143
+ that omission and does not invent an executable entrypoint. If runtime metadata
144
+ is supplied for an instruction, its fields still must satisfy this contract.
145
+ Executable manifests and legacy manifests without an explicit kind retain the
146
+ strict runtime requirement.
147
+
142
148
  | field | type | default | meaning |
143
149
  |---|---|---|---|
144
150
  | `runtime` | `"bun" \| "node" \| "python3"` | *(required)* | Execution runtime. `bun` is the Hasna default |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.9.11",
3
+ "version": "0.9.13",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {