@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 +106 -0
- package/README.md +62 -2
- package/dist/budget.d.ts +22 -0
- package/dist/budget.js +83 -0
- package/dist/dispatch.d.ts +73 -0
- package/dist/dispatch.js +699 -0
- package/dist/events.d.ts +200 -0
- package/dist/events.js +210 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/receive.d.ts +27 -0
- package/dist/receive.js +193 -0
- package/dist/registration.d.ts +95 -0
- package/dist/registration.js +102 -0
- package/dist/site-rules.d.ts +58 -0
- package/dist/site-rules.js +296 -0
- package/package.json +32 -4
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
|
-
#
|
|
1
|
+
# @sema-agent/mods-kernel
|
|
2
2
|
|
|
3
|
-
|
|
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.
|
package/dist/budget.d.ts
ADDED
|
@@ -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>;
|