@hasna/skills 0.10.58 → 0.10.59

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/bin/index.js CHANGED
@@ -36888,7 +36888,7 @@ var package_default;
36888
36888
  var init_package = __esm(() => {
36889
36889
  package_default = {
36890
36890
  name: "@hasna/skills",
36891
- version: "0.10.58",
36891
+ version: "0.10.59",
36892
36892
  description: "Skills library for AI coding agents",
36893
36893
  type: "module",
36894
36894
  bin: {
@@ -116856,7 +116856,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
116856
116856
  const pluginRootStat = lstatSync37(pluginRoot, { throwIfNoEntry: false });
116857
116857
  if (pluginRootStat && (!pluginRootStat.isDirectory() || pluginRootStat.isSymbolicLink()))
116858
116858
  refuse6("Claude plugin root is not a regular directory");
116859
- keys3(request2.candidate, ["marketplace", "root", "catalogPath", "catalogSha256", "closureSha256", "plugins", ...hasOwn2(request2.candidate, "releaseManifest") ? ["releaseManifest"] : [], ...hasOwn2(request2.candidate, "functionHooksEnv") ? ["functionHooksEnv"] : []], "candidate");
116859
+ keys3(request2.candidate, ["marketplace", "root", "catalogPath", "catalogSha256", "closureSha256", "plugins", ...hasOwn2(request2.candidate, "releaseManifest") ? ["releaseManifest"] : [], ...hasOwn2(request2.candidate, "functionHooksEnv") ? ["functionHooksEnv"] : [], ...hasOwn2(request2.candidate, "settingsMarketplaceSource") ? ["settingsMarketplaceSource"] : []], "candidate");
116860
116860
  const candidate2 = request2.candidate;
116861
116861
  canonicalDir(candidate2.root, "candidate root");
116862
116862
  if (typeof candidate2.marketplace !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(candidate2.marketplace))
@@ -116865,6 +116865,8 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
116865
116865
  refuse6("candidate must select between one and 32 plugins from one marketplace");
116866
116866
  if (candidate2.functionHooksEnv !== undefined && candidate2.functionHooksEnv !== "1")
116867
116867
  refuse6("function-hook environment mutation only supports the explicit value 1");
116868
+ if (hasOwn2(candidate2, "settingsMarketplaceSource") && (candidate2.settingsMarketplaceSource !== "directory" || request2.scope.kind !== "user" || !["2.1.293", "2.1.293 (Claude Code)"].includes(request2.native.executable.version)))
116869
+ refuse6("settings marketplace source operation requires directory source and the measured Claude 2.1.293 user scope");
116868
116870
  abs(candidate2.catalogPath, "catalog path");
116869
116871
  if (!candidate2.catalogPath.startsWith(candidate2.root + sep15))
116870
116872
  refuse6("catalog must be inside the frozen candidate root");
@@ -117011,6 +117013,30 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
117011
117013
  const registrations = jsonFile(expectedPaths.installedPlugins, "Claude installed plugins");
117012
117014
  if (registrations && (registrations.version !== 2 || !object11(registrations.plugins)))
117013
117015
  refuse6("current installed plugin registry has an unsupported shape");
117016
+ if (candidate2.settingsMarketplaceSource === "directory" && registrations) {
117017
+ keys3(registrations, ["version", "plugins"], "current complete installed plugin registry");
117018
+ for (const rows of Object.values(registrations.plugins)) {
117019
+ if (!Array.isArray(rows))
117020
+ refuse6("current installed plugin rows are not an array");
117021
+ for (const row2 of rows) {
117022
+ if (!object11(row2))
117023
+ refuse6("current installed plugin row is not an object");
117024
+ keys3(row2, ["scope", "installPath", "version", "installedAt", "lastUpdated", ...Object.hasOwn(row2, "projectPath") ? ["projectPath"] : [], ...Object.hasOwn(row2, "gitCommitSha") ? ["gitCommitSha"] : []], "current complete installed plugin row");
117025
+ if (!["user", "project", "local"].includes(row2.scope) || typeof row2.version !== "string" || !row2.version)
117026
+ refuse6("current installed plugin scope or version is invalid");
117027
+ abs(row2.installPath, "current installed plugin path");
117028
+ if (row2.scope === "user") {
117029
+ if (Object.hasOwn(row2, "projectPath"))
117030
+ refuse6("current user plugin row has a project path");
117031
+ } else
117032
+ abs(row2.projectPath, "current installed plugin project path");
117033
+ if (!validUtcTimestamp(row2.installedAt) || !validUtcTimestamp(row2.lastUpdated))
117034
+ refuse6("current installed plugin timestamps are invalid");
117035
+ if (Object.hasOwn(row2, "gitCommitSha") && (typeof row2.gitCommitSha !== "string" || !/^[a-f0-9]{40}$/.test(row2.gitCommitSha)))
117036
+ refuse6("current installed plugin Git commit is outside the measured preservation contract");
117037
+ }
117038
+ }
117039
+ }
117014
117040
  const settingsAfter = settings ? structuredClone(settings) : {};
117015
117041
  if (settingsAfter.enabledPlugins === undefined)
117016
117042
  settingsAfter.enabledPlugins = {};
@@ -117088,8 +117114,48 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
117088
117114
  refuse6("target settings env is not an object");
117089
117115
  settingsAfter.env = { ...env3, CLAUDE_CODE_ENABLE_FUNCTION_HOOKS: "1" };
117090
117116
  }
117117
+ if (candidate2.settingsMarketplaceSource === "directory") {
117118
+ const extra = settingsAfter.extraKnownMarketplaces === undefined ? {} : settingsAfter.extraKnownMarketplaces;
117119
+ if (!object11(extra))
117120
+ refuse6("current extraKnownMarketplaces is not an object");
117121
+ for (const [name, row2] of Object.entries(extra)) {
117122
+ if (!object11(row2))
117123
+ refuse6("current settings marketplace row is not an object");
117124
+ const allowed = name === candidate2.marketplace ? ["source"] : ["source", "autoUpdate"];
117125
+ if (Object.keys(row2).some((key) => !allowed.includes(key)) || !Object.hasOwn(row2, "source"))
117126
+ refuse6("current settings marketplace metadata cannot be preserved by the measured native operation");
117127
+ if (Object.hasOwn(row2, "autoUpdate") && typeof row2.autoUpdate !== "boolean")
117128
+ refuse6("current settings marketplace autoUpdate is not a boolean");
117129
+ keys3(row2.source, ["source", "path"], "current settings marketplace directory source");
117130
+ if (row2.source.source !== "directory")
117131
+ refuse6("current settings marketplace source is outside the measured directory contract");
117132
+ abs(row2.source.path, "current settings marketplace directory path");
117133
+ }
117134
+ settingsAfter.extraKnownMarketplaces = { ...extra, [candidate2.marketplace]: { source: { source: "directory", path: candidate2.root } } };
117135
+ for (const row2 of Object.values(marketplaces ?? {})) {
117136
+ if (!object11(row2))
117137
+ refuse6("current known marketplace row is not an object");
117138
+ keys3(row2, ["source", "installLocation", "lastUpdated", ...Object.hasOwn(row2, "autoUpdate") ? ["autoUpdate"] : []], "current known marketplace row");
117139
+ if (!object11(row2.source))
117140
+ refuse6("current known marketplace source is not an object");
117141
+ if (row2.source.source === "directory") {
117142
+ keys3(row2.source, ["source", "path"], "current known marketplace directory source");
117143
+ abs(row2.source.path, "current known marketplace directory path");
117144
+ } else if (row2.source.source === "github") {
117145
+ keys3(row2.source, ["source", "repo"], "current known marketplace GitHub source");
117146
+ if (typeof row2.source.repo !== "string" || row2.source.repo.length > 512 || !/^[A-Za-z0-9][A-Za-z0-9_.-]*\/[A-Za-z0-9][A-Za-z0-9_.-]*$/.test(row2.source.repo))
117147
+ refuse6("current known marketplace GitHub repository is not an owner/repository identifier");
117148
+ } else
117149
+ refuse6("current known marketplace source is outside the measured preservation contract");
117150
+ abs(row2.installLocation, "current known marketplace install location");
117151
+ if (!validUtcTimestamp(row2.lastUpdated))
117152
+ refuse6("current known marketplace timestamp is invalid");
117153
+ if (Object.hasOwn(row2, "autoUpdate") && typeof row2.autoUpdate !== "boolean")
117154
+ refuse6("current known marketplace autoUpdate is not a boolean");
117155
+ }
117156
+ }
117091
117157
  if (!isDeepStrictEqual18(delta.settingsAfter, settingsAfter))
117092
- refuse6("complete settings document differs from the exact selected plugin/options/environment operations");
117158
+ refuse6("complete settings document differs from the exact selected plugin/options/environment/marketplace operations");
117093
117159
  const marketplaceRowBefore = marketplaces?.[candidate2.marketplace];
117094
117160
  if (marketplaceRowBefore !== undefined && !object11(marketplaceRowBefore))
117095
117161
  refuse6("current marketplace row has an unsupported shape");
package/bin/mcp.js CHANGED
@@ -20019,7 +20019,7 @@ var package_default;
20019
20019
  var init_package = __esm(() => {
20020
20020
  package_default = {
20021
20021
  name: "@hasna/skills",
20022
- version: "0.10.58",
20022
+ version: "0.10.59",
20023
20023
  description: "Skills library for AI coding agents",
20024
20024
  type: "module",
20025
20025
  bin: {
package/bin/migrate.js CHANGED
@@ -25,7 +25,7 @@ import { join as join5 } from "path";
25
25
  // package.json
26
26
  var package_default = {
27
27
  name: "@hasna/skills",
28
- version: "0.10.58",
28
+ version: "0.10.59",
29
29
  description: "Skills library for AI coding agents",
30
30
  type: "module",
31
31
  bin: {
package/bin/server.js CHANGED
@@ -24140,7 +24140,7 @@ restoreLaunchCwd();
24140
24140
  // package.json
24141
24141
  var package_default = {
24142
24142
  name: "@hasna/skills",
24143
- version: "0.10.58",
24143
+ version: "0.10.59",
24144
24144
  description: "Skills library for AI coding agents",
24145
24145
  type: "module",
24146
24146
  bin: {
package/bin/worker.js CHANGED
@@ -24143,7 +24143,7 @@ import { randomUUID as randomUUID6 } from "crypto";
24143
24143
  // package.json
24144
24144
  var package_default = {
24145
24145
  name: "@hasna/skills",
24146
- version: "0.10.58",
24146
+ version: "0.10.59",
24147
24147
  description: "Skills library for AI coding agents",
24148
24148
  type: "module",
24149
24149
  bin: {
package/dist/index.js CHANGED
@@ -11834,7 +11834,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
11834
11834
  // package.json
11835
11835
  var package_default = {
11836
11836
  name: "@hasna/skills",
11837
- version: "0.10.58",
11837
+ version: "0.10.59",
11838
11838
  description: "Skills library for AI coding agents",
11839
11839
  type: "module",
11840
11840
  bin: {
@@ -40,6 +40,7 @@ export interface ClaudeProspectiveReviewRequest {
40
40
  sha256: string;
41
41
  };
42
42
  functionHooksEnv?: "1";
43
+ settingsMarketplaceSource?: "directory";
43
44
  };
44
45
  preimages: {
45
46
  settings: {
package/dist/sdk/index.js CHANGED
@@ -32373,7 +32373,7 @@ var init_event_sink = __esm(() => {
32373
32373
  // package.json
32374
32374
  var package_default = {
32375
32375
  name: "@hasna/skills",
32376
- version: "0.10.58",
32376
+ version: "0.10.59",
32377
32377
  description: "Skills library for AI coding agents",
32378
32378
  type: "module",
32379
32379
  bin: {
@@ -194,7 +194,32 @@ 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. The validator shallow-merges
197
+ environment document is preserved unchanged. For a measured Claude 2.1.293
198
+ user-scoped install, `candidate.settingsMarketplaceSource: "directory"`
199
+ explicitly declares the native settings registration. Skills derives
200
+ `extraKnownMarketplaces[candidate.marketplace].source` from the exact frozen
201
+ candidate root. The measured operation accepts existing directory sources
202
+ only. Foreign entries may also carry a boolean `autoUpdate`; other metadata
203
+ refuses before writing because the native parser drops unknown fields.
204
+ Selected-entry metadata, including `autoUpdate`, also refuses because this
205
+ Claude release replaces that entire entry. The complete supplied settings
206
+ document must match the derived projection, preserving all foreign entries.
207
+ The same declared operation preflights every authoritative
208
+ `known_marketplaces.json` row: exact `source`, `installLocation`, `lastUpdated`
209
+ and optional boolean `autoUpdate`. Sources are either `{source: "directory",
210
+ path: <normalized absolute path>}` or `{source: "github", repo: "owner/repository"}`.
211
+ Other source keys and row metadata refuse before the native parser can drop them.
212
+ The complete `installed_plugins.json` document must contain only `version` and
213
+ `plugins`. Every existing row, including untouched plugins and other scopes,
214
+ must have `scope`, `installPath`, `version`, `installedAt` and `lastUpdated`,
215
+ with a project path for project/local scope and an optional 40-character
216
+ lowercase hexadecimal `gitCommitSha`. Unsupported metadata or malformed fields
217
+ refuse before installation; supported foreign rows remain exact in the required
218
+ after-document. Existing selected-row restrictions still apply.
219
+ Omission preserves the settings field unchanged; other values, versions and project scope
220
+ refuse. The installer must still verify the actual native executable and
221
+ poststate; a supplied version string does not establish consumer identity.
222
+ The validator shallow-merges
198
223
  each declared options patch into the selected plugin's existing `options`;
199
224
  the patch must explicitly bind `enabled: true`, and the validator enforces that
200
225
  value after merging. This preserves all other selected options and unrelated
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.10.58",
3
+ "version": "0.10.59",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {