hngr 0.6.0 → 0.7.0

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.
@@ -42,6 +42,7 @@ const EXCLUDED_PATHS = [
42
42
  "/api/v1/capabilities/{capability_id}/versions/{version}/content",
43
43
  "/api/v1/capabilities/{capability_id}/versions/{version}/files",
44
44
  "/api/v1/capabilities/{capability_id}/versions/{version}/file",
45
+ "/api/v1/capabilities/{capability_id}/versions/{version}/derive",
45
46
  "/api/v1/auth/methods",
46
47
  "/api/v1/auth/oidc/login",
47
48
  "/api/v1/auth/oidc/callback",
@@ -1479,6 +1480,42 @@ const COMMANDS = deriveCommands({
1479
1480
  }
1480
1481
  }
1481
1482
  },
1483
+ "/api/v1/capabilities/{capability_id}/versions/{version}/derive": { "post": {
1484
+ "operationId": "deriveCapabilityVersion",
1485
+ "summary": "Publish a new Version by editing the files of the current Skill Version.",
1486
+ "description": "Derives a new Version from the package of `{version}` by replacing the\nlisted entries and publishes it through the same pipeline as\n`publishCapabilityVersion`: CalVer allocation, the current-version\nswitch and the `capability.version_published` Audit Event all follow\nthe existing publishing rules. Only a Skill Capability accepts this\noperation; an MCP Capability answers 400.\n\n`{version}` must be the Capability's Current Version; any other CalVer\nanswers 409 `/problems/version-conflict`. The check runs again after\nthe Capability row is locked, so a concurrent publish is reported\nrather than silently replaced. Each `edits` path is matched exactly\nagainst a non-directory entry of the baseline package (case\nsensitive); an unknown path, a directory, a non-text entry, an entry\nlarger than 256 KiB, or more than 1 MiB of edits in total answers 400.\n\nThe new Version inherits the baseline Version's `readme` unchanged,\nincluding a null value, for which the existing display rule falls back\nto the package's `SKILL.md`. The request has no README field. This\noperation does not increment `download_count`.\n\nThe caller must manage the Capability's Namespace, under the same\nrules as `publishCapabilityVersion`: a deleted or unavailable\nCapability, one in an unusable Namespace, and a private one the caller\ndoes not manage answer 404. A replayed `Idempotency-Key` returns the\nfirst response without deriving again.\n",
1487
+ "security": [{ "sessionCookie": [] }, { "bearerToken": [] }],
1488
+ "parameters": [
1489
+ { "$ref": "#/components/parameters/CapabilityID" },
1490
+ {
1491
+ "name": "version",
1492
+ "in": "path",
1493
+ "required": true,
1494
+ "schema": { "$ref": "#/components/schemas/CalVer" }
1495
+ },
1496
+ { "$ref": "#/components/parameters/IdempotencyKey" }
1497
+ ],
1498
+ "requestBody": {
1499
+ "required": true,
1500
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeriveCapabilityVersionRequest" } } }
1501
+ },
1502
+ "responses": {
1503
+ "201": {
1504
+ "description": "The Capability with its new current version.",
1505
+ "headers": { "Location": {
1506
+ "description": "`/api/v1/capabilities/{capability_id}/versions/{version}`",
1507
+ "schema": { "type": "string" }
1508
+ } },
1509
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Capability" } } }
1510
+ },
1511
+ "400": { "$ref": "#/components/responses/Problem" },
1512
+ "401": { "$ref": "#/components/responses/Problem" },
1513
+ "403": { "$ref": "#/components/responses/Problem" },
1514
+ "404": { "$ref": "#/components/responses/Problem" },
1515
+ "409": { "$ref": "#/components/responses/Problem" },
1516
+ "default": { "$ref": "#/components/responses/Problem" }
1517
+ }
1518
+ } },
1482
1519
  "/api/v1/capabilities/{capability_id}/versions/{version}/content": { "get": {
1483
1520
  "operationId": "lookupCapabilityContent",
1484
1521
  "summary": "Return the Content of one Version of a Capability.",
@@ -3412,6 +3449,34 @@ const COMMANDS = deriveCommands({
3412
3449
  },
3413
3450
  "additionalProperties": false
3414
3451
  },
3452
+ "DeriveCapabilityVersionRequest": {
3453
+ "type": "object",
3454
+ "required": ["edits"],
3455
+ "properties": { "edits": {
3456
+ "type": "array",
3457
+ "description": "Entries to replace in the baseline package. Paths must be unique\nand must exist as non-directory entries of the baseline package.\n",
3458
+ "minItems": 1,
3459
+ "maxItems": 200,
3460
+ "items": { "$ref": "#/components/schemas/DeriveCapabilityVersionEdit" }
3461
+ } },
3462
+ "additionalProperties": false
3463
+ },
3464
+ "DeriveCapabilityVersionEdit": {
3465
+ "type": "object",
3466
+ "required": ["path", "content"],
3467
+ "properties": {
3468
+ "path": {
3469
+ "type": "string",
3470
+ "minLength": 1,
3471
+ "maxLength": 4096
3472
+ },
3473
+ "content": {
3474
+ "type": "string",
3475
+ "description": "UTF-8 text. The server enforces 256 KiB per entry and 1 MiB for\nthe whole request by UTF-8 byte length.\n"
3476
+ }
3477
+ },
3478
+ "additionalProperties": false
3479
+ },
3415
3480
  "Capability": {
3416
3481
  "type": "object",
3417
3482
  "required": [
@@ -1,4 +1,4 @@
1
- import { t as commandCatalog } from "./catalog-r53AMymQ.mjs";
1
+ import { t as commandCatalog } from "./catalog-yVsOzNKU.mjs";
2
2
  // src/commands/commands.ts
3
3
  function run(ctx) {
4
4
  const catalog = commandCatalog();
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as kebabCase, i as normalizeCommandName, n as COMMANDS, o as COMMAND_ALIASES, r as findCommand, t as commandCatalog } from "./catalog-r53AMymQ.mjs";
1
+ import { a as kebabCase, i as normalizeCommandName, n as COMMANDS, o as COMMAND_ALIASES, r as findCommand, t as commandCatalog } from "./catalog-yVsOzNKU.mjs";
2
2
  import { C as HngrError, S as CancelledError, c as redactUrlForDisplay, g as resolveConnection, i as buildRequestUrl, o as redactQuery, r as apiRequest, s as redactSensitive, u as DEFAULT_SERVER_URL, w as renderError } from "./http-DgHX7Fux.mjs";
3
3
  import { t as collectPages } from "./pagination-BXyFxGYA.mjs";
4
4
  import { createRequire } from "node:module";
@@ -5279,7 +5279,7 @@ function isYargsInstance(y) {
5279
5279
  // ../../node_modules/.pnpm/yargs@18.2.0/node_modules/yargs/index.mjs
5280
5280
  const Yargs = YargsFactory(esm_default);
5281
5281
  // package.json
5282
- var version = "0.6.0";
5282
+ var version = "0.7.0";
5283
5283
  // src/generated/completion.ts
5284
5284
  function isCompletionShell(value) {
5285
5285
  return value === "bash" || value === "zsh" || value === "fish";
@@ -7075,7 +7075,7 @@ function buildParser(onMatched) {
7075
7075
  parser.command("commands", "Print the command catalog", () => {}, (argv) => {
7076
7076
  onMatched({
7077
7077
  argv,
7078
- run: async (ctx) => (await import("./commands-_R93Y2z-.mjs")).run(ctx)
7078
+ run: async (ctx) => (await import("./commands-KKAq0m6z.mjs")).run(ctx)
7079
7079
  });
7080
7080
  });
7081
7081
  parser.command("auth", "Manage credentials", (auth) => {
@@ -7155,7 +7155,7 @@ function buildParser(onMatched) {
7155
7155
  }), (argv) => {
7156
7156
  onMatched({
7157
7157
  argv,
7158
- run: async (ctx, matchedArgv) => (await import("./skills-B92ip3mJ.mjs")).add(ctx, matchedArgv)
7158
+ run: async (ctx, matchedArgv) => (await import("./skills-BH59pgRw.mjs")).add(ctx, matchedArgv)
7159
7159
  });
7160
7160
  });
7161
7161
  skills.command("publish <paths..>", "Publish a local skill directory as a capability or a new version", (publish) => publish.option("namespace", {
@@ -7183,7 +7183,7 @@ function buildParser(onMatched) {
7183
7183
  }), (argv) => {
7184
7184
  onMatched({
7185
7185
  argv,
7186
- run: async (ctx, matchedArgv) => (await import("./skills-B92ip3mJ.mjs")).publish(ctx, matchedArgv)
7186
+ run: async (ctx, matchedArgv) => (await import("./skills-BH59pgRw.mjs")).publish(ctx, matchedArgv)
7187
7187
  });
7188
7188
  });
7189
7189
  return skills.demandCommand(1);
@@ -241,12 +241,12 @@ function readSkillPackage(buffer) {
241
241
  if (seen.has(folded)) throw invalid$1(`entry ${JSON.stringify(name)} appears more than once`);
242
242
  seen.add(folded);
243
243
  }
244
- const manifests = files.filter((entry) => lastSegment$1(entry.name).toLowerCase() === "skill.md");
245
- if (manifests.length === 0) throw invalid$1("the package has no SKILL.md");
246
- if (manifests.length > 1) throw invalid$1(`the package has more than one SKILL.md: ${manifests.map((entry) => entry.name).join(", ")}`);
247
244
  const root = packageRoot$1(names);
248
245
  const expectedManifest = `${root}SKILL.md`;
249
- if (manifests[0]?.name !== expectedManifest) throw invalid$1(`found ${manifests[0]?.name}, but the package needs SKILL.md at its root or inside its single top-level directory`);
246
+ if (!files.find((entry) => entry.name === expectedManifest)) {
247
+ const manifests = files.filter((entry) => lastSegment$1(entry.name).toLowerCase() === "skill.md");
248
+ throw invalid$1(manifests.length === 0 ? "the package has no SKILL.md" : `found ${manifests.map((entry) => entry.name).join(", ")}, but the package needs SKILL.md at its root or inside its single top-level directory`);
249
+ }
250
250
  let actualBytes = 0;
251
251
  const entries = [];
252
252
  let manifest;
@@ -455,11 +455,11 @@ async function packageSkillDirectory(dir) {
455
455
  if (seen.has(folded)) throw invalid(`entry ${JSON.stringify(entry.path)} appears more than once`);
456
456
  seen.add(folded);
457
457
  }
458
- const manifests = entries.filter((entry) => lastSegment(entry.path).toLowerCase() === "skill.md");
459
- if (manifests.length === 0) throw invalid("the directory has no SKILL.md");
460
- if (manifests.length > 1) throw invalid(`the directory has more than one SKILL.md: ${manifests.map((entry) => entry.path).join(", ")}`);
461
458
  const expected = `${packageRoot(entries.map((entry) => entry.path))}SKILL.md`;
462
- if (manifests[0]?.path !== expected) throw invalid(`found ${manifests[0]?.path}, but the package needs SKILL.md at its root or inside its single top-level directory`);
459
+ if (!entries.some((entry) => entry.path === expected)) {
460
+ const manifests = entries.filter((entry) => lastSegment(entry.path).toLowerCase() === "skill.md");
461
+ throw invalid(manifests.length === 0 ? "the directory has no SKILL.md" : `found ${manifests.map((entry) => entry.path).join(", ")}, but the package needs SKILL.md at its root or inside its single top-level directory`);
462
+ }
463
463
  return {
464
464
  zip: buildZip(entries),
465
465
  fileCount: entries.length,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hngr",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "The Hangar CLI: install skills and MCP servers into coding agents, and drive the Management API.",
5
5
  "keywords": [
6
6
  "hangar",