@hasna/skills 0.5.11 → 0.6.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 (51) hide show
  1. package/README.md +95 -53
  2. package/bin/index.js +17704 -30170
  3. package/bin/mcp.js +6856 -21003
  4. package/bin/migrate.js +108 -6
  5. package/bin/server.js +5827 -565
  6. package/bin/worker.js +489 -135
  7. package/dist/admin-contract.d.ts +13 -13
  8. package/dist/admin-contract.js +28 -47
  9. package/dist/cli/commands/agent-integration.d.ts +2 -0
  10. package/dist/cli/commands/context.d.ts +19 -0
  11. package/dist/cli/commands/install.d.ts +1 -0
  12. package/dist/cli/commands/profile-sync.d.ts +10 -0
  13. package/dist/cli/commands/profiles.d.ts +2 -0
  14. package/dist/cli/commands/runtime.d.ts +0 -3
  15. package/dist/cli/output.d.ts +2 -0
  16. package/dist/index.d.ts +5 -0
  17. package/dist/index.js +5406 -19111
  18. package/dist/lib/agent-integration.d.ts +74 -0
  19. package/dist/lib/cloud-executions.d.ts +39 -0
  20. package/dist/lib/managed-policy.d.ts +6 -0
  21. package/dist/lib/profile-admin.d.ts +4 -0
  22. package/dist/lib/profile-client.d.ts +19 -0
  23. package/dist/lib/read-access.d.ts +3 -23
  24. package/dist/lib/selected-document.d.ts +6 -0
  25. package/dist/lib/selected-run.d.ts +31 -0
  26. package/dist/lib/selection-cache.d.ts +40 -0
  27. package/dist/lib/selection-resolver.d.ts +75 -0
  28. package/dist/lib/skill-context.d.ts +43 -0
  29. package/dist/lib/skillinfo.d.ts +2 -0
  30. package/dist/sdk/execution/dispatchers/ecs.d.ts +8 -0
  31. package/dist/sdk/index.d.ts +2 -0
  32. package/dist/sdk/index.js +9911 -8305
  33. package/dist/server/app.d.ts +7 -1
  34. package/dist/server/artifact-storage.d.ts +7 -10
  35. package/dist/server/auth.d.ts +2 -0
  36. package/dist/server/config.d.ts +2 -0
  37. package/dist/server/profile-api.d.ts +3 -0
  38. package/dist/server/runtime-api.d.ts +31 -0
  39. package/dist/server/runtime-policy.d.ts +25 -0
  40. package/dist/server/runtime-store.d.ts +73 -0
  41. package/dist/server/runtime-worker.d.ts +19 -0
  42. package/dist/server/selection-store.d.ts +39 -0
  43. package/dist/server/sqlite-store.d.ts +2 -0
  44. package/dist/server/store.d.ts +3 -0
  45. package/dist/server/types.d.ts +3 -0
  46. package/dist/types/skill-selection.d.ts +41 -0
  47. package/migrations/postgres/0007_skill_profiles.sql +19 -0
  48. package/migrations/postgres/0008_skill_runtime.sql +14 -0
  49. package/migrations/sqlite/0007_skill_profiles.sql +19 -0
  50. package/migrations/sqlite/0008_skill_runtime.sql +14 -0
  51. package/package.json +1 -1
package/bin/migrate.js CHANGED
@@ -7,7 +7,7 @@ import { join as join6 } from "path";
7
7
  // package.json
8
8
  var package_default = {
9
9
  name: "@hasna/skills",
10
- version: "0.5.11",
10
+ version: "0.6.1",
11
11
  description: "Skills library for AI coding agents",
12
12
  type: "module",
13
13
  bin: {
@@ -191,6 +191,7 @@ function resolveServerConfig(env = process.env) {
191
191
  seedBundledCorpus: (env.HASNA_SKILLS_SEED_BUNDLED_CORPUS ?? "1") !== "0",
192
192
  artifactBucket: env.HASNA_SKILLS_S3_BUCKET || env.SKILLS_S3_BUCKET || undefined,
193
193
  artifactPrefix: normalizePrefix(env.HASNA_SKILLS_S3_PREFIX || env.SKILLS_S3_PREFIX || "skills/artifacts"),
194
+ runArtifactPrefix: env.HASNA_SKILLS_S3_RUN_PREFIX ? normalizePrefix(env.HASNA_SKILLS_S3_RUN_PREFIX) : undefined,
194
195
  inlineWorker: env.HASNA_SKILLS_INLINE_WORKER === "1",
195
196
  bundleSigningKey: env.HASNA_SKILLS_API_SIGNING_KEY || env.HASNA_SKILLS_SIGNING_KEY || undefined,
196
197
  requestBodyLimitBytes: parsePositiveInt(env.HASNA_SKILLS_REQUEST_BODY_LIMIT_BYTES, 1e6),
@@ -439,7 +440,105 @@ function defaultStartDirs() {
439
440
 
440
441
  // src/server/sqlite-store.ts
441
442
  import { Database } from "bun:sqlite";
442
- import { randomUUID as randomUUID2 } from "crypto";
443
+
444
+ // src/server/selection-store.ts
445
+ import { randomUUID } from "crypto";
446
+ function selections(value) {
447
+ return typeof value === "string" ? JSON.parse(value) : structuredClone(value);
448
+ }
449
+ function time(value) {
450
+ return value instanceof Date ? value.toISOString() : String(value);
451
+ }
452
+ function profile(row) {
453
+ return {
454
+ id: String(row.profile_id),
455
+ workspaceId: String(row.org_id),
456
+ revision: String(row.revision),
457
+ selections: selections(row.selections_json),
458
+ updatedAt: time(row.updated_at)
459
+ };
460
+ }
461
+ function state(row) {
462
+ return {
463
+ stationId: String(row.station_id),
464
+ workspaceId: String(row.org_id),
465
+ actorId: String(row.actor_id),
466
+ profileId: String(row.profile_id),
467
+ profileRevision: String(row.profile_revision),
468
+ selections: selections(row.selections_json),
469
+ appliedAt: time(row.applied_at)
470
+ };
471
+ }
472
+
473
+ class MemorySkillSelectionStore {
474
+ profiles = new Map;
475
+ states = new Map;
476
+ key(...values) {
477
+ return JSON.stringify(values);
478
+ }
479
+ async getProfile(p, id) {
480
+ return structuredClone(this.profiles.get(this.key(p.orgId, id)) ?? null);
481
+ }
482
+ async saveProfile(p, id, selected, expected) {
483
+ const key = this.key(p.orgId, id), previous = this.profiles.get(key);
484
+ if ((previous?.revision ?? null) !== expected)
485
+ return null;
486
+ const next = {
487
+ id,
488
+ workspaceId: p.orgId,
489
+ revision: randomUUID(),
490
+ selections: structuredClone(selected),
491
+ updatedAt: new Date().toISOString()
492
+ };
493
+ this.profiles.set(key, next);
494
+ return structuredClone(next);
495
+ }
496
+ async getStationState(p, id) {
497
+ return structuredClone(this.states.get(this.key(p.orgId, p.userId, id)) ?? null);
498
+ }
499
+ async saveStationState(p, id, input) {
500
+ if (this.profiles.get(this.key(p.orgId, input.profileId))?.revision !== input.profileRevision)
501
+ return null;
502
+ const next = {
503
+ ...structuredClone(input),
504
+ stationId: id,
505
+ workspaceId: p.orgId,
506
+ actorId: p.userId,
507
+ appliedAt: new Date().toISOString()
508
+ };
509
+ this.states.set(this.key(p.orgId, p.userId, id), next);
510
+ return structuredClone(next);
511
+ }
512
+ }
513
+
514
+ class SqliteSkillSelectionStore {
515
+ db;
516
+ constructor(db) {
517
+ this.db = db;
518
+ }
519
+ async getProfile(p, id) {
520
+ const row = this.db.query("SELECT * FROM skills_profiles WHERE org_id=? AND profile_id=?").get(p.orgId, id);
521
+ return row ? profile(row) : null;
522
+ }
523
+ async saveProfile(p, id, selected, expected) {
524
+ const revision = randomUUID(), timestamp = new Date().toISOString();
525
+ const row = expected === null ? this.db.query("INSERT INTO skills_profiles(org_id,profile_id,revision,selections_json,updated_at) VALUES(?,?,?,?,?) ON CONFLICT(org_id,profile_id) DO NOTHING RETURNING *").get(p.orgId, id, revision, JSON.stringify(selected), timestamp) : this.db.query("UPDATE skills_profiles SET revision=?,selections_json=?,updated_at=? WHERE org_id=? AND profile_id=? AND revision=? RETURNING *").get(revision, JSON.stringify(selected), timestamp, p.orgId, id, expected);
526
+ return row ? profile(row) : null;
527
+ }
528
+ async getStationState(p, id) {
529
+ const row = this.db.query("SELECT * FROM skills_station_state WHERE org_id=? AND actor_id=? AND station_id=?").get(p.orgId, p.userId, id);
530
+ return row ? state(row) : null;
531
+ }
532
+ async saveStationState(p, id, input) {
533
+ const row = this.db.query(`INSERT INTO skills_station_state(org_id,actor_id,station_id,profile_id,profile_revision,selections_json,applied_at)
534
+ SELECT ?,?,?,?,?,?,? WHERE EXISTS(SELECT 1 FROM skills_profiles WHERE org_id=? AND profile_id=? AND revision=?)
535
+ ON CONFLICT(org_id,actor_id,station_id) DO UPDATE SET profile_id=excluded.profile_id,profile_revision=excluded.profile_revision,selections_json=excluded.selections_json,applied_at=excluded.applied_at RETURNING *`).get(p.orgId, p.userId, id, input.profileId, input.profileRevision, JSON.stringify(input.selections), new Date().toISOString(), p.orgId, input.profileId, input.profileRevision);
536
+ return row ? state(row) : null;
537
+ }
538
+ }
539
+
540
+ // src/server/sqlite-store.ts
541
+ import { randomUUID as randomUUID3 } from "crypto";
443
542
  import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync as readdirSync2 } from "fs";
444
543
  import { dirname as dirname3, join as join5 } from "path";
445
544
 
@@ -457,12 +556,12 @@ function publicPrincipal(partial = {}) {
457
556
  userId: partial.userId || "user_dev",
458
557
  email: partial.email || "dev@example.com",
459
558
  role: partial.role || "owner",
460
- scopes: partial.scopes || ["skills:read", "runs:write"]
559
+ scopes: partial.scopes ?? ["*"]
461
560
  };
462
561
  }
463
562
 
464
563
  // src/server/rows.ts
465
- import { randomUUID } from "crypto";
564
+ import { randomUUID as randomUUID2 } from "crypto";
466
565
 
467
566
  // src/lib/skill-entry-path.ts
468
567
  class SkillEntryPaths {
@@ -772,7 +871,7 @@ function normalizeLimit(limit) {
772
871
  return Number.isFinite(limit) ? Math.max(0, Math.trunc(limit)) : 0;
773
872
  }
774
873
  function runId() {
775
- return `run_${Date.now().toString(36)}_${randomUUID().slice(0, 8)}`;
874
+ return `run_${Date.now().toString(36)}_${randomUUID2().slice(0, 8)}`;
776
875
  }
777
876
  function rowToRun(row) {
778
877
  return {
@@ -992,6 +1091,9 @@ var NO_REVISION_SENTINEL = "0000000000000000000000000000000000000000000000000000
992
1091
  var LAST_USED_RESOLUTION_MS = 60000;
993
1092
 
994
1093
  class SqliteSkillsStore {
1094
+ get selectionStore() {
1095
+ return new SqliteSkillSelectionStore(this.db);
1096
+ }
995
1097
  backend;
996
1098
  db;
997
1099
  closed = false;
@@ -1093,7 +1195,7 @@ class SqliteSkillsStore {
1093
1195
  JSON.stringify(input.input),
1094
1196
  JSON.stringify(input.args),
1095
1197
  input.idempotencyKey ?? null,
1096
- randomUUID2(),
1198
+ randomUUID3(),
1097
1199
  nowIso()
1098
1200
  ]);
1099
1201
  return rowToRun(row);