@hasna/skills 0.8.2 → 0.8.3
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 +70 -2
- package/bin/index.js +585 -282
- package/bin/mcp.js +255 -109
- package/bin/migrate.js +82 -24
- package/bin/server.js +1222 -430
- package/bin/worker.js +395 -87
- package/dist/cli/commands/grants.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/lib/execution-grant-client.d.ts +5 -0
- package/dist/lib/execution-grants.d.ts +49 -0
- package/dist/lib/selected-manifest.d.ts +6 -0
- package/dist/lib/selected-run.d.ts +9 -0
- package/dist/sdk/index.d.ts +2 -0
- package/dist/sdk/index.js +9205 -8724
- package/dist/server/execution-grant-store.d.ts +29 -0
- package/dist/server/execution-grants-api.d.ts +4 -0
- package/dist/server/sqlite-store.d.ts +2 -0
- package/dist/server/store.d.ts +3 -0
- package/dist/server/types.d.ts +2 -0
- package/migrations/postgres/0009_execution_grants.sql +15 -0
- package/migrations/sqlite/0009_execution_grants.sql +15 -0
- package/package.json +1 -1
package/bin/worker.js
CHANGED
|
@@ -76164,11 +76164,11 @@ var init_dist_es9 = __esm(() => {
|
|
|
76164
76164
|
});
|
|
76165
76165
|
|
|
76166
76166
|
// src/server/worker.ts
|
|
76167
|
-
import { randomUUID as
|
|
76167
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
76168
76168
|
// package.json
|
|
76169
76169
|
var package_default = {
|
|
76170
76170
|
name: "@hasna/skills",
|
|
76171
|
-
version: "0.8.
|
|
76171
|
+
version: "0.8.3",
|
|
76172
76172
|
description: "Skills library for AI coding agents",
|
|
76173
76173
|
type: "module",
|
|
76174
76174
|
bin: {
|
|
@@ -87454,11 +87454,82 @@ function looksLikeSqlitePath(value) {
|
|
|
87454
87454
|
return SQLITE_EXTENSIONS.some((extension) => value.toLowerCase().endsWith(extension));
|
|
87455
87455
|
}
|
|
87456
87456
|
|
|
87457
|
+
// src/server/execution-grant-store.ts
|
|
87458
|
+
import { randomUUID } from "crypto";
|
|
87459
|
+
function next(p2, id, grants, expected) {
|
|
87460
|
+
return {
|
|
87461
|
+
schema: "hasna.skills-execution-grants.v1",
|
|
87462
|
+
profileId: id,
|
|
87463
|
+
workspaceId: p2.orgId,
|
|
87464
|
+
revision: randomUUID(),
|
|
87465
|
+
previousRevision: expected,
|
|
87466
|
+
updatedAt: new Date().toISOString(),
|
|
87467
|
+
actorId: p2.userId,
|
|
87468
|
+
grants: structuredClone(grants)
|
|
87469
|
+
};
|
|
87470
|
+
}
|
|
87471
|
+
function document(row) {
|
|
87472
|
+
return row ? typeof row.document_json === "string" ? JSON.parse(row.document_json) : structuredClone(row.document_json) : null;
|
|
87473
|
+
}
|
|
87474
|
+
|
|
87475
|
+
class MemoryExecutionGrantStore {
|
|
87476
|
+
current = new Map;
|
|
87477
|
+
history = new Map;
|
|
87478
|
+
async get(p2, id, revision) {
|
|
87479
|
+
return structuredClone((revision ? this.history.get(JSON.stringify([p2.orgId, id, revision])) : this.current.get(JSON.stringify([p2.orgId, id]))) ?? null);
|
|
87480
|
+
}
|
|
87481
|
+
async save(p2, id, grants, expected) {
|
|
87482
|
+
const key = JSON.stringify([p2.orgId, id]);
|
|
87483
|
+
if ((this.current.get(key)?.revision ?? null) !== expected)
|
|
87484
|
+
return null;
|
|
87485
|
+
const value = next(p2, id, grants, expected);
|
|
87486
|
+
this.current.set(key, value);
|
|
87487
|
+
this.history.set(JSON.stringify([p2.orgId, id, value.revision]), value);
|
|
87488
|
+
return structuredClone(value);
|
|
87489
|
+
}
|
|
87490
|
+
}
|
|
87491
|
+
|
|
87492
|
+
class SqliteExecutionGrantStore {
|
|
87493
|
+
db;
|
|
87494
|
+
constructor(db) {
|
|
87495
|
+
this.db = db;
|
|
87496
|
+
}
|
|
87497
|
+
async get(p2, id, revision) {
|
|
87498
|
+
return document(revision ? this.db.query("SELECT document_json FROM skills_execution_grant_revisions WHERE org_id=? AND profile_id=? AND revision=?").get(p2.orgId, id, revision) : this.db.query("SELECT document_json FROM skills_execution_grants WHERE org_id=? AND profile_id=?").get(p2.orgId, id));
|
|
87499
|
+
}
|
|
87500
|
+
async save(p2, id, grants, expected) {
|
|
87501
|
+
return this.db.transaction(() => {
|
|
87502
|
+
const value = next(p2, id, grants, expected), json = JSON.stringify(value);
|
|
87503
|
+
const row = expected === null ? this.db.query("INSERT INTO skills_execution_grants(org_id,profile_id,revision,document_json) VALUES(?,?,?,?) ON CONFLICT(org_id,profile_id) DO NOTHING RETURNING document_json").get(p2.orgId, id, value.revision, json) : this.db.query("UPDATE skills_execution_grants SET revision=?,document_json=? WHERE org_id=? AND profile_id=? AND revision=? RETURNING document_json").get(value.revision, json, p2.orgId, id, expected);
|
|
87504
|
+
if (!row)
|
|
87505
|
+
return null;
|
|
87506
|
+
this.db.query("INSERT INTO skills_execution_grant_revisions(org_id,profile_id,revision,document_json) VALUES(?,?,?,?)").run(p2.orgId, id, value.revision, json);
|
|
87507
|
+
return document(row);
|
|
87508
|
+
})();
|
|
87509
|
+
}
|
|
87510
|
+
}
|
|
87511
|
+
|
|
87512
|
+
class PostgresExecutionGrantStore {
|
|
87513
|
+
sql;
|
|
87514
|
+
constructor(sql) {
|
|
87515
|
+
this.sql = sql;
|
|
87516
|
+
}
|
|
87517
|
+
async get(p2, id, revision) {
|
|
87518
|
+
const rows = revision ? await this.sql`SELECT document_json FROM skills_execution_grant_revisions WHERE org_id=${p2.orgId} AND profile_id=${id} AND revision=${revision}` : await this.sql`SELECT document_json FROM skills_execution_grants WHERE org_id=${p2.orgId} AND profile_id=${id}`;
|
|
87519
|
+
return document(rows[0]);
|
|
87520
|
+
}
|
|
87521
|
+
async save(p2, id, grants, expected) {
|
|
87522
|
+
const value = next(p2, id, grants, expected), json = JSON.stringify(value);
|
|
87523
|
+
const rows = expected === null ? await this.sql`WITH changed AS (INSERT INTO skills_execution_grants(org_id,profile_id,revision,document_json) VALUES(${p2.orgId},${id},${value.revision},${json}::jsonb) ON CONFLICT(org_id,profile_id) DO NOTHING RETURNING *) INSERT INTO skills_execution_grant_revisions(org_id,profile_id,revision,document_json) SELECT org_id,profile_id,revision,document_json FROM changed RETURNING document_json` : await this.sql`WITH changed AS (UPDATE skills_execution_grants SET revision=${value.revision},document_json=${json}::jsonb WHERE org_id=${p2.orgId} AND profile_id=${id} AND revision=${expected} RETURNING *) INSERT INTO skills_execution_grant_revisions(org_id,profile_id,revision,document_json) SELECT org_id,profile_id,revision,document_json FROM changed RETURNING document_json`;
|
|
87524
|
+
return document(rows[0]);
|
|
87525
|
+
}
|
|
87526
|
+
}
|
|
87527
|
+
|
|
87457
87528
|
// src/server/sqlite-store.ts
|
|
87458
87529
|
import { Database } from "bun:sqlite";
|
|
87459
87530
|
|
|
87460
87531
|
// src/server/selection-store.ts
|
|
87461
|
-
import { randomUUID } from "crypto";
|
|
87532
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
87462
87533
|
function selections(value) {
|
|
87463
87534
|
return typeof value === "string" ? JSON.parse(value) : structuredClone(value);
|
|
87464
87535
|
}
|
|
@@ -87499,15 +87570,15 @@ class MemorySkillSelectionStore {
|
|
|
87499
87570
|
const key = this.key(p2.orgId, id), previous = this.profiles.get(key);
|
|
87500
87571
|
if ((previous?.revision ?? null) !== expected)
|
|
87501
87572
|
return null;
|
|
87502
|
-
const
|
|
87573
|
+
const next2 = {
|
|
87503
87574
|
id,
|
|
87504
87575
|
workspaceId: p2.orgId,
|
|
87505
|
-
revision:
|
|
87576
|
+
revision: randomUUID2(),
|
|
87506
87577
|
selections: structuredClone(selected),
|
|
87507
87578
|
updatedAt: new Date().toISOString()
|
|
87508
87579
|
};
|
|
87509
|
-
this.profiles.set(key,
|
|
87510
|
-
return structuredClone(
|
|
87580
|
+
this.profiles.set(key, next2);
|
|
87581
|
+
return structuredClone(next2);
|
|
87511
87582
|
}
|
|
87512
87583
|
async getStationState(p2, id) {
|
|
87513
87584
|
return structuredClone(this.states.get(this.key(p2.orgId, p2.userId, id)) ?? null);
|
|
@@ -87515,15 +87586,15 @@ class MemorySkillSelectionStore {
|
|
|
87515
87586
|
async saveStationState(p2, id, input) {
|
|
87516
87587
|
if (this.profiles.get(this.key(p2.orgId, input.profileId))?.revision !== input.profileRevision)
|
|
87517
87588
|
return null;
|
|
87518
|
-
const
|
|
87589
|
+
const next2 = {
|
|
87519
87590
|
...structuredClone(input),
|
|
87520
87591
|
stationId: id,
|
|
87521
87592
|
workspaceId: p2.orgId,
|
|
87522
87593
|
actorId: p2.userId,
|
|
87523
87594
|
appliedAt: new Date().toISOString()
|
|
87524
87595
|
};
|
|
87525
|
-
this.states.set(this.key(p2.orgId, p2.userId, id),
|
|
87526
|
-
return structuredClone(
|
|
87596
|
+
this.states.set(this.key(p2.orgId, p2.userId, id), next2);
|
|
87597
|
+
return structuredClone(next2);
|
|
87527
87598
|
}
|
|
87528
87599
|
}
|
|
87529
87600
|
|
|
@@ -87537,7 +87608,7 @@ class SqliteSkillSelectionStore {
|
|
|
87537
87608
|
return row ? profile(row) : null;
|
|
87538
87609
|
}
|
|
87539
87610
|
async saveProfile(p2, id, selected, expected) {
|
|
87540
|
-
const revision =
|
|
87611
|
+
const revision = randomUUID2(), timestamp = new Date().toISOString();
|
|
87541
87612
|
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(p2.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, p2.orgId, id, expected);
|
|
87542
87613
|
return row ? profile(row) : null;
|
|
87543
87614
|
}
|
|
@@ -87563,7 +87634,7 @@ class PostgresSkillSelectionStore {
|
|
|
87563
87634
|
return rows[0] ? profile(rows[0]) : null;
|
|
87564
87635
|
}
|
|
87565
87636
|
async saveProfile(p2, id, selected, expected) {
|
|
87566
|
-
const revision =
|
|
87637
|
+
const revision = randomUUID2(), timestamp = new Date().toISOString();
|
|
87567
87638
|
const rows = expected === null ? await this.sql`INSERT INTO skills_profiles(org_id,profile_id,revision,selections_json,updated_at) VALUES(${p2.orgId},${id},${revision},${JSON.stringify(selected)}::jsonb,${timestamp}) ON CONFLICT(org_id,profile_id) DO NOTHING RETURNING *` : await this.sql`UPDATE skills_profiles SET revision=${revision},selections_json=${JSON.stringify(selected)}::jsonb,updated_at=${timestamp} WHERE org_id=${p2.orgId} AND profile_id=${id} AND revision=${expected} RETURNING *`;
|
|
87568
87639
|
return rows[0] ? profile(rows[0]) : null;
|
|
87569
87640
|
}
|
|
@@ -87581,7 +87652,7 @@ class PostgresSkillSelectionStore {
|
|
|
87581
87652
|
}
|
|
87582
87653
|
|
|
87583
87654
|
// src/server/sqlite-store.ts
|
|
87584
|
-
import { randomUUID as
|
|
87655
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
87585
87656
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, readdirSync } from "fs";
|
|
87586
87657
|
import { dirname as dirname3, join as join5 } from "path";
|
|
87587
87658
|
|
|
@@ -87642,7 +87713,7 @@ function defaultStartDirs() {
|
|
|
87642
87713
|
}
|
|
87643
87714
|
|
|
87644
87715
|
// src/server/rows.ts
|
|
87645
|
-
import { randomUUID as
|
|
87716
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
87646
87717
|
function nowIso() {
|
|
87647
87718
|
return new Date().toISOString();
|
|
87648
87719
|
}
|
|
@@ -87650,7 +87721,7 @@ function normalizeLimit(limit) {
|
|
|
87650
87721
|
return Number.isFinite(limit) ? Math.max(0, Math.trunc(limit)) : 0;
|
|
87651
87722
|
}
|
|
87652
87723
|
function runId() {
|
|
87653
|
-
return `run_${Date.now().toString(36)}_${
|
|
87724
|
+
return `run_${Date.now().toString(36)}_${randomUUID3().slice(0, 8)}`;
|
|
87654
87725
|
}
|
|
87655
87726
|
function rowToRun(row) {
|
|
87656
87727
|
return {
|
|
@@ -87873,6 +87944,9 @@ class SqliteSkillsStore {
|
|
|
87873
87944
|
get selectionStore() {
|
|
87874
87945
|
return new SqliteSkillSelectionStore(this.db);
|
|
87875
87946
|
}
|
|
87947
|
+
get executionGrantStore() {
|
|
87948
|
+
return new SqliteExecutionGrantStore(this.db);
|
|
87949
|
+
}
|
|
87876
87950
|
backend;
|
|
87877
87951
|
db;
|
|
87878
87952
|
closed = false;
|
|
@@ -87974,7 +88048,7 @@ class SqliteSkillsStore {
|
|
|
87974
88048
|
JSON.stringify(input.input),
|
|
87975
88049
|
JSON.stringify(input.args),
|
|
87976
88050
|
input.idempotencyKey ?? null,
|
|
87977
|
-
|
|
88051
|
+
randomUUID4(),
|
|
87978
88052
|
nowIso()
|
|
87979
88053
|
]);
|
|
87980
88054
|
return rowToRun(row);
|
|
@@ -88284,21 +88358,21 @@ class SqliteSkillsStore {
|
|
|
88284
88358
|
if (expectedRevisionId !== current.revisionId) {
|
|
88285
88359
|
throw new SkillRevisionConflictError(slug, expectedRevisionId, current.revisionId);
|
|
88286
88360
|
}
|
|
88287
|
-
const
|
|
88361
|
+
const next2 = { ...current, ...patch };
|
|
88288
88362
|
return this.db.transaction(() => {
|
|
88289
|
-
const revisionId = revisionIdOfRecord(
|
|
88363
|
+
const revisionId = revisionIdOfRecord(next2);
|
|
88290
88364
|
const row = this.get(`UPDATE skills_registry
|
|
88291
88365
|
SET display_name = ?, description = ?, category = ?, tags_json = ?, kind = ?, version = ?, skill_md = ?,
|
|
88292
88366
|
revision_id = ?, revision_number = revision_number + 1, updated_at = ?
|
|
88293
88367
|
WHERE org_id = ? AND slug = ? AND tombstoned_at IS NULL AND revision_id = ?
|
|
88294
88368
|
RETURNING *`, [
|
|
88295
|
-
|
|
88296
|
-
|
|
88297
|
-
|
|
88298
|
-
JSON.stringify(
|
|
88299
|
-
|
|
88300
|
-
|
|
88301
|
-
|
|
88369
|
+
next2.displayName,
|
|
88370
|
+
next2.description,
|
|
88371
|
+
next2.category,
|
|
88372
|
+
JSON.stringify(next2.tags),
|
|
88373
|
+
next2.kind,
|
|
88374
|
+
next2.version ?? null,
|
|
88375
|
+
next2.skillMd ?? null,
|
|
88302
88376
|
revisionId,
|
|
88303
88377
|
nowIso(),
|
|
88304
88378
|
principal.orgId,
|
|
@@ -88318,7 +88392,7 @@ class SqliteSkillsStore {
|
|
|
88318
88392
|
}
|
|
88319
88393
|
this.db.run("DELETE FROM skills_tags WHERE org_id = ? AND slug = ?", [principal.orgId, slug]);
|
|
88320
88394
|
const insertTag = this.db.prepare("INSERT OR IGNORE INTO skills_tags (org_id, slug, tag) VALUES (?, ?, ?)");
|
|
88321
|
-
for (const tag of
|
|
88395
|
+
for (const tag of next2.tags) {
|
|
88322
88396
|
if (!tag.trim())
|
|
88323
88397
|
continue;
|
|
88324
88398
|
insertTag.run(principal.orgId, slug, tag);
|
|
@@ -88494,8 +88568,245 @@ function parseScopes(value) {
|
|
|
88494
88568
|
}
|
|
88495
88569
|
}
|
|
88496
88570
|
|
|
88497
|
-
// node_modules/@hasna/
|
|
88571
|
+
// node_modules/@hasna/secrets/dist/sdk.js
|
|
88498
88572
|
import { createRequire } from "module";
|
|
88573
|
+
import { createRequire as createRequire2 } from "module";
|
|
88574
|
+
var __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
88575
|
+
var CredentialResolutionError;
|
|
88576
|
+
var CredentialFileUnsafeError;
|
|
88577
|
+
var MAX_CREDENTIAL_FILE_BYTES;
|
|
88578
|
+
var SAFE_APP_SLUG;
|
|
88579
|
+
var SAFE_PROFILE;
|
|
88580
|
+
var ILLEGAL_IN_HEADER_VALUE;
|
|
88581
|
+
var VAULT_POINTER_SHAPE;
|
|
88582
|
+
var CREDENTIAL_SHAPED_KEY;
|
|
88583
|
+
var INSPECT_CUSTOM;
|
|
88584
|
+
var CREDENTIAL_SEAL;
|
|
88585
|
+
var AMBIENT_ENVIRONMENT;
|
|
88586
|
+
var SECRETS_PACKAGE_SPECIFIER;
|
|
88587
|
+
var requireSecretsSdk;
|
|
88588
|
+
var ASCII_CONTROL_PATTERN;
|
|
88589
|
+
var DNS_LABEL_PATTERN;
|
|
88590
|
+
var ClientTransportConfigurationError;
|
|
88591
|
+
var HasnaHttpError;
|
|
88592
|
+
var DEFAULT_RETRY_STATUSES;
|
|
88593
|
+
var IDEMPOTENT_METHODS;
|
|
88594
|
+
var AUTHORITY_OVERRIDE_HEADERS;
|
|
88595
|
+
var init_transport = __esm2(() => {
|
|
88596
|
+
CredentialResolutionError = class CredentialResolutionError2 extends Error {
|
|
88597
|
+
appName;
|
|
88598
|
+
attempted;
|
|
88599
|
+
constructor(appName, message, attempted) {
|
|
88600
|
+
super(message);
|
|
88601
|
+
this.name = "CredentialResolutionError";
|
|
88602
|
+
this.appName = appName;
|
|
88603
|
+
this.attempted = attempted;
|
|
88604
|
+
}
|
|
88605
|
+
};
|
|
88606
|
+
CredentialFileUnsafeError = class CredentialFileUnsafeError2 extends Error {
|
|
88607
|
+
path;
|
|
88608
|
+
constructor(path, reason) {
|
|
88609
|
+
super(`Refusing unsafe credential/config file ${path}: ${reason}.`);
|
|
88610
|
+
this.name = "CredentialFileUnsafeError";
|
|
88611
|
+
this.path = path;
|
|
88612
|
+
}
|
|
88613
|
+
};
|
|
88614
|
+
MAX_CREDENTIAL_FILE_BYTES = 64 * 1024;
|
|
88615
|
+
SAFE_APP_SLUG = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
88616
|
+
SAFE_PROFILE = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
|
|
88617
|
+
ILLEGAL_IN_HEADER_VALUE = /[^\t\x20-\x7e]/;
|
|
88618
|
+
VAULT_POINTER_SHAPE = /^[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-_.]*){2,}$/;
|
|
88619
|
+
CREDENTIAL_SHAPED_KEY = /(?:^|_)(?:API_KEY|KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTH)(?:_|$)/;
|
|
88620
|
+
INSPECT_CUSTOM = Symbol.for("nodejs.util.inspect.custom");
|
|
88621
|
+
CREDENTIAL_SEAL = Symbol.for("hasna:contracts:sealedCredential");
|
|
88622
|
+
AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
88623
|
+
SECRETS_PACKAGE_SPECIFIER = "@hasna/" + "secrets";
|
|
88624
|
+
requireSecretsSdk = createRequire(import.meta.url);
|
|
88625
|
+
ASCII_CONTROL_PATTERN = /[\u0000-\u001f\u007f]/;
|
|
88626
|
+
DNS_LABEL_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
88627
|
+
ClientTransportConfigurationError = class ClientTransportConfigurationError2 extends Error {
|
|
88628
|
+
appName;
|
|
88629
|
+
sources;
|
|
88630
|
+
constructor(appName, message, sources = []) {
|
|
88631
|
+
super(message);
|
|
88632
|
+
this.name = "ClientTransportConfigurationError";
|
|
88633
|
+
this.appName = appName;
|
|
88634
|
+
this.sources = Object.freeze([...sources]);
|
|
88635
|
+
}
|
|
88636
|
+
};
|
|
88637
|
+
HasnaHttpError = class HasnaHttpError2 extends Error {
|
|
88638
|
+
status;
|
|
88639
|
+
method;
|
|
88640
|
+
path;
|
|
88641
|
+
credentialSource;
|
|
88642
|
+
credentialTier;
|
|
88643
|
+
constructor(method, path, status, body, credential) {
|
|
88644
|
+
const guidance = credential ? `. ${credential.guidance}` : "";
|
|
88645
|
+
super(`Hasna cloud request failed: ${method} ${path} -> ${status}${guidance}`);
|
|
88646
|
+
this.name = "HasnaHttpError";
|
|
88647
|
+
this.status = status;
|
|
88648
|
+
this.method = method;
|
|
88649
|
+
this.path = path;
|
|
88650
|
+
Object.defineProperty(this, "body", {
|
|
88651
|
+
value: body,
|
|
88652
|
+
enumerable: status !== 401 && status !== 403,
|
|
88653
|
+
writable: false,
|
|
88654
|
+
configurable: false
|
|
88655
|
+
});
|
|
88656
|
+
this.credentialSource = credential?.source ?? null;
|
|
88657
|
+
this.credentialTier = credential?.tier ?? null;
|
|
88658
|
+
}
|
|
88659
|
+
};
|
|
88660
|
+
DEFAULT_RETRY_STATUSES = [408, 425, 429, 500, 502, 503, 504];
|
|
88661
|
+
IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
88662
|
+
AUTHORITY_OVERRIDE_HEADERS = new Set([
|
|
88663
|
+
"host",
|
|
88664
|
+
":authority",
|
|
88665
|
+
"forwarded",
|
|
88666
|
+
"x-forwarded-host",
|
|
88667
|
+
"x-original-host"
|
|
88668
|
+
]);
|
|
88669
|
+
});
|
|
88670
|
+
var MAX_CREDENTIAL_FILE_BYTES2;
|
|
88671
|
+
var INSPECT_CUSTOM2;
|
|
88672
|
+
var CREDENTIAL_SEAL2;
|
|
88673
|
+
var AMBIENT_ENVIRONMENT2;
|
|
88674
|
+
var SECRETS_PACKAGE_SPECIFIER2;
|
|
88675
|
+
var requireSecretsSdk2;
|
|
88676
|
+
var IDEMPOTENT_METHODS2;
|
|
88677
|
+
var AUTHORITY_OVERRIDE_HEADERS2;
|
|
88678
|
+
var init_storage = __esm2(() => {
|
|
88679
|
+
MAX_CREDENTIAL_FILE_BYTES2 = 64 * 1024;
|
|
88680
|
+
INSPECT_CUSTOM2 = Symbol.for("nodejs.util.inspect.custom");
|
|
88681
|
+
CREDENTIAL_SEAL2 = Symbol.for("hasna:contracts:sealedCredential");
|
|
88682
|
+
AMBIENT_ENVIRONMENT2 = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
88683
|
+
SECRETS_PACKAGE_SPECIFIER2 = "@hasna/" + "secrets";
|
|
88684
|
+
requireSecretsSdk2 = createRequire2(import.meta.url);
|
|
88685
|
+
IDEMPOTENT_METHODS2 = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
88686
|
+
AUTHORITY_OVERRIDE_HEADERS2 = new Set([
|
|
88687
|
+
"host",
|
|
88688
|
+
":authority",
|
|
88689
|
+
"forwarded",
|
|
88690
|
+
"x-forwarded-host",
|
|
88691
|
+
"x-original-host"
|
|
88692
|
+
]);
|
|
88693
|
+
});
|
|
88694
|
+
var PATHS_RESOLVER_APP_SLUG_RE2;
|
|
88695
|
+
var SQLITE_SIDECAR_FILES;
|
|
88696
|
+
var LEGACY_SERVICE_FILES;
|
|
88697
|
+
var init_data_dir = __esm2(() => {
|
|
88698
|
+
PATHS_RESOLVER_APP_SLUG_RE2 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
88699
|
+
SQLITE_SIDECAR_FILES = ["vault.db-wal", "vault.db-shm", "vault.db-journal"];
|
|
88700
|
+
LEGACY_SERVICE_FILES = [
|
|
88701
|
+
"vault.key",
|
|
88702
|
+
"vault.key.enc",
|
|
88703
|
+
"kms.json",
|
|
88704
|
+
"aws.json",
|
|
88705
|
+
".serve-token"
|
|
88706
|
+
];
|
|
88707
|
+
});
|
|
88708
|
+
var SecretsTestIsolationError;
|
|
88709
|
+
var TEST_ENTRYPOINT_RE;
|
|
88710
|
+
var init_test_isolation = __esm2(() => {
|
|
88711
|
+
init_data_dir();
|
|
88712
|
+
SecretsTestIsolationError = class SecretsTestIsolationError2 extends Error {
|
|
88713
|
+
constructor(message) {
|
|
88714
|
+
super(message);
|
|
88715
|
+
this.name = "SecretsTestIsolationError";
|
|
88716
|
+
}
|
|
88717
|
+
};
|
|
88718
|
+
TEST_ENTRYPOINT_RE = /\.(test|spec)\.[cm]?[jt]sx?$/;
|
|
88719
|
+
});
|
|
88720
|
+
var init_client = __esm2(() => {
|
|
88721
|
+
init_transport();
|
|
88722
|
+
init_storage();
|
|
88723
|
+
init_test_isolation();
|
|
88724
|
+
init_transport();
|
|
88725
|
+
});
|
|
88726
|
+
init_client();
|
|
88727
|
+
init_client();
|
|
88728
|
+
|
|
88729
|
+
// src/lib/profile-limits.ts
|
|
88730
|
+
var MAX_PROFILE_SELECTIONS = 4096;
|
|
88731
|
+
var MAX_PROFILE_DOCUMENT_BYTES = 8 * 1024 * 1024;
|
|
88732
|
+
var MAX_SKILL_SESSION_ID_CHARS = 256;
|
|
88733
|
+
var PROFILE_SESSION_ENVELOPE_BYTES = MAX_PROFILE_SELECTIONS * 67 + MAX_SKILL_SESSION_ID_CHARS * 6 + 256;
|
|
88734
|
+
var MAX_RESOLVED_PROFILE_BYTES = MAX_PROFILE_DOCUMENT_BYTES - PROFILE_SESSION_ENVELOPE_BYTES;
|
|
88735
|
+
|
|
88736
|
+
// src/lib/selection-cache.ts
|
|
88737
|
+
var MAX_CACHED_PROFILE_AGE_MS = 24 * 60 * 60 * 1000;
|
|
88738
|
+
|
|
88739
|
+
// src/lib/execution-grants.ts
|
|
88740
|
+
var MAX_EXECUTION_GRANT_BYTES = 2 * 1024 * 1024;
|
|
88741
|
+
|
|
88742
|
+
// src/lib/hosted-skill-set.ts
|
|
88743
|
+
var HOSTED_RUNTIMES = new Set(["hosted"]);
|
|
88744
|
+
var HOSTED_SOURCES = new Set(["remote", "private-hosted"]);
|
|
88745
|
+
var HOSTED_METADATA_SET_EMPTY_ERROR = [
|
|
88746
|
+
"The hosted metadata skill set is empty, but the packaging guards that depend on it",
|
|
88747
|
+
"only mean anything while it is non-empty: an empty set makes every one of them pass",
|
|
88748
|
+
"vacuously and silently removes the protection that keeps hosted implementation source",
|
|
88749
|
+
"out of the published package.",
|
|
88750
|
+
"",
|
|
88751
|
+
"If emptying the set is intentional (every hosted skill was deleted or converted to a",
|
|
88752
|
+
"runnable in-repo skill), retire the derived guards in the SAME change \u2014 do not let them",
|
|
88753
|
+
"stay green and empty."
|
|
88754
|
+
].join(`
|
|
88755
|
+
`);
|
|
88756
|
+
var SLUG = "[^,{}/]+";
|
|
88757
|
+
var BRACE_SOURCE_EXCLUSION = new RegExp(`^!skills/\\{(${SLUG}(?:,${SLUG})+)\\}/src$`);
|
|
88758
|
+
var SINGLE_SOURCE_EXCLUSION = new RegExp(`^!skills/(${SLUG})/src$`);
|
|
88759
|
+
|
|
88760
|
+
// src/lib/skill-validation.ts
|
|
88761
|
+
var RESERVED_SKILL_ENTRIES = new Set([
|
|
88762
|
+
".env",
|
|
88763
|
+
".npmrc",
|
|
88764
|
+
".pypirc",
|
|
88765
|
+
".netrc",
|
|
88766
|
+
"id_rsa",
|
|
88767
|
+
"id_ed25519"
|
|
88768
|
+
]);
|
|
88769
|
+
var KNOWN_TOP_LEVEL_ENTRIES = new Set([
|
|
88770
|
+
".claude",
|
|
88771
|
+
".env.example",
|
|
88772
|
+
".gitignore",
|
|
88773
|
+
".skills",
|
|
88774
|
+
"CLAUDE.md",
|
|
88775
|
+
"AGENTS.md",
|
|
88776
|
+
"LICENSE",
|
|
88777
|
+
"PROJECT_OVERVIEW.md",
|
|
88778
|
+
"QUICKSTART.md",
|
|
88779
|
+
"README.md",
|
|
88780
|
+
"SKILL.md",
|
|
88781
|
+
"api-docs-list.json",
|
|
88782
|
+
"auth.ts",
|
|
88783
|
+
"bun.lock",
|
|
88784
|
+
"bunfig.toml",
|
|
88785
|
+
"data",
|
|
88786
|
+
"dist",
|
|
88787
|
+
"examples",
|
|
88788
|
+
"exports",
|
|
88789
|
+
"http-client.ts",
|
|
88790
|
+
"index.ts",
|
|
88791
|
+
"install.sh",
|
|
88792
|
+
"installer.ts",
|
|
88793
|
+
"logs",
|
|
88794
|
+
"node_modules",
|
|
88795
|
+
"package.json",
|
|
88796
|
+
"scripts",
|
|
88797
|
+
"skill-install.ts",
|
|
88798
|
+
"skill.json",
|
|
88799
|
+
"src",
|
|
88800
|
+
"tests",
|
|
88801
|
+
"references",
|
|
88802
|
+
"assets",
|
|
88803
|
+
"tsconfig.json",
|
|
88804
|
+
"vision.ts"
|
|
88805
|
+
]);
|
|
88806
|
+
var VALID_PROVENANCE_SOURCES = new Set(["official", "custom", "remote", "private", "private-hosted", "upstream", "extension"]);
|
|
88807
|
+
|
|
88808
|
+
// node_modules/@hasna/contracts/dist/client/transport.js
|
|
88809
|
+
import { createRequire as createRequire3 } from "module";
|
|
88499
88810
|
function envToken(name) {
|
|
88500
88811
|
return name.toUpperCase().replace(/-/g, "_");
|
|
88501
88812
|
}
|
|
@@ -88507,13 +88818,13 @@ function clientTransportEnvKeys(name) {
|
|
|
88507
88818
|
};
|
|
88508
88819
|
}
|
|
88509
88820
|
var MAX_PACKAGE_BYTES = 1024 * 1024;
|
|
88510
|
-
var
|
|
88511
|
-
var
|
|
88512
|
-
var
|
|
88513
|
-
var
|
|
88514
|
-
var
|
|
88515
|
-
var
|
|
88516
|
-
var
|
|
88821
|
+
var MAX_CREDENTIAL_FILE_BYTES3 = 64 * 1024;
|
|
88822
|
+
var INSPECT_CUSTOM3 = Symbol.for("nodejs.util.inspect.custom");
|
|
88823
|
+
var CREDENTIAL_SEAL3 = Symbol.for("hasna:contracts:sealedCredential");
|
|
88824
|
+
var AMBIENT_ENVIRONMENT3 = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
88825
|
+
var requireSecretsSdk3 = createRequire3(import.meta.url);
|
|
88826
|
+
var IDEMPOTENT_METHODS3 = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
88827
|
+
var AUTHORITY_OVERRIDE_HEADERS3 = new Set([
|
|
88517
88828
|
"host",
|
|
88518
88829
|
":authority",
|
|
88519
88830
|
"forwarded",
|
|
@@ -88535,13 +88846,6 @@ var MAX_MANIFEST_BYTES = MAX_SKILL_MD_BYTES + 64000;
|
|
|
88535
88846
|
var ALLOWED_PUBLISH_PARTS = new Set(["manifest", "bundle"]);
|
|
88536
88847
|
var MAX_VERSION_MANIFEST_BYTES = 512 * 1024;
|
|
88537
88848
|
|
|
88538
|
-
// src/lib/profile-limits.ts
|
|
88539
|
-
var MAX_PROFILE_SELECTIONS = 4096;
|
|
88540
|
-
var MAX_PROFILE_DOCUMENT_BYTES = 8 * 1024 * 1024;
|
|
88541
|
-
var MAX_SKILL_SESSION_ID_CHARS = 256;
|
|
88542
|
-
var PROFILE_SESSION_ENVELOPE_BYTES = MAX_PROFILE_SELECTIONS * 67 + MAX_SKILL_SESSION_ID_CHARS * 6 + 256;
|
|
88543
|
-
var MAX_RESOLVED_PROFILE_BYTES = MAX_PROFILE_DOCUMENT_BYTES - PROFILE_SESSION_ENVELOPE_BYTES;
|
|
88544
|
-
|
|
88545
88849
|
// src/sdk/execution/storage.ts
|
|
88546
88850
|
class MemoryRunExecutionStore {
|
|
88547
88851
|
durable = false;
|
|
@@ -88619,15 +88923,15 @@ class MemoryRunExecutionStore {
|
|
|
88619
88923
|
if (attempt.leaseGeneration !== input.expectedLeaseGeneration) {
|
|
88620
88924
|
return { ok: false, reason: "STALE_GENERATION" };
|
|
88621
88925
|
}
|
|
88622
|
-
const
|
|
88926
|
+
const next2 = {
|
|
88623
88927
|
...attempt,
|
|
88624
88928
|
leaseGeneration: attempt.leaseGeneration + 1,
|
|
88625
88929
|
workerId: input.workerId,
|
|
88626
88930
|
claimedAt: new Date().toISOString(),
|
|
88627
88931
|
status: "leased"
|
|
88628
88932
|
};
|
|
88629
|
-
this.attempts.set(attempt.attemptId,
|
|
88630
|
-
return { ok: true, attempt:
|
|
88933
|
+
this.attempts.set(attempt.attemptId, next2);
|
|
88934
|
+
return { ok: true, attempt: next2, leaseGeneration: next2.leaseGeneration };
|
|
88631
88935
|
}
|
|
88632
88936
|
async recordLaunchIntent(input) {
|
|
88633
88937
|
const run = this.runs.get(input.runId);
|
|
@@ -88639,28 +88943,28 @@ class MemoryRunExecutionStore {
|
|
|
88639
88943
|
return { ok: false, reason: "NO_SUCH_ATTEMPT" };
|
|
88640
88944
|
if (attempt.status === "terminal")
|
|
88641
88945
|
return { ok: false, reason: "ATTEMPT_TERMINAL" };
|
|
88642
|
-
const
|
|
88946
|
+
const next2 = {
|
|
88643
88947
|
...attempt,
|
|
88644
88948
|
clientToken: input.clientToken,
|
|
88645
88949
|
requestDigest: input.requestDigest,
|
|
88646
88950
|
startedBy: input.startedBy,
|
|
88647
88951
|
launchState: "launching"
|
|
88648
88952
|
};
|
|
88649
|
-
this.attempts.set(attempt.attemptId,
|
|
88953
|
+
this.attempts.set(attempt.attemptId, next2);
|
|
88650
88954
|
this.runs.set(input.runId, { ...run, currentAttemptId: attempt.attemptId, updatedAt: new Date().toISOString() });
|
|
88651
|
-
return { ok: true, attempt:
|
|
88955
|
+
return { ok: true, attempt: next2 };
|
|
88652
88956
|
}
|
|
88653
88957
|
async recordLaunchState(input) {
|
|
88654
88958
|
const attempt = this.attempts.get(input.attemptId);
|
|
88655
88959
|
if (!attempt)
|
|
88656
88960
|
return null;
|
|
88657
|
-
const
|
|
88961
|
+
const next2 = {
|
|
88658
88962
|
...attempt,
|
|
88659
88963
|
launchState: input.launchState,
|
|
88660
88964
|
...input.taskId === undefined ? {} : { taskId: input.taskId }
|
|
88661
88965
|
};
|
|
88662
|
-
this.attempts.set(attempt.attemptId,
|
|
88663
|
-
return
|
|
88966
|
+
this.attempts.set(attempt.attemptId, next2);
|
|
88967
|
+
return next2;
|
|
88664
88968
|
}
|
|
88665
88969
|
async recordTransition(transition) {
|
|
88666
88970
|
this.transitions.push(transition);
|
|
@@ -88669,9 +88973,9 @@ class MemoryRunExecutionStore {
|
|
|
88669
88973
|
const attempt = this.attempts.get(attemptId);
|
|
88670
88974
|
if (!attempt)
|
|
88671
88975
|
return null;
|
|
88672
|
-
const
|
|
88673
|
-
this.attempts.set(attemptId,
|
|
88674
|
-
return
|
|
88976
|
+
const next2 = { ...attempt, status: "terminal" };
|
|
88977
|
+
this.attempts.set(attemptId, next2);
|
|
88978
|
+
return next2;
|
|
88675
88979
|
}
|
|
88676
88980
|
async writeReceipt(receipt) {
|
|
88677
88981
|
this.receipts.set(receipt.runId + "\x00" + receipt.attemptId, receipt);
|
|
@@ -88689,22 +88993,22 @@ class MemoryRunExecutionStore {
|
|
|
88689
88993
|
this.attempts.set(attemptId, { ...attempt, status: "terminal" });
|
|
88690
88994
|
}
|
|
88691
88995
|
}
|
|
88692
|
-
const
|
|
88996
|
+
const next2 = {
|
|
88693
88997
|
...run,
|
|
88694
88998
|
status,
|
|
88695
88999
|
terminalReceiptId: receiptId,
|
|
88696
89000
|
updatedAt: new Date().toISOString()
|
|
88697
89001
|
};
|
|
88698
|
-
this.runs.set(runId2,
|
|
88699
|
-
return
|
|
89002
|
+
this.runs.set(runId2, next2);
|
|
89003
|
+
return next2;
|
|
88700
89004
|
}
|
|
88701
89005
|
async setRunStatus(runId2, status) {
|
|
88702
89006
|
const run = this.runs.get(runId2);
|
|
88703
89007
|
if (!run)
|
|
88704
89008
|
return null;
|
|
88705
|
-
const
|
|
88706
|
-
this.runs.set(runId2,
|
|
88707
|
-
return
|
|
89009
|
+
const next2 = { ...run, status, updatedAt: new Date().toISOString() };
|
|
89010
|
+
this.runs.set(runId2, next2);
|
|
89011
|
+
return next2;
|
|
88708
89012
|
}
|
|
88709
89013
|
}
|
|
88710
89014
|
function isMemoryTerminal(status) {
|
|
@@ -88782,28 +89086,28 @@ async function failRun(store, run, code, message) {
|
|
|
88782
89086
|
try {
|
|
88783
89087
|
await store.appendLog(run.id, run.orgId, "error", message);
|
|
88784
89088
|
} catch {}
|
|
88785
|
-
const
|
|
89089
|
+
const next2 = await fencedTransition(store, run, {
|
|
88786
89090
|
status: "failed",
|
|
88787
89091
|
errorCode: code,
|
|
88788
89092
|
errorMessage: message,
|
|
88789
89093
|
completedAt: new Date().toISOString()
|
|
88790
89094
|
});
|
|
88791
|
-
return
|
|
89095
|
+
return next2 ?? run;
|
|
88792
89096
|
}
|
|
88793
89097
|
async function fencedTransition(store, run, patch) {
|
|
88794
89098
|
if (!store.transitionRun)
|
|
88795
89099
|
return store.updateRun(run.id, patch);
|
|
88796
|
-
const
|
|
88797
|
-
if (!
|
|
89100
|
+
const next2 = await store.transitionRun(run.id, patch, run.leaseGeneration);
|
|
89101
|
+
if (!next2) {
|
|
88798
89102
|
try {
|
|
88799
89103
|
await store.appendLog(run.id, run.orgId, "warn", `late write rejected: run no longer owned at lease_generation ${run.leaseGeneration}`);
|
|
88800
89104
|
} catch {}
|
|
88801
89105
|
}
|
|
88802
|
-
return
|
|
89106
|
+
return next2;
|
|
88803
89107
|
}
|
|
88804
89108
|
|
|
88805
89109
|
// src/server/store.ts
|
|
88806
|
-
import { randomUUID as
|
|
89110
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
88807
89111
|
function recordFieldsOf(input, carriedBundle, carriedSkillMd) {
|
|
88808
89112
|
return {
|
|
88809
89113
|
slug: input.slug,
|
|
@@ -88846,6 +89150,7 @@ function instantiateStore(target, sqliteOptions) {
|
|
|
88846
89150
|
|
|
88847
89151
|
class MemorySkillsStore {
|
|
88848
89152
|
selectionStore = new MemorySkillSelectionStore;
|
|
89153
|
+
executionGrantStore = new MemoryExecutionGrantStore;
|
|
88849
89154
|
backend = { kind: "memory", durable: false, label: "memory (non-durable)" };
|
|
88850
89155
|
apiKeys = new Map;
|
|
88851
89156
|
runs = new Map;
|
|
@@ -88890,7 +89195,7 @@ class MemorySkillsStore {
|
|
|
88890
89195
|
input: input.input,
|
|
88891
89196
|
args: input.args,
|
|
88892
89197
|
...idemKey ? { idempotencyKey: idemKey } : {},
|
|
88893
|
-
correlationId:
|
|
89198
|
+
correlationId: randomUUID5(),
|
|
88894
89199
|
costCents: 0,
|
|
88895
89200
|
leaseGeneration: 0,
|
|
88896
89201
|
createdAt: now
|
|
@@ -88939,11 +89244,11 @@ class MemorySkillsStore {
|
|
|
88939
89244
|
return run ? [...this.logs.get(runId2) ?? []] : [];
|
|
88940
89245
|
}
|
|
88941
89246
|
async addArtifact(artifact) {
|
|
88942
|
-
const
|
|
89247
|
+
const next2 = { ...artifact, createdAt: nowIso() };
|
|
88943
89248
|
const artifacts = this.artifacts.get(artifact.runId) ?? [];
|
|
88944
|
-
artifacts.push(
|
|
89249
|
+
artifacts.push(next2);
|
|
88945
89250
|
this.artifacts.set(artifact.runId, artifacts);
|
|
88946
|
-
return
|
|
89251
|
+
return next2;
|
|
88947
89252
|
}
|
|
88948
89253
|
async listArtifacts(principal, runId2) {
|
|
88949
89254
|
const run = await this.getRun(principal, runId2);
|
|
@@ -89049,15 +89354,15 @@ class MemorySkillsStore {
|
|
|
89049
89354
|
if (latest.revisionId !== current.revisionId) {
|
|
89050
89355
|
throw new SkillRevisionConflictError(slug, expectedRevisionId, latest.revisionId);
|
|
89051
89356
|
}
|
|
89052
|
-
const
|
|
89357
|
+
const next2 = {
|
|
89053
89358
|
...latest,
|
|
89054
89359
|
...patch,
|
|
89055
89360
|
updatedAt: nowIso(),
|
|
89056
89361
|
revisionId: revisionIdOfRecord({ ...latest, ...patch }),
|
|
89057
89362
|
revisionNumber: latest.revisionNumber + 1
|
|
89058
89363
|
};
|
|
89059
|
-
this.skills.set(skillKey(principal.orgId, slug),
|
|
89060
|
-
return
|
|
89364
|
+
this.skills.set(skillKey(principal.orgId, slug), next2);
|
|
89365
|
+
return next2;
|
|
89061
89366
|
}
|
|
89062
89367
|
async deleteSkill(principal, slug, tombstoneWindowMs) {
|
|
89063
89368
|
const current = await this.getSkill(principal, slug);
|
|
@@ -89066,9 +89371,9 @@ class MemorySkillsStore {
|
|
|
89066
89371
|
if (!current.tombstonedAt) {
|
|
89067
89372
|
const tombstoned = nowIso();
|
|
89068
89373
|
const purgeAfter = new Date(Date.now() + tombstoneWindowMs).toISOString();
|
|
89069
|
-
const
|
|
89070
|
-
this.skills.set(skillKey(principal.orgId, slug),
|
|
89071
|
-
return
|
|
89374
|
+
const next2 = { ...current, tombstonedAt: tombstoned, tombstonePurgeAfter: purgeAfter, updatedAt: tombstoned };
|
|
89375
|
+
this.skills.set(skillKey(principal.orgId, slug), next2);
|
|
89376
|
+
return next2;
|
|
89072
89377
|
}
|
|
89073
89378
|
return current;
|
|
89074
89379
|
}
|
|
@@ -89140,9 +89445,9 @@ class MemorySkillsStore {
|
|
|
89140
89445
|
const run = this.runs.get(runId2);
|
|
89141
89446
|
if (!run)
|
|
89142
89447
|
return null;
|
|
89143
|
-
const
|
|
89144
|
-
this.runs.set(runId2,
|
|
89145
|
-
return
|
|
89448
|
+
const next2 = { ...run, ...patch };
|
|
89449
|
+
this.runs.set(runId2, next2);
|
|
89450
|
+
return next2;
|
|
89146
89451
|
}
|
|
89147
89452
|
}
|
|
89148
89453
|
function skillKey(orgId, slug) {
|
|
@@ -89159,6 +89464,9 @@ class PostgresSkillsStore {
|
|
|
89159
89464
|
get selectionStore() {
|
|
89160
89465
|
return new PostgresSkillSelectionStore(this.sql);
|
|
89161
89466
|
}
|
|
89467
|
+
get executionGrantStore() {
|
|
89468
|
+
return new PostgresExecutionGrantStore(this.sql);
|
|
89469
|
+
}
|
|
89162
89470
|
backend = { kind: "postgres", durable: true, label: "postgres" };
|
|
89163
89471
|
sql;
|
|
89164
89472
|
constructor(databaseUrl) {
|
|
@@ -89258,7 +89566,7 @@ class PostgresSkillsStore {
|
|
|
89258
89566
|
const id = runId();
|
|
89259
89567
|
const rows = await tx`
|
|
89260
89568
|
INSERT INTO skills_runs (id, org_id, user_id, skill_slug, requested_slug, status, input_json, args_json, idempotency_key, correlation_id)
|
|
89261
|
-
VALUES (${id}, ${input.principal.orgId}, ${input.principal.userId}, ${input.slug}, ${input.slug}, ${"queued"}, ${JSON.stringify(input.input)}::jsonb, ${JSON.stringify(input.args)}::jsonb, ${input.idempotencyKey ?? null}, ${
|
|
89569
|
+
VALUES (${id}, ${input.principal.orgId}, ${input.principal.userId}, ${input.slug}, ${input.slug}, ${"queued"}, ${JSON.stringify(input.input)}::jsonb, ${JSON.stringify(input.args)}::jsonb, ${input.idempotencyKey ?? null}, ${randomUUID5()})
|
|
89262
89570
|
RETURNING *
|
|
89263
89571
|
`;
|
|
89264
89572
|
return rowToRun(rows[0]);
|
|
@@ -89564,14 +89872,14 @@ class PostgresSkillsStore {
|
|
|
89564
89872
|
if (expectedRevisionId !== current.revisionId) {
|
|
89565
89873
|
throw new SkillRevisionConflictError(slug, expectedRevisionId, current.revisionId);
|
|
89566
89874
|
}
|
|
89567
|
-
const
|
|
89875
|
+
const next2 = { ...current, ...patch };
|
|
89568
89876
|
return await this.sql.begin(async (tx) => {
|
|
89569
|
-
const revisionId = revisionIdOfRecord(
|
|
89877
|
+
const revisionId = revisionIdOfRecord(next2);
|
|
89570
89878
|
const updated = await tx`
|
|
89571
89879
|
UPDATE skills_registry
|
|
89572
|
-
SET display_name = ${
|
|
89573
|
-
tags_json = ${JSON.stringify(
|
|
89574
|
-
skill_md = ${
|
|
89880
|
+
SET display_name = ${next2.displayName}, description = ${next2.description}, category = ${next2.category},
|
|
89881
|
+
tags_json = ${JSON.stringify(next2.tags)}::jsonb, kind = ${next2.kind}, version = ${next2.version ?? null},
|
|
89882
|
+
skill_md = ${next2.skillMd ?? null}, revision_id = ${revisionId}, revision_number = revision_number + 1, updated_at = now()
|
|
89575
89883
|
WHERE org_id = ${principal.orgId} AND slug = ${slug} AND tombstoned_at IS NULL AND revision_id = ${current.revisionId}
|
|
89576
89884
|
RETURNING *
|
|
89577
89885
|
`;
|
|
@@ -89586,7 +89894,7 @@ class PostgresSkillsStore {
|
|
|
89586
89894
|
return null;
|
|
89587
89895
|
}
|
|
89588
89896
|
await tx`DELETE FROM skills_tags WHERE org_id = ${principal.orgId} AND slug = ${slug}`;
|
|
89589
|
-
for (const tag of
|
|
89897
|
+
for (const tag of next2.tags) {
|
|
89590
89898
|
if (!tag.trim())
|
|
89591
89899
|
continue;
|
|
89592
89900
|
await tx`
|
|
@@ -89761,7 +90069,7 @@ function assertDurableTarget(target, config) {
|
|
|
89761
90069
|
}
|
|
89762
90070
|
|
|
89763
90071
|
// src/server/worker.ts
|
|
89764
|
-
async function runWorkerOnce(store, workerId = `worker_${
|
|
90072
|
+
async function runWorkerOnce(store, workerId = `worker_${randomUUID6().slice(0, 8)}`, storage = new ArtifactStorage) {
|
|
89765
90073
|
const run = await store.claimNextRun({ workerId });
|
|
89766
90074
|
if (!run)
|
|
89767
90075
|
return false;
|
|
@@ -89799,7 +90107,7 @@ Environment:
|
|
|
89799
90107
|
assertDurableStore(store, config);
|
|
89800
90108
|
const storage = new ArtifactStorage({ bucket: config.artifactBucket, prefix: config.artifactPrefix, runPrefix: config.runArtifactPrefix });
|
|
89801
90109
|
console.log(`skills worker ${process.env.HASNA_SKILLS_WORKER_ID || ""} storage: ${resolveDatabaseTarget(config.databaseUrl).label}`);
|
|
89802
|
-
const workerId = process.env.HASNA_SKILLS_WORKER_ID || `worker_${
|
|
90110
|
+
const workerId = process.env.HASNA_SKILLS_WORKER_ID || `worker_${randomUUID6().slice(0, 8)}`;
|
|
89803
90111
|
const once = process.argv.includes("--once");
|
|
89804
90112
|
const idleMs = Number.parseInt(process.env.HASNA_SKILLS_WORKER_IDLE_MS || "1000", 10);
|
|
89805
90113
|
const pause = Number.isFinite(idleMs) ? idleMs : 1000;
|