@shardworks/nexus-arbor 0.1.101
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 +15 -0
- package/README.md +115 -0
- package/dist/arbor.d.ts +31 -0
- package/dist/arbor.d.ts.map +1 -0
- package/dist/arbor.js +143 -0
- package/dist/arbor.js.map +1 -0
- package/dist/guild-lifecycle.d.ts +47 -0
- package/dist/guild-lifecycle.d.ts.map +1 -0
- package/dist/guild-lifecycle.js +164 -0
- package/dist/guild-lifecycle.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sean Boots
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# `@shardworks/nexus-arbor`
|
|
2
|
+
|
|
3
|
+
The guild runtime host for Nexus Mk 2.1. The arbor reads `guild.json`, loads all declared plugins, validates the dependency graph, starts each apparatus in dependency order, and wires the `guild()` singleton. It is the bootstrap layer — every entry point (the CLI, the MCP server, the Clockworks daemon) calls `createGuild()` once at startup.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
@shardworks/nexus-core — public SDK, types, guild() singleton
|
|
7
|
+
@shardworks/nexus-arbor — guild host, createGuild(), Guild object
|
|
8
|
+
@shardworks/nexus (cli) — nsg binary, framework commands + Instrumentarium tools
|
|
9
|
+
plugins — import from nexus-core only
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Plugin authors import from `@shardworks/nexus-core`. The arbor is an internal concern of the CLI and session provider — plugins never depend on it directly.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@shardworks/nexus-arbor": "workspace:*"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## API
|
|
29
|
+
|
|
30
|
+
### `createGuild(root?)`
|
|
31
|
+
|
|
32
|
+
The single entry point. Creates and starts a guild, returning the `Guild` object.
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { createGuild } from '@shardworks/nexus-arbor';
|
|
36
|
+
|
|
37
|
+
const guild = await createGuild('/path/to/guild');
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
If `root` is omitted, auto-detects by walking up from cwd until `guild.json` is found.
|
|
41
|
+
|
|
42
|
+
`createGuild()` also sets the `guild()` singleton from `@shardworks/nexus-core`, so apparatus code can call `guild()` immediately after startup.
|
|
43
|
+
|
|
44
|
+
### `Guild`
|
|
45
|
+
|
|
46
|
+
The object returned by `createGuild()` — also accessible via `guild()` from `@shardworks/nexus-core`.
|
|
47
|
+
|
|
48
|
+
| Method | Returns | Description |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `home` | `string` | Absolute path to the guild root |
|
|
51
|
+
| `apparatus<T>(name)` | `T` | Retrieve a started apparatus's `provides` API by plugin id. Throws if the apparatus has no `provides` |
|
|
52
|
+
| `config<T>(pluginId)` | `T` | Read the plugin-specific configuration section from `guild.json` |
|
|
53
|
+
| `guildConfig()` | `GuildConfig` | The full parsed `guild.json` |
|
|
54
|
+
| `kits()` | `LoadedKit[]` | All loaded kits (snapshot copy) |
|
|
55
|
+
| `apparatuses()` | `LoadedApparatus[]` | All loaded apparatus in start order (snapshot copy) |
|
|
56
|
+
|
|
57
|
+
### `LoadedKit` and `LoadedApparatus`
|
|
58
|
+
|
|
59
|
+
Installed plugin packages as seen by the runtime:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
interface LoadedKit {
|
|
63
|
+
packageName: string; // full npm name, e.g. '@shardworks/nexus-stdlib'
|
|
64
|
+
id: string; // derived plugin id, e.g. 'nexus-stdlib'
|
|
65
|
+
version: string;
|
|
66
|
+
kit: Kit; // the package's Kit object
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface LoadedApparatus {
|
|
70
|
+
packageName: string;
|
|
71
|
+
id: string;
|
|
72
|
+
version: string;
|
|
73
|
+
apparatus: Apparatus; // the package's Apparatus object
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
type LoadedPlugin = LoadedKit | LoadedApparatus;
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Type guards: `isLoadedKit(p)` and `isLoadedApparatus(p)` from `@shardworks/nexus-core`.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Plugin Lifecycle
|
|
84
|
+
|
|
85
|
+
`createGuild()` runs the full plugin lifecycle on each call:
|
|
86
|
+
|
|
87
|
+
1. **Load** — imports all declared plugin packages from `node_modules`, discriminates kit vs. apparatus.
|
|
88
|
+
2. **Validate** — checks `requires` declarations (apparatus and kit), detects circular apparatus dependencies. Fails loudly before any apparatus starts.
|
|
89
|
+
3. **Warn** — advisory warnings for kit contributions that no apparatus `consumes`, and for missing `recommends`.
|
|
90
|
+
4. **Wire** — sets the `guild()` singleton. The `provides` map is populated progressively as each apparatus starts; dependency ordering guarantees declared deps are available.
|
|
91
|
+
5. **Start** — fires `plugin:initialized` for all kits, then calls `start(ctx)` on each apparatus in dependency-resolved order, firing `plugin:initialized` after each.
|
|
92
|
+
|
|
93
|
+
Apparatus start order is determined by topological sort on `apparatus.requires`. Circular dependencies throw with a descriptive error. Kit `requires` validate that the named apparatus is installed but do not affect start order (kits have no lifecycle).
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Guild Lifecycle Internals
|
|
98
|
+
|
|
99
|
+
Pure validation and ordering logic lives in `guild-lifecycle.ts`, separated from I/O:
|
|
100
|
+
|
|
101
|
+
| Function | Description |
|
|
102
|
+
|---|---|
|
|
103
|
+
| `validateRequires(kits, apparatuses)` | Validates all `requires` declarations and detects circular dependencies |
|
|
104
|
+
| `topoSort(apparatuses)` | Topological sort by `requires` — determines apparatus start order |
|
|
105
|
+
| `collectStartupWarnings(kits, apparatuses)` | Advisory warnings for unconsumed contributions and missing recommends |
|
|
106
|
+
| `buildStartupContext(eventHandlers)` | Creates the `StartupContext` passed to `apparatus.start()` |
|
|
107
|
+
| `fireEvent(eventHandlers, event, ...args)` | Fires lifecycle events to registered handlers |
|
|
108
|
+
|
|
109
|
+
These are exported for testing but are not part of the consumer-facing API.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Lazy Startup
|
|
114
|
+
|
|
115
|
+
The arbor does no work at import time. `createGuild()` is async and performs all plugin loading, validation, and startup in a single call. There is no background process or persistent state — the `Guild` object is alive for the lifetime of the process that created it.
|
package/dist/arbor.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Arbor — the guild runtime.
|
|
3
|
+
*
|
|
4
|
+
* `createGuild()` is the single entry point. It reads guild.json, loads all
|
|
5
|
+
* declared plugins, validates dependencies, starts apparatus in order, wires
|
|
6
|
+
* the guild() singleton, and returns the Guild object.
|
|
7
|
+
*
|
|
8
|
+
* The full plugin lifecycle:
|
|
9
|
+
* 1. Load — imports all declared plugin packages, discriminates kit vs apparatus
|
|
10
|
+
* 2. Validate — checks `requires` declarations, detects circular dependencies
|
|
11
|
+
* 3. Start — calls start(ctx) on each apparatus in dependency-resolved order
|
|
12
|
+
* 4. Events — fires `plugin:initialized` after each plugin loads
|
|
13
|
+
* 5. Warn — advisory warnings for mismatched kit contributions / recommends
|
|
14
|
+
*
|
|
15
|
+
* Pure logic (validation, ordering, events) lives in guild-lifecycle.ts.
|
|
16
|
+
* This file handles I/O and orchestration.
|
|
17
|
+
*/
|
|
18
|
+
import type { Guild } from '@shardworks/nexus-core';
|
|
19
|
+
/**
|
|
20
|
+
* Create and start a guild.
|
|
21
|
+
*
|
|
22
|
+
* Reads guild.json, loads all declared plugins, validates dependencies,
|
|
23
|
+
* starts apparatus in dependency order, and returns the Guild object.
|
|
24
|
+
* Also sets the guild() singleton so apparatus code can access it.
|
|
25
|
+
*
|
|
26
|
+
* @param root - Absolute path to the guild root. Defaults to auto-detection
|
|
27
|
+
* by walking up from cwd until guild.json is found.
|
|
28
|
+
* @returns The initialized Guild — the same object guild() returns.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createGuild(root?: string): Promise<Guild>;
|
|
31
|
+
//# sourceMappingURL=arbor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arbor.d.ts","sourceRoot":"","sources":["../src/arbor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAaH,OAAO,KAAK,EACV,KAAK,EAGN,MAAM,wBAAwB,CAAC;AAahC;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAgI/D"}
|
package/dist/arbor.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Arbor — the guild runtime.
|
|
3
|
+
*
|
|
4
|
+
* `createGuild()` is the single entry point. It reads guild.json, loads all
|
|
5
|
+
* declared plugins, validates dependencies, starts apparatus in order, wires
|
|
6
|
+
* the guild() singleton, and returns the Guild object.
|
|
7
|
+
*
|
|
8
|
+
* The full plugin lifecycle:
|
|
9
|
+
* 1. Load — imports all declared plugin packages, discriminates kit vs apparatus
|
|
10
|
+
* 2. Validate — checks `requires` declarations, detects circular dependencies
|
|
11
|
+
* 3. Start — calls start(ctx) on each apparatus in dependency-resolved order
|
|
12
|
+
* 4. Events — fires `plugin:initialized` after each plugin loads
|
|
13
|
+
* 5. Warn — advisory warnings for mismatched kit contributions / recommends
|
|
14
|
+
*
|
|
15
|
+
* Pure logic (validation, ordering, events) lives in guild-lifecycle.ts.
|
|
16
|
+
* This file handles I/O and orchestration.
|
|
17
|
+
*/
|
|
18
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
19
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
20
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
21
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return path;
|
|
25
|
+
};
|
|
26
|
+
import { readGuildConfig, writeGuildConfig, findGuildRoot, isKit, isApparatus, setGuild, resolveGuildPackageEntry, resolvePackageNameForPluginId, readGuildPackageJson, } from '@shardworks/nexus-core';
|
|
27
|
+
import { validateRequires, topoSort, collectStartupWarnings, buildStartupContext, fireEvent, } from "./guild-lifecycle.js";
|
|
28
|
+
// ── Public API ────────────────────────────────────────────────────────
|
|
29
|
+
/**
|
|
30
|
+
* Create and start a guild.
|
|
31
|
+
*
|
|
32
|
+
* Reads guild.json, loads all declared plugins, validates dependencies,
|
|
33
|
+
* starts apparatus in dependency order, and returns the Guild object.
|
|
34
|
+
* Also sets the guild() singleton so apparatus code can access it.
|
|
35
|
+
*
|
|
36
|
+
* @param root - Absolute path to the guild root. Defaults to auto-detection
|
|
37
|
+
* by walking up from cwd until guild.json is found.
|
|
38
|
+
* @returns The initialized Guild — the same object guild() returns.
|
|
39
|
+
*/
|
|
40
|
+
export async function createGuild(root) {
|
|
41
|
+
const guildRoot = root ?? findGuildRoot();
|
|
42
|
+
const config = readGuildConfig(guildRoot);
|
|
43
|
+
const kits = [];
|
|
44
|
+
const apparatuses = [];
|
|
45
|
+
const eventHandlers = new Map();
|
|
46
|
+
// ── Load phase ─────────────────────────────────────────────────────
|
|
47
|
+
for (const pluginId of config.plugins) {
|
|
48
|
+
const packageName = resolvePackageNameForPluginId(guildRoot, pluginId);
|
|
49
|
+
if (!packageName) {
|
|
50
|
+
console.warn(`[arbor] No package found in package.json for plugin "${pluginId}" — skipping`);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const { version } = readGuildPackageJson(guildRoot, packageName);
|
|
54
|
+
try {
|
|
55
|
+
const entryPath = resolveGuildPackageEntry(guildRoot, packageName);
|
|
56
|
+
const mod = await import(__rewriteRelativeImportExtension(entryPath));
|
|
57
|
+
const raw = mod.default;
|
|
58
|
+
if (isApparatus(raw)) {
|
|
59
|
+
apparatuses.push({ packageName, id: pluginId, version, apparatus: raw.apparatus });
|
|
60
|
+
}
|
|
61
|
+
else if (isKit(raw)) {
|
|
62
|
+
kits.push({ packageName, id: pluginId, version, kit: raw.kit });
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
console.warn(`[arbor] Plugin "${packageName}" does not export a kit or apparatus — skipping. ` +
|
|
66
|
+
`Plugins must export { kit: ... } or { apparatus: ... }.`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
71
|
+
console.warn(`[arbor] Failed to load plugin "${packageName}": ${message}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// ── Validation phase ───────────────────────────────────────────────
|
|
75
|
+
validateRequires(kits, apparatuses);
|
|
76
|
+
// ── Startup warnings ───────────────────────────────────────────────
|
|
77
|
+
for (const warning of collectStartupWarnings(kits, apparatuses)) {
|
|
78
|
+
console.warn(warning);
|
|
79
|
+
}
|
|
80
|
+
// ── Start phase ────────────────────────────────────────────────────
|
|
81
|
+
const orderedApparatuses = topoSort(apparatuses);
|
|
82
|
+
const provides = new Map();
|
|
83
|
+
// Wire guild singleton before any apparatus starts so start() methods
|
|
84
|
+
// can call guild(). The provides Map is populated progressively as each
|
|
85
|
+
// apparatus starts; dependency ordering guarantees declared deps are
|
|
86
|
+
// available.
|
|
87
|
+
const guildInstance = {
|
|
88
|
+
home: guildRoot,
|
|
89
|
+
apparatus(name) {
|
|
90
|
+
const p = provides.get(name);
|
|
91
|
+
if (p === undefined) {
|
|
92
|
+
throw new Error(`[guild] apparatus("${name}") is not available. ` +
|
|
93
|
+
`No loaded apparatus provides this id. Check guild.json plugins list.`);
|
|
94
|
+
}
|
|
95
|
+
return p;
|
|
96
|
+
},
|
|
97
|
+
config(pluginId) {
|
|
98
|
+
// GuildConfig types only the framework-level keys (name, nexus, plugins, etc.).
|
|
99
|
+
// Plugin-specific config sections (e.g. "animator", "stacks") are additional
|
|
100
|
+
// top-level keys in guild.json that GuildConfig doesn't model. The cast is safe
|
|
101
|
+
// because guild.json is a plain JSON object — all keys are accessible at runtime.
|
|
102
|
+
// Plugins can use module augmentation on GuildConfig to get typed access; this
|
|
103
|
+
// generic path remains the untyped fallback.
|
|
104
|
+
const cfg = config;
|
|
105
|
+
return (cfg[pluginId] ?? {});
|
|
106
|
+
},
|
|
107
|
+
writeConfig(pluginId, value) {
|
|
108
|
+
// Update the in-memory config so subsequent reads reflect the change,
|
|
109
|
+
// then persist to disk. The cast is the same pattern as config() above.
|
|
110
|
+
const cfg = config;
|
|
111
|
+
cfg[pluginId] = value;
|
|
112
|
+
writeGuildConfig(guildRoot, config);
|
|
113
|
+
},
|
|
114
|
+
guildConfig() {
|
|
115
|
+
return config;
|
|
116
|
+
},
|
|
117
|
+
kits() { return [...kits]; },
|
|
118
|
+
apparatuses() { return [...orderedApparatuses]; },
|
|
119
|
+
};
|
|
120
|
+
setGuild(guildInstance);
|
|
121
|
+
// Fire plugin:initialized for all kits before starting any apparatus
|
|
122
|
+
for (const kit of kits) {
|
|
123
|
+
await fireEvent(eventHandlers, 'plugin:initialized', kit);
|
|
124
|
+
}
|
|
125
|
+
// Start each apparatus in dependency order
|
|
126
|
+
const startupCtx = buildStartupContext(eventHandlers);
|
|
127
|
+
for (const app of orderedApparatuses) {
|
|
128
|
+
// Register provides before start() so apparatuses with eager provides are
|
|
129
|
+
// visible to later startups that run during this loop.
|
|
130
|
+
if (app.apparatus.provides !== undefined) {
|
|
131
|
+
provides.set(app.id, app.apparatus.provides);
|
|
132
|
+
}
|
|
133
|
+
await app.apparatus.start(startupCtx);
|
|
134
|
+
// Re-check after start() for deferred provides (e.g. Stacks uses a getter
|
|
135
|
+
// that returns undefined until start() populates the backing variable).
|
|
136
|
+
if (!provides.has(app.id) && app.apparatus.provides !== undefined) {
|
|
137
|
+
provides.set(app.id, app.apparatus.provides);
|
|
138
|
+
}
|
|
139
|
+
await fireEvent(eventHandlers, 'plugin:initialized', app);
|
|
140
|
+
}
|
|
141
|
+
return guildInstance;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=arbor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arbor.js","sourceRoot":"","sources":["../src/arbor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;;;;;;;;;AAEH,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,KAAK,EACL,WAAW,EACX,QAAQ,EACR,wBAAwB,EACxB,6BAA6B,EAC7B,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAOhC,OAAO,EACL,gBAAgB,EAChB,QAAQ,EACR,sBAAsB,EACtB,mBAAmB,EACnB,SAAS,GACV,MAAM,sBAAsB,CAAC;AAG9B,yEAAyE;AAEzE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAa;IAC7C,MAAM,SAAS,GAAG,IAAI,IAAI,aAAa,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAE1C,MAAM,IAAI,GAA8B,EAAE,CAAC;IAC3C,MAAM,WAAW,GAAuB,EAAE,CAAC;IAC3C,MAAM,aAAa,GAAoB,IAAI,GAAG,EAAE,CAAC;IAEjD,sEAAsE;IAEtE,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACtC,MAAM,WAAW,GAAG,6BAA6B,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QACvE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,wDAAwD,QAAQ,cAAc,CAAC,CAAC;YAC7F,SAAS;QACX,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,GAAG,oBAAoB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAEjE,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,wBAAwB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;YACnE,MAAM,GAAG,GAAG,MAAM,MAAM,kCAAC,SAAS,EAAyB,CAAC;YAC5D,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC;YAExB,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrB,WAAW,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;YACrF,CAAC;iBAAM,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtB,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;YAClE,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CACV,mBAAmB,WAAW,mDAAmD;oBACjF,yDAAyD,CAC1D,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO,CAAC,IAAI,CAAC,kCAAkC,WAAW,MAAM,OAAO,EAAE,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IAED,sEAAsE;IAEtE,gBAAgB,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAEpC,sEAAsE;IAEtE,KAAK,MAAM,OAAO,IAAI,sBAAsB,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC;QAChE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;IAED,sEAAsE;IAEtE,MAAM,kBAAkB,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAmB,CAAC;IAE5C,sEAAsE;IACtE,wEAAwE;IACxE,qEAAqE;IACrE,aAAa;IAEb,MAAM,aAAa,GAAU;QAC3B,IAAI,EAAE,SAAS;QAEf,SAAS,CAAI,IAAY;YACvB,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CACb,sBAAsB,IAAI,uBAAuB;oBACjD,sEAAsE,CACvE,CAAC;YACJ,CAAC;YACD,OAAO,CAAM,CAAC;QAChB,CAAC;QAED,MAAM,CAA8B,QAAgB;YAClD,gFAAgF;YAChF,6EAA6E;YAC7E,gFAAgF;YAChF,kFAAkF;YAClF,+EAA+E;YAC/E,6CAA6C;YAC7C,MAAM,GAAG,GAAG,MAA4C,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAM,CAAC;QACpC,CAAC;QAED,WAAW,CAA8B,QAAgB,EAAE,KAAQ;YACjE,sEAAsE;YACtE,wEAAwE;YACxE,MAAM,GAAG,GAAG,MAA4C,CAAC;YACzD,GAAG,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC;YACtB,gBAAgB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACtC,CAAC;QAED,WAAW;YACT,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,IAAI,KAAY,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,WAAW,KAAK,OAAO,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;KAClD,CAAC;IACF,QAAQ,CAAC,aAAa,CAAC,CAAC;IAExB,qEAAqE;IACrE,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,SAAS,CAAC,aAAa,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;IAC5D,CAAC;IAED,2CAA2C;IAC3C,MAAM,UAAU,GAAG,mBAAmB,CAAC,aAAa,CAAC,CAAC;IACtD,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;QACrC,0EAA0E;QAC1E,uDAAuD;QACvD,IAAI,GAAG,CAAC,SAAS,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACzC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAEtC,0EAA0E;QAC1E,wEAAwE;QACxE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAClE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,SAAS,CAAC,aAAa,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,aAAa,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guild lifecycle — pure logic for plugin validation, ordering, and events.
|
|
3
|
+
*
|
|
4
|
+
* All functions here operate on in-memory data structures (LoadedKit[],
|
|
5
|
+
* LoadedApparatus[], Maps) with no I/O. This makes them independently
|
|
6
|
+
* testable with synthetic fixtures.
|
|
7
|
+
*
|
|
8
|
+
* `createGuild()` in arbor.ts is the orchestrator that performs I/O
|
|
9
|
+
* (config reading, dynamic imports) then delegates to these functions.
|
|
10
|
+
*/
|
|
11
|
+
import type { StartupContext, LoadedKit, LoadedApparatus } from '@shardworks/nexus-core';
|
|
12
|
+
export type EventHandlerMap = Map<string, Array<(...args: unknown[]) => void | Promise<void>>>;
|
|
13
|
+
/**
|
|
14
|
+
* Validate all `requires` declarations and detect circular dependencies.
|
|
15
|
+
* Throws with a descriptive error on the first problem found.
|
|
16
|
+
*
|
|
17
|
+
* Checks:
|
|
18
|
+
* - Apparatus requires: every named dependency must exist (kit or apparatus).
|
|
19
|
+
* - Kit requires: every named dependency must be an apparatus (kits can't
|
|
20
|
+
* depend on kits).
|
|
21
|
+
* - Cycle detection: no circular dependency chains among apparatuses.
|
|
22
|
+
*/
|
|
23
|
+
export declare function validateRequires(kits: LoadedKit[], apparatuses: LoadedApparatus[]): void;
|
|
24
|
+
/**
|
|
25
|
+
* Sort apparatuses in dependency-resolved order using topological sort.
|
|
26
|
+
* validateRequires() must be called first to ensure the graph is acyclic.
|
|
27
|
+
*/
|
|
28
|
+
export declare function topoSort(apparatuses: LoadedApparatus[]): LoadedApparatus[];
|
|
29
|
+
/**
|
|
30
|
+
* Collect advisory warnings for kit contributions that no apparatus
|
|
31
|
+
* consumes, and for missing recommended apparatuses.
|
|
32
|
+
*
|
|
33
|
+
* Returns an array of warning strings. The caller decides how to emit
|
|
34
|
+
* them (console.warn, logger, etc.).
|
|
35
|
+
*/
|
|
36
|
+
export declare function collectStartupWarnings(kits: LoadedKit[], apparatuses: LoadedApparatus[]): string[];
|
|
37
|
+
/**
|
|
38
|
+
* Build a StartupContext for an apparatus's start() call.
|
|
39
|
+
* The context provides event subscription; handlers are stored in the
|
|
40
|
+
* shared eventHandlers map so fireEvent can invoke them later.
|
|
41
|
+
*/
|
|
42
|
+
export declare function buildStartupContext(eventHandlers: EventHandlerMap): StartupContext;
|
|
43
|
+
/**
|
|
44
|
+
* Fire a lifecycle event, awaiting each handler sequentially.
|
|
45
|
+
*/
|
|
46
|
+
export declare function fireEvent(eventHandlers: EventHandlerMap, event: string, ...args: unknown[]): Promise<void>;
|
|
47
|
+
//# sourceMappingURL=guild-lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guild-lifecycle.d.ts","sourceRoot":"","sources":["../src/guild-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,eAAe,EAChB,MAAM,wBAAwB,CAAC;AAIhC,MAAM,MAAM,eAAe,GAAG,GAAG,CAC/B,MAAM,EACN,KAAK,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CACpD,CAAC;AAIF;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,SAAS,EAAE,EACjB,WAAW,EAAE,eAAe,EAAE,GAC7B,IAAI,CA2DN;AAID;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,WAAW,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE,CAoB1E;AAID;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAS,SAAS,EAAE,EACxB,WAAW,EAAE,eAAe,EAAE,GAC7B,MAAM,EAAE,CA4CV;AAID;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,eAAe,GAC7B,cAAc,CAQhB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,aAAa,EAAE,eAAe,EAC9B,KAAK,EAAU,MAAM,EACrB,GAAG,IAAI,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC,IAAI,CAAC,CAKf"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guild lifecycle — pure logic for plugin validation, ordering, and events.
|
|
3
|
+
*
|
|
4
|
+
* All functions here operate on in-memory data structures (LoadedKit[],
|
|
5
|
+
* LoadedApparatus[], Maps) with no I/O. This makes them independently
|
|
6
|
+
* testable with synthetic fixtures.
|
|
7
|
+
*
|
|
8
|
+
* `createGuild()` in arbor.ts is the orchestrator that performs I/O
|
|
9
|
+
* (config reading, dynamic imports) then delegates to these functions.
|
|
10
|
+
*/
|
|
11
|
+
// ── Validation ───────────────────────────────────────────────────────
|
|
12
|
+
/**
|
|
13
|
+
* Validate all `requires` declarations and detect circular dependencies.
|
|
14
|
+
* Throws with a descriptive error on the first problem found.
|
|
15
|
+
*
|
|
16
|
+
* Checks:
|
|
17
|
+
* - Apparatus requires: every named dependency must exist (kit or apparatus).
|
|
18
|
+
* - Kit requires: every named dependency must be an apparatus (kits can't
|
|
19
|
+
* depend on kits).
|
|
20
|
+
* - Cycle detection: no circular dependency chains among apparatuses.
|
|
21
|
+
*/
|
|
22
|
+
export function validateRequires(kits, apparatuses) {
|
|
23
|
+
const apparatusIds = new Set(apparatuses.map((a) => a.id));
|
|
24
|
+
const allIds = new Set([
|
|
25
|
+
...kits.map((k) => k.id),
|
|
26
|
+
...apparatuses.map((a) => a.id),
|
|
27
|
+
]);
|
|
28
|
+
// Check apparatus requires
|
|
29
|
+
for (const app of apparatuses) {
|
|
30
|
+
for (const dep of app.apparatus.requires ?? []) {
|
|
31
|
+
if (!allIds.has(dep)) {
|
|
32
|
+
throw new Error(`[arbor] "${app.id}" requires "${dep}", which is not installed.`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Check kit requires (must be apparatus names — kits can't depend on kits)
|
|
37
|
+
for (const kit of kits) {
|
|
38
|
+
for (const dep of kit.kit.requires ?? []) {
|
|
39
|
+
if (!apparatusIds.has(dep)) {
|
|
40
|
+
if (!allIds.has(dep)) {
|
|
41
|
+
throw new Error(`[arbor] kit "${kit.id}" requires "${dep}", which is not installed.`);
|
|
42
|
+
}
|
|
43
|
+
throw new Error(`[arbor] kit "${kit.id}" requires "${dep}", but that plugin is a kit, not an apparatus. ` +
|
|
44
|
+
`Kit requires must name apparatus plugins.`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Detect circular dependencies among apparatuses
|
|
49
|
+
const visiting = new Set();
|
|
50
|
+
const visited = new Set();
|
|
51
|
+
function visit(id, chain) {
|
|
52
|
+
if (visited.has(id))
|
|
53
|
+
return;
|
|
54
|
+
if (visiting.has(id)) {
|
|
55
|
+
const cycle = [...chain, id].join(' → ');
|
|
56
|
+
throw new Error(`[arbor] Circular dependency detected: ${cycle}`);
|
|
57
|
+
}
|
|
58
|
+
visiting.add(id);
|
|
59
|
+
const app = apparatuses.find((a) => a.id === id);
|
|
60
|
+
if (app) {
|
|
61
|
+
for (const dep of app.apparatus.requires ?? []) {
|
|
62
|
+
visit(dep, [...chain, id]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
visiting.delete(id);
|
|
66
|
+
visited.add(id);
|
|
67
|
+
}
|
|
68
|
+
for (const app of apparatuses) {
|
|
69
|
+
visit(app.id, []);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// ── Dependency ordering ──────────────────────────────────────────────
|
|
73
|
+
/**
|
|
74
|
+
* Sort apparatuses in dependency-resolved order using topological sort.
|
|
75
|
+
* validateRequires() must be called first to ensure the graph is acyclic.
|
|
76
|
+
*/
|
|
77
|
+
export function topoSort(apparatuses) {
|
|
78
|
+
const sorted = [];
|
|
79
|
+
const visited = new Set();
|
|
80
|
+
function visit(id) {
|
|
81
|
+
if (visited.has(id))
|
|
82
|
+
return;
|
|
83
|
+
const app = apparatuses.find((a) => a.id === id);
|
|
84
|
+
if (!app)
|
|
85
|
+
return;
|
|
86
|
+
for (const dep of app.apparatus.requires ?? []) {
|
|
87
|
+
visit(dep);
|
|
88
|
+
}
|
|
89
|
+
visited.add(id);
|
|
90
|
+
sorted.push(app);
|
|
91
|
+
}
|
|
92
|
+
for (const app of apparatuses) {
|
|
93
|
+
visit(app.id);
|
|
94
|
+
}
|
|
95
|
+
return sorted;
|
|
96
|
+
}
|
|
97
|
+
// ── Startup warnings ─────────────────────────────────────────────────
|
|
98
|
+
/**
|
|
99
|
+
* Collect advisory warnings for kit contributions that no apparatus
|
|
100
|
+
* consumes, and for missing recommended apparatuses.
|
|
101
|
+
*
|
|
102
|
+
* Returns an array of warning strings. The caller decides how to emit
|
|
103
|
+
* them (console.warn, logger, etc.).
|
|
104
|
+
*/
|
|
105
|
+
export function collectStartupWarnings(kits, apparatuses) {
|
|
106
|
+
const warnings = [];
|
|
107
|
+
const consumedTypes = new Set();
|
|
108
|
+
const installedIds = new Set(apparatuses.map((a) => a.id));
|
|
109
|
+
for (const app of apparatuses) {
|
|
110
|
+
for (const token of app.apparatus.consumes ?? []) {
|
|
111
|
+
consumedTypes.add(token);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Check apparatus recommends
|
|
115
|
+
for (const app of apparatuses) {
|
|
116
|
+
for (const rec of app.apparatus.recommends ?? []) {
|
|
117
|
+
if (!installedIds.has(rec)) {
|
|
118
|
+
warnings.push(`[arbor] warn: "${app.id}" recommends "${rec}" but it is not installed.`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
for (const kit of kits) {
|
|
123
|
+
// Check kit recommends
|
|
124
|
+
for (const rec of kit.kit.recommends ?? []) {
|
|
125
|
+
if (!installedIds.has(rec)) {
|
|
126
|
+
warnings.push(`[arbor] warn: "${kit.id}" recommends "${rec}" but it is not installed.`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Check contribution types against consumes
|
|
130
|
+
for (const key of Object.keys(kit.kit)) {
|
|
131
|
+
if (key === 'requires' || key === 'recommends')
|
|
132
|
+
continue;
|
|
133
|
+
if (!consumedTypes.has(key)) {
|
|
134
|
+
warnings.push(`[arbor] warn: "${kit.id}" contributes "${key}" but no installed apparatus declares consumes: ["${key}"]`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return warnings;
|
|
139
|
+
}
|
|
140
|
+
// ── Event system ─────────────────────────────────────────────────────
|
|
141
|
+
/**
|
|
142
|
+
* Build a StartupContext for an apparatus's start() call.
|
|
143
|
+
* The context provides event subscription; handlers are stored in the
|
|
144
|
+
* shared eventHandlers map so fireEvent can invoke them later.
|
|
145
|
+
*/
|
|
146
|
+
export function buildStartupContext(eventHandlers) {
|
|
147
|
+
return {
|
|
148
|
+
on(event, handler) {
|
|
149
|
+
const list = eventHandlers.get(event) ?? [];
|
|
150
|
+
list.push(handler);
|
|
151
|
+
eventHandlers.set(event, list);
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Fire a lifecycle event, awaiting each handler sequentially.
|
|
157
|
+
*/
|
|
158
|
+
export async function fireEvent(eventHandlers, event, ...args) {
|
|
159
|
+
const handlers = eventHandlers.get(event) ?? [];
|
|
160
|
+
for (const h of handlers) {
|
|
161
|
+
await h(...args);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=guild-lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guild-lifecycle.js","sourceRoot":"","sources":["../src/guild-lifecycle.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @shardworks/nexus-arbor — guild runtime
|
|
3
|
+
*
|
|
4
|
+
* The arbor is the guild host: plugin loading, dependency validation,
|
|
5
|
+
* apparatus lifecycle management. It does NOT own tool discovery — that
|
|
6
|
+
* belongs to The Instrumentarium (tools-apparatus).
|
|
7
|
+
*
|
|
8
|
+
* Plugin authors never import from arbor — they import from @shardworks/nexus-core.
|
|
9
|
+
* The CLI imports from arbor to create the guild runtime and trigger startup.
|
|
10
|
+
*
|
|
11
|
+
* Package dependency graph:
|
|
12
|
+
* core — public SDK, types, tool() factory
|
|
13
|
+
* arbor — guild host, createGuild()
|
|
14
|
+
* cli — nsg binary, Commander.js, framework commands + Instrumentarium tools
|
|
15
|
+
* plugins — import from core only
|
|
16
|
+
*/
|
|
17
|
+
export { createGuild } from './arbor.ts';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @shardworks/nexus-arbor — guild runtime
|
|
3
|
+
*
|
|
4
|
+
* The arbor is the guild host: plugin loading, dependency validation,
|
|
5
|
+
* apparatus lifecycle management. It does NOT own tool discovery — that
|
|
6
|
+
* belongs to The Instrumentarium (tools-apparatus).
|
|
7
|
+
*
|
|
8
|
+
* Plugin authors never import from arbor — they import from @shardworks/nexus-core.
|
|
9
|
+
* The CLI imports from arbor to create the guild runtime and trigger startup.
|
|
10
|
+
*
|
|
11
|
+
* Package dependency graph:
|
|
12
|
+
* core — public SDK, types, tool() factory
|
|
13
|
+
* arbor — guild host, createGuild()
|
|
14
|
+
* cli — nsg binary, Commander.js, framework commands + Instrumentarium tools
|
|
15
|
+
* plugins — import from core only
|
|
16
|
+
*/
|
|
17
|
+
export { createGuild } from "./arbor.js";
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shardworks/nexus-arbor",
|
|
3
|
+
"version": "0.1.101",
|
|
4
|
+
"license": "ISC",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/shardworks/nexus",
|
|
8
|
+
"directory": "packages/framework/arbor"
|
|
9
|
+
},
|
|
10
|
+
"description": "The Arbor — guild runtime host: loads plugins, validates dependencies, starts apparatus in order, wires the guild() singleton",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@shardworks/nexus-core": "0.1.101"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "25.5.0"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc",
|
|
29
|
+
"test": "node --disable-warning=ExperimentalWarning --experimental-transform-types --test 'src/**/*.test.ts'",
|
|
30
|
+
"typecheck": "tsc --noEmit"
|
|
31
|
+
}
|
|
32
|
+
}
|