@hasna/skills 0.10.70 → 0.10.72

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/dist/storage.js CHANGED
@@ -53,13 +53,13 @@ import {
53
53
  mkdirSync as mkdirSync3,
54
54
  readFileSync as readFileSync3,
55
55
  readdirSync,
56
- statSync,
56
+ statSync as statSync2,
57
57
  writeFileSync as writeFileSync3
58
58
  } from "fs";
59
59
  import { dirname as dirname2, join as join4, normalize, relative, sep } from "path";
60
60
 
61
61
  // src/lib/config.ts
62
- import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync } from "fs";
62
+ import { closeSync, constants, existsSync as existsSync2, fstatSync, lstatSync, openSync, readFileSync, statSync, writeFileSync, mkdirSync } from "fs";
63
63
  import { join as join2, dirname } from "path";
64
64
 
65
65
  // src/lib/retired-settings.ts
@@ -195,7 +195,8 @@ function skillsDataRootForHome(home) {
195
195
  var ENUM_KEYS = {
196
196
  defaultAgent: ["claude", "codex", "gemini", "pi", "opencode", "all"],
197
197
  defaultScope: ["global", "project"],
198
- format: ["compact", "json", "csv"]
198
+ format: ["compact", "json", "csv"],
199
+ sessionPinMigration: ["auto", "off"]
199
200
  };
200
201
  var STRING_KEYS = ["extensionsDir"];
201
202
  function validKeys() {
@@ -266,6 +267,9 @@ function saveConfig(key, value, scope = "project") {
266
267
  if (!validKeys().includes(key)) {
267
268
  throw new Error(`Unknown config key: ${key}. Valid keys: ${validKeys().join(", ")}`);
268
269
  }
270
+ if (key === "sessionPinMigration" && scope !== "global") {
271
+ throw new Error(`${key} is read only from the global configuration. Use: skills config set ${key} <auto|off> --global`);
272
+ }
269
273
  const normalized = normalizeConfigValue(key, value);
270
274
  if (normalized === undefined) {
271
275
  const allowed = allowedValues(key);
@@ -959,7 +963,7 @@ function walkFiles(dir) {
959
963
  const files = [];
960
964
  for (const entry of readdirSync(dir)) {
961
965
  const full = join4(dir, entry);
962
- const stats = statSync(full);
966
+ const stats = statSync2(full);
963
967
  if (stats.isDirectory())
964
968
  files.push(...walkFiles(full));
965
969
  else
@@ -194,8 +194,9 @@ closure. Nontrivial `metadata.pluginRoot` values and native catalog or selected
194
194
  plugin dependency declarations refuse because this validator does not resolve
195
195
  or review unselected external plugins.
196
196
  The request may declare `functionHooksEnv: "1"`; without that declaration the
197
- environment document is preserved unchanged. For a measured Claude 2.1.293
198
- user-scoped install, `candidate.settingsMarketplaceSource: "directory"`
197
+ environment document is preserved unchanged. For a measured Claude 2.1.276,
198
+ 2.1.278, 2.1.282, 2.1.287, 2.1.293, 2.1.296 or 2.1.299 user-scoped install,
199
+ `candidate.settingsMarketplaceSource: "directory"`
199
200
  explicitly declares the native settings registration. Skills derives
200
201
  `extraKnownMarketplaces[candidate.marketplace].source` from the exact frozen
201
202
  candidate root. The measured operation accepts existing directory sources
@@ -329,9 +330,23 @@ What the software currently enforces is narrower:
329
330
  managed row's `installPath` to be `cache/<marketplace>/<plugin>/<version>`,
330
331
  checks every file in every retained cache version against the admission
331
332
  receipts without the review listing them, and binds unmanaged rows exactly.
333
+ - Claude rewrites the 13-digit millisecond timestamp in
334
+ `.claude/plugins/cache/<marketplace>/<plugin>/<version>/.orphaned_at` when it
335
+ starts. Capturing that exact path with `captureDiscoveryByteSources` or
336
+ `captureDiscoveryPathSources` (including the installer `path-bytes`
337
+ operation) produces a `claude-plugin-orphaned-at-v1` witness, and a fresh
338
+ explicit review converts a plain byte or `path-bytes` witness of it to that
339
+ form. The witness binds the marker's presence or absence, not its bytes or
340
+ inode. Every capture and check still requires a regular, non-symlink file
341
+ owned by the current user, at most 32 bytes, matching `^[1-9][0-9]{12}$`.
342
+ The name stays in `directories` membership, so other added or removed names
343
+ are still detected. A marker at any other depth, any other name, and any
344
+ Skills-owned producer tree keep their exact byte witnesses. A stored review
345
+ that binds the marker's bytes keeps that meaning and needs one fresh review.
332
346
  - An entirely absent retired Claude version root exempts only its plain byte
333
347
  sources (`hashMode` omitted or `"bytes"`, with no `format`, `fields` or
334
- `managedPlugins`). Such a source with a non-null `sha256` is also the only
348
+ `managedPlugins`) and a present `claude-plugin-orphaned-at-v1` marker. Such a
349
+ source with a non-null `sha256` is also the only
335
350
  thing that identifies the root, and the root qualifies only while it stays
336
351
  entirely absent and the reviewed settings and registry select a different,
337
352
  verified version. Every other source under that root is re-hashed as usual,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.10.70",
3
+ "version": "0.10.72",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {