chainlesschain 0.37.10 → 0.37.12

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.
Files changed (39) hide show
  1. package/README.md +166 -10
  2. package/package.json +1 -1
  3. package/src/commands/a2a.js +374 -0
  4. package/src/commands/bi.js +240 -0
  5. package/src/commands/cowork.js +317 -0
  6. package/src/commands/economy.js +375 -0
  7. package/src/commands/evolution.js +398 -0
  8. package/src/commands/hmemory.js +273 -0
  9. package/src/commands/hook.js +260 -0
  10. package/src/commands/init.js +184 -0
  11. package/src/commands/lowcode.js +320 -0
  12. package/src/commands/plugin.js +55 -2
  13. package/src/commands/sandbox.js +366 -0
  14. package/src/commands/skill.js +254 -201
  15. package/src/commands/workflow.js +359 -0
  16. package/src/commands/zkp.js +277 -0
  17. package/src/index.js +44 -0
  18. package/src/lib/a2a-protocol.js +371 -0
  19. package/src/lib/agent-coordinator.js +273 -0
  20. package/src/lib/agent-economy.js +369 -0
  21. package/src/lib/app-builder.js +377 -0
  22. package/src/lib/bi-engine.js +299 -0
  23. package/src/lib/cowork/ab-comparator-cli.js +180 -0
  24. package/src/lib/cowork/code-knowledge-graph-cli.js +232 -0
  25. package/src/lib/cowork/debate-review-cli.js +144 -0
  26. package/src/lib/cowork/decision-kb-cli.js +153 -0
  27. package/src/lib/cowork/project-style-analyzer-cli.js +168 -0
  28. package/src/lib/cowork-adapter.js +106 -0
  29. package/src/lib/evolution-system.js +508 -0
  30. package/src/lib/hierarchical-memory.js +471 -0
  31. package/src/lib/hook-manager.js +387 -0
  32. package/src/lib/plugin-manager.js +118 -0
  33. package/src/lib/project-detector.js +53 -0
  34. package/src/lib/sandbox-v2.js +503 -0
  35. package/src/lib/service-container.js +183 -0
  36. package/src/lib/skill-loader.js +274 -0
  37. package/src/lib/workflow-engine.js +503 -0
  38. package/src/lib/zkp-engine.js +241 -0
  39. package/src/repl/agent-repl.js +117 -112
@@ -0,0 +1,366 @@
1
+ /**
2
+ * Security Sandbox v2 commands
3
+ * chainlesschain sandbox create|exec|destroy|list|audit|quota|monitor
4
+ */
5
+
6
+ import chalk from "chalk";
7
+ import ora from "ora";
8
+ import { logger } from "../lib/logger.js";
9
+ import { bootstrap, shutdown } from "../runtime/bootstrap.js";
10
+ import {
11
+ createSandbox,
12
+ executeSandbox,
13
+ destroySandbox,
14
+ listSandboxes,
15
+ getAuditLog,
16
+ getSandbox,
17
+ setQuota,
18
+ monitorBehavior,
19
+ } from "../lib/sandbox-v2.js";
20
+
21
+ export function registerSandboxCommand(program) {
22
+ const sandbox = program
23
+ .command("sandbox")
24
+ .description("Security sandbox v2 — isolated agent execution environments");
25
+
26
+ // sandbox create <agent-id>
27
+ sandbox
28
+ .command("create")
29
+ .description("Create a new sandbox for an agent")
30
+ .argument("<agent-id>", "Agent ID to sandbox")
31
+ .option("--allow-read <paths>", "Comma-separated allowed read paths")
32
+ .option("--allow-write <paths>", "Comma-separated allowed write paths")
33
+ .option("--allowed-hosts <hosts>", "Comma-separated allowed network hosts")
34
+ .option("--json", "Output as JSON")
35
+ .action(async (agentId, options) => {
36
+ try {
37
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
38
+ if (!ctx.db) {
39
+ logger.error("Database not available");
40
+ process.exit(1);
41
+ }
42
+ const db = ctx.db.getDatabase();
43
+ const spinner = ora("Creating sandbox...").start();
44
+
45
+ const perms = {};
46
+ if (options.allowRead || options.allowWrite) {
47
+ perms.fileSystem = {
48
+ read: options.allowRead
49
+ ? options.allowRead.split(",").map((p) => p.trim())
50
+ : ["/tmp"],
51
+ write: options.allowWrite
52
+ ? options.allowWrite.split(",").map((p) => p.trim())
53
+ : ["/tmp"],
54
+ denied: ["/etc", "/usr", "/sys"],
55
+ };
56
+ }
57
+ if (options.allowedHosts) {
58
+ perms.network = {
59
+ allowed: options.allowedHosts.split(",").map((h) => h.trim()),
60
+ denied: [],
61
+ maxConnections: 10,
62
+ };
63
+ }
64
+
65
+ const sandboxOpts =
66
+ Object.keys(perms).length > 0 ? { permissions: perms } : {};
67
+ const result = createSandbox(db, agentId, sandboxOpts);
68
+ spinner.succeed("Sandbox created");
69
+
70
+ if (options.json) {
71
+ console.log(JSON.stringify(result, null, 2));
72
+ } else {
73
+ logger.log(chalk.bold("Sandbox Created:"));
74
+ logger.log(` ID: ${chalk.cyan(result.id)}`);
75
+ logger.log(` Status: ${chalk.green(result.status)}`);
76
+ logger.log(
77
+ ` Quota: CPU=${result.quota.cpu}, Memory=${(result.quota.memory / 1024 / 1024).toFixed(0)}MB`,
78
+ );
79
+ }
80
+
81
+ await shutdown();
82
+ } catch (err) {
83
+ logger.error(`Failed: ${err.message}`);
84
+ process.exit(1);
85
+ }
86
+ });
87
+
88
+ // sandbox exec <sandbox-id> <code>
89
+ sandbox
90
+ .command("exec")
91
+ .description("Execute code within a sandbox")
92
+ .argument("<sandbox-id>", "Sandbox ID")
93
+ .argument("<code>", "Code to execute")
94
+ .option("--json", "Output as JSON")
95
+ .action(async (sandboxId, code, options) => {
96
+ try {
97
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
98
+ if (!ctx.db) {
99
+ logger.error("Database not available");
100
+ process.exit(1);
101
+ }
102
+ const db = ctx.db.getDatabase();
103
+ const spinner = ora("Executing in sandbox...").start();
104
+
105
+ const result = executeSandbox(db, sandboxId, code);
106
+ spinner.succeed("Execution complete");
107
+
108
+ if (options.json) {
109
+ console.log(JSON.stringify(result, null, 2));
110
+ } else {
111
+ logger.log(chalk.bold("Execution Result:"));
112
+ logger.log(` Output: ${result.output}`);
113
+ logger.log(
114
+ ` Exit Code: ${result.exitCode === 0 ? chalk.green(0) : chalk.red(result.exitCode)}`,
115
+ );
116
+ logger.log(` Duration: ${result.duration}ms`);
117
+ logger.log(` CPU Used: ${result.resourceUsage.cpu}`);
118
+ }
119
+
120
+ await shutdown();
121
+ } catch (err) {
122
+ logger.error(`Failed: ${err.message}`);
123
+ process.exit(1);
124
+ }
125
+ });
126
+
127
+ // sandbox destroy <sandbox-id>
128
+ sandbox
129
+ .command("destroy")
130
+ .description("Destroy a sandbox")
131
+ .argument("<sandbox-id>", "Sandbox ID to destroy")
132
+ .option("--json", "Output as JSON")
133
+ .action(async (sandboxId, options) => {
134
+ try {
135
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
136
+ if (!ctx.db) {
137
+ logger.error("Database not available");
138
+ process.exit(1);
139
+ }
140
+ const db = ctx.db.getDatabase();
141
+
142
+ const result = destroySandbox(db, sandboxId);
143
+
144
+ if (options.json) {
145
+ console.log(JSON.stringify(result, null, 2));
146
+ } else {
147
+ logger.log(chalk.yellow(`Sandbox ${sandboxId} destroyed.`));
148
+ }
149
+
150
+ await shutdown();
151
+ } catch (err) {
152
+ logger.error(`Failed: ${err.message}`);
153
+ process.exit(1);
154
+ }
155
+ });
156
+
157
+ // sandbox list
158
+ sandbox
159
+ .command("list")
160
+ .description("List active sandboxes")
161
+ .option("--json", "Output as JSON")
162
+ .action(async (options) => {
163
+ try {
164
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
165
+ if (!ctx.db) {
166
+ logger.error("Database not available");
167
+ process.exit(1);
168
+ }
169
+ const db = ctx.db.getDatabase();
170
+ const sandboxes = listSandboxes(db);
171
+
172
+ if (options.json) {
173
+ console.log(JSON.stringify(sandboxes, null, 2));
174
+ } else if (sandboxes.length === 0) {
175
+ logger.info("No active sandboxes.");
176
+ } else {
177
+ logger.log(chalk.bold(`Active Sandboxes (${sandboxes.length}):\n`));
178
+ for (const s of sandboxes) {
179
+ logger.log(` ${chalk.cyan(s.id)}`);
180
+ logger.log(
181
+ ` Agent: ${s.agentId} Status: ${chalk.green(s.status)}`,
182
+ );
183
+ logger.log(
184
+ ` CPU: ${s.resourceUsage.cpu}/${s.quota.cpu} Memory: ${s.resourceUsage.memory}/${s.quota.memory}`,
185
+ );
186
+ }
187
+ }
188
+
189
+ await shutdown();
190
+ } catch (err) {
191
+ logger.error(`Failed: ${err.message}`);
192
+ process.exit(1);
193
+ }
194
+ });
195
+
196
+ // sandbox audit [sandbox-id]
197
+ sandbox
198
+ .command("audit")
199
+ .description("Show audit log for sandboxes")
200
+ .argument("[sandbox-id]", "Optional sandbox ID to filter")
201
+ .option("--action <name>", "Filter by action type")
202
+ .option("--limit <n>", "Limit entries", parseInt)
203
+ .option("--json", "Output as JSON")
204
+ .action(async (sandboxId, options) => {
205
+ try {
206
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
207
+ if (!ctx.db) {
208
+ logger.error("Database not available");
209
+ process.exit(1);
210
+ }
211
+ const db = ctx.db.getDatabase();
212
+
213
+ const entries = getAuditLog(db, sandboxId || null, {
214
+ action: options.action,
215
+ limit: options.limit,
216
+ });
217
+
218
+ if (options.json) {
219
+ console.log(JSON.stringify(entries, null, 2));
220
+ } else if (entries.length === 0) {
221
+ logger.info("No audit entries found.");
222
+ } else {
223
+ logger.log(chalk.bold(`Audit Log (${entries.length} entries):\n`));
224
+ for (const e of entries) {
225
+ const ts = chalk.gray(e.timestamp);
226
+ const action = chalk.yellow(e.action);
227
+ logger.log(` ${ts} ${action} sandbox=${e.sandboxId}`);
228
+ }
229
+ }
230
+
231
+ await shutdown();
232
+ } catch (err) {
233
+ logger.error(`Failed: ${err.message}`);
234
+ process.exit(1);
235
+ }
236
+ });
237
+
238
+ // sandbox quota <sandbox-id>
239
+ sandbox
240
+ .command("quota")
241
+ .description("Show or set sandbox quota")
242
+ .argument("<sandbox-id>", "Sandbox ID")
243
+ .option("--cpu <n>", "Set CPU quota", parseInt)
244
+ .option("--memory <n>", "Set memory quota in MB", parseInt)
245
+ .option("--json", "Output as JSON")
246
+ .action(async (sandboxId, options) => {
247
+ try {
248
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
249
+ if (!ctx.db) {
250
+ logger.error("Database not available");
251
+ process.exit(1);
252
+ }
253
+ const db = ctx.db.getDatabase();
254
+
255
+ if (options.cpu || options.memory) {
256
+ const current = getSandbox(db, sandboxId);
257
+ if (!current) {
258
+ logger.error("Sandbox not found");
259
+ process.exit(1);
260
+ }
261
+ const newQuota = { ...current.quota };
262
+ if (options.cpu) newQuota.cpu = options.cpu;
263
+ if (options.memory) newQuota.memory = options.memory * 1024 * 1024;
264
+
265
+ const result = setQuota(db, sandboxId, newQuota);
266
+ if (options.json) {
267
+ console.log(JSON.stringify(result, null, 2));
268
+ } else {
269
+ logger.log(chalk.green("Quota updated."));
270
+ logger.log(
271
+ ` CPU: ${newQuota.cpu} Memory: ${(newQuota.memory / 1024 / 1024).toFixed(0)}MB`,
272
+ );
273
+ }
274
+ } else {
275
+ const info = getSandbox(db, sandboxId);
276
+ if (!info) {
277
+ logger.error("Sandbox not found");
278
+ process.exit(1);
279
+ }
280
+ if (options.json) {
281
+ console.log(
282
+ JSON.stringify(
283
+ { quota: info.quota, resourceUsage: info.resourceUsage },
284
+ null,
285
+ 2,
286
+ ),
287
+ );
288
+ } else {
289
+ logger.log(chalk.bold("Quota:"));
290
+ logger.log(
291
+ ` CPU: ${info.resourceUsage.cpu} / ${info.quota.cpu}`,
292
+ );
293
+ logger.log(
294
+ ` Memory: ${info.resourceUsage.memory} / ${info.quota.memory}`,
295
+ );
296
+ logger.log(
297
+ ` Storage: ${info.resourceUsage.storage} / ${info.quota.storage}`,
298
+ );
299
+ logger.log(
300
+ ` Network: ${info.resourceUsage.network} / ${info.quota.network}`,
301
+ );
302
+ }
303
+ }
304
+
305
+ await shutdown();
306
+ } catch (err) {
307
+ logger.error(`Failed: ${err.message}`);
308
+ process.exit(1);
309
+ }
310
+ });
311
+
312
+ // sandbox monitor <sandbox-id>
313
+ sandbox
314
+ .command("monitor")
315
+ .description("Monitor sandbox behavior and detect suspicious patterns")
316
+ .argument("<sandbox-id>", "Sandbox ID to monitor")
317
+ .option("--json", "Output as JSON")
318
+ .action(async (sandboxId, options) => {
319
+ try {
320
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
321
+ if (!ctx.db) {
322
+ logger.error("Database not available");
323
+ process.exit(1);
324
+ }
325
+ const db = ctx.db.getDatabase();
326
+ const spinner = ora("Analyzing behavior...").start();
327
+
328
+ const result = monitorBehavior(db, sandboxId);
329
+ spinner.succeed("Analysis complete");
330
+
331
+ if (options.json) {
332
+ console.log(JSON.stringify(result, null, 2));
333
+ } else {
334
+ logger.log(chalk.bold("Behavior Analysis:"));
335
+ logger.log(` Total Events: ${result.totalEvents}`);
336
+ const riskColor =
337
+ result.riskScore > 50
338
+ ? chalk.red
339
+ : result.riskScore > 20
340
+ ? chalk.yellow
341
+ : chalk.green;
342
+ logger.log(` Risk Score: ${riskColor(result.riskScore)}/100`);
343
+
344
+ if (result.patterns.length > 0) {
345
+ logger.log(chalk.bold("\n Detected Patterns:"));
346
+ for (const p of result.patterns) {
347
+ const sev =
348
+ p.severity === "high"
349
+ ? chalk.red(p.severity)
350
+ : chalk.yellow(p.severity);
351
+ logger.log(
352
+ ` - ${p.type} (count: ${p.count}, severity: ${sev})`,
353
+ );
354
+ }
355
+ } else {
356
+ logger.log(chalk.green("\n No suspicious patterns detected."));
357
+ }
358
+ }
359
+
360
+ await shutdown();
361
+ } catch (err) {
362
+ logger.error(`Failed: ${err.message}`);
363
+ process.exit(1);
364
+ }
365
+ });
366
+ }