@allternit/ix 0.1.0 → 0.1.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/README.md +6 -6
- package/dist/adapters/json-render.d.ts +5 -5
- package/dist/adapters/json-render.js +12 -12
- package/dist/collab/visual-editor.d.ts +1 -1
- package/dist/collab/visual-editor.js +4 -4
- package/dist/collab/visual-editor.js.map +1 -1
- package/dist/collab/yjs-adapter.d.ts +1 -1
- package/dist/collab/yjs-adapter.js +2 -2
- package/dist/collab/yjs-adapter.js.map +1 -1
- package/dist/collab/yjs-client.js +1 -1
- package/dist/collab/yjs-client.js.map +1 -1
- package/dist/collab/yjs-types.js +1 -1
- package/dist/collab/yjs-types.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/pipeline/llm-to-ix.d.ts +5 -5
- package/dist/pipeline/llm-to-ix.d.ts.map +1 -1
- package/dist/pipeline/llm-to-ix.js +6 -6
- package/dist/react/renderer.d.ts +2 -2
- package/dist/react/renderer.js +3 -3
- package/dist/react/renderer.js.map +1 -1
- package/dist/renderer/renderer.d.ts +1 -1
- package/dist/renderer/renderer.js +1 -1
- package/dist/runtime/capsule-runtime.d.ts +1 -1
- package/dist/runtime/capsule-runtime.js +1 -1
- package/dist/sdk/api.d.ts +3 -3
- package/dist/sdk/api.js +3 -3
- package/dist/sdk/index.d.ts +2 -2
- package/dist/sdk/index.js +2 -2
- package/dist/sdk/react.d.ts +2 -2
- package/dist/sdk/react.js +2 -2
- package/dist/state/index.d.ts +1 -1
- package/dist/state/index.js +1 -1
- package/dist/state/store.d.ts +1 -1
- package/dist/state/store.js +3 -3
- package/dist/state/store.js.map +1 -1
- package/dist/svelte/index.d.ts +1 -1
- package/dist/svelte/index.js +1 -1
- package/dist/svelte/renderer.d.ts +3 -3
- package/dist/svelte/renderer.js +4 -4
- package/dist/svelte/renderer.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js +1 -1
- package/dist/vue/renderer.d.ts +3 -3
- package/dist/vue/renderer.js +5 -5
- package/dist/vue/renderer.js.map +1 -1
- package/package.json +8 -8
- package/dist/adapters/json-render.d.ts.bak +0 -211
- package/dist/adapters/json-render.js.bak +0 -576
- package/dist/catalog/registry.d.ts.bak +0 -65
- package/dist/catalog/registry.js.bak +0 -388
- package/dist/collab/capsule-registry.d.ts.bak +0 -114
- package/dist/collab/capsule-registry.js.bak +0 -271
- package/dist/collab/index.d.ts.bak +0 -21
- package/dist/collab/index.js.bak +0 -32
- package/dist/collab/visual-editor.d.ts.bak +0 -199
- package/dist/collab/visual-editor.js.bak +0 -259
- package/dist/collab/yjs-adapter.d.ts.bak +0 -95
- package/dist/collab/yjs-adapter.js.bak +0 -282
- package/dist/collab/yjs-client.d.ts.bak +0 -101
- package/dist/collab/yjs-client.js.bak +0 -193
- package/dist/collab/yjs-protocols.d.ts.bak +0 -128
- package/dist/collab/yjs-protocols.js.bak +0 -245
- package/dist/collab/yjs-types.d.ts.bak +0 -201
- package/dist/collab/yjs-types.js.bak +0 -45
- package/dist/index.d.ts.bak +0 -38
- package/dist/index.js.bak +0 -48
- package/dist/pipeline/llm-to-ix.d.ts.bak +0 -249
- package/dist/pipeline/llm-to-ix.js.bak +0 -992
- package/dist/react/index.d.ts.bak +0 -18
- package/dist/react/index.js.bak +0 -18
- package/dist/react/renderer.d.ts.bak +0 -47
- package/dist/react/renderer.js.bak +0 -420
- package/dist/renderer/renderer.d.ts.bak +0 -55
- package/dist/renderer/renderer.js.bak +0 -232
- package/dist/runtime/capsule-runtime.d.ts.bak +0 -227
- package/dist/runtime/capsule-runtime.js.bak +0 -563
- package/dist/runtime/policy-gates.d.ts.bak +0 -116
- package/dist/runtime/policy-gates.js.bak +0 -317
- package/dist/schema/ui-ir.d.ts.bak +0 -26
- package/dist/schema/ui-ir.js.bak +0 -51
- package/dist/sdk/api.d.ts.bak +0 -101
- package/dist/sdk/api.js.bak +0 -177
- package/dist/sdk/index.d.ts.bak +0 -9
- package/dist/sdk/index.js.bak +0 -10
- package/dist/sdk/react.d.ts.bak +0 -63
- package/dist/sdk/react.js.bak +0 -161
- package/dist/state/index.d.ts.bak +0 -8
- package/dist/state/index.js.bak +0 -8
- package/dist/state/patch.d.ts.bak +0 -73
- package/dist/state/patch.js.bak +0 -437
- package/dist/state/store.d.ts.bak +0 -50
- package/dist/state/store.js.bak +0 -246
- package/dist/svelte/index.d.ts.bak +0 -15
- package/dist/svelte/index.js.bak +0 -15
- package/dist/svelte/renderer.d.ts.bak +0 -35
- package/dist/svelte/renderer.js.bak +0 -317
- package/dist/types/index.d.ts.bak +0 -349
- package/dist/types/index.js.bak +0 -152
- package/dist/vue/index.d.ts.bak +0 -18
- package/dist/vue/index.js.bak +0 -18
- package/dist/vue/renderer.d.ts.bak +0 -46
- package/dist/vue/renderer.js.bak +0 -302
|
@@ -1,563 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* IX Capsule Runtime
|
|
3
|
-
*
|
|
4
|
-
* Integration with P3.9 MCP Apps capsule infrastructure for sandboxed
|
|
5
|
-
* execution of A2R-IX UI capsules.
|
|
6
|
-
*/
|
|
7
|
-
import { applyPatchToStore } from '../state/patch';
|
|
8
|
-
/**
|
|
9
|
-
* GAP-63: System metrics collector using Node.js APIs
|
|
10
|
-
*/
|
|
11
|
-
class MetricsCollector {
|
|
12
|
-
startUsage = null;
|
|
13
|
-
startTime;
|
|
14
|
-
networkStats = {
|
|
15
|
-
requestCount: 0,
|
|
16
|
-
successCount: 0,
|
|
17
|
-
errorCount: 0,
|
|
18
|
-
bytesSent: 0,
|
|
19
|
-
bytesReceived: 0,
|
|
20
|
-
responseTimes: [],
|
|
21
|
-
};
|
|
22
|
-
constructor() {
|
|
23
|
-
this.startTime = Date.now();
|
|
24
|
-
// Capture initial CPU usage if available (Node.js environment)
|
|
25
|
-
if (typeof process !== 'undefined' && process.cpuUsage) {
|
|
26
|
-
this.startUsage = process.cpuUsage();
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Collect current CPU metrics
|
|
31
|
-
*/
|
|
32
|
-
collectCPU() {
|
|
33
|
-
if (typeof process === 'undefined' || !process.cpuUsage) {
|
|
34
|
-
return {
|
|
35
|
-
userTime: 0,
|
|
36
|
-
systemTime: 0,
|
|
37
|
-
totalTime: 0,
|
|
38
|
-
usagePercent: 0,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
const currentUsage = process.cpuUsage(this.startUsage || undefined);
|
|
42
|
-
const userTime = currentUsage.user / 1000; // Convert microseconds to milliseconds
|
|
43
|
-
const systemTime = currentUsage.system / 1000;
|
|
44
|
-
const totalTime = userTime + systemTime;
|
|
45
|
-
// Calculate percentage based on elapsed time
|
|
46
|
-
const elapsedMs = Date.now() - this.startTime;
|
|
47
|
-
const usagePercent = elapsedMs > 0 ? (totalTime / elapsedMs) * 100 : 0;
|
|
48
|
-
return {
|
|
49
|
-
userTime,
|
|
50
|
-
systemTime,
|
|
51
|
-
totalTime,
|
|
52
|
-
usagePercent: Math.min(usagePercent, 100), // Cap at 100%
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Collect current memory metrics
|
|
57
|
-
*/
|
|
58
|
-
collectMemory() {
|
|
59
|
-
if (typeof process === 'undefined' || !process.memoryUsage) {
|
|
60
|
-
return {
|
|
61
|
-
heapUsed: 0,
|
|
62
|
-
heapTotal: 0,
|
|
63
|
-
external: 0,
|
|
64
|
-
rss: 0,
|
|
65
|
-
arrayBuffers: 0,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
const usage = process.memoryUsage();
|
|
69
|
-
return {
|
|
70
|
-
heapUsed: usage.heapUsed,
|
|
71
|
-
heapTotal: usage.heapTotal,
|
|
72
|
-
external: usage.external || 0,
|
|
73
|
-
rss: usage.rss,
|
|
74
|
-
arrayBuffers: usage.arrayBuffers || 0,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Record a network request
|
|
79
|
-
*/
|
|
80
|
-
recordRequest(bytesSent) {
|
|
81
|
-
this.networkStats.requestCount++;
|
|
82
|
-
this.networkStats.bytesSent += bytesSent;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Record a successful response
|
|
86
|
-
*/
|
|
87
|
-
recordResponse(bytesReceived, responseTime) {
|
|
88
|
-
this.networkStats.successCount++;
|
|
89
|
-
this.networkStats.bytesReceived += bytesReceived;
|
|
90
|
-
this.networkStats.responseTimes.push(responseTime);
|
|
91
|
-
// Keep only last 100 response times for average calculation
|
|
92
|
-
if (this.networkStats.responseTimes.length > 100) {
|
|
93
|
-
this.networkStats.responseTimes.shift();
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Record a network error
|
|
98
|
-
*/
|
|
99
|
-
recordNetworkError() {
|
|
100
|
-
this.networkStats.errorCount++;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Collect network metrics
|
|
104
|
-
*/
|
|
105
|
-
collectNetwork() {
|
|
106
|
-
const avgResponseTime = this.networkStats.responseTimes.length > 0
|
|
107
|
-
? this.networkStats.responseTimes.reduce((a, b) => a + b, 0) / this.networkStats.responseTimes.length
|
|
108
|
-
: 0;
|
|
109
|
-
return {
|
|
110
|
-
requestCount: this.networkStats.requestCount,
|
|
111
|
-
successCount: this.networkStats.successCount,
|
|
112
|
-
errorCount: this.networkStats.errorCount,
|
|
113
|
-
bytesSent: this.networkStats.bytesSent,
|
|
114
|
-
bytesReceived: this.networkStats.bytesReceived,
|
|
115
|
-
avgResponseTime,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Get average response time
|
|
120
|
-
*/
|
|
121
|
-
getAverageResponseTime() {
|
|
122
|
-
if (this.networkStats.responseTimes.length === 0)
|
|
123
|
-
return 0;
|
|
124
|
-
return this.networkStats.responseTimes.reduce((a, b) => a + b, 0) / this.networkStats.responseTimes.length;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Create IX Capsule
|
|
129
|
-
*/
|
|
130
|
-
export function createIXCapsule(config) {
|
|
131
|
-
let active = true;
|
|
132
|
-
let currentUI = config.ui;
|
|
133
|
-
const stateStore = config.stateStore;
|
|
134
|
-
const subscribers = new Set();
|
|
135
|
-
const metricsCollector = new MetricsCollector();
|
|
136
|
-
const metrics = {
|
|
137
|
-
renderCount: 0,
|
|
138
|
-
actionCount: 0,
|
|
139
|
-
stateUpdateCount: 0,
|
|
140
|
-
errorCount: 0,
|
|
141
|
-
startTime: Date.now(),
|
|
142
|
-
lastActivity: Date.now(),
|
|
143
|
-
};
|
|
144
|
-
/**
|
|
145
|
-
* Emit event to subscribers
|
|
146
|
-
*/
|
|
147
|
-
function emit(event) {
|
|
148
|
-
if (!active)
|
|
149
|
-
return;
|
|
150
|
-
metrics.lastActivity = Date.now();
|
|
151
|
-
subscribers.forEach((cb) => {
|
|
152
|
-
try {
|
|
153
|
-
cb(event);
|
|
154
|
-
}
|
|
155
|
-
catch (error) {
|
|
156
|
-
console.error('IX Capsule subscriber error:', error);
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
config.onEvent?.(event);
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Check policy gates
|
|
163
|
-
*/
|
|
164
|
-
async function checkPolicies(type, context) {
|
|
165
|
-
if (!config.policyGates || config.policyGates.length === 0) {
|
|
166
|
-
return { allowed: true };
|
|
167
|
-
}
|
|
168
|
-
const fullContext = { ...context, timestamp: Date.now() };
|
|
169
|
-
for (const gate of config.policyGates) {
|
|
170
|
-
const result = await gate.check(type, fullContext);
|
|
171
|
-
if (!result.allowed) {
|
|
172
|
-
return result;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
return { allowed: true };
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Get current UI
|
|
179
|
-
*/
|
|
180
|
-
function getUI() {
|
|
181
|
-
return currentUI;
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Update UI definition
|
|
185
|
-
*/
|
|
186
|
-
function updateUI(ui) {
|
|
187
|
-
if (!active) {
|
|
188
|
-
throw new Error(`Capsule ${config.id} is not active`);
|
|
189
|
-
}
|
|
190
|
-
currentUI = ui;
|
|
191
|
-
metrics.renderCount++;
|
|
192
|
-
emit({
|
|
193
|
-
type: 'lifecycle',
|
|
194
|
-
capsuleId: config.id,
|
|
195
|
-
lifecycle: 'update',
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Apply state patch
|
|
200
|
-
*/
|
|
201
|
-
function applyPatch(patch) {
|
|
202
|
-
if (!active)
|
|
203
|
-
return;
|
|
204
|
-
const result = applyPatchToStore(stateStore, patch);
|
|
205
|
-
if (result.success) {
|
|
206
|
-
metrics.stateUpdateCount++;
|
|
207
|
-
// Emit state change events for affected paths
|
|
208
|
-
patch.forEach((op) => {
|
|
209
|
-
if (op.op !== 'test' && op.op !== 'remove') {
|
|
210
|
-
const path = op.path.slice(1).replace(/\//g, '.');
|
|
211
|
-
const value = stateStore.get(path);
|
|
212
|
-
emit({
|
|
213
|
-
type: 'state-change',
|
|
214
|
-
capsuleId: config.id,
|
|
215
|
-
path,
|
|
216
|
-
value,
|
|
217
|
-
});
|
|
218
|
-
config.onStateChange?.(path, value);
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
metrics.errorCount++;
|
|
224
|
-
emit({
|
|
225
|
-
type: 'error',
|
|
226
|
-
capsuleId: config.id,
|
|
227
|
-
error: new Error(result.error || 'Patch failed'),
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Get state value
|
|
233
|
-
*/
|
|
234
|
-
function getState(path) {
|
|
235
|
-
return stateStore.get(path);
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Set state value
|
|
239
|
-
*/
|
|
240
|
-
function setState(path, value) {
|
|
241
|
-
if (!active)
|
|
242
|
-
return;
|
|
243
|
-
stateStore.set(path, value);
|
|
244
|
-
metrics.stateUpdateCount++;
|
|
245
|
-
emit({
|
|
246
|
-
type: 'state-change',
|
|
247
|
-
capsuleId: config.id,
|
|
248
|
-
path,
|
|
249
|
-
value,
|
|
250
|
-
});
|
|
251
|
-
config.onStateChange?.(path, value);
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Dispatch action with policy checking
|
|
255
|
-
*/
|
|
256
|
-
async function dispatch(actionId, params) {
|
|
257
|
-
if (!active) {
|
|
258
|
-
throw new Error(`Capsule ${config.id} is not active`);
|
|
259
|
-
}
|
|
260
|
-
// Find action definition
|
|
261
|
-
const action = currentUI.actions.find((a) => a.id === actionId);
|
|
262
|
-
if (!action) {
|
|
263
|
-
const error = new Error(`Action not found: ${actionId}`);
|
|
264
|
-
emit({
|
|
265
|
-
type: 'error',
|
|
266
|
-
capsuleId: config.id,
|
|
267
|
-
error,
|
|
268
|
-
});
|
|
269
|
-
throw error;
|
|
270
|
-
}
|
|
271
|
-
// Check policies
|
|
272
|
-
const policyResult = await checkPolicies('action', {
|
|
273
|
-
capsuleId: config.id,
|
|
274
|
-
actionId,
|
|
275
|
-
params,
|
|
276
|
-
state: stateStore.snapshot(),
|
|
277
|
-
});
|
|
278
|
-
if (!policyResult.allowed) {
|
|
279
|
-
emit({
|
|
280
|
-
type: 'error',
|
|
281
|
-
capsuleId: config.id,
|
|
282
|
-
error: new Error(`Policy denied: ${policyResult.reason}`),
|
|
283
|
-
});
|
|
284
|
-
return false;
|
|
285
|
-
}
|
|
286
|
-
metrics.actionCount++;
|
|
287
|
-
emit({
|
|
288
|
-
type: 'action',
|
|
289
|
-
capsuleId: config.id,
|
|
290
|
-
action: actionId,
|
|
291
|
-
params,
|
|
292
|
-
});
|
|
293
|
-
return true;
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Subscribe to events
|
|
297
|
-
*/
|
|
298
|
-
function subscribe(callback) {
|
|
299
|
-
subscribers.add(callback);
|
|
300
|
-
return () => {
|
|
301
|
-
subscribers.delete(callback);
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
/**
|
|
305
|
-
* Destroy capsule
|
|
306
|
-
*/
|
|
307
|
-
function destroy() {
|
|
308
|
-
if (!active)
|
|
309
|
-
return;
|
|
310
|
-
// Emit unmount event before marking inactive
|
|
311
|
-
emit({
|
|
312
|
-
type: 'lifecycle',
|
|
313
|
-
capsuleId: config.id,
|
|
314
|
-
lifecycle: 'unmount',
|
|
315
|
-
});
|
|
316
|
-
active = false;
|
|
317
|
-
subscribers.clear();
|
|
318
|
-
config.onDestroy?.();
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Check if active
|
|
322
|
-
*/
|
|
323
|
-
function isActive() {
|
|
324
|
-
return active;
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* GAP-62: Get capsule metrics
|
|
328
|
-
* Returns comprehensive metrics including CPU, memory, and network stats
|
|
329
|
-
*/
|
|
330
|
-
function getMetrics() {
|
|
331
|
-
const now = Date.now();
|
|
332
|
-
return {
|
|
333
|
-
renderCount: metrics.renderCount,
|
|
334
|
-
actionCount: metrics.actionCount,
|
|
335
|
-
stateUpdateCount: metrics.stateUpdateCount,
|
|
336
|
-
errorCount: metrics.errorCount,
|
|
337
|
-
startTime: metrics.startTime,
|
|
338
|
-
lastActivity: metrics.lastActivity,
|
|
339
|
-
uptime: now - metrics.startTime,
|
|
340
|
-
// GAP-63: Collect system metrics
|
|
341
|
-
cpu: metricsCollector.collectCPU(),
|
|
342
|
-
memory: metricsCollector.collectMemory(),
|
|
343
|
-
network: metricsCollector.collectNetwork(),
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
// Initialize
|
|
347
|
-
emit({
|
|
348
|
-
type: 'lifecycle',
|
|
349
|
-
capsuleId: config.id,
|
|
350
|
-
lifecycle: 'mount',
|
|
351
|
-
});
|
|
352
|
-
return {
|
|
353
|
-
id: config.id,
|
|
354
|
-
getUI,
|
|
355
|
-
updateUI,
|
|
356
|
-
applyPatch,
|
|
357
|
-
getState,
|
|
358
|
-
setState,
|
|
359
|
-
dispatch,
|
|
360
|
-
subscribe,
|
|
361
|
-
destroy,
|
|
362
|
-
isActive,
|
|
363
|
-
getMetrics,
|
|
364
|
-
};
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* IX Capsule Registry
|
|
368
|
-
*/
|
|
369
|
-
export class IXCapsuleRegistry {
|
|
370
|
-
capsules = new Map();
|
|
371
|
-
defaultPolicyGates = [];
|
|
372
|
-
/**
|
|
373
|
-
* Set default policy gates for all capsules
|
|
374
|
-
*/
|
|
375
|
-
setDefaultPolicyGates(gates) {
|
|
376
|
-
this.defaultPolicyGates = gates;
|
|
377
|
-
}
|
|
378
|
-
/**
|
|
379
|
-
* Create and register capsule
|
|
380
|
-
*/
|
|
381
|
-
create(config) {
|
|
382
|
-
const capsule = createIXCapsule({
|
|
383
|
-
...config,
|
|
384
|
-
policyGates: config.policyGates ?? this.defaultPolicyGates,
|
|
385
|
-
});
|
|
386
|
-
this.capsules.set(config.id, capsule);
|
|
387
|
-
return capsule;
|
|
388
|
-
}
|
|
389
|
-
/**
|
|
390
|
-
* Get capsule by ID
|
|
391
|
-
*/
|
|
392
|
-
get(id) {
|
|
393
|
-
return this.capsules.get(id);
|
|
394
|
-
}
|
|
395
|
-
/**
|
|
396
|
-
* Check if capsule exists
|
|
397
|
-
*/
|
|
398
|
-
has(id) {
|
|
399
|
-
return this.capsules.has(id);
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* Remove capsule
|
|
403
|
-
*/
|
|
404
|
-
remove(id) {
|
|
405
|
-
const capsule = this.capsules.get(id);
|
|
406
|
-
if (capsule) {
|
|
407
|
-
capsule.destroy();
|
|
408
|
-
this.capsules.delete(id);
|
|
409
|
-
return true;
|
|
410
|
-
}
|
|
411
|
-
return false;
|
|
412
|
-
}
|
|
413
|
-
/**
|
|
414
|
-
* List all capsules
|
|
415
|
-
*/
|
|
416
|
-
list() {
|
|
417
|
-
return Array.from(this.capsules.values());
|
|
418
|
-
}
|
|
419
|
-
/**
|
|
420
|
-
* Get active capsules
|
|
421
|
-
*/
|
|
422
|
-
getActive() {
|
|
423
|
-
return this.list().filter((c) => c.isActive());
|
|
424
|
-
}
|
|
425
|
-
/**
|
|
426
|
-
* Broadcast patch to all capsules
|
|
427
|
-
*/
|
|
428
|
-
broadcastPatch(patch) {
|
|
429
|
-
this.capsules.forEach((capsule) => {
|
|
430
|
-
capsule.applyPatch(patch);
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
/**
|
|
434
|
-
* Destroy all capsules
|
|
435
|
-
*/
|
|
436
|
-
clear() {
|
|
437
|
-
this.capsules.forEach((capsule) => capsule.destroy());
|
|
438
|
-
this.capsules.clear();
|
|
439
|
-
}
|
|
440
|
-
/**
|
|
441
|
-
* GAP-62/64: Get metrics for all capsules
|
|
442
|
-
* Returns aggregated metrics for all registered capsules
|
|
443
|
-
*/
|
|
444
|
-
getMetrics() {
|
|
445
|
-
const metrics = {};
|
|
446
|
-
for (const [id, capsule] of this.capsules) {
|
|
447
|
-
if (capsule.isActive()) {
|
|
448
|
-
metrics[id] = capsule.getMetrics();
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
return metrics;
|
|
452
|
-
}
|
|
453
|
-
/**
|
|
454
|
-
* GAP-64: Get aggregated metrics across all capsules
|
|
455
|
-
* Returns summary statistics for the entire registry
|
|
456
|
-
*/
|
|
457
|
-
getAggregatedMetrics() {
|
|
458
|
-
const allMetrics = Object.values(this.getMetrics());
|
|
459
|
-
if (allMetrics.length === 0) {
|
|
460
|
-
return {
|
|
461
|
-
totalCapsules: 0,
|
|
462
|
-
activeCapsules: 0,
|
|
463
|
-
totalRenders: 0,
|
|
464
|
-
totalActions: 0,
|
|
465
|
-
totalStateUpdates: 0,
|
|
466
|
-
totalErrors: 0,
|
|
467
|
-
avgUptime: 0,
|
|
468
|
-
totalMemoryUsed: 0,
|
|
469
|
-
avgCpuUsage: 0,
|
|
470
|
-
};
|
|
471
|
-
}
|
|
472
|
-
const now = Date.now();
|
|
473
|
-
const activeCapsules = allMetrics.filter(m => m.uptime > 0);
|
|
474
|
-
const totalRenders = allMetrics.reduce((sum, m) => sum + m.renderCount, 0);
|
|
475
|
-
const totalActions = allMetrics.reduce((sum, m) => sum + m.actionCount, 0);
|
|
476
|
-
const totalStateUpdates = allMetrics.reduce((sum, m) => sum + m.stateUpdateCount, 0);
|
|
477
|
-
const totalErrors = allMetrics.reduce((sum, m) => sum + m.errorCount, 0);
|
|
478
|
-
const avgUptime = activeCapsules.reduce((sum, m) => sum + m.uptime, 0) / activeCapsules.length;
|
|
479
|
-
const totalMemoryUsed = activeCapsules.reduce((sum, m) => sum + (m.memory?.heapUsed || 0), 0);
|
|
480
|
-
const avgCpuUsage = activeCapsules.length > 0
|
|
481
|
-
? activeCapsules.reduce((sum, m) => sum + (m.cpu?.usagePercent || 0), 0) / activeCapsules.length
|
|
482
|
-
: 0;
|
|
483
|
-
return {
|
|
484
|
-
totalCapsules: this.capsules.size,
|
|
485
|
-
activeCapsules: activeCapsules.length,
|
|
486
|
-
totalRenders,
|
|
487
|
-
totalActions,
|
|
488
|
-
totalStateUpdates,
|
|
489
|
-
totalErrors,
|
|
490
|
-
avgUptime,
|
|
491
|
-
totalMemoryUsed,
|
|
492
|
-
avgCpuUsage,
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
/**
|
|
496
|
-
* GAP-64: Export metrics for external monitoring systems
|
|
497
|
-
* Returns metrics in a format suitable for Prometheus, DataDog, etc.
|
|
498
|
-
*/
|
|
499
|
-
exportMetrics() {
|
|
500
|
-
const aggregated = this.getAggregatedMetrics();
|
|
501
|
-
const individual = this.getMetrics();
|
|
502
|
-
return {
|
|
503
|
-
timestamp: Date.now(),
|
|
504
|
-
summary: aggregated,
|
|
505
|
-
capsules: individual,
|
|
506
|
-
// Prometheus-style metrics
|
|
507
|
-
prometheus: this.toPrometheusFormat(individual, aggregated),
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
* Convert metrics to Prometheus format
|
|
512
|
-
*/
|
|
513
|
-
toPrometheusFormat(individual, aggregated) {
|
|
514
|
-
const lines = [];
|
|
515
|
-
// Help and type annotations
|
|
516
|
-
lines.push('# HELP ix_capsule_renders_total Total number of renders per capsule');
|
|
517
|
-
lines.push('# TYPE ix_capsule_renders_total counter');
|
|
518
|
-
for (const [id, m] of Object.entries(individual)) {
|
|
519
|
-
lines.push(`ix_capsule_renders_total{capsule_id="${id}"} ${m.renderCount}`);
|
|
520
|
-
}
|
|
521
|
-
lines.push('');
|
|
522
|
-
lines.push('# HELP ix_capsule_actions_total Total number of actions per capsule');
|
|
523
|
-
lines.push('# TYPE ix_capsule_actions_total counter');
|
|
524
|
-
for (const [id, m] of Object.entries(individual)) {
|
|
525
|
-
lines.push(`ix_capsule_actions_total{capsule_id="${id}"} ${m.actionCount}`);
|
|
526
|
-
}
|
|
527
|
-
lines.push('');
|
|
528
|
-
lines.push('# HELP ix_capsule_errors_total Total number of errors per capsule');
|
|
529
|
-
lines.push('# TYPE ix_capsule_errors_total counter');
|
|
530
|
-
for (const [id, m] of Object.entries(individual)) {
|
|
531
|
-
lines.push(`ix_capsule_errors_total{capsule_id="${id}"} ${m.errorCount}`);
|
|
532
|
-
}
|
|
533
|
-
lines.push('');
|
|
534
|
-
lines.push('# HELP ix_capsule_memory_bytes Memory usage per capsule');
|
|
535
|
-
lines.push('# TYPE ix_capsule_memory_bytes gauge');
|
|
536
|
-
for (const [id, m] of Object.entries(individual)) {
|
|
537
|
-
if (m.memory) {
|
|
538
|
-
lines.push(`ix_capsule_memory_bytes{capsule_id="${id}",type="heap_used"} ${m.memory.heapUsed}`);
|
|
539
|
-
lines.push(`ix_capsule_memory_bytes{capsule_id="${id}",type="heap_total"} ${m.memory.heapTotal}`);
|
|
540
|
-
lines.push(`ix_capsule_memory_bytes{capsule_id="${id}",type="rss"} ${m.memory.rss}`);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
lines.push('');
|
|
544
|
-
lines.push('# HELP ix_capsule_cpu_usage_percent CPU usage percentage per capsule');
|
|
545
|
-
lines.push('# TYPE ix_capsule_cpu_usage_percent gauge');
|
|
546
|
-
for (const [id, m] of Object.entries(individual)) {
|
|
547
|
-
if (m.cpu) {
|
|
548
|
-
lines.push(`ix_capsule_cpu_usage_percent{capsule_id="${id}"} ${m.cpu.usagePercent.toFixed(2)}`);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
lines.push('');
|
|
552
|
-
lines.push('# HELP ix_registry_capsules_total Total number of capsules in registry');
|
|
553
|
-
lines.push('# TYPE ix_registry_capsules_total gauge');
|
|
554
|
-
lines.push(`ix_registry_capsules_total{state="active"} ${aggregated.activeCapsules}`);
|
|
555
|
-
lines.push(`ix_registry_capsules_total{state="total"} ${aggregated.totalCapsules}`);
|
|
556
|
-
return lines.join('\n');
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
/**
|
|
560
|
-
* Global capsule registry
|
|
561
|
-
*/
|
|
562
|
-
export const globalCapsuleRegistry = new IXCapsuleRegistry();
|
|
563
|
-
//# sourceMappingURL=capsule-runtime.js.map
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Policy Gates
|
|
3
|
-
*
|
|
4
|
-
* Security controls for IX capsule execution.
|
|
5
|
-
*
|
|
6
|
-
* Policy gates enforce security boundaries for:
|
|
7
|
-
* - Action execution (rate limiting, allowlists)
|
|
8
|
-
* - State changes (validation, sanitization)
|
|
9
|
-
* - Rendering (component restrictions, prop filtering)
|
|
10
|
-
*/
|
|
11
|
-
export interface PolicyContext {
|
|
12
|
-
/** Capsule ID */
|
|
13
|
-
capsuleId: string;
|
|
14
|
-
/** Action being performed */
|
|
15
|
-
actionId?: string;
|
|
16
|
-
/** Action parameters */
|
|
17
|
-
params?: Record<string, unknown>;
|
|
18
|
-
/** State snapshot */
|
|
19
|
-
state?: Record<string, unknown>;
|
|
20
|
-
/** Component being rendered */
|
|
21
|
-
component?: string;
|
|
22
|
-
/** Props being passed */
|
|
23
|
-
props?: Record<string, unknown>;
|
|
24
|
-
/** Timestamp */
|
|
25
|
-
timestamp: number;
|
|
26
|
-
/** User/agent identifier */
|
|
27
|
-
agentId?: string;
|
|
28
|
-
}
|
|
29
|
-
export interface PolicyResult {
|
|
30
|
-
allowed: boolean;
|
|
31
|
-
reason?: string;
|
|
32
|
-
/** Modified context (for sanitization) */
|
|
33
|
-
context?: PolicyContext;
|
|
34
|
-
/** Audit log entry */
|
|
35
|
-
audit?: Record<string, unknown>;
|
|
36
|
-
}
|
|
37
|
-
export interface PolicyGate {
|
|
38
|
-
name: string;
|
|
39
|
-
check: (type: 'action' | 'state-change' | 'render', context: PolicyContext) => Promise<PolicyResult> | PolicyResult;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Rate Limiting Policy Gate
|
|
43
|
-
*
|
|
44
|
-
* Limits action execution rate per capsule.
|
|
45
|
-
*/
|
|
46
|
-
export declare function createRateLimitGate(options: {
|
|
47
|
-
maxActionsPerMinute: number;
|
|
48
|
-
burstSize?: number;
|
|
49
|
-
windowMs?: number;
|
|
50
|
-
}): PolicyGate;
|
|
51
|
-
/**
|
|
52
|
-
* Action Allowlist Policy Gate
|
|
53
|
-
*
|
|
54
|
-
* Only allows specific actions to execute.
|
|
55
|
-
*/
|
|
56
|
-
export declare function createActionAllowlistGate(allowedActions: string[]): PolicyGate;
|
|
57
|
-
/**
|
|
58
|
-
* Component Restrictions Policy Gate
|
|
59
|
-
*
|
|
60
|
-
* Restricts which components can be rendered.
|
|
61
|
-
*/
|
|
62
|
-
export declare function createComponentRestrictionsGate(options: {
|
|
63
|
-
allowedComponents?: string[];
|
|
64
|
-
blockedComponents?: string[];
|
|
65
|
-
maxDepth?: number;
|
|
66
|
-
}): PolicyGate;
|
|
67
|
-
/**
|
|
68
|
-
* State Validation Policy Gate
|
|
69
|
-
*
|
|
70
|
-
* Validates state changes against schema.
|
|
71
|
-
*/
|
|
72
|
-
export declare function createStateValidationGate(schema: {
|
|
73
|
-
[path: string]: {
|
|
74
|
-
type: 'string' | 'number' | 'boolean' | 'array' | 'object';
|
|
75
|
-
required?: boolean;
|
|
76
|
-
validate?: (value: unknown) => boolean | string;
|
|
77
|
-
};
|
|
78
|
-
}): PolicyGate;
|
|
79
|
-
/**
|
|
80
|
-
* Prop Sanitization Policy Gate
|
|
81
|
-
*
|
|
82
|
-
* Sanitizes component props to prevent XSS and injection attacks.
|
|
83
|
-
*/
|
|
84
|
-
export declare function createPropSanitizationGate(options: {
|
|
85
|
-
allowHTML?: boolean;
|
|
86
|
-
allowedTags?: string[];
|
|
87
|
-
allowedAttributes?: string[];
|
|
88
|
-
}): PolicyGate;
|
|
89
|
-
/**
|
|
90
|
-
* Resource Limiting Policy Gate
|
|
91
|
-
*
|
|
92
|
-
* Enforces resource limits on capsules.
|
|
93
|
-
*/
|
|
94
|
-
export declare function createResourceLimitGate(options: {
|
|
95
|
-
maxStateSize?: number;
|
|
96
|
-
maxComponents?: number;
|
|
97
|
-
maxActions?: number;
|
|
98
|
-
}): PolicyGate;
|
|
99
|
-
/**
|
|
100
|
-
* Audit Logging Policy Gate
|
|
101
|
-
*
|
|
102
|
-
* Logs all policy decisions for audit purposes.
|
|
103
|
-
*/
|
|
104
|
-
export declare function createAuditLogGate(options: {
|
|
105
|
-
logFn: (entry: Record<string, unknown>) => void;
|
|
106
|
-
logAllowed?: boolean;
|
|
107
|
-
}): PolicyGate;
|
|
108
|
-
/**
|
|
109
|
-
* Compose multiple policy gates
|
|
110
|
-
*/
|
|
111
|
-
export declare function composePolicyGates(...gates: PolicyGate[]): PolicyGate;
|
|
112
|
-
/**
|
|
113
|
-
* Create default security policy gates
|
|
114
|
-
*/
|
|
115
|
-
export declare function createDefaultPolicyGates(): PolicyGate[];
|
|
116
|
-
//# sourceMappingURL=policy-gates.d.ts.map
|