@hasna/skills 0.5.11 → 0.6.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.
- package/README.md +95 -53
- package/bin/index.js +17696 -30169
- package/bin/mcp.js +8358 -22504
- package/bin/migrate.js +108 -6
- package/bin/server.js +5827 -565
- package/bin/worker.js +489 -135
- package/dist/admin-contract.d.ts +13 -13
- package/dist/admin-contract.js +28 -47
- package/dist/cli/commands/agent-integration.d.ts +2 -0
- package/dist/cli/commands/context.d.ts +19 -0
- package/dist/cli/commands/install.d.ts +1 -0
- package/dist/cli/commands/profile-sync.d.ts +10 -0
- package/dist/cli/commands/profiles.d.ts +2 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5406 -19111
- package/dist/lib/agent-integration.d.ts +74 -0
- package/dist/lib/cloud-executions.d.ts +39 -0
- package/dist/lib/managed-policy.d.ts +6 -0
- package/dist/lib/profile-admin.d.ts +4 -0
- package/dist/lib/profile-client.d.ts +19 -0
- package/dist/lib/read-access.d.ts +3 -23
- package/dist/lib/selected-document.d.ts +6 -0
- package/dist/lib/selected-run.d.ts +31 -0
- package/dist/lib/selection-cache.d.ts +40 -0
- package/dist/lib/selection-resolver.d.ts +75 -0
- package/dist/lib/skill-context.d.ts +43 -0
- package/dist/lib/skillinfo.d.ts +2 -0
- package/dist/sdk/execution/dispatchers/ecs.d.ts +8 -0
- package/dist/sdk/index.d.ts +2 -0
- package/dist/sdk/index.js +9911 -8305
- package/dist/server/app.d.ts +7 -1
- package/dist/server/artifact-storage.d.ts +7 -10
- package/dist/server/auth.d.ts +2 -0
- package/dist/server/config.d.ts +2 -0
- package/dist/server/profile-api.d.ts +3 -0
- package/dist/server/runtime-api.d.ts +31 -0
- package/dist/server/runtime-policy.d.ts +25 -0
- package/dist/server/runtime-store.d.ts +73 -0
- package/dist/server/runtime-worker.d.ts +19 -0
- package/dist/server/selection-store.d.ts +39 -0
- package/dist/server/sqlite-store.d.ts +2 -0
- package/dist/server/store.d.ts +3 -0
- package/dist/server/types.d.ts +3 -0
- package/dist/types/skill-selection.d.ts +41 -0
- package/migrations/postgres/0007_skill_profiles.sql +19 -0
- package/migrations/postgres/0008_skill_runtime.sql +14 -0
- package/migrations/sqlite/0007_skill_profiles.sql +19 -0
- package/migrations/sqlite/0008_skill_runtime.sql +14 -0
- 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.
|
|
10
|
+
version: "0.6.0",
|
|
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
|
-
|
|
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
|
|
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)}_${
|
|
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
|
-
|
|
1198
|
+
randomUUID3(),
|
|
1097
1199
|
nowIso()
|
|
1098
1200
|
]);
|
|
1099
1201
|
return rowToRun(row);
|