hubskillz 0.2.2 → 0.3.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 (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +73 -30
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -102,7 +102,7 @@ Prompts are skipped when stdin is not a TTY: `sync` needs `--yes` to apply, `pro
102
102
  | `HUBSKILLZ_BASE_URL` | Server URL for self-hosted instances. |
103
103
  | `NO_COLOR` | Disables colours. Colours are also off when stdout is not a TTY. |
104
104
 
105
- The server URL resolves in this order: `--base-url` flag, `HUBSKILLZ_BASE_URL`, the config file, then `https://hubskillz.com`.
105
+ The server URL resolves in this order: `--base-url` flag, `HUBSKILLZ_BASE_URL`, the config file, then `https://api.hubskillz.com`.
106
106
 
107
107
  ## Exit codes
108
108
 
package/dist/index.js CHANGED
@@ -18911,6 +18911,7 @@ var MAX_FILES_PER_SKILL = 100;
18911
18911
  var MAX_FILE_CONTENT_CHARS = 2e5;
18912
18912
  var MAX_SKILLS_PER_REQUEST = 500;
18913
18913
  var MAX_SNAPSHOT_CHARS = MAX_FILE_CONTENT_CHARS;
18914
+ var MAX_INVENTORY_CHUNK_BYTES = 15e5;
18914
18915
  var inventoryFileSchema = external_exports.object({
18915
18916
  path: skillFilePathSchema,
18916
18917
  hash: external_exports.string().min(1),
@@ -18961,7 +18962,12 @@ var inventoryRequestSchema = external_exports.object({
18961
18962
  files: external_exports.array(inventoryFileSchema).max(MAX_FILES_PER_SKILL),
18962
18963
  upstream: inventoryUpstreamSchema.optional()
18963
18964
  })
18964
- ).max(MAX_SKILLS_PER_REQUEST)
18965
+ ).max(MAX_SKILLS_PER_REQUEST),
18966
+ /** Big surfaces travel in chunks: chunk 0 replaces, the others append. */
18967
+ chunk: external_exports.object({
18968
+ index: external_exports.number().int().min(0),
18969
+ total: external_exports.number().int().min(1)
18970
+ }).optional()
18965
18971
  });
18966
18972
  var inventoryItemSchema = external_exports.object({
18967
18973
  name: external_exports.string(),
@@ -18981,7 +18987,9 @@ var inventoryResponseSchema = external_exports.object({
18981
18987
  });
18982
18988
  var approvedQuerySchema = external_exports.object({ surfaceId: external_exports.string().min(1) });
18983
18989
  var approvedSkillSchema = external_exports.object({
18984
- name: external_exports.string(),
18990
+ // Kebab, not z.string(): the CLI joins this onto a path (commands/sync.ts),
18991
+ // so the response is validated rather than trusted.
18992
+ name: skillNameSchema,
18985
18993
  versionId: external_exports.string(),
18986
18994
  version: external_exports.number().int(),
18987
18995
  contentHash: external_exports.string(),
@@ -19160,7 +19168,7 @@ import { randomUUID } from "node:crypto";
19160
19168
  import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
19161
19169
  import { homedir, hostname as hostname3 } from "node:os";
19162
19170
  import { join } from "node:path";
19163
- var DEFAULT_BASE_URL = "https://hubskillz.com";
19171
+ var DEFAULT_BASE_URL = "https://api.hubskillz.com";
19164
19172
  var configSchema = external_exports.object({
19165
19173
  baseUrl: external_exports.string().min(1),
19166
19174
  token: external_exports.string().min(1),
@@ -19515,7 +19523,7 @@ function globalSurfaceLabel() {
19515
19523
  return hostname4();
19516
19524
  }
19517
19525
  function projectSurfaceLabel(dir) {
19518
- return `${hostname4()}:${basename(resolve2(dir))}`;
19526
+ return `${basename(resolve2(dir))} (${hostname4()})`;
19519
19527
  }
19520
19528
  async function exists(path) {
19521
19529
  try {
@@ -19622,25 +19630,49 @@ async function isDir(path) {
19622
19630
  function inventoryRequestOf(surface) {
19623
19631
  return {
19624
19632
  surface: surface.descriptor,
19625
- skills: surface.skills.map((skill) => {
19626
- const snapshot = skill.upstream === void 0 && skill.files.reduce((sum, file2) => sum + file2.content.length, 0) <= MAX_SNAPSHOT_CHARS;
19627
- const item = {
19628
- name: skill.name,
19629
- contentHash: skill.contentHash,
19630
- files: skill.files.map((file2) => {
19631
- const entry = {
19632
- path: file2.path,
19633
- hash: file2.hash,
19634
- size: file2.size
19635
- };
19636
- if (snapshot) entry.content = file2.content;
19637
- return entry;
19638
- })
19633
+ skills: surface.skills.map(inventorySkillOf)
19634
+ };
19635
+ }
19636
+ function inventoryChunksOf(surface) {
19637
+ const groups = [];
19638
+ let group = [];
19639
+ let bytes = 0;
19640
+ for (const skill of surface.skills) {
19641
+ const item = inventorySkillOf(skill);
19642
+ const size = Buffer.byteLength(JSON.stringify(item), "utf8");
19643
+ if (group.length > 0 && (bytes + size > MAX_INVENTORY_CHUNK_BYTES || group.length >= MAX_SKILLS_PER_REQUEST)) {
19644
+ groups.push(group);
19645
+ group = [];
19646
+ bytes = 0;
19647
+ }
19648
+ group.push(item);
19649
+ bytes += size;
19650
+ }
19651
+ groups.push(group);
19652
+ if (groups.length === 1) return [inventoryRequestOf(surface)];
19653
+ return groups.map((skills, index) => ({
19654
+ surface: surface.descriptor,
19655
+ skills,
19656
+ chunk: { index, total: groups.length }
19657
+ }));
19658
+ }
19659
+ function inventorySkillOf(skill) {
19660
+ const snapshot = skill.upstream === void 0 && skill.files.reduce((sum, file2) => sum + file2.content.length, 0) <= MAX_SNAPSHOT_CHARS;
19661
+ const item = {
19662
+ name: skill.name,
19663
+ contentHash: skill.contentHash,
19664
+ files: skill.files.map((file2) => {
19665
+ const entry = {
19666
+ path: file2.path,
19667
+ hash: file2.hash,
19668
+ size: file2.size
19639
19669
  };
19640
- if (skill.upstream !== void 0) item.upstream = skill.upstream;
19641
- return item;
19670
+ if (snapshot) entry.content = file2.content;
19671
+ return entry;
19642
19672
  })
19643
19673
  };
19674
+ if (skill.upstream !== void 0) item.upstream = skill.upstream;
19675
+ return item;
19644
19676
  }
19645
19677
 
19646
19678
  // src/discover.ts
@@ -19863,13 +19895,20 @@ ${quickstart(config2)}`);
19863
19895
  return Result.ok(void 0);
19864
19896
  }
19865
19897
  async function postInventory(session, surface) {
19866
- return apiRequest({
19867
- session,
19868
- method: "POST",
19869
- path: "/api/cli/inventory",
19870
- schema: inventoryResponseSchema,
19871
- body: inventoryRequestOf(surface)
19872
- });
19898
+ const chunks = inventoryChunksOf(surface);
19899
+ let merged;
19900
+ for (const body of chunks) {
19901
+ const posted = await apiRequest({
19902
+ session,
19903
+ method: "POST",
19904
+ path: "/api/cli/inventory",
19905
+ schema: inventoryResponseSchema,
19906
+ body
19907
+ });
19908
+ if (posted.isFailure) return posted;
19909
+ merged = merged === void 0 ? posted.value : { ...merged, items: [...merged.items, ...posted.value.items] };
19910
+ }
19911
+ return Result.ok(merged ?? { surfaceId: "", items: [] });
19873
19912
  }
19874
19913
  function originOf(surface, name) {
19875
19914
  const skill = surface.skills.find((entry) => entry.name === name);
@@ -20107,6 +20146,10 @@ async function maybeAdopt(session, surface, inventory, options) {
20107
20146
  `Adopt ${plural(importable.length)} found here as approved in your directory?`
20108
20147
  );
20109
20148
  if (!wanted) return Result.ok(inventory);
20149
+ process.stdout.write(
20150
+ dim(`adopting ${plural(importable.length)}, this can take a minute...
20151
+ `)
20152
+ );
20110
20153
  const adopted = await apiRequest({
20111
20154
  session,
20112
20155
  method: "POST",
@@ -20276,7 +20319,7 @@ function detailOf(plan) {
20276
20319
  var GLOBAL_FLAGS = [
20277
20320
  {
20278
20321
  spec: "--base-url URL",
20279
- help: "Server to talk to (default: config file, then https://hubskillz.com)"
20322
+ help: "Server to talk to (default: config file, then https://api.hubskillz.com)"
20280
20323
  },
20281
20324
  { spec: "-h, --help", help: "Show help" },
20282
20325
  { spec: "-v, --version", help: "Show the version" }
@@ -20353,7 +20396,7 @@ function flagLines(flags) {
20353
20396
  }
20354
20397
  function usage() {
20355
20398
  const width = Math.max(...COMMANDS.map((command) => command.name.length));
20356
- return `${bold("hubskillz")} ${dim(`v${"0.2.2"}`)} keep your agent skills in sync
20399
+ return `${bold("hubskillz")} ${dim(`v${"0.3.1"}`)} keep your agent skills in sync
20357
20400
 
20358
20401
  ${bold("Usage")}
20359
20402
  hubskillz <command> [flags]
@@ -20432,7 +20475,7 @@ Run \`hubskillz help\` for usage.`)
20432
20475
  );
20433
20476
  }
20434
20477
  if (values.version === true) {
20435
- process.stdout.write(`${"0.2.2"}
20478
+ process.stdout.write(`${"0.3.1"}
20436
20479
  `);
20437
20480
  return Result.ok(void 0);
20438
20481
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hubskillz",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
4
4
  "description": "Keep your Claude Code skills in sync with your organization's approved catalog.",
5
5
  "license": "MIT",
6
6
  "author": "Jérôme Desmares",