@hasna/skills 0.5.7 → 0.5.9
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 +47 -1
- package/bin/index.js +315 -314
- package/bin/mcp.js +188 -186
- package/bin/migrate.js +4 -2
- package/bin/server.js +144 -123
- package/bin/worker.js +123 -121
- package/dist/admin-contract.js +8 -8
- package/dist/index.js +18 -16
- package/dist/lib/private-publication-recovery.d.ts +2 -1
- package/dist/lib/remote-private-publications.d.ts +2 -1
- package/dist/sdk/amounts.d.ts +5 -0
- package/dist/sdk/governance-store.d.ts +2 -0
- package/dist/sdk/index.d.ts +1 -0
- package/dist/sdk/index.js +404 -167
- package/dist/sdk/operations.d.ts +68 -0
- package/dist/sdk/runs.d.ts +1 -1
- package/dist/sdk/spend.d.ts +5 -2
- package/package.json +4 -2
- package/dist/cli/cli.test-utils.d.ts +0 -43
- package/dist/server/store-fixtures.d.ts +0 -31
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/** Provider-neutral guest operation client. Authority and IPC belong to the embedder.
|
|
2
|
+
* No credentials, endpoint discovery, provider SDK, or automatic retry is provided.
|
|
3
|
+
*/
|
|
4
|
+
export type SkillOperationJson = null | boolean | number | string | readonly SkillOperationJson[] | {
|
|
5
|
+
readonly [key: string]: SkillOperationJson;
|
|
6
|
+
};
|
|
7
|
+
export declare const SKILL_OPERATION_LIMITS: Readonly<{
|
|
8
|
+
requestBytes: 65536;
|
|
9
|
+
resultBytes: 1048576;
|
|
10
|
+
depth: 32;
|
|
11
|
+
nodes: 16384;
|
|
12
|
+
rememberedRequests: 256;
|
|
13
|
+
rememberedBytes: 1048576;
|
|
14
|
+
}>;
|
|
15
|
+
export type SkillOperationRefusal = "NOT_ALLOWED" | "APPROVAL_REQUIRED" | "BUDGET_EXHAUSTED" | "EXPIRED" | "CANCELLED" | "UNAVAILABLE" | "INVALID_INPUT";
|
|
16
|
+
export interface SkillOperationRequest {
|
|
17
|
+
readonly contractVersion: 1;
|
|
18
|
+
readonly requestId: string;
|
|
19
|
+
readonly operation: string;
|
|
20
|
+
readonly input: {
|
|
21
|
+
readonly [key: string]: SkillOperationJson;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
interface OperationIdentity {
|
|
25
|
+
readonly contractVersion: 1;
|
|
26
|
+
readonly requestId: string;
|
|
27
|
+
}
|
|
28
|
+
export type SkillOperationResult = OperationIdentity & ({
|
|
29
|
+
readonly status: "not-executed" | "pending" | "unknown";
|
|
30
|
+
} | {
|
|
31
|
+
readonly status: "succeeded";
|
|
32
|
+
readonly output: SkillOperationJson;
|
|
33
|
+
} | {
|
|
34
|
+
readonly status: "refused";
|
|
35
|
+
readonly code: SkillOperationRefusal;
|
|
36
|
+
});
|
|
37
|
+
/** Implementations must authenticate the captured run/attempt separately. A
|
|
38
|
+
* not-executed response is authoritative proof, never a guess from transport loss. */
|
|
39
|
+
export interface SkillOperationTransport {
|
|
40
|
+
invoke(request: SkillOperationRequest, options: {
|
|
41
|
+
signal: AbortSignal;
|
|
42
|
+
}): Promise<unknown>;
|
|
43
|
+
get(requestId: string, options: {
|
|
44
|
+
signal: AbortSignal;
|
|
45
|
+
}): Promise<unknown>;
|
|
46
|
+
}
|
|
47
|
+
export type SkillOperationClientErrorCode = "INVALID_REQUEST" | "REQUEST_CONFLICT" | "REQUEST_CAPACITY" | "ABORTED" | "UNKNOWN_OUTCOME" | "INVALID_RESPONSE" | "INVALID_CONFIGURATION";
|
|
48
|
+
export declare class SkillOperationClientError extends Error {
|
|
49
|
+
readonly code: SkillOperationClientErrorCode;
|
|
50
|
+
readonly outcome: "not-invoked" | "unknown";
|
|
51
|
+
constructor(code: SkillOperationClientErrorCode, outcome: "not-invoked" | "unknown");
|
|
52
|
+
}
|
|
53
|
+
export interface SkillOperationClient {
|
|
54
|
+
invoke(request: SkillOperationRequest, options?: {
|
|
55
|
+
signal?: AbortSignal;
|
|
56
|
+
}): Promise<SkillOperationResult>;
|
|
57
|
+
get(requestId: string, options?: {
|
|
58
|
+
signal?: AbortSignal;
|
|
59
|
+
}): Promise<SkillOperationResult>;
|
|
60
|
+
}
|
|
61
|
+
/** One client belongs to one captured authority scope. Remembered identities
|
|
62
|
+
* are bounded and never evicted. This is local misuse protection, not durable
|
|
63
|
+
* deduplication: the server must bind request IDs and payloads atomically.
|
|
64
|
+
* Each explicit call invokes transport once; uncertainty requires explicit get. */
|
|
65
|
+
export declare function createSkillOperationClient(transport: SkillOperationTransport, options?: {
|
|
66
|
+
timeoutMs?: number;
|
|
67
|
+
}): SkillOperationClient;
|
|
68
|
+
export {};
|
package/dist/sdk/runs.d.ts
CHANGED
|
@@ -211,7 +211,7 @@ export interface RunServiceGovernance {
|
|
|
211
211
|
events?: RunEventEmitter;
|
|
212
212
|
/** Resource envelope this run requests, checked against the org ceilings. */
|
|
213
213
|
quota?: RunQuota;
|
|
214
|
-
/** Estimated
|
|
214
|
+
/** Estimated integer cents (0..2147483647), reserved before dispatch. */
|
|
215
215
|
estimatedCents?: number;
|
|
216
216
|
}
|
|
217
217
|
/** Current implementation: the store's own atomic transitions, plus the optional admission chain. */
|
package/dist/sdk/spend.d.ts
CHANGED
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
* actual cost is charged (status "charged") or, when nothing was used, the
|
|
10
10
|
* reservation is released ("released") - the unused half never lingers.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* Each reservation or charge uses integer cents from 0 through 2147483647,
|
|
13
|
+
* matching the supported PostgreSQL and SQLite schema. Monthly ceilings and
|
|
14
|
+
* aggregates may exceed that per-row limit but must remain JavaScript-safe
|
|
15
|
+
* nonnegative integers. Invalid amounts throw RangeError before store access.
|
|
14
16
|
*/
|
|
15
17
|
import type { ApiPrincipal } from "../server/types.js";
|
|
16
18
|
import { type RunQuota, type SpendCeilings } from "./governance.js";
|
|
@@ -19,6 +21,7 @@ export interface SpendAdmissionInput {
|
|
|
19
21
|
principal: ApiPrincipal;
|
|
20
22
|
slug: string;
|
|
21
23
|
quota?: RunQuota;
|
|
24
|
+
/** Integer cents from 0 through 2147483647; omission estimates zero. */
|
|
22
25
|
estimatedCents?: number;
|
|
23
26
|
now?: Date;
|
|
24
27
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/skills",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.9",
|
|
4
4
|
"description": "Skills library for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -40,7 +40,9 @@
|
|
|
40
40
|
"docs/skill-standard.md",
|
|
41
41
|
"schemas/",
|
|
42
42
|
"LICENSE",
|
|
43
|
-
"README.md"
|
|
43
|
+
"README.md",
|
|
44
|
+
"!dist/**/*test-utils.d.ts",
|
|
45
|
+
"!dist/**/*fixtures.d.ts"
|
|
44
46
|
],
|
|
45
47
|
"main": "./dist/index.js",
|
|
46
48
|
"types": "./dist/index.d.ts",
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export declare const CLI_PATH: string;
|
|
2
|
-
export declare const EXPECTED_ALL_SKILL_COUNT: number;
|
|
3
|
-
export declare const EXPECTED_BASIC_SKILL_COUNT: 8;
|
|
4
|
-
export declare const EXPECTED_POPULATED_CATEGORY_COUNT: number;
|
|
5
|
-
export declare const PACKAGE_VERSION: string;
|
|
6
|
-
/**
|
|
7
|
-
* Retained for the ~36 call sites that already pass it. NEW TESTS DO NOT NEED IT:
|
|
8
|
-
* every test file calls useDefaultTestTimeout(), so a subprocess test written
|
|
9
|
-
* with no timeout argument is already covered — which is the point, because
|
|
10
|
-
* remembering to annotate the next one is exactly what did not happen.
|
|
11
|
-
*
|
|
12
|
-
* Aliased rather than left at its old 15000 so this constant can never sit BELOW
|
|
13
|
-
* the suite default and quietly give the slowest tests in the suite the tightest
|
|
14
|
-
* ceiling in it.
|
|
15
|
-
*/
|
|
16
|
-
export declare const SLOW_TEST_TIMEOUT = 30000;
|
|
17
|
-
export declare const CLEAN_CLI_HOME: string;
|
|
18
|
-
/**
|
|
19
|
-
* The one line an opted-in local install is allowed to print on stderr.
|
|
20
|
-
*
|
|
21
|
-
* Local mode is opt-in only and announces itself (owner ruling 2026-09-04,
|
|
22
|
-
* hasna/apps#1720; class-patch order 2026-09-06): with the explicit
|
|
23
|
-
* `HASNA_SKILLS_LOCAL=1` opt-in and no API credential or URL, the CLI says
|
|
24
|
-
* once, per process, that it is running on this machine. The harness below
|
|
25
|
-
* passes the opt-in itself, so the suite's local runs are deliberate ones —
|
|
26
|
-
* and "stderr is empty" remains the wrong assertion for a local command. Use
|
|
27
|
-
* {@link stderrWithoutLocalNotice}, which strips exactly this line and nothing
|
|
28
|
-
* else, so an unexpected warning still fails the test it would have failed
|
|
29
|
-
* before.
|
|
30
|
-
*/
|
|
31
|
-
export declare const LOCAL_MODE_NOTICE_MARKER = "skills: local mode";
|
|
32
|
-
/** `stderr` with the single local-mode notice line removed. */
|
|
33
|
-
export declare function stderrWithoutLocalNotice(stderr: string): string;
|
|
34
|
-
export declare function runCli(args: string[], env?: Record<string, string>): Promise<{
|
|
35
|
-
stdout: string;
|
|
36
|
-
stderr: string;
|
|
37
|
-
exitCode: number;
|
|
38
|
-
}>;
|
|
39
|
-
export declare function runCliInCwd(args: string[], cwd: string, env?: Record<string, string>): Promise<{
|
|
40
|
-
stdout: string;
|
|
41
|
-
stderr: string;
|
|
42
|
-
exitCode: number;
|
|
43
|
-
}>;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { type GovernanceStore } from "../sdk/governance-store.js";
|
|
2
|
-
import type { ApiPrincipal, SkillsProductStore } from "./types.js";
|
|
3
|
-
export declare const TEST_DATABASE_URL_ENV = "HASNA_SKILLS_TEST_DATABASE_URL";
|
|
4
|
-
export interface SeedApiKey {
|
|
5
|
-
token: string;
|
|
6
|
-
principal: Partial<ApiPrincipal>;
|
|
7
|
-
}
|
|
8
|
-
export interface StoreFixture {
|
|
9
|
-
store: SkillsProductStore;
|
|
10
|
-
/**
|
|
11
|
-
* Governance store over the same database as `store`, for surfaces that need
|
|
12
|
-
* the append-only lifecycle ledger and ceiling reads (cancellation).
|
|
13
|
-
*/
|
|
14
|
-
governanceStore: GovernanceStore;
|
|
15
|
-
/** True when the server must be told it is allowed to run on this store. */
|
|
16
|
-
allowEphemeralStore: boolean;
|
|
17
|
-
close(): Promise<void>;
|
|
18
|
-
}
|
|
19
|
-
export interface StoreBackendFixture {
|
|
20
|
-
name: string;
|
|
21
|
-
create(seed?: SeedApiKey[]): Promise<StoreFixture>;
|
|
22
|
-
}
|
|
23
|
-
/** Human-readable reasons a backend is absent from the current run. */
|
|
24
|
-
export declare function storeBackendNotices(): string[];
|
|
25
|
-
/**
|
|
26
|
-
* Every backend testable in this environment.
|
|
27
|
-
*
|
|
28
|
-
* Async because Postgres availability can only be established by connecting; a
|
|
29
|
-
* top-level await in the test file keeps that out of the describe bodies.
|
|
30
|
-
*/
|
|
31
|
-
export declare function resolveStoreBackends(): Promise<StoreBackendFixture[]>;
|