@hasna/skills 0.5.10 → 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 +3467 -1460
- package/bin/mcp.js +2638 -1713
- package/bin/migrate.js +110 -7
- package/bin/server.js +5487 -216
- package/bin/worker.js +372 -17
- package/dist/admin-contract.d.ts +13 -13
- package/dist/admin-contract.js +13 -13
- 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 +1273 -331
- 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 +9791 -8152
- 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/storage.js +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 +3 -2
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: {
|
|
@@ -123,7 +123,8 @@ var package_default = {
|
|
|
123
123
|
},
|
|
124
124
|
repository: {
|
|
125
125
|
type: "git",
|
|
126
|
-
url: "
|
|
126
|
+
url: "https://github.com/hasna/apps.git",
|
|
127
|
+
directory: "apps/skills"
|
|
127
128
|
},
|
|
128
129
|
homepage: "https://github.com/hasna/skills",
|
|
129
130
|
bugs: {
|
|
@@ -190,6 +191,7 @@ function resolveServerConfig(env = process.env) {
|
|
|
190
191
|
seedBundledCorpus: (env.HASNA_SKILLS_SEED_BUNDLED_CORPUS ?? "1") !== "0",
|
|
191
192
|
artifactBucket: env.HASNA_SKILLS_S3_BUCKET || env.SKILLS_S3_BUCKET || undefined,
|
|
192
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,
|
|
193
195
|
inlineWorker: env.HASNA_SKILLS_INLINE_WORKER === "1",
|
|
194
196
|
bundleSigningKey: env.HASNA_SKILLS_API_SIGNING_KEY || env.HASNA_SKILLS_SIGNING_KEY || undefined,
|
|
195
197
|
requestBodyLimitBytes: parsePositiveInt(env.HASNA_SKILLS_REQUEST_BODY_LIMIT_BYTES, 1e6),
|
|
@@ -438,7 +440,105 @@ function defaultStartDirs() {
|
|
|
438
440
|
|
|
439
441
|
// src/server/sqlite-store.ts
|
|
440
442
|
import { Database } from "bun:sqlite";
|
|
441
|
-
|
|
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";
|
|
442
542
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync as readdirSync2 } from "fs";
|
|
443
543
|
import { dirname as dirname3, join as join5 } from "path";
|
|
444
544
|
|
|
@@ -456,12 +556,12 @@ function publicPrincipal(partial = {}) {
|
|
|
456
556
|
userId: partial.userId || "user_dev",
|
|
457
557
|
email: partial.email || "dev@example.com",
|
|
458
558
|
role: partial.role || "owner",
|
|
459
|
-
scopes: partial.scopes
|
|
559
|
+
scopes: partial.scopes ?? ["*"]
|
|
460
560
|
};
|
|
461
561
|
}
|
|
462
562
|
|
|
463
563
|
// src/server/rows.ts
|
|
464
|
-
import { randomUUID } from "crypto";
|
|
564
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
465
565
|
|
|
466
566
|
// src/lib/skill-entry-path.ts
|
|
467
567
|
class SkillEntryPaths {
|
|
@@ -771,7 +871,7 @@ function normalizeLimit(limit) {
|
|
|
771
871
|
return Number.isFinite(limit) ? Math.max(0, Math.trunc(limit)) : 0;
|
|
772
872
|
}
|
|
773
873
|
function runId() {
|
|
774
|
-
return `run_${Date.now().toString(36)}_${
|
|
874
|
+
return `run_${Date.now().toString(36)}_${randomUUID2().slice(0, 8)}`;
|
|
775
875
|
}
|
|
776
876
|
function rowToRun(row) {
|
|
777
877
|
return {
|
|
@@ -991,6 +1091,9 @@ var NO_REVISION_SENTINEL = "0000000000000000000000000000000000000000000000000000
|
|
|
991
1091
|
var LAST_USED_RESOLUTION_MS = 60000;
|
|
992
1092
|
|
|
993
1093
|
class SqliteSkillsStore {
|
|
1094
|
+
get selectionStore() {
|
|
1095
|
+
return new SqliteSkillSelectionStore(this.db);
|
|
1096
|
+
}
|
|
994
1097
|
backend;
|
|
995
1098
|
db;
|
|
996
1099
|
closed = false;
|
|
@@ -1092,7 +1195,7 @@ class SqliteSkillsStore {
|
|
|
1092
1195
|
JSON.stringify(input.input),
|
|
1093
1196
|
JSON.stringify(input.args),
|
|
1094
1197
|
input.idempotencyKey ?? null,
|
|
1095
|
-
|
|
1198
|
+
randomUUID3(),
|
|
1096
1199
|
nowIso()
|
|
1097
1200
|
]);
|
|
1098
1201
|
return rowToRun(row);
|