@dot-agent/kernel-dsl 0.1.0
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 +178 -0
- package/README.md +244 -0
- package/index.js +111 -0
- package/package.json +69 -0
- package/pkg/dot_agent_kernel_dsl.d.ts +95 -0
- package/pkg/dot_agent_kernel_dsl.js +6 -0
- package/pkg/dot_agent_kernel_dsl_bg.wasm +0 -0
- package/pkg/dot_agent_kernel_dsl_bg.wasm.d.ts +25 -0
- package/pkg/index.js +99 -0
- package/pkg/package.json +10 -0
- package/scripts/discover-wasm-imports.js +113 -0
- package/scripts/patch-wasm-bindgen.js +45 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship made available under
|
|
36
|
+
the License, as indicated by a copyright notice that is included in
|
|
37
|
+
or attached to the work (an example is provided in the Appendix below).
|
|
38
|
+
|
|
39
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
40
|
+
form, that is based on (or derived from) the Work and for which the
|
|
41
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
42
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
43
|
+
of this License, Derivative Works shall not include works that remain
|
|
44
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
45
|
+
the Work and Derivative Works thereof.
|
|
46
|
+
|
|
47
|
+
"Contribution" shall mean, as submitted to the Licensor for inclusion
|
|
48
|
+
in the Work by the copyright owner or by an individual or Legal Entity
|
|
49
|
+
authorized to submit on behalf of the copyright owner. For the purposes
|
|
50
|
+
of this definition, "submitted" means any form of electronic, verbal,
|
|
51
|
+
or written communication sent to the Licensor or its representatives,
|
|
52
|
+
including but not limited to communication on electronic mailing lists,
|
|
53
|
+
source code control systems, and issue tracking systems that are managed
|
|
54
|
+
by, or on behalf of, the Licensor for the purpose of discussing and
|
|
55
|
+
improving the Work, but excluding communication that is conspicuously
|
|
56
|
+
marked or designated in writing by the copyright owner as "Not a
|
|
57
|
+
Contribution."
|
|
58
|
+
|
|
59
|
+
"Contributor" shall mean Licensor and any Legal Entity on behalf of
|
|
60
|
+
whom a Contribution has been received by the Licensor and included
|
|
61
|
+
within the Work.
|
|
62
|
+
|
|
63
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
64
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
65
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
66
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
67
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
68
|
+
Work and such Derivative Works in Source or Object form.
|
|
69
|
+
|
|
70
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
71
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
72
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
73
|
+
(except as stated in this section) patent license to make, have made,
|
|
74
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
75
|
+
where such license applies only to those patent licenses granted to
|
|
76
|
+
You under this License for that Work shall terminate as of the date
|
|
77
|
+
such litigation is filed.
|
|
78
|
+
|
|
79
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
80
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
81
|
+
modifications, and in Source or Object form, provided that You
|
|
82
|
+
meet the following conditions:
|
|
83
|
+
|
|
84
|
+
(a) You must give any other recipients of the Work or Derivative
|
|
85
|
+
Works a copy of this License; and
|
|
86
|
+
|
|
87
|
+
(b) You must cause any modified files to carry prominent notices
|
|
88
|
+
stating that You changed the files; and
|
|
89
|
+
|
|
90
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
91
|
+
that You distribute, all copyright, patent, trademark, and
|
|
92
|
+
attribution notices from the Source form of the Work,
|
|
93
|
+
excluding those notices that do not pertain to any part of
|
|
94
|
+
the Derivative Works; and
|
|
95
|
+
|
|
96
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
97
|
+
distribution, You must include a readable copy of the
|
|
98
|
+
attribution notices contained within such NOTICE file, in
|
|
99
|
+
at least one of the following places: within a NOTICE text
|
|
100
|
+
file distributed as part of the Derivative Works; within
|
|
101
|
+
the Source form or documentation, if provided along with the
|
|
102
|
+
Derivative Works; or, within a display generated by the
|
|
103
|
+
Derivative Works, if and wherever such third-party notices
|
|
104
|
+
normally appear. The contents of the NOTICE file are for
|
|
105
|
+
informational purposes only and do not modify the License.
|
|
106
|
+
You may add Your own attribution notices within Derivative
|
|
107
|
+
Works that You distribute, alongside or as an addendum to
|
|
108
|
+
the NOTICE text from the Work, provided that such additional
|
|
109
|
+
attribution notices cannot be construed as modifying the License.
|
|
110
|
+
|
|
111
|
+
You may add Your own license statement for Your modifications and
|
|
112
|
+
may provide additional grant of rights to use, copy, modify, merge,
|
|
113
|
+
publish, distribute, sublicense, and/or sell copies of the
|
|
114
|
+
Contribution, either in combined form with the Work or separate from
|
|
115
|
+
the Work. If You choose to provide additional grant of rights, You
|
|
116
|
+
must do so in a manner consistent with the terms of this License.
|
|
117
|
+
|
|
118
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
119
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
120
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
121
|
+
this License, without any additional terms or conditions.
|
|
122
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
123
|
+
the terms of any separate license agreement you may have executed
|
|
124
|
+
with Licensor regarding such Contributions.
|
|
125
|
+
|
|
126
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
127
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
128
|
+
except as required for reasonable and customary use in describing the
|
|
129
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
130
|
+
|
|
131
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
132
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
133
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
134
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
135
|
+
implied, including, without limitation, any warranties or conditions
|
|
136
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
137
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
138
|
+
appropriateness of using or reproducing the Work and assume any
|
|
139
|
+
risks associated with Your exercise of permissions under this License.
|
|
140
|
+
|
|
141
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
142
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
143
|
+
unless required by applicable law (such as deliberate and grossly
|
|
144
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
145
|
+
liable to You for damages, including any direct, indirect, special,
|
|
146
|
+
incidental, or exemplary damages of any character arising as a
|
|
147
|
+
result of this License or out of the use or inability to use the
|
|
148
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
149
|
+
work stoppage, computer failure or malfunction, or all other
|
|
150
|
+
commercial damages or losses), even if such Contributor has been
|
|
151
|
+
advised of the possibility of such damages.
|
|
152
|
+
|
|
153
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
154
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
155
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
156
|
+
or other liability obligations and/or rights consistent with this
|
|
157
|
+
License. However, in accepting such obligations, You may act only
|
|
158
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
159
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
160
|
+
defend, and hold each Contributor harmless for any liability
|
|
161
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
162
|
+
of your accepting any such warranty or additional liability.
|
|
163
|
+
|
|
164
|
+
END OF TERMS AND CONDITIONS
|
|
165
|
+
|
|
166
|
+
Copyright (c) 2026 Danilo Borges (https://github.com/daniloborges)
|
|
167
|
+
|
|
168
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
169
|
+
you may not use this file except in compliance with the License.
|
|
170
|
+
You may obtain a copy of the License at
|
|
171
|
+
|
|
172
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
173
|
+
|
|
174
|
+
Unless required by applicable law or agreed to in writing, software
|
|
175
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
176
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
177
|
+
See the License for the specific language governing permissions and
|
|
178
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# @dot-agent/kernel-dsl
|
|
2
|
+
|
|
3
|
+
Execution engine for the **agent behavior DSL** (`.description` and `.behavior` files), written in Rust and compiled to **WebAssembly**. Implements a Finite State Machine (FSM) that interprets `.behavior` files according to the full dot-agent-spec, running entirely in-memory on the client side (browser or Node.js).
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @dot-agent/kernel-dsl
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Basic Usage
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
import { AgentDSLKernel, init } from '@dot-agent/kernel-dsl';
|
|
17
|
+
|
|
18
|
+
// Initialize WASM once
|
|
19
|
+
await init();
|
|
20
|
+
|
|
21
|
+
// Create kernel instance
|
|
22
|
+
const kernel = new AgentDSLKernel();
|
|
23
|
+
|
|
24
|
+
// Load behavior DSL
|
|
25
|
+
const behavior = `
|
|
26
|
+
state welcome
|
|
27
|
+
goal "Help the user"
|
|
28
|
+
interact
|
|
29
|
+
on intent "help" transition to helping
|
|
30
|
+
|
|
31
|
+
state helping
|
|
32
|
+
goal "Provide assistance"
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
kernel.load_behavior(behavior);
|
|
36
|
+
|
|
37
|
+
// Get current state
|
|
38
|
+
console.log(kernel.get_current_state()); // "welcome"
|
|
39
|
+
|
|
40
|
+
// Listen to state changes and effects
|
|
41
|
+
kernel.observe((effect) => {
|
|
42
|
+
console.log('Effect:', effect);
|
|
43
|
+
|
|
44
|
+
switch (effect.type) {
|
|
45
|
+
case 'goal':
|
|
46
|
+
console.log('Goal:', effect.text);
|
|
47
|
+
break;
|
|
48
|
+
case 'transition':
|
|
49
|
+
console.log('Transitioned to:', effect.to);
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Send intents
|
|
55
|
+
kernel.send_intent("help");
|
|
56
|
+
|
|
57
|
+
// Get state graph
|
|
58
|
+
const graph = kernel.get_graph();
|
|
59
|
+
console.log('States:', graph.states);
|
|
60
|
+
console.log('Transitions:', graph.transitions);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### React Integration
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { AgentDSLKernel, init } from '@dot-agent/kernel-dsl';
|
|
67
|
+
import { useEffect, useState } from 'react';
|
|
68
|
+
|
|
69
|
+
export function AgentPanel() {
|
|
70
|
+
const [engine, setEngine] = useState<AgentDSLKernel | null>(null);
|
|
71
|
+
const [currentState, setCurrentState] = useState('');
|
|
72
|
+
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
(async () => {
|
|
75
|
+
await init();
|
|
76
|
+
const kernel = new AgentDSLKernel();
|
|
77
|
+
|
|
78
|
+
kernel.observe((effect) => {
|
|
79
|
+
if (effect.type === 'transition') {
|
|
80
|
+
setCurrentState(effect.to);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
setEngine(kernel);
|
|
85
|
+
})();
|
|
86
|
+
}, []);
|
|
87
|
+
|
|
88
|
+
if (!engine) return <div>Loading...</div>;
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<div>
|
|
92
|
+
<p>Current State: {currentState}</p>
|
|
93
|
+
<button onClick={() => engine.send_intent('help')}>Help</button>
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## WASM Runtime Requirements
|
|
100
|
+
|
|
101
|
+
The kernel-dsl WASM binary requires a complete runtime environment. See [`WASM_SHIM_ARCHITECTURE.md`](./WASM_SHIM_ARCHITECTURE.md) for:
|
|
102
|
+
- Why a shim is necessary
|
|
103
|
+
- Complete list of 31 required functions
|
|
104
|
+
- How to extend implementations (time, random, environment)
|
|
105
|
+
- Post-build patching process
|
|
106
|
+
|
|
107
|
+
**Note**: Initialization is handled automatically by the `init()` function. No manual setup needed.
|
|
108
|
+
|
|
109
|
+
## Architecture
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
src/
|
|
113
|
+
āāā lib.rs ā Public WASM API (#[wasm_bindgen], no business logic)
|
|
114
|
+
āāā effect.rs ā Effect enum + MemValue (serialized return types for JS)
|
|
115
|
+
āāā parser/
|
|
116
|
+
ā āāā mod.rs ā parse_behavior(text) ā BehaviorFile via tree-sitter
|
|
117
|
+
ā āāā ast.rs ā AST types (BehaviorFile, StateDef, Statement, ā¦) with serde
|
|
118
|
+
āāā engine/
|
|
119
|
+
āāā mod.rs ā AgentDSLKernel: orchestrates parser + FSM + memory
|
|
120
|
+
āāā fsm.rs ā State execution, intent dispatch, conditionals, get_graph()
|
|
121
|
+
āāā memory.rs ā MemoryStore: 4 domains (context/session/worksession/user)
|
|
122
|
+
|
|
123
|
+
build.rs ā Code generation: extracts node kinds from tree-sitter grammar
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The parser uses **tree-sitter** for robust parsing. The grammar is maintained in the [`dot-agent-tree-sitter`](https://github.com/daniloborges/dot-agent-tree-sitter) crate. `build.rs` automatically extracts node kinds from `tree-sitter/node-types.json` to keep parsing logic in sync with the grammar ā when the grammar changes, simply update the tree-sitter crate version and rebuild.
|
|
127
|
+
|
|
128
|
+
## Supported constructs
|
|
129
|
+
|
|
130
|
+
The parser and FSM cover the full `.agent DSL`:
|
|
131
|
+
|
|
132
|
+
| Construct | Example |
|
|
133
|
+
|-----------|---------|
|
|
134
|
+
| State | `state responsive` |
|
|
135
|
+
| Goal / Guide / Teach | `goal "text"` |
|
|
136
|
+
| Interact | `interact` |
|
|
137
|
+
| Inline intent | `on intent "planning" transition to planning` |
|
|
138
|
+
| Block intent | `on intent "search"` + indented block |
|
|
139
|
+
| Offtopic | `on offtopic` + block |
|
|
140
|
+
| Global event | `on event "session.ended"` + block |
|
|
141
|
+
| Memory assign | `set context.phase = "planning"` |
|
|
142
|
+
| Compound assign | `+=` / `-=` across all domains |
|
|
143
|
+
| Conditional | `if session.ready == true` + optional `else` |
|
|
144
|
+
| Transition | `transition to planning` |
|
|
145
|
+
| Run | `run script "file.js" silent` / `run subagent "agent.behavior" in background` |
|
|
146
|
+
| Temporal | `after 3 prompts guide "ā¦"` |
|
|
147
|
+
| Parallel | `parallel` + block |
|
|
148
|
+
| UI | `apply css "ā¦"` / `remove html "ā¦"` |
|
|
149
|
+
| Merge | `merge "other.behavior"` (recorded in AST, resolved by external runtime) |
|
|
150
|
+
| Async completion | `on complete` / `on failed` + block |
|
|
151
|
+
|
|
152
|
+
## Build
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
rustup target add wasm32-unknown-unknown
|
|
156
|
+
cargo install wasm-pack
|
|
157
|
+
wasm-pack build --target bundler
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The generated `pkg/` directory is consumed via the package root:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npm install @dot-agent/kernel-dsl
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## API
|
|
167
|
+
|
|
168
|
+
All methods return a **JSON array of `Effect` objects**, letting JS react to flow actions without polling.
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
const engine = new AgentDSLKernel();
|
|
172
|
+
|
|
173
|
+
// Load a .behavior file and receive the entry effects of the first state
|
|
174
|
+
const effects = engine.load_behavior(behaviorText);
|
|
175
|
+
// ā [{ type: "goal", text: "ā¦" }, { type: "request_interact" }]
|
|
176
|
+
|
|
177
|
+
// Dispatch an intent (name classified by the LLM layer)
|
|
178
|
+
engine.send_intent("planning");
|
|
179
|
+
|
|
180
|
+
// Flow handlers
|
|
181
|
+
engine.send_offtopic();
|
|
182
|
+
engine.send_event("session.ended");
|
|
183
|
+
|
|
184
|
+
// Async operation completion
|
|
185
|
+
engine.send_complete();
|
|
186
|
+
engine.send_failed();
|
|
187
|
+
|
|
188
|
+
// Temporal triggers ā call once per processed prompt
|
|
189
|
+
engine.tick_prompt();
|
|
190
|
+
|
|
191
|
+
// State reads
|
|
192
|
+
engine.get_current_state(); // string
|
|
193
|
+
engine.get_valid_intents(); // Array<string>
|
|
194
|
+
|
|
195
|
+
// Memory
|
|
196
|
+
engine.get_memory(); // [{ domain, key, value }]
|
|
197
|
+
engine.set_memory("session", "lang", '"pt"'); // value as JSON string
|
|
198
|
+
|
|
199
|
+
// State graph (for VS Code Flow Graph panel)
|
|
200
|
+
engine.get_graph();
|
|
201
|
+
// ā { states: ["responsive", "planning"], transitions: [{from, to, label}], current: "responsive" }
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Effect types
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
type Effect =
|
|
208
|
+
| { type: "goal"; text: string }
|
|
209
|
+
| { type: "guide"; text: string }
|
|
210
|
+
| { type: "teach"; text: string }
|
|
211
|
+
| { type: "request_interact" }
|
|
212
|
+
| { type: "transition"; from: string; to: string }
|
|
213
|
+
| { type: "run_script"; target: string; label: string | null; silent: boolean }
|
|
214
|
+
| { type: "run_subagent"; target: string; label: string | null; background: boolean }
|
|
215
|
+
| { type: "run_tool"; target: string; label: string | null }
|
|
216
|
+
| { type: "set_memory"; domain: string; key: string; value: string | number | boolean | null }
|
|
217
|
+
| { type: "apply_css"; value: string }
|
|
218
|
+
| { type: "remove_css"; value: string }
|
|
219
|
+
| { type: "apply_html"; value: string }
|
|
220
|
+
| { type: "remove_html"; value: string }
|
|
221
|
+
| { type: "apply_video"; value: string }
|
|
222
|
+
| { type: "remove_video"; value: string }
|
|
223
|
+
| { type: "parse_error"; message: string }
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
For the full API reference ā all effect types, handler implementation examples, memory domains, TypeScript types, and a React hook ā see [API.md](API.md).
|
|
227
|
+
|
|
228
|
+
### Dynamic import (Next.js / SSR)
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
import("@dot-agent/kernel-dsl").then(module => {
|
|
232
|
+
const engine = new module.AgentDSLKernel();
|
|
233
|
+
const effects = engine.load_behavior(behaviorText);
|
|
234
|
+
console.log(effects);
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## License
|
|
241
|
+
|
|
242
|
+
Copyright (c) 2026 Danilo Borges (https://github.com/daniloborges)
|
|
243
|
+
|
|
244
|
+
Licensed under the **Apache License, Version 2.0** ā see [`LICENSE`](LICENSE).
|
package/index.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
let _initialized = false;
|
|
2
|
+
let _module = null;
|
|
3
|
+
|
|
4
|
+
// Complete WASI + Rust runtime shim - 31 functions required
|
|
5
|
+
const wasiShim = {
|
|
6
|
+
// WASI file descriptor operations (5)
|
|
7
|
+
fd_write: () => 0,
|
|
8
|
+
fd_close: () => 0,
|
|
9
|
+
fd_seek: () => 0,
|
|
10
|
+
fd_prestat_get: () => 0,
|
|
11
|
+
fd_prestat_dir_name: () => 0,
|
|
12
|
+
|
|
13
|
+
// WASI environment (2)
|
|
14
|
+
environ_get: () => 0,
|
|
15
|
+
environ_sizes_get: () => 0,
|
|
16
|
+
|
|
17
|
+
// WASI time (1)
|
|
18
|
+
clock_time_get: () => 0,
|
|
19
|
+
|
|
20
|
+
// WASI misc (1)
|
|
21
|
+
random_get: () => 0,
|
|
22
|
+
proc_exit: () => 0,
|
|
23
|
+
|
|
24
|
+
// Rust UB Sanitizer handlers (11)
|
|
25
|
+
__ubsan_handle_type_mismatch_v1: () => 0,
|
|
26
|
+
__ubsan_handle_alignment_assumption: () => 0,
|
|
27
|
+
__ubsan_handle_out_of_bounds: () => 0,
|
|
28
|
+
__ubsan_handle_nonnull_arg: () => 0,
|
|
29
|
+
__ubsan_handle_load_invalid_value: () => 0,
|
|
30
|
+
__ubsan_handle_builtin_unreachable: () => 0,
|
|
31
|
+
__ubsan_handle_add_overflow: () => 0,
|
|
32
|
+
__ubsan_handle_sub_overflow: () => 0,
|
|
33
|
+
__ubsan_handle_mul_overflow: () => 0,
|
|
34
|
+
__ubsan_handle_divrem_overflow: () => 0,
|
|
35
|
+
__ubsan_handle_shift_out_of_bounds: () => 0,
|
|
36
|
+
__ubsan_handle_pointer_overflow: () => 0,
|
|
37
|
+
|
|
38
|
+
// wasm-bindgen JS interop (8)
|
|
39
|
+
__wbg_call_9c758de292015997: () => 0,
|
|
40
|
+
__wbg_new_d90091b82fdf5b91: () => 0,
|
|
41
|
+
__wbg_new_ce1ab61c1c2b300d: () => 0,
|
|
42
|
+
__wbg_push_a6822215aa43e71c: () => 0,
|
|
43
|
+
__wbg_set_6be42768c690e380: () => 0,
|
|
44
|
+
__wbg_set_dca99999bba88a9a: () => 0,
|
|
45
|
+
__wbg___wbindgen_throw_1506f2235d1bdba0: () => 0,
|
|
46
|
+
|
|
47
|
+
// wasm-bindgen internal (3)
|
|
48
|
+
__wbindgen_init_externref_table: () => 0,
|
|
49
|
+
__wbindgen_cast_0000000000000001: () => 0,
|
|
50
|
+
__wbindgen_cast_0000000000000002: () => 0,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export class AgentDSLKernel {
|
|
54
|
+
constructor() {
|
|
55
|
+
if (!_initialized) throw new Error('Must call init() first');
|
|
56
|
+
this._kernel = new _module.AgentDSLKernel();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get_current_state() { return this._kernel.get_current_state(); }
|
|
60
|
+
get_graph() { return this._kernel.get_graph(); }
|
|
61
|
+
get_memory() { return this._kernel.get_memory(); }
|
|
62
|
+
get_valid_intents() { return this._kernel.get_valid_intents(); }
|
|
63
|
+
load_behavior(text) { return this._kernel.load_behavior(text); }
|
|
64
|
+
observe(callback) { return this._kernel.observe(callback); }
|
|
65
|
+
send_complete() { return this._kernel.send_complete(); }
|
|
66
|
+
send_event(event) { return this._kernel.send_event(event); }
|
|
67
|
+
send_failed() { return this._kernel.send_failed(); }
|
|
68
|
+
send_fallback() { return this._kernel.send_fallback(); }
|
|
69
|
+
send_intent(intent) { return this._kernel.send_intent(intent); }
|
|
70
|
+
send_offtopic() { return this._kernel.send_offtopic(); }
|
|
71
|
+
tick_prompt() { return this._kernel.tick_prompt(); }
|
|
72
|
+
free() { return this._kernel.free(); }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function init() {
|
|
76
|
+
if (_initialized) return;
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const bgModule = await import('./pkg/dot_agent_kernel_dsl_bg.js');
|
|
80
|
+
|
|
81
|
+
// Load WASM buffer: fetch in browser, fs.readFile in Node.js
|
|
82
|
+
let wasmBuffer;
|
|
83
|
+
if (typeof window !== 'undefined') {
|
|
84
|
+
// Browser environment
|
|
85
|
+
const wasmPath = new URL('./pkg/dot_agent_kernel_dsl_bg.wasm', import.meta.url);
|
|
86
|
+
const wasmResponse = await fetch(wasmPath);
|
|
87
|
+
wasmBuffer = await wasmResponse.arrayBuffer();
|
|
88
|
+
} else {
|
|
89
|
+
// Node.js environment
|
|
90
|
+
const { readFile } = await import('node:fs/promises');
|
|
91
|
+
const { fileURLToPath } = await import('node:url');
|
|
92
|
+
const wasmPath = fileURLToPath(new URL('./pkg/dot_agent_kernel_dsl_bg.wasm', import.meta.url));
|
|
93
|
+
wasmBuffer = await readFile(wasmPath);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const importObject = {
|
|
97
|
+
env: wasiShim,
|
|
98
|
+
wasi_snapshot_preview1: wasiShim,
|
|
99
|
+
'./dot_agent_kernel_dsl_bg.js': { ...bgModule }
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const wasmModule = await WebAssembly.instantiate(wasmBuffer, importObject);
|
|
103
|
+
bgModule.__wbg_set_wasm(wasmModule.instance.exports);
|
|
104
|
+
_module = await import('./pkg/dot_agent_kernel_dsl.js');
|
|
105
|
+
|
|
106
|
+
_initialized = true;
|
|
107
|
+
} catch (err) {
|
|
108
|
+
console.error('Failed to initialize wasm:', err);
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dot-agent/kernel-dsl",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "WASM kernel for parsing and executing the agent behavior DSL",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./index.js",
|
|
7
|
+
"types": "./pkg/dot_agent_kernel_dsl.d.ts",
|
|
8
|
+
"license": "Apache-2.0",
|
|
9
|
+
"author": {
|
|
10
|
+
"name": "Danilo Borges",
|
|
11
|
+
"email": "contato@daniloborg.es",
|
|
12
|
+
"url": "https://daniloborg.es"
|
|
13
|
+
},
|
|
14
|
+
"contributors": [
|
|
15
|
+
{
|
|
16
|
+
"name": "Danilo Borges",
|
|
17
|
+
"email": "contato@daniloborg.es"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"homepage": "https://github.com/dot-agent-spec/kernel-dsl",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/dot-agent-spec/kernel-dsl"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/dot-agent-spec/kernel-dsl/issues"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"wasm",
|
|
30
|
+
"agent",
|
|
31
|
+
"dsl",
|
|
32
|
+
"behavior",
|
|
33
|
+
"fsm",
|
|
34
|
+
"state-machine",
|
|
35
|
+
"parser",
|
|
36
|
+
"webassembly"
|
|
37
|
+
],
|
|
38
|
+
"files": [
|
|
39
|
+
"index.js",
|
|
40
|
+
"scripts/discover-wasm-imports.js",
|
|
41
|
+
"scripts/patch-wasm-bindgen.js",
|
|
42
|
+
"pkg/dot_agent_kernel_dsl.js",
|
|
43
|
+
"pkg/dot_agent_kernel_dsl.d.ts",
|
|
44
|
+
"pkg/dot_agent_kernel_dsl_bg.wasm",
|
|
45
|
+
"pkg/dot_agent_kernel_dsl_bg.wasm.d.ts",
|
|
46
|
+
"pkg/package.json"
|
|
47
|
+
],
|
|
48
|
+
"exports": {
|
|
49
|
+
".": {
|
|
50
|
+
"import": "./index.js",
|
|
51
|
+
"types": "./pkg/dot_agent_kernel_dsl.d.ts"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=16.0.0"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "./scripts/build-wasm.sh && node scripts/patch-wasm-bindgen.js",
|
|
59
|
+
"build:release": "RELEASE=true ./scripts/build-wasm.sh && node scripts/patch-wasm-bindgen.js",
|
|
60
|
+
"patch": "node -e \"const fs=require('fs'),p=require('./pkg/package.json');p.name='@dot-agent/kernel-dsl';p.publishConfig={access:'public'};fs.writeFileSync('./pkg/package.json',JSON.stringify(p,null,2)+'\\n')\"",
|
|
61
|
+
"test:node": "node --test tests/node-compat.test.js",
|
|
62
|
+
"prepublishOnly": "npm run build:release && npm run patch"
|
|
63
|
+
},
|
|
64
|
+
"publishConfig": {
|
|
65
|
+
"access": "public"
|
|
66
|
+
},
|
|
67
|
+
"dependencies": {
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
export class AgentDSLKernel {
|
|
5
|
+
free(): void;
|
|
6
|
+
[Symbol.dispose](): void;
|
|
7
|
+
/**
|
|
8
|
+
* Return the name of the current state.
|
|
9
|
+
*/
|
|
10
|
+
get_current_state(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Return the state graph as { states, transitions, current }.
|
|
13
|
+
*
|
|
14
|
+
* Use this to render the Flow Graph panel in VS Code or any diagram tool.
|
|
15
|
+
*/
|
|
16
|
+
get_graph(): any;
|
|
17
|
+
/**
|
|
18
|
+
* Return the full memory store as a JSON array of { domain, key, value } entries.
|
|
19
|
+
*/
|
|
20
|
+
get_memory(): any;
|
|
21
|
+
/**
|
|
22
|
+
* Return an array of intent strings declared in the current state.
|
|
23
|
+
*
|
|
24
|
+
* Use this to build the list of valid intent names to pass to the LLM classifier.
|
|
25
|
+
*/
|
|
26
|
+
get_valid_intents(): Array<any>;
|
|
27
|
+
/**
|
|
28
|
+
* Parse and load a .behavior DSL text.
|
|
29
|
+
*
|
|
30
|
+
* Fires the observer for each entry effect of the first state (typically goal +
|
|
31
|
+
* request_interact). Also returns the effects array for imperative call sites.
|
|
32
|
+
* On parse error, fires and returns a single ParseError effect.
|
|
33
|
+
*/
|
|
34
|
+
load_behavior(text: string): any;
|
|
35
|
+
constructor();
|
|
36
|
+
/**
|
|
37
|
+
* Register a callback that WASM will call once per Effect as they are produced.
|
|
38
|
+
*
|
|
39
|
+
* This is the primary integration point ā the equivalent of the importObject in a
|
|
40
|
+
* raw WebAssembly.instantiate call. The callback receives a single Effect object
|
|
41
|
+
* per invocation and must implement all WASMāJS directives (goal, guide, teach,
|
|
42
|
+
* run_script, run_subagent, run_tool, apply_css, ā¦).
|
|
43
|
+
*
|
|
44
|
+
* Only one observer can be active at a time; calling observe() again replaces it.
|
|
45
|
+
*/
|
|
46
|
+
observe(callback: Function): void;
|
|
47
|
+
/**
|
|
48
|
+
* Signal that the last async operation (run_script, run_subagent, run_tool) completed successfully.
|
|
49
|
+
*
|
|
50
|
+
* Fires the observer with the effects of the current state's `on complete` block.
|
|
51
|
+
*/
|
|
52
|
+
send_complete(): any;
|
|
53
|
+
/**
|
|
54
|
+
* Signal that the runtime could not resolve the current action.
|
|
55
|
+
* Dispatch a named global event (e.g. "session.ended", "script.done").
|
|
56
|
+
*
|
|
57
|
+
* Matches top-level `on event "ā¦"` declarations. Use this to notify the FSM
|
|
58
|
+
* when an async operation triggered by run_script / run_subagent / run_tool completes.
|
|
59
|
+
*/
|
|
60
|
+
send_event(event: string): any;
|
|
61
|
+
/**
|
|
62
|
+
* Signal that the last async operation (run_script, run_subagent, run_tool) failed.
|
|
63
|
+
*
|
|
64
|
+
* Fires the observer with the effects of the current state's `on failed` block.
|
|
65
|
+
*/
|
|
66
|
+
send_failed(): any;
|
|
67
|
+
/**
|
|
68
|
+
* Dispatch a named intent to the FSM.
|
|
69
|
+
*
|
|
70
|
+
* Call this after the LLM classifies the user's message into an intent name that
|
|
71
|
+
* matches one of the `on intent "ā¦"` declarations in the current state.
|
|
72
|
+
* Fires the observer with transition + any entry effects of the new state.
|
|
73
|
+
*/
|
|
74
|
+
send_intent(intent: string): any;
|
|
75
|
+
/**
|
|
76
|
+
* Signal that the current message is off-topic.
|
|
77
|
+
*
|
|
78
|
+
* Fires the observer with the effects of the current state's `on offtopic` block.
|
|
79
|
+
*/
|
|
80
|
+
send_offtopic(): any;
|
|
81
|
+
/**
|
|
82
|
+
* Set a value in the memory store from JS.
|
|
83
|
+
*
|
|
84
|
+
* domain: "context" | "session" | "worksession" | "user"
|
|
85
|
+
* value_json: value serialized as a JSON primitive ("text", 42, true, null)
|
|
86
|
+
*/
|
|
87
|
+
set_memory(domain: string, key: string, value_json: string): void;
|
|
88
|
+
/**
|
|
89
|
+
* Notify the engine that a prompt turn was processed.
|
|
90
|
+
*
|
|
91
|
+
* Call once per LLM completion. Triggers any matching `after N prompts` handlers
|
|
92
|
+
* in the current state, firing their effects through the observer.
|
|
93
|
+
*/
|
|
94
|
+
tick_prompt(): any;
|
|
95
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const __wbg_agentdslkernel_free: (a: number, b: number) => void;
|
|
5
|
+
export const agentdslkernel_get_current_state: (a: number) => [number, number];
|
|
6
|
+
export const agentdslkernel_get_graph: (a: number) => any;
|
|
7
|
+
export const agentdslkernel_get_memory: (a: number) => any;
|
|
8
|
+
export const agentdslkernel_get_valid_intents: (a: number) => any;
|
|
9
|
+
export const agentdslkernel_load_behavior: (a: number, b: number, c: number) => any;
|
|
10
|
+
export const agentdslkernel_new: () => number;
|
|
11
|
+
export const agentdslkernel_observe: (a: number, b: any) => void;
|
|
12
|
+
export const agentdslkernel_send_complete: (a: number) => any;
|
|
13
|
+
export const agentdslkernel_send_event: (a: number, b: number, c: number) => any;
|
|
14
|
+
export const agentdslkernel_send_failed: (a: number) => any;
|
|
15
|
+
export const agentdslkernel_send_intent: (a: number, b: number, c: number) => any;
|
|
16
|
+
export const agentdslkernel_send_offtopic: (a: number) => any;
|
|
17
|
+
export const agentdslkernel_set_memory: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
18
|
+
export const agentdslkernel_tick_prompt: (a: number) => any;
|
|
19
|
+
export const __wbindgen_exn_store_command_export: (a: number) => void;
|
|
20
|
+
export const __externref_table_alloc_command_export: () => number;
|
|
21
|
+
export const __wbindgen_externrefs: WebAssembly.Table;
|
|
22
|
+
export const __wbindgen_free_command_export: (a: number, b: number, c: number) => void;
|
|
23
|
+
export const __wbindgen_malloc_command_export: (a: number, b: number) => number;
|
|
24
|
+
export const __wbindgen_realloc_command_export: (a: number, b: number, c: number, d: number) => number;
|
|
25
|
+
export const __wbindgen_start: () => void;
|
package/pkg/index.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
let _initialized = false;
|
|
2
|
+
let _module = null;
|
|
3
|
+
|
|
4
|
+
// Complete WASI + Rust runtime shim - 31 functions required
|
|
5
|
+
const wasiShim = {
|
|
6
|
+
// WASI file descriptor operations (5)
|
|
7
|
+
fd_write: () => 0,
|
|
8
|
+
fd_close: () => 0,
|
|
9
|
+
fd_seek: () => 0,
|
|
10
|
+
fd_prestat_get: () => 0,
|
|
11
|
+
fd_prestat_dir_name: () => 0,
|
|
12
|
+
|
|
13
|
+
// WASI environment (2)
|
|
14
|
+
environ_get: () => 0,
|
|
15
|
+
environ_sizes_get: () => 0,
|
|
16
|
+
|
|
17
|
+
// WASI time (1)
|
|
18
|
+
clock_time_get: () => 0,
|
|
19
|
+
|
|
20
|
+
// WASI misc (1)
|
|
21
|
+
random_get: () => 0,
|
|
22
|
+
proc_exit: () => 0,
|
|
23
|
+
|
|
24
|
+
// Rust UB Sanitizer handlers (11)
|
|
25
|
+
__ubsan_handle_type_mismatch_v1: () => 0,
|
|
26
|
+
__ubsan_handle_alignment_assumption: () => 0,
|
|
27
|
+
__ubsan_handle_out_of_bounds: () => 0,
|
|
28
|
+
__ubsan_handle_nonnull_arg: () => 0,
|
|
29
|
+
__ubsan_handle_load_invalid_value: () => 0,
|
|
30
|
+
__ubsan_handle_builtin_unreachable: () => 0,
|
|
31
|
+
__ubsan_handle_add_overflow: () => 0,
|
|
32
|
+
__ubsan_handle_sub_overflow: () => 0,
|
|
33
|
+
__ubsan_handle_mul_overflow: () => 0,
|
|
34
|
+
__ubsan_handle_divrem_overflow: () => 0,
|
|
35
|
+
__ubsan_handle_shift_out_of_bounds: () => 0,
|
|
36
|
+
__ubsan_handle_pointer_overflow: () => 0,
|
|
37
|
+
|
|
38
|
+
// wasm-bindgen JS interop (8)
|
|
39
|
+
__wbg_call_9c758de292015997: () => 0,
|
|
40
|
+
__wbg_new_d90091b82fdf5b91: () => 0,
|
|
41
|
+
__wbg_new_ce1ab61c1c2b300d: () => 0,
|
|
42
|
+
__wbg_push_a6822215aa43e71c: () => 0,
|
|
43
|
+
__wbg_set_6be42768c690e380: () => 0,
|
|
44
|
+
__wbg_set_dca99999bba88a9a: () => 0,
|
|
45
|
+
__wbg___wbindgen_throw_1506f2235d1bdba0: () => 0,
|
|
46
|
+
|
|
47
|
+
// wasm-bindgen internal (3)
|
|
48
|
+
__wbindgen_init_externref_table: () => 0,
|
|
49
|
+
__wbindgen_cast_0000000000000001: () => 0,
|
|
50
|
+
__wbindgen_cast_0000000000000002: () => 0,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export class AgentDSLKernel {
|
|
54
|
+
constructor() {
|
|
55
|
+
if (!_initialized) throw new Error('Must call init() first');
|
|
56
|
+
this._kernel = new _module.AgentDSLKernel();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get_current_state() { return this._kernel.get_current_state(); }
|
|
60
|
+
get_graph() { return this._kernel.get_graph(); }
|
|
61
|
+
get_memory() { return this._kernel.get_memory(); }
|
|
62
|
+
get_valid_intents() { return this._kernel.get_valid_intents(); }
|
|
63
|
+
load_behavior(text) { return this._kernel.load_behavior(text); }
|
|
64
|
+
observe(callback) { return this._kernel.observe(callback); }
|
|
65
|
+
send_complete() { return this._kernel.send_complete(); }
|
|
66
|
+
send_event(event) { return this._kernel.send_event(event); }
|
|
67
|
+
send_failed() { return this._kernel.send_failed(); }
|
|
68
|
+
send_fallback() { return this._kernel.send_fallback(); }
|
|
69
|
+
send_intent(intent) { return this._kernel.send_intent(intent); }
|
|
70
|
+
send_offtopic() { return this._kernel.send_offtopic(); }
|
|
71
|
+
tick_prompt() { return this._kernel.tick_prompt(); }
|
|
72
|
+
free() { return this._kernel.free(); }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function init() {
|
|
76
|
+
if (_initialized) return;
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const bgModule = await import('./pkg/dot_agent_kernel_dsl_bg.js');
|
|
80
|
+
const wasmPath = new URL('./pkg/dot_agent_kernel_dsl_bg.wasm', import.meta.url);
|
|
81
|
+
const wasmResponse = await fetch(wasmPath);
|
|
82
|
+
const wasmBuffer = await wasmResponse.arrayBuffer();
|
|
83
|
+
|
|
84
|
+
const importObject = {
|
|
85
|
+
env: wasiShim,
|
|
86
|
+
wasi_snapshot_preview1: wasiShim,
|
|
87
|
+
'./dot_agent_kernel_dsl_bg.js': { ...bgModule }
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const wasmModule = await WebAssembly.instantiate(wasmBuffer, importObject);
|
|
91
|
+
bgModule.__wbg_set_wasm(wasmModule.instance.exports);
|
|
92
|
+
_module = await import('./pkg/dot_agent_kernel_dsl.js');
|
|
93
|
+
|
|
94
|
+
_initialized = true;
|
|
95
|
+
} catch (err) {
|
|
96
|
+
console.error('Failed to initialize wasm:', err);
|
|
97
|
+
throw err;
|
|
98
|
+
}
|
|
99
|
+
}
|
package/pkg/package.json
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* WASM Import Discovery Tool
|
|
4
|
+
*
|
|
5
|
+
* Discovers all functions required by the kernel-dsl WASM binary
|
|
6
|
+
* by attempting instantiation with a Proxy that tracks all accesses.
|
|
7
|
+
*
|
|
8
|
+
* Usage: node scripts/discover-wasm-imports.js
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import { fileURLToPath } from 'url';
|
|
14
|
+
|
|
15
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
|
|
17
|
+
const accessedFunctions = new Set();
|
|
18
|
+
const functionCallCounts = new Map();
|
|
19
|
+
|
|
20
|
+
// Create proxy to track all accessed functions
|
|
21
|
+
const handler = {
|
|
22
|
+
get: (target, prop) => {
|
|
23
|
+
if (typeof prop === 'string') {
|
|
24
|
+
accessedFunctions.add(prop);
|
|
25
|
+
functionCallCounts.set(prop, (functionCallCounts.get(prop) || 0) + 1);
|
|
26
|
+
}
|
|
27
|
+
return (...args) => 0;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const wasiShimProxy = new Proxy({}, handler);
|
|
32
|
+
|
|
33
|
+
async function discoverImports() {
|
|
34
|
+
try {
|
|
35
|
+
const wasmPath = path.join(__dirname, '../pkg/dot_agent_kernel_dsl_bg.wasm');
|
|
36
|
+
|
|
37
|
+
if (!fs.existsSync(wasmPath)) {
|
|
38
|
+
console.error(`ā WASM file not found: ${wasmPath}`);
|
|
39
|
+
console.error('Run: npm run build');
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const wasmBuffer = fs.readFileSync(wasmPath);
|
|
44
|
+
|
|
45
|
+
// Try to instantiate with proxy that captures all accesses
|
|
46
|
+
const importObject = {
|
|
47
|
+
env: wasiShimProxy,
|
|
48
|
+
wasi_snapshot_preview1: wasiShimProxy,
|
|
49
|
+
'./dot_agent_kernel_dsl_bg.js': wasiShimProxy
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
await WebAssembly.instantiate(wasmBuffer, importObject);
|
|
54
|
+
} catch (e) {
|
|
55
|
+
// Expected to fail, but we've captured the function accesses
|
|
56
|
+
console.log('ā¹ļø WASM instantiation attempt complete (may have failed, but functions were captured)');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error('Error during discovery:', err.message);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Report findings
|
|
65
|
+
console.log('\nš DISCOVERED FUNCTIONS:\n');
|
|
66
|
+
|
|
67
|
+
const sorted = Array.from(accessedFunctions).sort();
|
|
68
|
+
|
|
69
|
+
console.log(`Total unique functions accessed: ${sorted.length}\n`);
|
|
70
|
+
|
|
71
|
+
// Group by category
|
|
72
|
+
const groups = {
|
|
73
|
+
'WASI (fd_*)': [],
|
|
74
|
+
'WASI (environ_*)': [],
|
|
75
|
+
'WASI (args_*)': [],
|
|
76
|
+
'WASI (clock/sched)': [],
|
|
77
|
+
'UBSAN (__ubsan_*)': [],
|
|
78
|
+
'wasm-bindgen (__wbg_*)': [],
|
|
79
|
+
'wasm-bindgen internal (__wbindgen_*)': [],
|
|
80
|
+
'Other': []
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
sorted.forEach(fn => {
|
|
84
|
+
if (fn.startsWith('fd_')) groups['WASI (fd_*)'].push(fn);
|
|
85
|
+
else if (fn.startsWith('environ_')) groups['WASI (environ_*)'].push(fn);
|
|
86
|
+
else if (fn.startsWith('args_')) groups['WASI (args_*)'].push(fn);
|
|
87
|
+
else if (fn.match(/^(clock|sched)/)) groups['WASI (clock/sched)'].push(fn);
|
|
88
|
+
else if (fn.startsWith('__ubsan_')) groups['UBSAN (__ubsan_*)'].push(fn);
|
|
89
|
+
else if (fn.startsWith('__wbg_') && !fn.startsWith('__wbindgen_')) groups['wasm-bindgen (__wbg_*)'].push(fn);
|
|
90
|
+
else if (fn.startsWith('__wbindgen_')) groups['wasm-bindgen internal (__wbindgen_*)'].push(fn);
|
|
91
|
+
else groups['Other'].push(fn);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
Object.entries(groups).forEach(([category, fns]) => {
|
|
95
|
+
if (fns.length > 0) {
|
|
96
|
+
console.log(`\n${category}:`);
|
|
97
|
+
fns.forEach(fn => {
|
|
98
|
+
const count = functionCallCounts.get(fn);
|
|
99
|
+
console.log(` ${fn}: ${count} ${count === 1 ? 'call' : 'calls'}`);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Generate JavaScript code
|
|
105
|
+
console.log('\n\nš GENERATED CODE FOR SHIM:\n');
|
|
106
|
+
console.log('const wasiShim = {');
|
|
107
|
+
sorted.forEach(fn => {
|
|
108
|
+
console.log(` ${fn}: () => 0,`);
|
|
109
|
+
});
|
|
110
|
+
console.log('};');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
discoverImports();
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const filePath = path.join(__dirname, '../pkg/dot_agent_kernel_dsl.js');
|
|
8
|
+
|
|
9
|
+
console.log('š Patching WASM-bindgen output...');
|
|
10
|
+
|
|
11
|
+
if (!fs.existsSync(filePath)) {
|
|
12
|
+
console.warn(`ā ļø File not found: ${filePath}`);
|
|
13
|
+
process.exit(0);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let content = fs.readFileSync(filePath, 'utf-8');
|
|
17
|
+
|
|
18
|
+
// Check if already patched
|
|
19
|
+
if (content.includes('MODIFIED: WASM is loaded manually')) {
|
|
20
|
+
console.log('ā
Already patched');
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Remove the problematic import lines that cause webpack parse errors
|
|
25
|
+
content = content
|
|
26
|
+
.replace(/import \* as wasm from ["']\.\/dot_agent_kernel_dsl_bg\.wasm["'];?\n/g, '')
|
|
27
|
+
.replace(/import { __wbg_set_wasm } from ["']\.\/dot_agent_kernel_dsl_bg\.js["'];?\n/g, '')
|
|
28
|
+
.replace(/^__wbg_set_wasm\(wasm\);\n/m, '')
|
|
29
|
+
.replace(/^wasm\.__wbindgen_start\(\);\n/m, '');
|
|
30
|
+
|
|
31
|
+
// Add comment explaining the change
|
|
32
|
+
if (!content.includes('MODIFIED:')) {
|
|
33
|
+
content = content.replace(
|
|
34
|
+
/\/\* @ts-self-types=/,
|
|
35
|
+
'/* @ts-self-types'
|
|
36
|
+
);
|
|
37
|
+
const tsLine = content.match(/\/\* @ts-self-types[^\n]*\n/)[0];
|
|
38
|
+
content = content.replace(
|
|
39
|
+
tsLine,
|
|
40
|
+
tsLine + '/* MODIFIED: WASM is loaded manually by index.js to avoid webpack parse errors */\n'
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
45
|
+
console.log('ā
Patched successfully');
|