@sema-agent/mods-kernel 0.0.0-stage → 7.54.1

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/LICENSE ADDED
@@ -0,0 +1,106 @@
1
+ Business Source License 1.1
2
+
3
+ Parameters
4
+
5
+ Licensor: clay (github.com/clayboby)
6
+ Licensed Work: @sema-agent/core (sema-core) and the satellite packages
7
+ published from this repository (currently
8
+ @sema-agent/mods-kernel)
9
+ (formerly published as @sema-ai/core)
10
+ The Licensed Work is (c) 2026 clay.
11
+ Additional Use Grant: You may make production use of the Licensed Work for
12
+ personal, educational, research, or other
13
+ non-commercial purposes. Commercial production use
14
+ requires a commercial license from the Licensor.
15
+ Change Date: 2030-07-13
16
+ Change License: Apache License, Version 2.0
17
+
18
+ For information about alternative licensing arrangements for the Licensed
19
+ Work, please contact the Licensor.
20
+
21
+ Notice
22
+
23
+ The Business Source License (this document, or the "License") is not an Open
24
+ Source license. However, the Licensed Work will eventually be made available
25
+ under an Open Source License, as stated in this License.
26
+
27
+ License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
28
+ "Business Source License" is a trademark of MariaDB Corporation Ab.
29
+
30
+ -----------------------------------------------------------------------------
31
+
32
+ Terms
33
+
34
+ The Licensor hereby grants you the right to copy, modify, create derivative
35
+ works, redistribute, and make non-production use of the Licensed Work. The
36
+ Licensor may make an Additional Use Grant, above, permitting limited
37
+ production use.
38
+
39
+ Effective on the Change Date, or the fourth anniversary of the first publicly
40
+ available distribution of a specific version of the Licensed Work under this
41
+ License, whichever comes first, the Licensor hereby grants you rights under
42
+ the terms of the Change License, and the rights granted in the paragraph
43
+ above terminate.
44
+
45
+ If your use of the Licensed Work does not comply with the requirements
46
+ currently in effect as described in this License, you must purchase a
47
+ commercial license from the Licensor, its affiliated entities, or authorized
48
+ resellers, or you must refrain from using the Licensed Work.
49
+
50
+ All copies of the original and modified Licensed Work, and derivative works
51
+ of the Licensed Work, are subject to this License. This License applies
52
+ separately for each version of the Licensed Work and the Change Date may vary
53
+ for each version of the Licensed Work released by Licensor.
54
+
55
+ You must conspicuously display this License on each original or modified copy
56
+ of the Licensed Work. If you receive the Licensed Work in original or
57
+ modified form from a third party, the terms and conditions set forth in this
58
+ License apply to your use of that work.
59
+
60
+ Any use of the Licensed Work in violation of this License will automatically
61
+ terminate your rights under this License for the current and all other
62
+ versions of the Licensed Work.
63
+
64
+ This License does not grant you any right in any trademark or logo of
65
+ Licensor or its affiliates (provided that you may use a trademark or logo of
66
+ Licensor as expressly required by this License).
67
+
68
+ TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
69
+ AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
70
+ EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
71
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
72
+ TITLE.
73
+
74
+ MariaDB hereby grants you permission to use this License's text to license
75
+ your works, and to refer to it using the trademark "Business Source License",
76
+ as long as you comply with the Covenants of Licensor below.
77
+
78
+ Covenants of Licensor
79
+
80
+ In consideration of the right to use this License's text and the "Business
81
+ Source License" name and trademark, Licensor covenants to MariaDB, and to all
82
+ other recipients of the licensed work to be provided by Licensor:
83
+
84
+ 1. To specify as the Change License the GPL Version 2.0 or any later version,
85
+ or a license that is compatible with GPL Version 2.0 or a later version,
86
+ where "compatible" means that software provided under the Change License can
87
+ be included in a program with software provided under GPL Version 2.0 or a
88
+ later version. Licensor may specify additional Change Licenses without
89
+ limitation.
90
+
91
+ 2. To either: (a) specify an additional grant of rights to use that does not
92
+ impose any additional restriction on the right granted in this License, as
93
+ the Additional Use Grant; or (b) insert the text "None".
94
+
95
+ 3. To specify a Change Date.
96
+
97
+ 4. Not to modify this License in any other way.
98
+
99
+ -----------------------------------------------------------------------------
100
+
101
+ Third-party notices
102
+
103
+ Versions of this package up to and including 1.277.1 were published under the
104
+ MIT License; those published copies remain governed by the license they were
105
+ distributed under. This package incorporates design and (where noted) prompt
106
+ content adapted from MIT-licensed projects — see NOTICE.md for attributions.
package/README.md CHANGED
@@ -1,3 +1,63 @@
1
- # Temporary Holding Version
1
+ # @sema-agent/mods-kernel
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The mods kernel of the sema engine: one extension bus — registration and its two seats, tiers, admission
4
+ through `plugin.register`, the `($, e, next)` chain with `next.to`, re-entry frames, site rules, the
5
+ failure / abort columns, `.catch` and the self budget. It is compiled from the same source the engine
6
+ embeds, so a shell or a client can run the same rules on its own bus. Zero dependencies; runs in Node and in
7
+ browsers; ships its own types.
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ npm install @sema-agent/mods-kernel
13
+ ```
14
+
15
+ ES modules only (`"type": "module"`), Node >= 20.18.1 where Node is used. One entry, `.`; there are no deep paths.
16
+
17
+ ## Version
18
+
19
+ `@sema-agent/mods-kernel@X.Y.Z` is cut with `@sema-agent/core@X.Y.Z`: the same version number, built from the same
20
+ commit. A package version moves with every core release whether or not the kernel changed; it says which core it was
21
+ cut with, not whether the contract moved.
22
+
23
+ ## Two copies: `KERNEL_CONTRACT_VERSION`
24
+
25
+ Two copies of the kernel interoperate on plain objects (no `instanceof`, no module identity). A host that loads
26
+ one copy beside another compares `KERNEL_CONTRACT_VERSION` for equality. Nothing in the kernel or the engine reads it,
27
+ so two copies that differ are told apart only by a host that compares them. The number is an integer independent of the
28
+ package version; it moves only when the chain semantics, the registration form, the event closed set (names and
29
+ `side`) or the failure columns (failure, abort, pinned keys — which keys, and how a pinned key is judged) change.
30
+
31
+ ## Which side raises an event
32
+
33
+ Every name in `MOD_EVENT_TABLE` carries a `side` — `engine`, `surface` or `both`, the closed set `MOD_EVENT_SIDES` — and
34
+ that is the one place the answer lives: `readOnSide(name, side)` and `stationOn(name, side)` read the same row.
35
+
36
+ ```js
37
+ import { KERNEL_CONTRACT_VERSION, MOD_EVENT_SIDES, MOD_EVENT_TABLE, readOnSide } from "@sema-agent/mods-kernel";
38
+
39
+ console.log(KERNEL_CONTRACT_VERSION); // an integer
40
+ console.log(MOD_EVENT_SIDES); // [ 'engine', 'surface', 'both' ]
41
+ console.log(MOD_EVENT_TABLE["tool.check"].side); // engine
42
+ console.log(MOD_EVENT_TABLE["ui.render"].side); // surface
43
+ console.log(readOnSide("plugin.register", "surface")); // true: its side is both
44
+ ```
45
+
46
+ ## Exports
47
+
48
+ Each name below is a runtime value or a type exported from the package root. The root's declarations are the
49
+ contract; a removed or re-kinded export is named as breaking in the `@sema-agent/core` release notes.
50
+
51
+ | Group | Names |
52
+ | --- | --- |
53
+ | Contract and closed sets | `KERNEL_CONTRACT_VERSION` `MOD_TIERS` `MOD_SEATS` `MOD_EVENT_SIDES` `MOD_FAILURE_ANSWERS` `MOD_ABORT_POSTURES` `NEXT_TO_TABLE` `SEAT_TIER_TABLE` |
54
+ | Event table and readers | `MOD_EVENT_TABLE` `isModEventName` `expandModPattern` `stationOn` `readOnSide` `nextToRefusal` |
55
+ | Event table types | `ModTier` `ModRegistrationTier` `ModSeat` `ModEventSide` `ModBusSide` `ModFailureAnswer` `ModAbortPosture` `ModStation` `ModEventRow` `ModEventName` |
56
+ | Budgets | `DEFAULT_MOD_BUDGET_MS` `CATCH_BUDGET_MS` `RUNAWAY_AFTER_MS` `POST_ABORT_GRACE_MS` `MAX_TIMER_MS` `resolveModBudgetMs` `ModBudgetReading` |
57
+ | Failure causes and site rules | `MOD_FAILURE_CAUSES` `ModFailureCause` `ModEventPayload` `ModAnswerCheck` `ModAnswerer` `ModMatcher` `ModSkip` |
58
+ | Registration | `ENGINE_ORIGIN` `MODS_INVALID_CODE` `MODS_REGISTRATION_REFUSED_CODE` `MOD_TRACE_OUTCOMES` `ModTraceOutcome` `ModUses` `ModOrigin` `ModPluginFacts` `ModDollarBase` `ModTraceEntry` `ModCaughtError` `ModNext` `ModHandler` `ModHandlerOptions` `On` `ModRegistration` `ModAdmissionRecord` `ModSeats` |
59
+ | Admission and the bus | `admitMods` `ModFrame` `ModBottomContext` `ModMethodBottom` `ModMethodSeat` `ModMethodBottoms` `ModDispatchOutcome` `ModDispatchOptions` `ModBus` `ModMountedHandler` `ModBusInput` |
60
+
61
+ ## License
62
+
63
+ Business Source License 1.1, the same terms as `@sema-agent/core`; the licence text is the `LICENSE` file in this package.
@@ -0,0 +1,22 @@
1
+ export declare const DEFAULT_MOD_BUDGET_MS = 10000;
2
+ export declare const CATCH_BUDGET_MS = 1000;
3
+ export declare const RUNAWAY_AFTER_MS = 5000;
4
+ export declare const POST_ABORT_GRACE_MS = 1000;
5
+ export declare const MAX_TIMER_MS = 2147483647;
6
+ export interface ModBudgetReading {
7
+ readonly ms: number;
8
+ readonly remainingMs: number;
9
+ }
10
+ export declare function resolveModBudgetMs(supplied: unknown, report: (err: Error) => void, name: string): number;
11
+ export interface SelfBudget {
12
+ readonly expired: Promise<"expired">;
13
+ isExpired(): boolean;
14
+ pause(): void;
15
+ resume(): void;
16
+ clear(): void;
17
+ usedMs(): number;
18
+ reading(): ModBudgetReading;
19
+ }
20
+ export declare function createSelfBudget(ms: number, onExpire: () => void): SelfBudget;
21
+ export declare function watchRunaway(settled: Promise<unknown>, onRunaway: () => void): void;
22
+ export declare function unrefTimer(timer: unknown): void;
package/dist/budget.js ADDED
@@ -0,0 +1,83 @@
1
+ export const DEFAULT_MOD_BUDGET_MS = 10_000;
2
+ export const CATCH_BUDGET_MS = 1_000;
3
+ export const RUNAWAY_AFTER_MS = 5_000;
4
+ export const POST_ABORT_GRACE_MS = 1_000;
5
+ export const MAX_TIMER_MS = 2_147_483_647;
6
+ export function resolveModBudgetMs(supplied, report, name) {
7
+ if (supplied === undefined)
8
+ return DEFAULT_MOD_BUDGET_MS;
9
+ if (typeof supplied === "number" && Number.isFinite(supplied) && supplied >= 0 && supplied <= MAX_TIMER_MS)
10
+ return supplied;
11
+ const got = typeof supplied === "number" ? String(supplied) : typeof supplied;
12
+ report(new Error(`${name}: budgetMs must be a non-negative finite number no greater than ${MAX_TIMER_MS} (got ${got}) — ` +
13
+ `every handler of this registration falls back to the ${DEFAULT_MOD_BUDGET_MS}ms default`));
14
+ return DEFAULT_MOD_BUDGET_MS;
15
+ }
16
+ export function createSelfBudget(ms, onExpire) {
17
+ let remaining = ms;
18
+ let runningSince;
19
+ let timer;
20
+ let pauses = 0;
21
+ let done = false;
22
+ let expired = false;
23
+ let fire = () => { };
24
+ const expiredP = new Promise((res) => (fire = res));
25
+ const left = () => (runningSince === undefined ? remaining : Math.max(0, remaining - (Date.now() - runningSince)));
26
+ const arm = () => {
27
+ runningSince = Date.now();
28
+ timer = setTimeout(() => {
29
+ if (done)
30
+ return;
31
+ expired = true;
32
+ done = true;
33
+ remaining = 0;
34
+ runningSince = undefined;
35
+ fire("expired");
36
+ onExpire();
37
+ }, remaining);
38
+ };
39
+ arm();
40
+ return {
41
+ expired: expiredP,
42
+ isExpired: () => expired,
43
+ pause() {
44
+ if (pauses++ !== 0 || done)
45
+ return;
46
+ clearTimeout(timer);
47
+ remaining = left();
48
+ runningSince = undefined;
49
+ },
50
+ resume() {
51
+ if (pauses === 0)
52
+ return;
53
+ if (--pauses !== 0 || done)
54
+ return;
55
+ arm();
56
+ },
57
+ clear() {
58
+ if (done)
59
+ return;
60
+ remaining = left();
61
+ runningSince = undefined;
62
+ done = true;
63
+ clearTimeout(timer);
64
+ },
65
+ usedMs: () => ms - left(),
66
+ reading: () => Object.freeze({ ms, remainingMs: left() }),
67
+ };
68
+ }
69
+ export function watchRunaway(settled, onRunaway) {
70
+ let over = false;
71
+ const mark = () => {
72
+ over = true;
73
+ };
74
+ settled.then(mark, mark);
75
+ unrefTimer(setTimeout(() => {
76
+ if (!over)
77
+ onRunaway();
78
+ }, RUNAWAY_AFTER_MS));
79
+ }
80
+ export function unrefTimer(timer) {
81
+ if (typeof timer === "object" && timer !== null && "unref" in timer && typeof timer.unref === "function")
82
+ timer.unref();
83
+ }
@@ -0,0 +1,73 @@
1
+ import { type ModBusSide, type ModEventName, type ModSeat } from "./events.js";
2
+ import { type ModAdmissionRecord, type ModDollarBase, type ModOrigin, type ModSeats } from "./registration.js";
3
+ import { type ModAnswerCheck, type ModEventPayload, type ModFailureCause, type ModMatcher, type ModSkip, type ProxyProbe } from "./site-rules.js";
4
+ export type ModFrame = {
5
+ readonly kind: "dollar";
6
+ readonly plugin: string;
7
+ } | {
8
+ readonly kind: "handler";
9
+ readonly plugin: string;
10
+ readonly handler: number;
11
+ };
12
+ export interface ModBottomContext {
13
+ readonly frames: readonly ModFrame[];
14
+ readonly signal: AbortSignal;
15
+ readonly origin: ModOrigin;
16
+ }
17
+ export type ModMethodBottom = (args: ModEventPayload, ctx: ModBottomContext) => unknown;
18
+ export interface ModMethodSeat {
19
+ readonly run: ModMethodBottom;
20
+ readonly enter?: (args: ModEventPayload) => ModEventPayload;
21
+ }
22
+ export type ModMethodBottoms = Partial<Record<ModEventName, ModMethodSeat>>;
23
+ export type ModDispatchOutcome = {
24
+ readonly kind: "answered";
25
+ readonly answer: unknown;
26
+ readonly answeredBy?: string;
27
+ readonly skipped: readonly ModSkip[];
28
+ } | {
29
+ readonly kind: "failed";
30
+ readonly registration: string;
31
+ readonly cause: ModFailureCause;
32
+ readonly reason: string;
33
+ readonly skipped: readonly ModSkip[];
34
+ } | {
35
+ readonly kind: "aborted";
36
+ };
37
+ export interface ModParticipant {
38
+ readonly plugin: string;
39
+ readonly seat: ModSeat;
40
+ readonly observe: boolean;
41
+ }
42
+ export interface ModDispatchOptions {
43
+ readonly bottom: (e: ModEventPayload, ctx: ModBottomContext) => unknown;
44
+ readonly signal?: AbortSignal;
45
+ readonly frames?: readonly ModFrame[];
46
+ readonly origin?: ModOrigin;
47
+ readonly checkAnswer?: ModAnswerCheck;
48
+ readonly participant?: (p: ModParticipant) => boolean;
49
+ }
50
+ export interface ModMountedHandler {
51
+ readonly plugin: string;
52
+ readonly seat: ModSeat;
53
+ readonly pattern: string;
54
+ readonly matcher?: ModMatcher;
55
+ readonly observe: boolean;
56
+ readonly caught: boolean;
57
+ }
58
+ export interface ModBus {
59
+ readonly records: readonly ModAdmissionRecord[];
60
+ mounted(): readonly ModMountedHandler[];
61
+ hasHandlers(event: ModEventName, participant?: (p: ModParticipant) => boolean): boolean;
62
+ dispatch(event: ModEventName, e: ModEventPayload, options: ModDispatchOptions): Promise<ModDispatchOutcome>;
63
+ }
64
+ export interface ModBusInput<D extends ModDollarBase = ModDollarBase> {
65
+ readonly side: ModBusSide;
66
+ readonly seats: ModSeats<D>;
67
+ readonly bottoms: ModMethodBottoms;
68
+ readonly report: (err: Error, classification?: "observational-hook-verdict-ignored") => void;
69
+ readonly describeThrown: (err: unknown) => string;
70
+ readonly isProxy?: ProxyProbe;
71
+ readonly signal?: AbortSignal;
72
+ }
73
+ export declare function admitMods<D extends ModDollarBase = ModDollarBase>(input: ModBusInput<D>): Promise<ModBus>;