@hasna/skills 0.7.2 → 0.8.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.
Files changed (50) hide show
  1. package/README.md +69 -18
  2. package/bin/index.js +31416 -17660
  3. package/bin/mcp.js +20185 -5957
  4. package/bin/migrate.js +24 -61
  5. package/bin/server.js +73578 -20340
  6. package/bin/worker.js +65161 -19252
  7. package/dist/admin-contract.js +34 -15
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.js +19581 -5535
  10. package/dist/lib/agent-discovery-bytes.d.ts +1 -0
  11. package/dist/lib/agent-discovery-path-bytes.d.ts +5 -0
  12. package/dist/lib/agent-discovery.d.ts +3 -1
  13. package/dist/lib/agent-policy-limits.d.ts +4 -0
  14. package/dist/lib/config.d.ts +3 -23
  15. package/dist/lib/installer.d.ts +1 -1
  16. package/dist/lib/portable-skills-types.d.ts +2 -0
  17. package/dist/lib/portable-skills.d.ts +1 -1
  18. package/dist/lib/registry-data/index.d.ts +1 -0
  19. package/dist/lib/registry-types.d.ts +2 -1
  20. package/dist/lib/registry.d.ts +2 -12
  21. package/dist/lib/release-dependencies.d.ts +30 -0
  22. package/dist/lib/skill-aliases.d.ts +2 -3
  23. package/dist/mcp/mcp-test-client.d.ts +2 -2
  24. package/dist/sdk/executor.d.ts +5 -5
  25. package/dist/sdk/index.js +89668 -40182
  26. package/dist/sdk/registry.d.ts +3 -3
  27. package/dist/server/config.d.ts +1 -2
  28. package/dist/server/handlers.d.ts +5 -2
  29. package/dist/server/registry.d.ts +6 -3
  30. package/dist/server/skills-api.d.ts +6 -38
  31. package/dist/storage.js +5 -42
  32. package/package.json +5 -3
  33. package/dist/lib/registry-data/business-marketing.d.ts +0 -2
  34. package/dist/lib/registry-data/communication.d.ts +0 -2
  35. package/dist/lib/registry-data/content-generation.d.ts +0 -2
  36. package/dist/lib/registry-data/data-analysis.d.ts +0 -2
  37. package/dist/lib/registry-data/design-branding.d.ts +0 -2
  38. package/dist/lib/registry-data/development-tools.d.ts +0 -2
  39. package/dist/lib/registry-data/education-learning.d.ts +0 -2
  40. package/dist/lib/registry-data/event-management.d.ts +0 -2
  41. package/dist/lib/registry-data/finance-compliance.d.ts +0 -2
  42. package/dist/lib/registry-data/health-wellness.d.ts +0 -2
  43. package/dist/lib/registry-data/media-processing.d.ts +0 -2
  44. package/dist/lib/registry-data/productivity-organization.d.ts +0 -2
  45. package/dist/lib/registry-data/project-management.d.ts +0 -2
  46. package/dist/lib/registry-data/research-writing.d.ts +0 -2
  47. package/dist/lib/registry-data/science-academic.d.ts +0 -2
  48. package/dist/lib/registry-data/travel-lifestyle.d.ts +0 -2
  49. package/dist/lib/registry-data/web-browser.d.ts +0 -2
  50. package/dist/server/seed-bundled.d.ts +0 -20
package/bin/migrate.js CHANGED
@@ -2,12 +2,12 @@
2
2
  // @bun
3
3
 
4
4
  // src/server/migrate.ts
5
- import { existsSync as existsSync4, readdirSync as readdirSync3, readFileSync as readFileSync3 } from "fs";
6
- import { join as join6 } from "path";
5
+ import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
6
+ import { join as join5 } from "path";
7
7
  // package.json
8
8
  var package_default = {
9
9
  name: "@hasna/skills",
10
- version: "0.7.2",
10
+ version: "0.8.0",
11
11
  description: "Skills library for AI coding agents",
12
12
  type: "module",
13
13
  bin: {
@@ -70,7 +70,8 @@ var package_default = {
70
70
  "verify:consumer-types": "bun run scripts/consumer-types.ts",
71
71
  prepare: "bun run build:js",
72
72
  prepack: "bun run build && bun run verify:release && bun run verify:consumer-types",
73
- prepublishOnly: "bun run typecheck && bun run test"
73
+ prepublishOnly: "bun run verify:producer && bun run typecheck && bun run test",
74
+ "verify:producer": "bun run scripts/release-dependencies.ts"
74
75
  },
75
76
  keywords: [
76
77
  "skills",
@@ -91,7 +92,8 @@ var package_default = {
91
92
  author: "Hasna",
92
93
  license: "Apache-2.0",
93
94
  devDependencies: {
94
- "@hasna/contracts": "1.0.2",
95
+ "@hasna/contracts": "1.1.0",
96
+ "@hasna/secrets": "0.4.2",
95
97
  "@types/bun": "1.3.14",
96
98
  "@types/node": "25.2.3",
97
99
  "@types/react": "^18.2.0",
@@ -188,7 +190,6 @@ function resolveServerConfig(env = process.env) {
188
190
  port,
189
191
  databaseUrl: env[DATABASE_URL_ENV] || env.DATABASE_URL || undefined,
190
192
  bootstrapApiKey: env.HASNA_SKILLS_BOOTSTRAP_API_KEY || undefined,
191
- seedBundledCorpus: (env.HASNA_SKILLS_SEED_BUNDLED_CORPUS ?? "1") !== "0",
192
193
  artifactBucket: env.HASNA_SKILLS_S3_BUCKET || env.SKILLS_S3_BUCKET || undefined,
193
194
  artifactPrefix: normalizePrefix(env.HASNA_SKILLS_S3_PREFIX || env.SKILLS_S3_PREFIX || "skills/artifacts"),
194
195
  runArtifactPrefix: env.HASNA_SKILLS_S3_RUN_PREFIX ? normalizePrefix(env.HASNA_SKILLS_S3_RUN_PREFIX) : undefined,
@@ -215,12 +216,11 @@ function normalizePrefix(value) {
215
216
  }
216
217
 
217
218
  // src/server/database-url.ts
218
- import { isAbsolute, join as join3 } from "path";
219
+ import { isAbsolute, join as join2 } from "path";
219
220
  import { fileURLToPath } from "url";
220
221
 
221
222
  // src/lib/config.ts
222
- import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync, copyFileSync, readdirSync, statSync } from "fs";
223
- import { join as join2, dirname } from "path";
223
+ import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync } from "fs";
224
224
 
225
225
  // src/lib/app-home.ts
226
226
  import { existsSync } from "fs";
@@ -280,12 +280,6 @@ function exactDataRoot() {
280
280
  }
281
281
  return;
282
282
  }
283
- function hasExactOverride(env = process.env) {
284
- return Boolean(env[DATA_DIR_ENV]?.trim()) || Boolean(env[HASNA_SKILLS_HOME_ENV]?.trim()) || Boolean(env[SKILLS_HOME_ENV]?.trim());
285
- }
286
- function hasOperatorOverride(env = process.env) {
287
- return hasExactOverride(env) || Boolean(env.HASNA_DATA_HOME?.trim());
288
- }
289
283
  function getDataRoot() {
290
284
  const exact = exactDataRoot();
291
285
  if (exact)
@@ -294,42 +288,11 @@ function getDataRoot() {
294
288
  return adoptResolverDataRoot(resolved) ? resolve(resolved) : resolve(legacyDataRoot());
295
289
  }
296
290
  // src/lib/config.ts
297
- function mergeDirectoryContents(sourceDir, targetDir) {
298
- if (!existsSync2(sourceDir))
299
- return;
300
- mkdirSync(targetDir, { recursive: true });
301
- for (const entry of readdirSync(sourceDir)) {
302
- const sourcePath = join2(sourceDir, entry);
303
- const targetPath = join2(targetDir, entry);
304
- try {
305
- const sourceStat = statSync(sourcePath);
306
- if (sourceStat.isDirectory()) {
307
- mergeDirectoryContents(sourcePath, targetPath);
308
- continue;
309
- }
310
- if (!existsSync2(targetPath))
311
- copyFileSync(sourcePath, targetPath);
312
- } catch {}
313
- }
314
- }
315
291
  function getDataDir() {
316
292
  const root = getDataRoot();
317
293
  try {
318
294
  mkdirSync(root, { recursive: true });
319
295
  } catch {}
320
- if (hasOperatorOverride())
321
- return root;
322
- const home = effectiveHome();
323
- const oldDir = join2(home, ".skills");
324
- const oldConfigFile = join2(home, ".skillsrc");
325
- try {
326
- mergeDirectoryContents(oldDir, root);
327
- } catch {}
328
- if (existsSync2(oldConfigFile) && !existsSync2(join2(root, "config.json"))) {
329
- try {
330
- copyFileSync(oldConfigFile, join2(root, "config.json"));
331
- } catch {}
332
- }
333
296
  return root;
334
297
  }
335
298
 
@@ -341,7 +304,7 @@ var SQLITE_SCHEMES = new Set(["sqlite", "sqlite3", "file"]);
341
304
  var MEMORY_SCHEMES = new Set(["memory"]);
342
305
  var SQLITE_EXTENSIONS = [".db", ".sqlite", ".sqlite3", ".db3"];
343
306
  function defaultSqlitePath() {
344
- return join3(getDataDir(), DEFAULT_SQLITE_FILENAME2);
307
+ return join2(getDataDir(), DEFAULT_SQLITE_FILENAME2);
345
308
  }
346
309
  function resolveDatabaseTarget(raw) {
347
310
  const value = raw?.trim();
@@ -368,7 +331,7 @@ function resolveDatabaseTarget(raw) {
368
331
  throw new Error(`unsupported database scheme "${scheme}:". Supported: postgres://, postgresql://, sqlite:, file:, ` + `an absolute or relative path to a .db/.sqlite file, ":memory:", or "memory:" (non-durable, tests only). ` + `Leave the setting empty to use the default SQLite database at ${defaultSqlitePath()}.`);
369
332
  }
370
333
  if (looksLikeSqlitePath(value)) {
371
- const path = isAbsolute(value) ? value : join3(process.cwd(), value);
334
+ const path = isAbsolute(value) ? value : join2(process.cwd(), value);
372
335
  return { kind: "sqlite", path, durable: true, label: `sqlite (${path})` };
373
336
  }
374
337
  throw new Error(`could not resolve a database backend from "${value}". Use postgres://\u2026, sqlite:\u2026, an absolute or ` + `relative path ending in ${SQLITE_EXTENSIONS.join("/")}, ":memory:", or leave it empty for the ` + `default SQLite database at ${defaultSqlitePath()}.`);
@@ -392,7 +355,7 @@ function sqlitePathFromUrl(value, scheme) {
392
355
  }
393
356
  return rest.slice(2).replace(/^\/\/+/, "/");
394
357
  }
395
- return isAbsolute(rest) ? rest : join3(process.cwd(), rest);
358
+ return isAbsolute(rest) ? rest : join2(process.cwd(), rest);
396
359
  }
397
360
  function looksLikeSqlitePath(value) {
398
361
  if (value.includes("/"))
@@ -402,17 +365,17 @@ function looksLikeSqlitePath(value) {
402
365
 
403
366
  // src/server/migrations-dir.ts
404
367
  import { existsSync as existsSync3 } from "fs";
405
- import { dirname as dirname2, join as join4 } from "path";
368
+ import { dirname, join as join3 } from "path";
406
369
  var MIGRATION_DIALECTS = ["postgres", "sqlite"];
407
370
  var MAX_WALK_UP = 6;
408
371
  function findMigrationsRoot(startDirs = defaultStartDirs()) {
409
372
  for (const start of startDirs) {
410
373
  let dir = start;
411
374
  for (let level = 0;level < MAX_WALK_UP; level += 1) {
412
- const candidate = join4(dir, "migrations");
413
- if (MIGRATION_DIALECTS.some((dialect) => existsSync3(join4(candidate, dialect))))
375
+ const candidate = join3(dir, "migrations");
376
+ if (MIGRATION_DIALECTS.some((dialect) => existsSync3(join3(candidate, dialect))))
414
377
  return candidate;
415
- const parent = dirname2(dir);
378
+ const parent = dirname(dir);
416
379
  if (parent === dir)
417
380
  break;
418
381
  dir = parent;
@@ -424,7 +387,7 @@ function resolveMigrationsDir(dialect, root = findMigrationsRoot()) {
424
387
  if (!root) {
425
388
  throw new Error(`could not locate the migrations directory for dialect "${dialect}". ` + `Expected a migrations/${dialect}/ folder alongside the package root.`);
426
389
  }
427
- const dir = join4(root, dialect);
390
+ const dir = join3(root, dialect);
428
391
  if (!existsSync3(dir)) {
429
392
  throw new Error(`migrations directory not found: ${dir}`);
430
393
  }
@@ -539,8 +502,8 @@ class SqliteSkillSelectionStore {
539
502
 
540
503
  // src/server/sqlite-store.ts
541
504
  import { randomUUID as randomUUID3 } from "crypto";
542
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync as readdirSync2 } from "fs";
543
- import { dirname as dirname3, join as join5 } from "path";
505
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync } from "fs";
506
+ import { dirname as dirname2, join as join4 } from "path";
544
507
 
545
508
  // src/server/auth.ts
546
509
  import { createHash } from "crypto";
@@ -1100,7 +1063,7 @@ class SqliteSkillsStore {
1100
1063
  constructor(path = SQLITE_MEMORY_PATH, options = {}) {
1101
1064
  const inMemory = path === SQLITE_MEMORY_PATH;
1102
1065
  if (!inMemory)
1103
- mkdirSync2(dirname3(path), { recursive: true });
1066
+ mkdirSync2(dirname2(path), { recursive: true });
1104
1067
  this.db = openDatabase(path);
1105
1068
  this.db.exec(`PRAGMA busy_timeout = ${Math.max(0, options.busyTimeoutMs ?? 5000)}`);
1106
1069
  if (!inMemory)
@@ -1653,14 +1616,14 @@ function applySqliteMigrations(db, migrationsDir = resolveMigrationsDir("sqlite"
1653
1616
  version text PRIMARY KEY,
1654
1617
  applied_at text NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
1655
1618
  )`);
1656
- const files = readdirSync2(migrationsDir).filter((name) => name.endsWith(".sql")).sort();
1619
+ const files = readdirSync(migrationsDir).filter((name) => name.endsWith(".sql")).sort();
1657
1620
  if (files.length === 0) {
1658
1621
  throw new Error(`no .sql migrations found in ${migrationsDir}`);
1659
1622
  }
1660
1623
  const appliedNow = [];
1661
1624
  for (const file of files) {
1662
1625
  const version = file.replace(/\.sql$/, "");
1663
- const text = readFileSync2(join5(migrationsDir, file), "utf8");
1626
+ const text = readFileSync2(join4(migrationsDir, file), "utf8");
1664
1627
  const apply = db.transaction(() => {
1665
1628
  const already = db.query("SELECT 1 AS present FROM schema_migrations WHERE version = ? LIMIT 1").get(version);
1666
1629
  if (already)
@@ -1742,14 +1705,14 @@ async function runPostgresMigrations(databaseUrl, migrationsDir) {
1742
1705
  const appliedRows = await sql`SELECT version FROM schema_migrations`;
1743
1706
  const applied = new Set(appliedRows.map((row) => row.version));
1744
1707
  const appliedNow = [];
1745
- const files = readdirSync3(migrationsDir).filter((name) => name.endsWith(".sql")).sort();
1708
+ const files = readdirSync2(migrationsDir).filter((name) => name.endsWith(".sql")).sort();
1746
1709
  if (files.length === 0)
1747
1710
  throw new Error(`no .sql migrations found in ${migrationsDir}`);
1748
1711
  for (const file of files) {
1749
1712
  const version = file.replace(/\.sql$/, "");
1750
1713
  if (applied.has(version))
1751
1714
  continue;
1752
- const sqlText = readFileSync3(join6(migrationsDir, file), "utf8");
1715
+ const sqlText = readFileSync3(join5(migrationsDir, file), "utf8");
1753
1716
  await sql.unsafe("BEGIN");
1754
1717
  try {
1755
1718
  await sql.unsafe(sqlText);