@hasna/skills 0.9.1 → 0.9.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 +10 -1
- package/bin/index.js +98 -13
- package/bin/maintenance.js +4913 -0
- package/bin/mcp.js +3 -2
- package/bin/migrate.js +55 -2
- package/bin/server.js +173 -10
- package/bin/worker.js +173 -10
- package/dist/index.js +42 -9
- package/dist/lib/agent-integration.d.ts +27 -0
- package/dist/lib/codex-hook-rpc.d.ts +1 -1
- package/dist/sdk/index.js +212 -17
- package/dist/server/maintenance-entry.d.ts +2 -0
- package/dist/server/maintenance.d.ts +1 -0
- package/dist/server/sqlite-store.d.ts +3 -1
- package/dist/server/store.d.ts +7 -1
- package/dist/server/types.d.ts +44 -0
- package/migrations/postgres/0005_operator_scope_receipts.sql +9 -0
- package/migrations/sqlite/0005_operator_scope_receipts.sql +7 -0
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -11448,7 +11448,7 @@ import { isAbsolute as isAbsolute10, join as join20, resolve as resolve10 } from
|
|
|
11448
11448
|
// package.json
|
|
11449
11449
|
var package_default = {
|
|
11450
11450
|
name: "@hasna/skills",
|
|
11451
|
-
version: "0.9.
|
|
11451
|
+
version: "0.9.3",
|
|
11452
11452
|
description: "Skills library for AI coding agents",
|
|
11453
11453
|
type: "module",
|
|
11454
11454
|
bin: {
|
|
@@ -11457,6 +11457,7 @@ var package_default = {
|
|
|
11457
11457
|
"skills-serve": "bin/server.js",
|
|
11458
11458
|
"skills-server": "bin/server.js",
|
|
11459
11459
|
"skills-worker": "bin/worker.js",
|
|
11460
|
+
"skills-maintenance": "bin/maintenance.js",
|
|
11460
11461
|
"skills-migrate": "bin/migrate.js"
|
|
11461
11462
|
},
|
|
11462
11463
|
exports: {
|
|
@@ -11497,7 +11498,7 @@ var package_default = {
|
|
|
11497
11498
|
types: "./dist/index.d.ts",
|
|
11498
11499
|
scripts: {
|
|
11499
11500
|
clean: "rm -rf bin/ dist/",
|
|
11500
|
-
build: "bun run clean && bun build ./src/cli/index.tsx --outdir ./bin --target bun && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/server/index.ts --outfile ./bin/server.js --target bun && bun build ./src/server/worker.ts --outfile ./bin/worker.js --target bun && bun build ./src/server/migrate.ts --outfile ./bin/migrate.js --target bun && bun build ./src/index.ts ./src/storage.ts ./src/sdk/index.ts ./src/admin-contract.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
11501
|
+
build: "bun run clean && bun build ./src/cli/index.tsx --outdir ./bin --target bun && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/server/index.ts --outfile ./bin/server.js --target bun && bun build ./src/server/worker.ts --outfile ./bin/worker.js --target bun && bun build ./src/server/migrate.ts --outfile ./bin/migrate.js --target bun && bun build ./src/server/maintenance.ts --outfile ./bin/maintenance.js --target bun && bun build ./src/index.ts ./src/storage.ts ./src/sdk/index.ts ./src/admin-contract.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
11501
11502
|
"build:js": "rm -rf dist && bun build ./src/index.ts ./src/storage.ts ./src/sdk/index.ts ./src/admin-contract.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
11502
11503
|
test: "bun test --timeout 30000",
|
|
11503
11504
|
dev: "bun run ./src/cli/index.tsx",
|
|
@@ -15738,6 +15739,35 @@ function treeHash(root2) {
|
|
|
15738
15739
|
visit2(root2);
|
|
15739
15740
|
return hash2.digest("hex");
|
|
15740
15741
|
}
|
|
15742
|
+
function selectNativeMigrationTargets(inventory, manifest) {
|
|
15743
|
+
if (manifest.schema !== "hasna.skills-native-migration-targets.v1" || !/^[0-9a-f]{64}$/.test(manifest.digest) || !Array.isArray(manifest.targets) || manifest.targets.length === 0)
|
|
15744
|
+
throw new Error("Invalid native migration target manifest");
|
|
15745
|
+
const identities = new Set;
|
|
15746
|
+
const selected = [];
|
|
15747
|
+
for (const target of manifest.targets) {
|
|
15748
|
+
const projectRoot = resolve15(target.projectRoot), normalized = relative5(projectRoot, resolve15(projectRoot, target.path));
|
|
15749
|
+
if (!isAbsolute15(target.projectRoot) || projectRoot !== target.projectRoot || !existsSync11(projectRoot) || !lstatSync18(projectRoot).isDirectory())
|
|
15750
|
+
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
15751
|
+
assertSafePath(projectRoot);
|
|
15752
|
+
if (isAbsolute15(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep6}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
|
|
15753
|
+
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
15754
|
+
const identity3 = `${target.agent}\x00${projectRoot}\x00${normalized}`;
|
|
15755
|
+
if (identities.has(identity3))
|
|
15756
|
+
throw new Error(`Duplicate native migration target: ${target.path}`);
|
|
15757
|
+
identities.add(identity3);
|
|
15758
|
+
const expected = resolve15(target.projectRoot, target.path);
|
|
15759
|
+
const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve15(entry2.path) === expected);
|
|
15760
|
+
if (matches.length !== 1)
|
|
15761
|
+
throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
|
|
15762
|
+
const entry = matches[0];
|
|
15763
|
+
if (entry.bridge || entry.system || entry.vendor)
|
|
15764
|
+
throw new Error(`Native migration target is protected or vendor-owned: ${entry.path}`);
|
|
15765
|
+
if (entry.hash !== target.treeSha256 || treeHash(entry.path) !== target.treeSha256)
|
|
15766
|
+
throw new Error(`Native migration target changed after review: ${entry.path}`);
|
|
15767
|
+
selected.push(entry);
|
|
15768
|
+
}
|
|
15769
|
+
return selected;
|
|
15770
|
+
}
|
|
15741
15771
|
function projectAncestorDirectories(projects) {
|
|
15742
15772
|
const directories = new Set;
|
|
15743
15773
|
for (const project of projects) {
|
|
@@ -15755,10 +15785,12 @@ function projectAncestorDirectories(projects) {
|
|
|
15755
15785
|
}
|
|
15756
15786
|
function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
15757
15787
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
15758
|
-
const
|
|
15788
|
+
const selectedAgents = options.agents ? new Set(options.agents) : undefined;
|
|
15789
|
+
const rootDefinitions = selectedAgents ? ROOTS.filter(([agent, path]) => selectedAgents.has(agent) || selectedAgents.has("hermes") && agent === "codex" && path === ".agents/skills") : ROOTS;
|
|
15790
|
+
const roots = rootDefinitions.map(([agent, path]) => [agent, canonicalAgentPath(join25(home, path), aliases)]);
|
|
15759
15791
|
const bridgePaths = Object.values(AGENT_ADAPTERS).map((adapter) => canonicalAgentPath(join25(home, adapter.root, CLI_BRIDGE_NAME), aliases));
|
|
15760
15792
|
for (const project of projectAncestorDirectories([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []])) {
|
|
15761
|
-
for (const [agent, path] of
|
|
15793
|
+
for (const [agent, path] of rootDefinitions)
|
|
15762
15794
|
roots.push([agent, canonicalAgentPath(join25(project, path), aliases)]);
|
|
15763
15795
|
}
|
|
15764
15796
|
const entries = [], seen = new Set;
|
|
@@ -16014,7 +16046,7 @@ function planAgentIntegration(options) {
|
|
|
16014
16046
|
return [agent, { command, profileId: profileId2 }];
|
|
16015
16047
|
}));
|
|
16016
16048
|
const discoveries = [...new Set(options.agents)].map((agent) => resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, canonical: (path) => canonicalAgentPath(path, aliases) }));
|
|
16017
|
-
const nativeSkills = inventoryNativeSkills(home, { includeVendor: true, guardHermes: options.agents.includes("hermes"), projectDir: options.projectDir, agentRoots: discoveries.flatMap((binding) => binding.roots.map((path) => ({ agent: binding.agent, path }))), allowRootAliases: options.allowRootAliases });
|
|
16049
|
+
const nativeSkills = inventoryNativeSkills(home, { includeVendor: true, guardHermes: options.agents.includes("hermes"), agents: options.agents, projectDir: options.projectDir, agentRoots: discoveries.flatMap((binding) => binding.roots.map((path) => ({ agent: binding.agent, path }))), allowRootAliases: options.allowRootAliases });
|
|
16018
16050
|
const changes = [];
|
|
16019
16051
|
for (const agent of [...new Set(options.agents)]) {
|
|
16020
16052
|
if (!INTEGRATION_AGENTS.includes(agent))
|
|
@@ -16226,12 +16258,13 @@ function archiveNativeSkills(inventory, options) {
|
|
|
16226
16258
|
if (!expected || treeHash(entry.path) !== entry.hash || !isOwnedCliBridge(entry.path, [expected]))
|
|
16227
16259
|
throw new Error(`Skills bridge changed after planning: ${entry.path}`);
|
|
16228
16260
|
}
|
|
16229
|
-
const selected = inventory.filter((entry) => !entry.bridge && !entry.system && (entry.vendor ? options.includeVendor : entry.managed || options.includeUnmanaged));
|
|
16261
|
+
const selected = options.targetManifest ? selectNativeMigrationTargets(inventory, options.targetManifest) : inventory.filter((entry) => !entry.bridge && !entry.system && (entry.vendor ? options.includeVendor : entry.managed || options.includeUnmanaged));
|
|
16230
16262
|
for (const entry of selected)
|
|
16231
16263
|
if (treeHash(entry.path) !== entry.hash)
|
|
16232
16264
|
throw new Error(`Native skill changed after planning: ${entry.path}`);
|
|
16265
|
+
const targetManifest = options.targetManifest ? { schema: options.targetManifest.schema, digest: options.targetManifest.digest, targetCount: options.targetManifest.targets.length } : undefined;
|
|
16233
16266
|
if (!selected.length)
|
|
16234
|
-
return { entries: [], ...aliases.length ? { rootAliases: aliases } : {} };
|
|
16267
|
+
return { entries: [], ...targetManifest ? { targetManifest } : {}, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
16235
16268
|
const operationId = randomUUID3(), archiveRoot = join25(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join25(archiveRoot, "receipt.json");
|
|
16236
16269
|
const entries = selected.map((entry, index) => ({
|
|
16237
16270
|
source: entry.vendor ? join25(entry.path, "SKILL.md") : entry.path,
|
|
@@ -16240,7 +16273,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
16240
16273
|
...entry.vendor ? { discoveryOnly: true } : {},
|
|
16241
16274
|
status: "planned"
|
|
16242
16275
|
}));
|
|
16243
|
-
const journal = { version: 2, operationId, status: "planned", entries, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
16276
|
+
const journal = { version: 2, operationId, status: "planned", entries, ...targetManifest ? { targetManifest } : {}, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
16244
16277
|
const moved = [];
|
|
16245
16278
|
const verifyArchive = (entry) => {
|
|
16246
16279
|
assertSafePath(entry.archive);
|
|
@@ -16334,7 +16367,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
16334
16367
|
} catch {}
|
|
16335
16368
|
throw new Error(`Native archive failed; inspect the recovery journal at ${receiptPath} before retrying.`, { cause: error });
|
|
16336
16369
|
}
|
|
16337
|
-
return { entries: entries.map(({ status, conflict, ...entry }) => entry), receiptPath, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
16370
|
+
return { entries: entries.map(({ status, conflict, ...entry }) => entry), receiptPath, ...targetManifest ? { targetManifest } : {}, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
16338
16371
|
}
|
|
16339
16372
|
function assertNativeExportAllowed(dataDir2 = getDataDirReadOnly()) {
|
|
16340
16373
|
if (requiresCliSkillLoading(dataDir2))
|
|
@@ -22,6 +22,17 @@ export interface NativeSkillEntry {
|
|
|
22
22
|
bridgeHome?: string;
|
|
23
23
|
rootAlias?: AgentRootAlias;
|
|
24
24
|
}
|
|
25
|
+
export interface NativeMigrationTarget {
|
|
26
|
+
agent: string;
|
|
27
|
+
projectRoot: string;
|
|
28
|
+
path: string;
|
|
29
|
+
treeSha256: string;
|
|
30
|
+
}
|
|
31
|
+
export interface NativeMigrationTargetManifest {
|
|
32
|
+
schema: "hasna.skills-native-migration-targets.v1";
|
|
33
|
+
targets: NativeMigrationTarget[];
|
|
34
|
+
digest: string;
|
|
35
|
+
}
|
|
25
36
|
export interface AgentConfigChange {
|
|
26
37
|
path: string;
|
|
27
38
|
before: string | null;
|
|
@@ -40,11 +51,21 @@ export interface AgentIntegrationPlan {
|
|
|
40
51
|
discoveryAfter?: AgentDiscoveryBinding[];
|
|
41
52
|
rootAliases?: AgentRootAlias[];
|
|
42
53
|
}
|
|
54
|
+
/** Parse the reviewed exact-target binding used by native migration. Paths are
|
|
55
|
+
* deliberately project-relative so a manifest cannot silently select another
|
|
56
|
+
* checkout when a project root changes. */
|
|
57
|
+
export declare function parseNativeMigrationTargetManifest(input: string | Buffer): NativeMigrationTargetManifest;
|
|
58
|
+
/** Read a manifest without following links or opening special files, with a
|
|
59
|
+
* finite bound so a CLI cannot block on an untrusted path. */
|
|
60
|
+
export declare function readNativeMigrationTargetManifest(path: string): NativeMigrationTargetManifest;
|
|
61
|
+
/** Validate every reviewed target before any archive directory or journal is created. */
|
|
62
|
+
export declare function selectNativeMigrationTargets(inventory: NativeSkillEntry[], manifest: NativeMigrationTargetManifest): NativeSkillEntry[];
|
|
43
63
|
export declare function inventoryNativeSkills(home?: string, options?: {
|
|
44
64
|
includeVendor?: boolean;
|
|
45
65
|
guardHermes?: boolean;
|
|
46
66
|
projectDir?: string;
|
|
47
67
|
projectDirs?: string[];
|
|
68
|
+
agents?: readonly IntegrationAgent[];
|
|
48
69
|
agentRoots?: Array<{
|
|
49
70
|
agent: string;
|
|
50
71
|
path: string;
|
|
@@ -75,6 +96,7 @@ export declare function archiveNativeSkills(inventory: NativeSkillEntry[], optio
|
|
|
75
96
|
includeUnmanaged?: boolean;
|
|
76
97
|
includeVendor?: boolean;
|
|
77
98
|
allowRootAliases?: boolean;
|
|
99
|
+
targetManifest?: NativeMigrationTargetManifest;
|
|
78
100
|
}): {
|
|
79
101
|
entries: Array<{
|
|
80
102
|
source: string;
|
|
@@ -84,6 +106,11 @@ export declare function archiveNativeSkills(inventory: NativeSkillEntry[], optio
|
|
|
84
106
|
}>;
|
|
85
107
|
receiptPath?: string;
|
|
86
108
|
rootAliases?: AgentRootAlias[];
|
|
109
|
+
targetManifest?: {
|
|
110
|
+
schema: string;
|
|
111
|
+
digest: string;
|
|
112
|
+
targetCount: number;
|
|
113
|
+
};
|
|
87
114
|
};
|
|
88
115
|
/** Run before any prompt context load. Missing ownership or reappearing native
|
|
89
116
|
* discovery files require repair; verified cache availability is not an override. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const SUPPORTED_CODEX_HOOK_VERSIONS: readonly ["codex-cli 0.153.0", "codex-cli 0.154.0", "codex-cli 0.155.0"];
|
|
1
|
+
export declare const SUPPORTED_CODEX_HOOK_VERSIONS: readonly ["codex-cli 0.153.0", "codex-cli 0.154.0", "codex-cli 0.155.0", "codex-cli 0.155.1"];
|
|
2
2
|
export interface CodexHookRpc {
|
|
3
3
|
version: string;
|
|
4
4
|
processId?: number;
|
package/dist/sdk/index.js
CHANGED
|
@@ -32373,7 +32373,7 @@ var init_event_sink = __esm(() => {
|
|
|
32373
32373
|
// package.json
|
|
32374
32374
|
var package_default = {
|
|
32375
32375
|
name: "@hasna/skills",
|
|
32376
|
-
version: "0.9.
|
|
32376
|
+
version: "0.9.3",
|
|
32377
32377
|
description: "Skills library for AI coding agents",
|
|
32378
32378
|
type: "module",
|
|
32379
32379
|
bin: {
|
|
@@ -32382,6 +32382,7 @@ var package_default = {
|
|
|
32382
32382
|
"skills-serve": "bin/server.js",
|
|
32383
32383
|
"skills-server": "bin/server.js",
|
|
32384
32384
|
"skills-worker": "bin/worker.js",
|
|
32385
|
+
"skills-maintenance": "bin/maintenance.js",
|
|
32385
32386
|
"skills-migrate": "bin/migrate.js"
|
|
32386
32387
|
},
|
|
32387
32388
|
exports: {
|
|
@@ -32422,7 +32423,7 @@ var package_default = {
|
|
|
32422
32423
|
types: "./dist/index.d.ts",
|
|
32423
32424
|
scripts: {
|
|
32424
32425
|
clean: "rm -rf bin/ dist/",
|
|
32425
|
-
build: "bun run clean && bun build ./src/cli/index.tsx --outdir ./bin --target bun && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/server/index.ts --outfile ./bin/server.js --target bun && bun build ./src/server/worker.ts --outfile ./bin/worker.js --target bun && bun build ./src/server/migrate.ts --outfile ./bin/migrate.js --target bun && bun build ./src/index.ts ./src/storage.ts ./src/sdk/index.ts ./src/admin-contract.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
32426
|
+
build: "bun run clean && bun build ./src/cli/index.tsx --outdir ./bin --target bun && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/server/index.ts --outfile ./bin/server.js --target bun && bun build ./src/server/worker.ts --outfile ./bin/worker.js --target bun && bun build ./src/server/migrate.ts --outfile ./bin/migrate.js --target bun && bun build ./src/server/maintenance.ts --outfile ./bin/maintenance.js --target bun && bun build ./src/index.ts ./src/storage.ts ./src/sdk/index.ts ./src/admin-contract.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
32426
32427
|
"build:js": "rm -rf dist && bun build ./src/index.ts ./src/storage.ts ./src/sdk/index.ts ./src/admin-contract.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
32427
32428
|
test: "bun test --timeout 30000",
|
|
32428
32429
|
dev: "bun run ./src/cli/index.tsx",
|
|
@@ -40661,6 +40662,35 @@ function treeHash(root2) {
|
|
|
40661
40662
|
visit2(root2);
|
|
40662
40663
|
return hash2.digest("hex");
|
|
40663
40664
|
}
|
|
40665
|
+
function selectNativeMigrationTargets(inventory, manifest) {
|
|
40666
|
+
if (manifest.schema !== "hasna.skills-native-migration-targets.v1" || !/^[0-9a-f]{64}$/.test(manifest.digest) || !Array.isArray(manifest.targets) || manifest.targets.length === 0)
|
|
40667
|
+
throw new Error("Invalid native migration target manifest");
|
|
40668
|
+
const identities = new Set;
|
|
40669
|
+
const selected = [];
|
|
40670
|
+
for (const target of manifest.targets) {
|
|
40671
|
+
const projectRoot = resolve14(target.projectRoot), normalized = relative3(projectRoot, resolve14(projectRoot, target.path));
|
|
40672
|
+
if (!isAbsolute15(target.projectRoot) || projectRoot !== target.projectRoot || !existsSync6(projectRoot) || !lstatSync17(projectRoot).isDirectory())
|
|
40673
|
+
throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
|
|
40674
|
+
assertSafePath(projectRoot);
|
|
40675
|
+
if (isAbsolute15(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep4}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
|
|
40676
|
+
throw new Error(`Invalid native migration target: ${target.path}`);
|
|
40677
|
+
const identity3 = `${target.agent}\x00${projectRoot}\x00${normalized}`;
|
|
40678
|
+
if (identities.has(identity3))
|
|
40679
|
+
throw new Error(`Duplicate native migration target: ${target.path}`);
|
|
40680
|
+
identities.add(identity3);
|
|
40681
|
+
const expected = resolve14(target.projectRoot, target.path);
|
|
40682
|
+
const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve14(entry2.path) === expected);
|
|
40683
|
+
if (matches.length !== 1)
|
|
40684
|
+
throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
|
|
40685
|
+
const entry = matches[0];
|
|
40686
|
+
if (entry.bridge || entry.system || entry.vendor)
|
|
40687
|
+
throw new Error(`Native migration target is protected or vendor-owned: ${entry.path}`);
|
|
40688
|
+
if (entry.hash !== target.treeSha256 || treeHash(entry.path) !== target.treeSha256)
|
|
40689
|
+
throw new Error(`Native migration target changed after review: ${entry.path}`);
|
|
40690
|
+
selected.push(entry);
|
|
40691
|
+
}
|
|
40692
|
+
return selected;
|
|
40693
|
+
}
|
|
40664
40694
|
function projectAncestorDirectories(projects) {
|
|
40665
40695
|
const directories = new Set;
|
|
40666
40696
|
for (const project of projects) {
|
|
@@ -40678,10 +40708,12 @@ function projectAncestorDirectories(projects) {
|
|
|
40678
40708
|
}
|
|
40679
40709
|
function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
40680
40710
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
40681
|
-
const
|
|
40711
|
+
const selectedAgents = options.agents ? new Set(options.agents) : undefined;
|
|
40712
|
+
const rootDefinitions = selectedAgents ? ROOTS.filter(([agent, path]) => selectedAgents.has(agent) || selectedAgents.has("hermes") && agent === "codex" && path === ".agents/skills") : ROOTS;
|
|
40713
|
+
const roots = rootDefinitions.map(([agent, path]) => [agent, canonicalAgentPath(join21(home, path), aliases)]);
|
|
40682
40714
|
const bridgePaths = Object.values(AGENT_ADAPTERS).map((adapter) => canonicalAgentPath(join21(home, adapter.root, CLI_BRIDGE_NAME), aliases));
|
|
40683
40715
|
for (const project of projectAncestorDirectories([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []])) {
|
|
40684
|
-
for (const [agent, path] of
|
|
40716
|
+
for (const [agent, path] of rootDefinitions)
|
|
40685
40717
|
roots.push([agent, canonicalAgentPath(join21(project, path), aliases)]);
|
|
40686
40718
|
}
|
|
40687
40719
|
const entries = [], seen = new Set;
|
|
@@ -40937,7 +40969,7 @@ function planAgentIntegration(options) {
|
|
|
40937
40969
|
return [agent, { command, profileId: profileId2 }];
|
|
40938
40970
|
}));
|
|
40939
40971
|
const discoveries = [...new Set(options.agents)].map((agent) => resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, canonical: (path) => canonicalAgentPath(path, aliases) }));
|
|
40940
|
-
const nativeSkills = inventoryNativeSkills(home, { includeVendor: true, guardHermes: options.agents.includes("hermes"), projectDir: options.projectDir, agentRoots: discoveries.flatMap((binding) => binding.roots.map((path) => ({ agent: binding.agent, path }))), allowRootAliases: options.allowRootAliases });
|
|
40972
|
+
const nativeSkills = inventoryNativeSkills(home, { includeVendor: true, guardHermes: options.agents.includes("hermes"), agents: options.agents, projectDir: options.projectDir, agentRoots: discoveries.flatMap((binding) => binding.roots.map((path) => ({ agent: binding.agent, path }))), allowRootAliases: options.allowRootAliases });
|
|
40941
40973
|
const changes = [];
|
|
40942
40974
|
for (const agent of [...new Set(options.agents)]) {
|
|
40943
40975
|
if (!INTEGRATION_AGENTS.includes(agent))
|
|
@@ -41149,12 +41181,13 @@ function archiveNativeSkills(inventory, options) {
|
|
|
41149
41181
|
if (!expected || treeHash(entry.path) !== entry.hash || !isOwnedCliBridge(entry.path, [expected]))
|
|
41150
41182
|
throw new Error(`Skills bridge changed after planning: ${entry.path}`);
|
|
41151
41183
|
}
|
|
41152
|
-
const selected = inventory.filter((entry) => !entry.bridge && !entry.system && (entry.vendor ? options.includeVendor : entry.managed || options.includeUnmanaged));
|
|
41184
|
+
const selected = options.targetManifest ? selectNativeMigrationTargets(inventory, options.targetManifest) : inventory.filter((entry) => !entry.bridge && !entry.system && (entry.vendor ? options.includeVendor : entry.managed || options.includeUnmanaged));
|
|
41153
41185
|
for (const entry of selected)
|
|
41154
41186
|
if (treeHash(entry.path) !== entry.hash)
|
|
41155
41187
|
throw new Error(`Native skill changed after planning: ${entry.path}`);
|
|
41188
|
+
const targetManifest = options.targetManifest ? { schema: options.targetManifest.schema, digest: options.targetManifest.digest, targetCount: options.targetManifest.targets.length } : undefined;
|
|
41156
41189
|
if (!selected.length)
|
|
41157
|
-
return { entries: [], ...aliases.length ? { rootAliases: aliases } : {} };
|
|
41190
|
+
return { entries: [], ...targetManifest ? { targetManifest } : {}, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
41158
41191
|
const operationId = randomUUID3(), archiveRoot = join21(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join21(archiveRoot, "receipt.json");
|
|
41159
41192
|
const entries = selected.map((entry, index) => ({
|
|
41160
41193
|
source: entry.vendor ? join21(entry.path, "SKILL.md") : entry.path,
|
|
@@ -41163,7 +41196,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
41163
41196
|
...entry.vendor ? { discoveryOnly: true } : {},
|
|
41164
41197
|
status: "planned"
|
|
41165
41198
|
}));
|
|
41166
|
-
const journal = { version: 2, operationId, status: "planned", entries, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
41199
|
+
const journal = { version: 2, operationId, status: "planned", entries, ...targetManifest ? { targetManifest } : {}, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
41167
41200
|
const moved = [];
|
|
41168
41201
|
const verifyArchive = (entry) => {
|
|
41169
41202
|
assertSafePath(entry.archive);
|
|
@@ -41257,7 +41290,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
41257
41290
|
} catch {}
|
|
41258
41291
|
throw new Error(`Native archive failed; inspect the recovery journal at ${receiptPath} before retrying.`, { cause: error });
|
|
41259
41292
|
}
|
|
41260
|
-
return { entries: entries.map(({ status, conflict, ...entry }) => entry), receiptPath, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
41293
|
+
return { entries: entries.map(({ status, conflict, ...entry }) => entry), receiptPath, ...targetManifest ? { targetManifest } : {}, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
41261
41294
|
}
|
|
41262
41295
|
function assertNativeExportAllowed(dataDir2 = getDataDirReadOnly()) {
|
|
41263
41296
|
if (requiresCliSkillLoading(dataDir2))
|
|
@@ -55195,6 +55228,10 @@ class SkillLifecycleConflictError extends Error {
|
|
|
55195
55228
|
this.name = "SkillLifecycleConflictError";
|
|
55196
55229
|
}
|
|
55197
55230
|
}
|
|
55231
|
+
function validOperatorScopeEnrollmentInput(input) {
|
|
55232
|
+
const bounded = (value, max = 256) => typeof value === "string" && value.length > 0 && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value);
|
|
55233
|
+
return bounded(input.keyId) && bounded(input.stationId) && bounded(input.orgId) && bounded(input.operationId) && bounded(input.manifestDigest, 64) && /^[a-f0-9]{64}$/.test(input.manifestDigest) && bounded(input.operatorJobId) && bounded(input.operatorTaskArn, 512) && input.expectedScopes.length > 0 && input.expectedScopes.length <= 32 && input.expectedScopes.every((scope) => bounded(scope, 128) && /^[a-z][a-z0-9_-]*:[a-z][a-z0-9_-]*$/.test(scope));
|
|
55234
|
+
}
|
|
55198
55235
|
|
|
55199
55236
|
// src/lib/revision.ts
|
|
55200
55237
|
import { createHash as createHash20 } from "crypto";
|
|
@@ -55343,6 +55380,54 @@ class SqliteSkillsStore {
|
|
|
55343
55380
|
}
|
|
55344
55381
|
return { kind: "updated", scopes };
|
|
55345
55382
|
}
|
|
55383
|
+
async enrollPublishScopeByOperator(input) {
|
|
55384
|
+
if (!validOperatorScopeEnrollmentInput(input))
|
|
55385
|
+
return { kind: "invalid" };
|
|
55386
|
+
if (input.expectedScopes.includes("skills:publish"))
|
|
55387
|
+
return { kind: "stale", scopes: input.expectedScopes };
|
|
55388
|
+
const operation = this.get("SELECT org_id, target_id FROM skills_audit_events WHERE action = ? AND operator_operation_id = ? LIMIT 1", ["api_key_scopes_added", input.operationId]);
|
|
55389
|
+
if (operation && (String(operation.org_id) !== input.orgId || String(operation.target_id) !== input.keyId))
|
|
55390
|
+
return { kind: "target_mismatch" };
|
|
55391
|
+
const row = this.get("SELECT id, org_id, name, scopes_json FROM api_keys WHERE id = ? AND revoked_at IS NULL LIMIT 1", [input.keyId]);
|
|
55392
|
+
if (!row)
|
|
55393
|
+
return { kind: "not_found" };
|
|
55394
|
+
if (String(row.org_id) !== input.orgId)
|
|
55395
|
+
return { kind: "target_mismatch" };
|
|
55396
|
+
const current = parseScopes(row.scopes_json);
|
|
55397
|
+
const prior = this.get("SELECT metadata_json FROM skills_audit_events WHERE action = ? AND target_type = ? AND target_id = ? AND json_extract(metadata_json, '$.operator_operation_id') = ? LIMIT 1", ["api_key_scopes_added", "api_key", input.keyId, input.operationId]);
|
|
55398
|
+
if (prior) {
|
|
55399
|
+
try {
|
|
55400
|
+
if (JSON.parse(String(prior.metadata_json)).target_manifest_digest !== input.manifestDigest)
|
|
55401
|
+
return { kind: "target_mismatch" };
|
|
55402
|
+
} catch {
|
|
55403
|
+
return { kind: "target_mismatch" };
|
|
55404
|
+
}
|
|
55405
|
+
return current.includes("skills:publish") ? { kind: "already_applied", scopes: current } : { kind: "stale", scopes: current };
|
|
55406
|
+
}
|
|
55407
|
+
if (current.length !== input.expectedScopes.length || current.some((scope, index) => scope !== input.expectedScopes[index]))
|
|
55408
|
+
return { kind: "stale", scopes: current };
|
|
55409
|
+
const scopes = [...current, "skills:publish"];
|
|
55410
|
+
const tx = this.db.transaction(() => {
|
|
55411
|
+
const changed = this.db.run("UPDATE api_keys SET scopes_json = ? WHERE id = ? AND org_id = ? AND revoked_at IS NULL AND scopes_json = ?", [JSON.stringify(scopes), input.keyId, input.orgId, JSON.stringify(input.expectedScopes)]);
|
|
55412
|
+
if (changed.changes !== 1)
|
|
55413
|
+
return false;
|
|
55414
|
+
this.db.run("INSERT INTO skills_audit_events (org_id, user_id, api_key_id, action, target_type, target_id, operator_operation_id, metadata_json) VALUES (?, NULL, NULL, ?, ?, ?, ?, ?)", [input.orgId, "api_key_scopes_added", "api_key", input.keyId, input.operationId, JSON.stringify({ added: ["skills:publish"], scopes, operator_operation_id: input.operationId, operator_job_id: input.operatorJobId, operator_task_arn: input.operatorTaskArn, target_manifest_digest: input.manifestDigest, station_id: input.stationId })]);
|
|
55415
|
+
return true;
|
|
55416
|
+
});
|
|
55417
|
+
if (!tx()) {
|
|
55418
|
+
const latest = this.get("SELECT scopes_json FROM api_keys WHERE id = ? AND org_id = ? AND revoked_at IS NULL LIMIT 1", [input.keyId, input.orgId]);
|
|
55419
|
+
return { kind: "stale", scopes: latest ? parseScopes(latest.scopes_json) : current };
|
|
55420
|
+
}
|
|
55421
|
+
return { kind: "updated", scopes };
|
|
55422
|
+
}
|
|
55423
|
+
async inspectOperatorScopeTarget(keyId, orgId) {
|
|
55424
|
+
const row = this.get("SELECT org_id, scopes_json FROM api_keys WHERE id = ? AND revoked_at IS NULL LIMIT 1", [keyId]);
|
|
55425
|
+
if (!row)
|
|
55426
|
+
return { kind: "not_found" };
|
|
55427
|
+
if (String(row.org_id) !== orgId)
|
|
55428
|
+
return { kind: "target_mismatch" };
|
|
55429
|
+
return { kind: "found", scopes: parseScopes(row.scopes_json) };
|
|
55430
|
+
}
|
|
55346
55431
|
async createRun(input) {
|
|
55347
55432
|
if (input.idempotencyKey) {
|
|
55348
55433
|
const existing = this.get("SELECT * FROM skills_runs WHERE org_id = ? AND idempotency_key = ? LIMIT 1", [input.principal.orgId, input.idempotencyKey]);
|
|
@@ -62590,6 +62675,7 @@ class MemorySkillsStore {
|
|
|
62590
62675
|
bundles = new Map;
|
|
62591
62676
|
versions = new Map;
|
|
62592
62677
|
pins = new Map;
|
|
62678
|
+
operatorEnrollments = new Map;
|
|
62593
62679
|
constructor(apiKeys = []) {
|
|
62594
62680
|
for (const key of apiKeys)
|
|
62595
62681
|
this.addApiKey(key.token, key.principal);
|
|
@@ -62619,6 +62705,41 @@ class MemorySkillsStore {
|
|
|
62619
62705
|
}
|
|
62620
62706
|
return { kind: "not_found" };
|
|
62621
62707
|
}
|
|
62708
|
+
async enrollPublishScopeByOperator(input) {
|
|
62709
|
+
if (!validOperatorScopeEnrollmentInput(input))
|
|
62710
|
+
return { kind: "invalid" };
|
|
62711
|
+
const previous = this.operatorEnrollments.get(input.operationId);
|
|
62712
|
+
if (previous) {
|
|
62713
|
+
if (previous.keyId !== input.keyId || previous.manifestDigest !== input.manifestDigest)
|
|
62714
|
+
return { kind: "target_mismatch" };
|
|
62715
|
+
for (const target of this.apiKeys.values()) {
|
|
62716
|
+
if (target.apiKeyId === input.keyId && target.orgId === input.orgId && target.scopes.includes("skills:publish")) {
|
|
62717
|
+
return { kind: "already_applied", scopes: [...target.scopes] };
|
|
62718
|
+
}
|
|
62719
|
+
}
|
|
62720
|
+
return { kind: "stale", scopes: [] };
|
|
62721
|
+
}
|
|
62722
|
+
for (const [hash3, target] of this.apiKeys) {
|
|
62723
|
+
if (target.apiKeyId !== input.keyId || target.orgId !== input.orgId)
|
|
62724
|
+
continue;
|
|
62725
|
+
if (target.scopes.length !== input.expectedScopes.length || target.scopes.some((scope2, index) => scope2 !== input.expectedScopes[index])) {
|
|
62726
|
+
return { kind: "stale", scopes: [...target.scopes] };
|
|
62727
|
+
}
|
|
62728
|
+
const scopes = target.scopes.includes("skills:publish") ? [...target.scopes] : [...target.scopes, "skills:publish"];
|
|
62729
|
+
this.apiKeys.set(hash3, { ...target, scopes });
|
|
62730
|
+
this.operatorEnrollments.set(input.operationId, { keyId: input.keyId, manifestDigest: input.manifestDigest });
|
|
62731
|
+
return { kind: "updated", scopes };
|
|
62732
|
+
}
|
|
62733
|
+
return { kind: "not_found" };
|
|
62734
|
+
}
|
|
62735
|
+
async inspectOperatorScopeTarget(keyId, orgId) {
|
|
62736
|
+
for (const target of this.apiKeys.values()) {
|
|
62737
|
+
if (target.apiKeyId !== keyId)
|
|
62738
|
+
continue;
|
|
62739
|
+
return target.orgId === orgId ? { kind: "found", scopes: [...target.scopes] } : { kind: "target_mismatch" };
|
|
62740
|
+
}
|
|
62741
|
+
return { kind: "not_found" };
|
|
62742
|
+
}
|
|
62622
62743
|
async createRun(input) {
|
|
62623
62744
|
const idemKey = input.idempotencyKey?.trim();
|
|
62624
62745
|
const idemMapKey = idemKey ? `${input.principal.orgId}:${idemKey}` : undefined;
|
|
@@ -63033,24 +63154,98 @@ class PostgresSkillsStore {
|
|
|
63033
63154
|
if (current.length !== expectedScopes.length || current.some((scope2, index) => scope2 !== expectedScopes[index])) {
|
|
63034
63155
|
return { kind: "stale", scopes: current };
|
|
63035
63156
|
}
|
|
63036
|
-
const
|
|
63037
|
-
const updated = await tx`
|
|
63038
|
-
UPDATE api_keys SET scopes_json = ${JSON.stringify(scopes)}::jsonb
|
|
63039
|
-
WHERE id = ${keyId} AND org_id = ${actor.orgId} AND revoked_at IS NULL
|
|
63040
|
-
AND scopes_json = ${JSON.stringify(expectedScopes)}::jsonb
|
|
63041
|
-
RETURNING scopes_json
|
|
63042
|
-
`;
|
|
63157
|
+
const updated = await this.casUpdateApiKeyScopes(tx, keyId, actor.orgId, expectedScopes, addScopes);
|
|
63043
63158
|
if (!updated[0]) {
|
|
63044
63159
|
const latest = await tx`SELECT scopes_json FROM api_keys WHERE id = ${keyId} AND org_id = ${actor.orgId} AND revoked_at IS NULL LIMIT 1`;
|
|
63045
63160
|
return { kind: "stale", scopes: latest[0] ? parseJsonArray(latest[0].scopes_json) : current };
|
|
63046
63161
|
}
|
|
63047
63162
|
await tx`
|
|
63048
63163
|
INSERT INTO skills_audit_events (org_id, user_id, api_key_id, action, target_type, target_id, metadata_json)
|
|
63049
|
-
VALUES (${actor.orgId}, ${actor.userId}, ${actor.apiKeyId}, ${"api_key_scopes_added"}, ${"api_key"}, ${keyId}, ${JSON.stringify({ added: addScopes, scopes })}::jsonb)
|
|
63164
|
+
VALUES (${actor.orgId}, ${actor.userId}, ${actor.apiKeyId}, ${"api_key_scopes_added"}, ${"api_key"}, ${keyId}, ${JSON.stringify({ added: addScopes, scopes: parseJsonArray(updated[0].scopes_json) })}::jsonb)
|
|
63165
|
+
`;
|
|
63166
|
+
return { kind: "updated", scopes: parseJsonArray(updated[0].scopes_json) };
|
|
63167
|
+
});
|
|
63168
|
+
}
|
|
63169
|
+
async casUpdateApiKeyScopes(tx, keyId, orgId, expectedScopes, addScopes) {
|
|
63170
|
+
const current = expectedScopes;
|
|
63171
|
+
const scopes = [...current, ...addScopes.filter((scope2) => !current.includes(scope2))];
|
|
63172
|
+
return tx`
|
|
63173
|
+
UPDATE api_keys SET scopes_json = ${JSON.stringify(scopes)}::jsonb
|
|
63174
|
+
WHERE id = ${keyId} AND org_id = ${orgId} AND revoked_at IS NULL
|
|
63175
|
+
AND scopes_json = ${JSON.stringify(expectedScopes)}::jsonb
|
|
63176
|
+
RETURNING scopes_json
|
|
63177
|
+
`;
|
|
63178
|
+
}
|
|
63179
|
+
async enrollPublishScopeByOperator(input) {
|
|
63180
|
+
if (!validOperatorScopeEnrollmentInput(input))
|
|
63181
|
+
return { kind: "invalid" };
|
|
63182
|
+
if (input.expectedScopes.includes("skills:publish"))
|
|
63183
|
+
return { kind: "stale", scopes: input.expectedScopes };
|
|
63184
|
+
return this.sql.begin(async (tx) => {
|
|
63185
|
+
const operation = await tx`
|
|
63186
|
+
SELECT org_id, target_id FROM skills_audit_events
|
|
63187
|
+
WHERE action = ${"api_key_scopes_added"} AND operator_operation_id = ${input.operationId}
|
|
63188
|
+
LIMIT 1
|
|
63189
|
+
`;
|
|
63190
|
+
if (operation[0] && (String(operation[0].org_id) !== input.orgId || String(operation[0].target_id) !== input.keyId))
|
|
63191
|
+
return { kind: "target_mismatch" };
|
|
63192
|
+
const rows = await tx`
|
|
63193
|
+
SELECT id, org_id, name, scopes_json FROM api_keys
|
|
63194
|
+
WHERE id = ${input.keyId} AND revoked_at IS NULL
|
|
63195
|
+
FOR UPDATE
|
|
63196
|
+
`;
|
|
63197
|
+
const row = rows[0];
|
|
63198
|
+
if (!row)
|
|
63199
|
+
return { kind: "not_found" };
|
|
63200
|
+
if (String(row.org_id) !== input.orgId)
|
|
63201
|
+
return { kind: "target_mismatch" };
|
|
63202
|
+
const current = parseJsonArray(row.scopes_json);
|
|
63203
|
+
const prior = await tx`
|
|
63204
|
+
SELECT metadata_json, metadata_json->>'target_manifest_digest' AS manifest_digest FROM skills_audit_events
|
|
63205
|
+
WHERE action = ${"api_key_scopes_added"} AND target_type = ${"api_key"} AND target_id = ${input.keyId}
|
|
63206
|
+
AND operator_operation_id = ${input.operationId}
|
|
63207
|
+
LIMIT 1
|
|
63208
|
+
`;
|
|
63209
|
+
if (prior[0]) {
|
|
63210
|
+
const priorMetadata = typeof prior[0].metadata_json === "string" ? JSON.parse(prior[0].metadata_json) : prior[0].metadata_json;
|
|
63211
|
+
const priorDigest = prior[0].manifest_digest ?? priorMetadata?.target_manifest_digest;
|
|
63212
|
+
if (String(priorDigest) !== input.manifestDigest)
|
|
63213
|
+
return { kind: "target_mismatch" };
|
|
63214
|
+
if (!current.includes("skills:publish"))
|
|
63215
|
+
return { kind: "stale", scopes: current };
|
|
63216
|
+
return { kind: "already_applied", scopes: current };
|
|
63217
|
+
}
|
|
63218
|
+
if (current.length !== input.expectedScopes.length || current.some((scope2, index) => scope2 !== input.expectedScopes[index])) {
|
|
63219
|
+
return { kind: "stale", scopes: current };
|
|
63220
|
+
}
|
|
63221
|
+
const updated = await this.casUpdateApiKeyScopes(tx, input.keyId, input.orgId, input.expectedScopes, ["skills:publish"]);
|
|
63222
|
+
if (!updated[0])
|
|
63223
|
+
return { kind: "stale", scopes: current };
|
|
63224
|
+
const scopes = parseJsonArray(updated[0].scopes_json);
|
|
63225
|
+
await tx`
|
|
63226
|
+
INSERT INTO skills_audit_events (org_id, user_id, api_key_id, action, target_type, target_id, operator_operation_id, metadata_json)
|
|
63227
|
+
VALUES (${input.orgId}, NULL, NULL, ${"api_key_scopes_added"}, ${"api_key"}, ${input.keyId}, ${input.operationId}, ${JSON.stringify({
|
|
63228
|
+
added: ["skills:publish"],
|
|
63229
|
+
scopes,
|
|
63230
|
+
operator_operation_id: input.operationId,
|
|
63231
|
+
operator_job_id: input.operatorJobId,
|
|
63232
|
+
operator_task_arn: input.operatorTaskArn,
|
|
63233
|
+
target_manifest_digest: input.manifestDigest,
|
|
63234
|
+
station_id: input.stationId
|
|
63235
|
+
})}::jsonb)
|
|
63050
63236
|
`;
|
|
63051
63237
|
return { kind: "updated", scopes };
|
|
63052
63238
|
});
|
|
63053
63239
|
}
|
|
63240
|
+
async inspectOperatorScopeTarget(keyId, orgId) {
|
|
63241
|
+
const rows = await this.sql`SELECT org_id, scopes_json FROM api_keys WHERE id = ${keyId} AND revoked_at IS NULL LIMIT 1`;
|
|
63242
|
+
const row = rows[0];
|
|
63243
|
+
if (!row)
|
|
63244
|
+
return { kind: "not_found" };
|
|
63245
|
+
if (String(row.org_id) !== orgId)
|
|
63246
|
+
return { kind: "target_mismatch" };
|
|
63247
|
+
return { kind: "found", scopes: parseJsonArray(row.scopes_json) };
|
|
63248
|
+
}
|
|
63054
63249
|
async withContext(orgId, worker, fn) {
|
|
63055
63250
|
return this.sql.begin(async (tx) => {
|
|
63056
63251
|
await tx`SELECT set_config('app.skills_org_id', ${orgId ?? ""}, true)`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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, ApiKeyScopeUpdateResult, ServerSkillRecord, SkillLifecyclePatch, SkillsProductStore, StoreBackendInfo, UpdateSkillPatch } from "./types.js";
|
|
18
|
+
import type { ApiPrincipal, ClaimRunInput, CreateRunInput, PublishSkillInput, RunTransitionPatch, ServerArtifact, ServerPin, ServerRunLog, ServerRunRecord, ServerSkillBundle, ServerSkillVersion, ApiKeyScopeUpdateResult, OperatorScopeEnrollmentInput, OperatorScopeEnrollmentResult, OperatorScopeTargetSnapshot, 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;
|
|
@@ -53,6 +53,8 @@ export declare class SqliteSkillsStore implements SkillsProductStore {
|
|
|
53
53
|
ensureBootstrapApiKey(token: string, principal?: Partial<ApiPrincipal>): Promise<void>;
|
|
54
54
|
authenticateApiKeyHash(hash: string): Promise<ApiPrincipal | null>;
|
|
55
55
|
updateApiKeyScopes(actor: ApiPrincipal, keyId: string, expectedScopes: string[], addScopes: string[]): Promise<ApiKeyScopeUpdateResult>;
|
|
56
|
+
enrollPublishScopeByOperator(input: OperatorScopeEnrollmentInput): Promise<OperatorScopeEnrollmentResult>;
|
|
57
|
+
inspectOperatorScopeTarget(keyId: string, orgId: string): Promise<OperatorScopeTargetSnapshot>;
|
|
56
58
|
createRun(input: CreateRunInput): Promise<ServerRunRecord>;
|
|
57
59
|
listRuns(principal: ApiPrincipal, limit: number): Promise<ServerRunRecord[]>;
|
|
58
60
|
getRun(principal: ApiPrincipal, id: string): Promise<ServerRunRecord | null>;
|
package/dist/server/store.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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, ApiKeyScopeUpdateResult, SkillsProductStore, StoreBackendInfo, UpdateSkillPatch } from "./types.js";
|
|
3
|
+
import type { ApiPrincipal, ClaimRunInput, CreateRunInput, PublishSkillInput, RunTransitionPatch, ServerArtifact, ServerPin, ServerRunLog, ServerRunRecord, ServerSkillBundle, ServerSkillRecord, ServerSkillVersion, ApiKeyScopeUpdateResult, OperatorScopeEnrollmentInput, OperatorScopeEnrollmentResult, OperatorScopeTargetSnapshot, SkillsProductStore, StoreBackendInfo, UpdateSkillPatch } from "./types.js";
|
|
4
4
|
import { type SkillLifecyclePatch } from "./types.js";
|
|
5
5
|
import { type SqliteStoreOptions } from "./sqlite-store.js";
|
|
6
6
|
export declare function createArtifactId(): string;
|
|
@@ -38,6 +38,7 @@ export declare class MemorySkillsStore implements SkillsProductStore {
|
|
|
38
38
|
private bundles;
|
|
39
39
|
private versions;
|
|
40
40
|
private pins;
|
|
41
|
+
private operatorEnrollments;
|
|
41
42
|
constructor(apiKeys?: Array<{
|
|
42
43
|
token: string;
|
|
43
44
|
principal?: Partial<ApiPrincipal>;
|
|
@@ -46,6 +47,8 @@ export declare class MemorySkillsStore implements SkillsProductStore {
|
|
|
46
47
|
ensureBootstrapApiKey(token: string, principal?: Partial<ApiPrincipal>): Promise<void>;
|
|
47
48
|
authenticateApiKeyHash(hash: string): Promise<ApiPrincipal | null>;
|
|
48
49
|
updateApiKeyScopes(actor: ApiPrincipal, keyId: string, expectedScopes: string[], addScopes: string[]): Promise<ApiKeyScopeUpdateResult>;
|
|
50
|
+
enrollPublishScopeByOperator(input: OperatorScopeEnrollmentInput): Promise<OperatorScopeEnrollmentResult>;
|
|
51
|
+
inspectOperatorScopeTarget(keyId: string, orgId: string): Promise<OperatorScopeTargetSnapshot>;
|
|
49
52
|
createRun(input: CreateRunInput): Promise<ServerRunRecord>;
|
|
50
53
|
listRuns(principal: ApiPrincipal, limit: number): Promise<ServerRunRecord[]>;
|
|
51
54
|
getRun(principal: ApiPrincipal, runId: string): Promise<ServerRunRecord | null>;
|
|
@@ -122,6 +125,9 @@ export declare class PostgresSkillsStore implements SkillsProductStore {
|
|
|
122
125
|
ensureBootstrapApiKey(token: string, principal?: Partial<ApiPrincipal>): Promise<void>;
|
|
123
126
|
authenticateApiKeyHash(hash: string): Promise<ApiPrincipal | null>;
|
|
124
127
|
updateApiKeyScopes(actor: ApiPrincipal, keyId: string, expectedScopes: string[], addScopes: string[]): Promise<ApiKeyScopeUpdateResult>;
|
|
128
|
+
private casUpdateApiKeyScopes;
|
|
129
|
+
enrollPublishScopeByOperator(input: OperatorScopeEnrollmentInput): Promise<OperatorScopeEnrollmentResult>;
|
|
130
|
+
inspectOperatorScopeTarget(keyId: string, orgId: string): Promise<OperatorScopeTargetSnapshot>;
|
|
125
131
|
/**
|
|
126
132
|
* Run a callback under an RLS tenant or worker context, on one pooled
|
|
127
133
|
* connection, for the duration of one transaction only.
|