@hasna/skills 0.8.12 → 0.9.2
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 +21 -5
- package/bin/index.js +271 -19
- package/bin/mcp.js +248 -154
- package/bin/migrate.js +100 -10
- package/bin/server.js +596 -51
- package/bin/worker.js +283 -20
- package/dist/cli/commands/registry.d.ts +1 -0
- package/dist/index.js +122 -13
- package/dist/lib/agent-integration.d.ts +26 -0
- package/dist/lib/cloud-executions.d.ts +20 -0
- package/dist/lib/registry-types.d.ts +3 -0
- package/dist/lib/remote-client.d.ts +11 -0
- package/dist/lib/revision.d.ts +3 -0
- package/dist/sdk/execution/admission.d.ts +2 -1
- package/dist/sdk/execution/types.d.ts +9 -0
- package/dist/sdk/index.d.ts +1 -0
- package/dist/sdk/index.js +1301 -502
- package/dist/server/runtime-policy.d.ts +4 -2
- package/dist/server/runtime-pure-contract.d.ts +51 -0
- package/dist/server/runtime-store.d.ts +4 -0
- package/dist/server/runtime-worker.d.ts +2 -1
- package/dist/server/selection-store.d.ts +9 -1
- package/dist/server/skills-api.d.ts +2 -1
- package/dist/server/sqlite-store.d.ts +4 -1
- package/dist/server/store.d.ts +6 -1
- package/dist/server/types.d.ts +27 -0
- package/migrations/postgres/0010_skill_archive_lifecycle.sql +5 -0
- package/migrations/sqlite/0010_skill_archive_lifecycle.sql +5 -0
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { EcsDispatcherConfig } from "../sdk/execution/dispatchers/ecs.js";
|
|
2
2
|
import type { FrozenAdmission, AttemptRecord } from "../sdk/execution/types.js";
|
|
3
|
+
import { type PureReviewedBundle } from "./runtime-pure-contract.js";
|
|
3
4
|
export declare const RUNTIME_MAX_INPUT_BYTES = 100000;
|
|
4
5
|
export declare const RUNTIME_MAX_BUNDLE_BYTES = 1000000;
|
|
5
6
|
export declare const RUNTIME_MAX_ARTIFACT_BYTES = 2000000;
|
|
@@ -9,11 +10,12 @@ export interface RuntimeConfig extends EcsDispatcherConfig {
|
|
|
9
10
|
imageDigest: string;
|
|
10
11
|
apiOrigin: string;
|
|
11
12
|
/** Only independently reviewed exact bundles enter this first credential-free lane. */
|
|
12
|
-
reviewedBundles: {
|
|
13
|
+
reviewedBundles: ({
|
|
13
14
|
slug: "pdf-generate";
|
|
14
15
|
version: string;
|
|
15
16
|
sha256: string;
|
|
16
|
-
|
|
17
|
+
executionContract?: never;
|
|
18
|
+
} | PureReviewedBundle)[];
|
|
17
19
|
}
|
|
18
20
|
export declare function readRuntimeConfig(env?: Record<string, string | undefined>): RuntimeConfig | null;
|
|
19
21
|
export declare function runtimeInput(value: unknown): {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** Trusted pure interface; publishing a skill never grants admission to it. */
|
|
2
|
+
import { type SkillBundleEntry } from "../lib/skill-bundle.js";
|
|
3
|
+
import type { FrozenAdmission, PureExecutionContract } from "../sdk/execution/types.js";
|
|
4
|
+
export declare const PURE_DESCRIPTOR: Readonly<{
|
|
5
|
+
id: "regex-test.v1";
|
|
6
|
+
runtime: "bun";
|
|
7
|
+
adapter: "skills-input-json.v1";
|
|
8
|
+
input: Readonly<{
|
|
9
|
+
patternBytes: 512;
|
|
10
|
+
textBytes: 4096;
|
|
11
|
+
totalBytes: 8192;
|
|
12
|
+
flags: "dgimsuvy";
|
|
13
|
+
}>;
|
|
14
|
+
output: "regex-matches.v1";
|
|
15
|
+
secrets: "none";
|
|
16
|
+
egress: "deny";
|
|
17
|
+
maxDurationMs: 5000;
|
|
18
|
+
maxMemoryMb: 512;
|
|
19
|
+
maxCpuUnits: 256;
|
|
20
|
+
stdoutBytes: 16384;
|
|
21
|
+
stderrBytes: 8192;
|
|
22
|
+
artifactsBytes: 0;
|
|
23
|
+
}>;
|
|
24
|
+
export declare const PURE_DESCRIPTOR_DIGEST: string;
|
|
25
|
+
export declare const PURE_LIMITS: Readonly<{
|
|
26
|
+
maxDurationMs: 5000;
|
|
27
|
+
maxMemoryMb: 512;
|
|
28
|
+
maxCpuUnits: 256;
|
|
29
|
+
maxArtifactsBytes: 0;
|
|
30
|
+
maxConcurrency: 1;
|
|
31
|
+
}>;
|
|
32
|
+
export interface PureInput {
|
|
33
|
+
pattern: string;
|
|
34
|
+
text: string;
|
|
35
|
+
flags: string;
|
|
36
|
+
}
|
|
37
|
+
export interface PureReviewedBundle {
|
|
38
|
+
slug: string;
|
|
39
|
+
version: string;
|
|
40
|
+
sha256: string;
|
|
41
|
+
tenantId: string;
|
|
42
|
+
imageDigest: string;
|
|
43
|
+
executionContract: PureExecutionContract;
|
|
44
|
+
}
|
|
45
|
+
/** JSON.parse alone silently discards duplicate keys, including escaped spellings. */
|
|
46
|
+
export declare function uniqueJson(text: string): unknown;
|
|
47
|
+
export declare function pureInput(value: unknown): PureInput;
|
|
48
|
+
export declare function assertPureContract(value: unknown): asserts value is PureExecutionContract;
|
|
49
|
+
export declare function assertPureAdmission(a: FrozenAdmission): PureExecutionContract;
|
|
50
|
+
export declare function inspectPureBundle(bytes: Uint8Array, contract: PureExecutionContract): Promise<SkillBundleEntry[]>;
|
|
51
|
+
export declare function validatePureOutput(stdout: string, input: PureInput): void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import type { FrozenAdmission } from "../sdk/execution/types.js";
|
|
3
|
+
import { type PureInput } from "./runtime-pure-contract.js";
|
|
3
4
|
import type { RuntimeResult } from "./runtime-store.js";
|
|
4
5
|
export interface RuntimeWork {
|
|
5
6
|
admission: FrozenAdmission;
|
|
@@ -7,7 +8,7 @@ export interface RuntimeWork {
|
|
|
7
8
|
input: {
|
|
8
9
|
content: string;
|
|
9
10
|
title?: string;
|
|
10
|
-
};
|
|
11
|
+
} | PureInput;
|
|
11
12
|
}
|
|
12
13
|
export interface SupervisorOptions {
|
|
13
14
|
executable?: string;
|
|
@@ -2,6 +2,7 @@ import type { Database } from "bun:sqlite";
|
|
|
2
2
|
import type { ApiPrincipal } from "./types.js";
|
|
3
3
|
import type { SkillProfile, SkillSelection, StationSkillState, StationSkillStateInput } from "../types/skill-selection.js";
|
|
4
4
|
export interface SkillSelectionStore {
|
|
5
|
+
profilesReferencingSkill(principal: ApiPrincipal, slug: string): Promise<string[]>;
|
|
5
6
|
getProfile(principal: ApiPrincipal, id: string): Promise<SkillProfile | null>;
|
|
6
7
|
/** null expected revision means create-only; null result means CAS conflict. */
|
|
7
8
|
saveProfile(principal: ApiPrincipal, id: string, selections: SkillSelection[], expected: string | null): Promise<SkillProfile | null>;
|
|
@@ -15,6 +16,7 @@ export declare class MemorySkillSelectionStore implements SkillSelectionStore {
|
|
|
15
16
|
private states;
|
|
16
17
|
private key;
|
|
17
18
|
getProfile(p: ApiPrincipal, id: string): Promise<SkillProfile | null>;
|
|
19
|
+
profilesReferencingSkill(p: ApiPrincipal, slug: string): Promise<string[]>;
|
|
18
20
|
saveProfile(p: ApiPrincipal, id: string, selected: SkillSelection[], expected: string | null): Promise<SkillProfile | null>;
|
|
19
21
|
getStationState(p: ApiPrincipal, id: string): Promise<StationSkillState | null>;
|
|
20
22
|
saveStationState(p: ApiPrincipal, id: string, input: StationSkillStateInput): Promise<StationSkillState | null>;
|
|
@@ -22,15 +24,21 @@ export declare class MemorySkillSelectionStore implements SkillSelectionStore {
|
|
|
22
24
|
export declare class SqliteSkillSelectionStore implements SkillSelectionStore {
|
|
23
25
|
private db;
|
|
24
26
|
constructor(db: Database);
|
|
27
|
+
profilesReferencingSkill(p: ApiPrincipal, slug: string): Promise<string[]>;
|
|
25
28
|
getProfile(p: ApiPrincipal, id: string): Promise<SkillProfile | null>;
|
|
26
29
|
saveProfile(p: ApiPrincipal, id: string, selected: SkillSelection[], expected: string | null): Promise<SkillProfile | null>;
|
|
27
30
|
getStationState(p: ApiPrincipal, id: string): Promise<StationSkillState | null>;
|
|
28
31
|
saveStationState(p: ApiPrincipal, id: string, input: StationSkillStateInput): Promise<StationSkillState | null>;
|
|
29
32
|
}
|
|
30
33
|
type Sql = (strings: TemplateStringsArray, ...values: unknown[]) => Promise<Row[]>;
|
|
34
|
+
type SqlTransaction = Sql;
|
|
35
|
+
interface SqlWithTransaction extends Sql {
|
|
36
|
+
begin<T>(fn: (tx: SqlTransaction) => Promise<T>): Promise<T>;
|
|
37
|
+
}
|
|
31
38
|
export declare class PostgresSkillSelectionStore implements SkillSelectionStore {
|
|
32
39
|
private sql;
|
|
33
|
-
constructor(sql:
|
|
40
|
+
constructor(sql: SqlWithTransaction);
|
|
41
|
+
profilesReferencingSkill(p: ApiPrincipal, slug: string): Promise<string[]>;
|
|
34
42
|
getProfile(p: ApiPrincipal, id: string): Promise<SkillProfile | null>;
|
|
35
43
|
saveProfile(p: ApiPrincipal, id: string, selected: SkillSelection[], expected: string | null): Promise<SkillProfile | null>;
|
|
36
44
|
getStationState(p: ApiPrincipal, id: string): Promise<StationSkillState | null>;
|
|
@@ -2,7 +2,7 @@ import { type OwnedBytes } from "../lib/skill-bundle.js";
|
|
|
2
2
|
import type { SkillMeta } from "../lib/registry-types.js";
|
|
3
3
|
import type { ArtifactStorage } from "./artifact-storage.js";
|
|
4
4
|
import type { SkillsServerConfig } from "./config.js";
|
|
5
|
-
import { type ApiPrincipal, type PublishSkillInput, type ServerPin, type ServerSkillRecord, type ServerSkillVersion, type SkillsProductStore } from "./types.js";
|
|
5
|
+
import { type ApiPrincipal, type PublishSkillInput, type ServerPin, type ServerSkillRecord, type ServerSkillVersion, type SkillLifecyclePatch, type SkillsProductStore } from "./types.js";
|
|
6
6
|
/** Wire shape of a pin: the client-facing facts, without the storage columns. */
|
|
7
7
|
export declare function pinPayload(pin: ServerPin): Record<string, unknown>;
|
|
8
8
|
/**
|
|
@@ -20,6 +20,7 @@ export declare class SkillRequestError extends Error {
|
|
|
20
20
|
readonly code: string;
|
|
21
21
|
constructor(status: number, code: string, message: string);
|
|
22
22
|
}
|
|
23
|
+
export declare function skillLifecyclePatch(body: Record<string, unknown>): SkillLifecyclePatch;
|
|
23
24
|
/** SkillMeta shape for a published row, so a client can treat both kinds alike. */
|
|
24
25
|
export declare function publishedSkillMeta(record: ServerSkillRecord): SkillMeta;
|
|
25
26
|
/**
|
|
@@ -15,7 +15,7 @@ import { SqliteExecutionGrantStore } from "./execution-grant-store.js";
|
|
|
15
15
|
*/
|
|
16
16
|
import { Database } from "bun:sqlite";
|
|
17
17
|
import { SqliteSkillSelectionStore } from "./selection-store.js";
|
|
18
|
-
import type { ApiPrincipal, ClaimRunInput, CreateRunInput, PublishSkillInput, RunTransitionPatch, ServerArtifact, ServerPin, ServerRunLog, ServerRunRecord, ServerSkillBundle, ServerSkillVersion, ServerSkillRecord, SkillsProductStore, StoreBackendInfo, UpdateSkillPatch } from "./types.js";
|
|
18
|
+
import type { ApiPrincipal, ClaimRunInput, CreateRunInput, PublishSkillInput, RunTransitionPatch, ServerArtifact, ServerPin, ServerRunLog, ServerRunRecord, ServerSkillBundle, ServerSkillVersion, ApiKeyScopeUpdateResult, ServerSkillRecord, SkillLifecyclePatch, SkillsProductStore, StoreBackendInfo, UpdateSkillPatch } from "./types.js";
|
|
19
19
|
export interface SqliteStoreOptions {
|
|
20
20
|
/** Apply pending migrations on open. Default true - it is what makes zero-config work. */
|
|
21
21
|
migrate?: boolean;
|
|
@@ -52,6 +52,7 @@ export declare class SqliteSkillsStore implements SkillsProductStore {
|
|
|
52
52
|
close(): Promise<void>;
|
|
53
53
|
ensureBootstrapApiKey(token: string, principal?: Partial<ApiPrincipal>): Promise<void>;
|
|
54
54
|
authenticateApiKeyHash(hash: string): Promise<ApiPrincipal | null>;
|
|
55
|
+
updateApiKeyScopes(actor: ApiPrincipal, keyId: string, expectedScopes: string[], addScopes: string[]): Promise<ApiKeyScopeUpdateResult>;
|
|
55
56
|
createRun(input: CreateRunInput): Promise<ServerRunRecord>;
|
|
56
57
|
listRuns(principal: ApiPrincipal, limit: number): Promise<ServerRunRecord[]>;
|
|
57
58
|
getRun(principal: ApiPrincipal, id: string): Promise<ServerRunRecord | null>;
|
|
@@ -102,6 +103,8 @@ export declare class SqliteSkillsStore implements SkillsProductStore {
|
|
|
102
103
|
publishSkill(input: PublishSkillInput): Promise<ServerSkillRecord>;
|
|
103
104
|
listSkills(principal: ApiPrincipal): Promise<ServerSkillRecord[]>;
|
|
104
105
|
getSkill(principal: ApiPrincipal, slug: string): Promise<ServerSkillRecord | null>;
|
|
106
|
+
setSkillLifecycle(principal: ApiPrincipal, slug: string, patch: SkillLifecyclePatch, expectedRevisionId?: string): Promise<ServerSkillRecord | null>;
|
|
107
|
+
private getSkillSync;
|
|
105
108
|
updateSkill(principal: ApiPrincipal, slug: string, patch: UpdateSkillPatch, expectedRevisionId?: string): Promise<ServerSkillRecord | null>;
|
|
106
109
|
deleteSkill(principal: ApiPrincipal, slug: string, tombstoneWindowMs: number): Promise<ServerSkillRecord | null>;
|
|
107
110
|
purgeExpiredTombstones(principal: ApiPrincipal): Promise<ServerSkillRecord[]>;
|
package/dist/server/store.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { MemoryExecutionGrantStore, PostgresExecutionGrantStore } from "./execution-grant-store.js";
|
|
2
2
|
import { MemorySkillSelectionStore, PostgresSkillSelectionStore } from "./selection-store.js";
|
|
3
|
-
import type { ApiPrincipal, ClaimRunInput, CreateRunInput, PublishSkillInput, RunTransitionPatch, ServerArtifact, ServerPin, ServerRunLog, ServerRunRecord, ServerSkillBundle, ServerSkillRecord, ServerSkillVersion, SkillsProductStore, StoreBackendInfo, UpdateSkillPatch } from "./types.js";
|
|
3
|
+
import type { ApiPrincipal, ClaimRunInput, CreateRunInput, PublishSkillInput, RunTransitionPatch, ServerArtifact, ServerPin, ServerRunLog, ServerRunRecord, ServerSkillBundle, ServerSkillRecord, ServerSkillVersion, ApiKeyScopeUpdateResult, SkillsProductStore, StoreBackendInfo, UpdateSkillPatch } from "./types.js";
|
|
4
|
+
import { type SkillLifecyclePatch } from "./types.js";
|
|
4
5
|
import { type SqliteStoreOptions } from "./sqlite-store.js";
|
|
5
6
|
export declare function createArtifactId(): string;
|
|
6
7
|
export interface StoreOptions {
|
|
@@ -44,6 +45,7 @@ export declare class MemorySkillsStore implements SkillsProductStore {
|
|
|
44
45
|
addApiKey(token: string, principal?: Partial<ApiPrincipal>): ApiPrincipal;
|
|
45
46
|
ensureBootstrapApiKey(token: string, principal?: Partial<ApiPrincipal>): Promise<void>;
|
|
46
47
|
authenticateApiKeyHash(hash: string): Promise<ApiPrincipal | null>;
|
|
48
|
+
updateApiKeyScopes(actor: ApiPrincipal, keyId: string, expectedScopes: string[], addScopes: string[]): Promise<ApiKeyScopeUpdateResult>;
|
|
47
49
|
createRun(input: CreateRunInput): Promise<ServerRunRecord>;
|
|
48
50
|
listRuns(principal: ApiPrincipal, limit: number): Promise<ServerRunRecord[]>;
|
|
49
51
|
getRun(principal: ApiPrincipal, runId: string): Promise<ServerRunRecord | null>;
|
|
@@ -76,6 +78,7 @@ export declare class MemorySkillsStore implements SkillsProductStore {
|
|
|
76
78
|
getSkillVersion(principal: ApiPrincipal, slug: string, version: string): Promise<ServerSkillVersion | null>;
|
|
77
79
|
listSkills(principal: ApiPrincipal): Promise<ServerSkillRecord[]>;
|
|
78
80
|
getSkill(principal: ApiPrincipal, slug: string): Promise<ServerSkillRecord | null>;
|
|
81
|
+
setSkillLifecycle(principal: ApiPrincipal, slug: string, patch: SkillLifecyclePatch, expectedRevisionId?: string): Promise<ServerSkillRecord | null>;
|
|
79
82
|
updateSkill(principal: ApiPrincipal, slug: string, patch: UpdateSkillPatch, expectedRevisionId?: string): Promise<ServerSkillRecord | null>;
|
|
80
83
|
deleteSkill(principal: ApiPrincipal, slug: string, tombstoneWindowMs: number): Promise<ServerSkillRecord | null>;
|
|
81
84
|
purgeExpiredTombstones(principal: ApiPrincipal): Promise<ServerSkillRecord[]>;
|
|
@@ -118,6 +121,7 @@ export declare class PostgresSkillsStore implements SkillsProductStore {
|
|
|
118
121
|
close(): Promise<void>;
|
|
119
122
|
ensureBootstrapApiKey(token: string, principal?: Partial<ApiPrincipal>): Promise<void>;
|
|
120
123
|
authenticateApiKeyHash(hash: string): Promise<ApiPrincipal | null>;
|
|
124
|
+
updateApiKeyScopes(actor: ApiPrincipal, keyId: string, expectedScopes: string[], addScopes: string[]): Promise<ApiKeyScopeUpdateResult>;
|
|
121
125
|
/**
|
|
122
126
|
* Run a callback under an RLS tenant or worker context, on one pooled
|
|
123
127
|
* connection, for the duration of one transaction only.
|
|
@@ -163,6 +167,7 @@ export declare class PostgresSkillsStore implements SkillsProductStore {
|
|
|
163
167
|
publishSkill(input: PublishSkillInput): Promise<ServerSkillRecord>;
|
|
164
168
|
listSkills(principal: ApiPrincipal): Promise<ServerSkillRecord[]>;
|
|
165
169
|
getSkill(principal: ApiPrincipal, slug: string): Promise<ServerSkillRecord | null>;
|
|
170
|
+
setSkillLifecycle(principal: ApiPrincipal, slug: string, patch: SkillLifecyclePatch, expectedRevisionId?: string): Promise<ServerSkillRecord | null>;
|
|
166
171
|
updateSkill(principal: ApiPrincipal, slug: string, patch: UpdateSkillPatch, expectedRevisionId?: string): Promise<ServerSkillRecord | null>;
|
|
167
172
|
deleteSkill(principal: ApiPrincipal, slug: string, tombstoneWindowMs: number): Promise<ServerSkillRecord | null>;
|
|
168
173
|
purgeExpiredTombstones(principal: ApiPrincipal): Promise<ServerSkillRecord[]>;
|
package/dist/server/types.d.ts
CHANGED
|
@@ -45,6 +45,11 @@ export declare class SkillVersionExistsError extends Error {
|
|
|
45
45
|
readonly attemptedSha256: string;
|
|
46
46
|
constructor(slug: string, version: string, existingSha256: string, attemptedSha256: string);
|
|
47
47
|
}
|
|
48
|
+
export declare class SkillLifecycleConflictError extends Error {
|
|
49
|
+
readonly slug: string;
|
|
50
|
+
readonly profiles: string[];
|
|
51
|
+
constructor(slug: string, profiles: string[]);
|
|
52
|
+
}
|
|
48
53
|
export interface ApiPrincipal {
|
|
49
54
|
apiKeyId: string;
|
|
50
55
|
orgId: string;
|
|
@@ -55,6 +60,15 @@ export interface ApiPrincipal {
|
|
|
55
60
|
role: string;
|
|
56
61
|
scopes: string[];
|
|
57
62
|
}
|
|
63
|
+
export type ApiKeyScopeUpdateResult = {
|
|
64
|
+
kind: "updated";
|
|
65
|
+
scopes: string[];
|
|
66
|
+
} | {
|
|
67
|
+
kind: "not_found";
|
|
68
|
+
} | {
|
|
69
|
+
kind: "stale";
|
|
70
|
+
scopes: string[];
|
|
71
|
+
};
|
|
58
72
|
export interface ServerRunRecord {
|
|
59
73
|
id: string;
|
|
60
74
|
orgId: string;
|
|
@@ -162,6 +176,16 @@ export interface ServerSkillRecord {
|
|
|
162
176
|
*/
|
|
163
177
|
tombstonedAt?: string;
|
|
164
178
|
tombstonePurgeAfter?: string;
|
|
179
|
+
/** Catalog lifecycle state. Archived rows retain versions and bundles for explicit reads. */
|
|
180
|
+
lifecycle: "active" | "archived";
|
|
181
|
+
archivedAt?: string;
|
|
182
|
+
archiveReason?: string;
|
|
183
|
+
replacementSlug?: string;
|
|
184
|
+
}
|
|
185
|
+
export interface SkillLifecyclePatch {
|
|
186
|
+
lifecycle: "active" | "archived";
|
|
187
|
+
reason?: string;
|
|
188
|
+
replacementSlug?: string;
|
|
165
189
|
}
|
|
166
190
|
/**
|
|
167
191
|
* Bundle bytes, addressed by their own digest.
|
|
@@ -313,6 +337,8 @@ export interface SkillsProductStore {
|
|
|
313
337
|
*/
|
|
314
338
|
verifyConnectivity?(): Promise<void>;
|
|
315
339
|
authenticateApiKeyHash(hash: string): Promise<ApiPrincipal | null>;
|
|
340
|
+
/** Guarded metadata-only scope admission for an existing key. */
|
|
341
|
+
updateApiKeyScopes?(actor: ApiPrincipal, keyId: string, expectedScopes: string[], addScopes: string[]): Promise<ApiKeyScopeUpdateResult>;
|
|
316
342
|
ensureBootstrapApiKey?(token: string, principal?: Partial<ApiPrincipal>): Promise<void>;
|
|
317
343
|
createRun(input: CreateRunInput): Promise<ServerRunRecord>;
|
|
318
344
|
listRuns(principal: ApiPrincipal, limit: number): Promise<ServerRunRecord[]>;
|
|
@@ -350,6 +376,7 @@ export interface SkillsProductStore {
|
|
|
350
376
|
* when the org has no skill by that slug, or when the row is tombstoned.
|
|
351
377
|
*/
|
|
352
378
|
updateSkill(principal: ApiPrincipal, slug: string, patch: UpdateSkillPatch, expectedRevisionId?: string): Promise<ServerSkillRecord | null>;
|
|
379
|
+
setSkillLifecycle(principal: ApiPrincipal, slug: string, patch: SkillLifecyclePatch, expectedRevisionId?: string): Promise<ServerSkillRecord | null>;
|
|
353
380
|
/**
|
|
354
381
|
* Tombstone a skill instead of hard-deleting it (todos d061fcda): the row is stamped
|
|
355
382
|
* tombstoned_at + tombstone_purge_after (now + tombstoneWindowMs) and kept, so reads
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
ALTER TABLE skills_registry ADD COLUMN lifecycle text NOT NULL DEFAULT 'active' CHECK (lifecycle IN ('active','archived'));
|
|
2
|
+
ALTER TABLE skills_registry ADD COLUMN archived_at timestamptz;
|
|
3
|
+
ALTER TABLE skills_registry ADD COLUMN archive_reason text;
|
|
4
|
+
ALTER TABLE skills_registry ADD COLUMN replacement_slug text;
|
|
5
|
+
CREATE INDEX IF NOT EXISTS skills_registry_org_lifecycle_idx ON skills_registry (org_id, lifecycle, slug);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
ALTER TABLE skills_registry ADD COLUMN lifecycle text NOT NULL DEFAULT 'active' CHECK (lifecycle IN ('active','archived'));
|
|
2
|
+
ALTER TABLE skills_registry ADD COLUMN archived_at text;
|
|
3
|
+
ALTER TABLE skills_registry ADD COLUMN archive_reason text;
|
|
4
|
+
ALTER TABLE skills_registry ADD COLUMN replacement_slug text;
|
|
5
|
+
CREATE INDEX IF NOT EXISTS skills_registry_org_lifecycle_idx ON skills_registry (org_id, lifecycle, slug);
|