chainlesschain 0.37.12 → 0.40.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.
Files changed (48) hide show
  1. package/package.json +3 -2
  2. package/src/commands/agent.js +7 -1
  3. package/src/commands/ask.js +24 -9
  4. package/src/commands/chat.js +7 -1
  5. package/src/commands/cli-anything.js +266 -0
  6. package/src/commands/compliance.js +216 -0
  7. package/src/commands/dao.js +312 -0
  8. package/src/commands/dlp.js +278 -0
  9. package/src/commands/evomap.js +558 -0
  10. package/src/commands/hardening.js +230 -0
  11. package/src/commands/matrix.js +168 -0
  12. package/src/commands/nostr.js +185 -0
  13. package/src/commands/pqc.js +162 -0
  14. package/src/commands/scim.js +218 -0
  15. package/src/commands/serve.js +109 -0
  16. package/src/commands/siem.js +156 -0
  17. package/src/commands/social.js +480 -0
  18. package/src/commands/terraform.js +148 -0
  19. package/src/constants.js +1 -0
  20. package/src/index.js +60 -0
  21. package/src/lib/autonomous-agent.js +487 -0
  22. package/src/lib/cli-anything-bridge.js +379 -0
  23. package/src/lib/cli-context-engineering.js +472 -0
  24. package/src/lib/compliance-manager.js +290 -0
  25. package/src/lib/content-recommender.js +205 -0
  26. package/src/lib/dao-governance.js +296 -0
  27. package/src/lib/dlp-engine.js +304 -0
  28. package/src/lib/evomap-client.js +135 -0
  29. package/src/lib/evomap-federation.js +240 -0
  30. package/src/lib/evomap-governance.js +250 -0
  31. package/src/lib/evomap-manager.js +227 -0
  32. package/src/lib/git-integration.js +1 -1
  33. package/src/lib/hardening-manager.js +275 -0
  34. package/src/lib/llm-providers.js +14 -1
  35. package/src/lib/matrix-bridge.js +196 -0
  36. package/src/lib/nostr-bridge.js +195 -0
  37. package/src/lib/permanent-memory.js +370 -0
  38. package/src/lib/plan-mode.js +211 -0
  39. package/src/lib/pqc-manager.js +196 -0
  40. package/src/lib/scim-manager.js +212 -0
  41. package/src/lib/session-manager.js +38 -0
  42. package/src/lib/siem-exporter.js +137 -0
  43. package/src/lib/social-manager.js +283 -0
  44. package/src/lib/task-model-selector.js +232 -0
  45. package/src/lib/terraform-manager.js +201 -0
  46. package/src/lib/ws-server.js +474 -0
  47. package/src/repl/agent-repl.js +796 -41
  48. package/src/repl/chat-repl.js +14 -6
package/src/index.js CHANGED
@@ -47,14 +47,44 @@ import { registerA2aCommand } from "./commands/a2a.js";
47
47
  import { registerSandboxCommand } from "./commands/sandbox.js";
48
48
  import { registerEvolutionCommand } from "./commands/evolution.js";
49
49
 
50
+ // Phase 7: EvoMap Federation + DAO Governance
51
+ import { registerDaoCommand } from "./commands/dao.js";
52
+
50
53
  // Phase 8: Blockchain & Enterprise
51
54
  import { registerEconomyCommand } from "./commands/economy.js";
52
55
  import { registerZkpCommand } from "./commands/zkp.js";
53
56
  import { registerBiCommand } from "./commands/bi.js";
54
57
 
58
+ // Phase 8: Security & Compliance
59
+ import { registerComplianceCommand } from "./commands/compliance.js";
60
+ import { registerDlpCommand } from "./commands/dlp.js";
61
+ import { registerSiemCommand } from "./commands/siem.js";
62
+ import { registerPqcCommand } from "./commands/pqc.js";
63
+
64
+ // Phase 8: Communication Bridges
65
+ import { registerNostrCommand } from "./commands/nostr.js";
66
+ import { registerMatrixCommand } from "./commands/matrix.js";
67
+ import { registerScimCommand } from "./commands/scim.js";
68
+
69
+ // Phase 8: Infrastructure & Hardening
70
+ import { registerTerraformCommand } from "./commands/terraform.js";
71
+ import { registerHardeningCommand } from "./commands/hardening.js";
72
+
73
+ // Phase 8: Social Platform
74
+ import { registerSocialCommand } from "./commands/social.js";
75
+
55
76
  // Phase 9: Low-Code & Multi-Agent
56
77
  import { registerLowcodeCommand } from "./commands/lowcode.js";
57
78
 
79
+ // EvoMap: Gene Exchange Protocol
80
+ import { registerEvoMapCommand } from "./commands/evomap.js";
81
+
82
+ // CLI-Anything: Agent-Native Software Integration
83
+ import { registerCliAnythingCommand } from "./commands/cli-anything.js";
84
+
85
+ // WebSocket Server Interface
86
+ import { registerServeCommand } from "./commands/serve.js";
87
+
58
88
  export function createProgram() {
59
89
  const program = new Command();
60
90
 
@@ -131,13 +161,43 @@ export function createProgram() {
131
161
  registerSandboxCommand(program);
132
162
  registerEvolutionCommand(program);
133
163
 
164
+ // Phase 7: EvoMap Federation + DAO Governance
165
+ registerDaoCommand(program);
166
+
134
167
  // Phase 8: Blockchain & Enterprise
135
168
  registerEconomyCommand(program);
136
169
  registerZkpCommand(program);
137
170
  registerBiCommand(program);
138
171
 
172
+ // Phase 8: Security & Compliance
173
+ registerComplianceCommand(program);
174
+ registerDlpCommand(program);
175
+ registerSiemCommand(program);
176
+ registerPqcCommand(program);
177
+
178
+ // Phase 8: Communication Bridges
179
+ registerNostrCommand(program);
180
+ registerMatrixCommand(program);
181
+ registerScimCommand(program);
182
+
183
+ // Phase 8: Infrastructure & Hardening
184
+ registerTerraformCommand(program);
185
+ registerHardeningCommand(program);
186
+
187
+ // Phase 8: Social Platform
188
+ registerSocialCommand(program);
189
+
139
190
  // Phase 9: Low-Code & Multi-Agent
140
191
  registerLowcodeCommand(program);
141
192
 
193
+ // EvoMap: Gene Exchange Protocol
194
+ registerEvoMapCommand(program);
195
+
196
+ // CLI-Anything: Agent-Native Software Integration
197
+ registerCliAnythingCommand(program);
198
+
199
+ // WebSocket Server Interface
200
+ registerServeCommand(program);
201
+
142
202
  return program;
143
203
  }
@@ -0,0 +1,487 @@
1
+ /**
2
+ * CLI Autonomous Agent — ReAct-style self-directed task execution.
3
+ *
4
+ * Submits a goal → decomposes into sub-steps → runs Reason→Act→Observe loop
5
+ * with self-correction on failure. Single-goal, session-scoped.
6
+ *
7
+ * Lightweight port of desktop-app-vue/src/main/ai-engine/autonomous/autonomous-agent-runner.js
8
+ */
9
+
10
+ import { EventEmitter } from "events";
11
+
12
+ // Exported for test injection
13
+ export const _deps = {
14
+ Date,
15
+ };
16
+
17
+ /**
18
+ * Goal status
19
+ */
20
+ export const GoalStatus = {
21
+ PENDING: "pending",
22
+ RUNNING: "running",
23
+ PAUSED: "paused",
24
+ COMPLETED: "completed",
25
+ FAILED: "failed",
26
+ CANCELLED: "cancelled",
27
+ };
28
+
29
+ /**
30
+ * Step status
31
+ */
32
+ export const StepStatus = {
33
+ PENDING: "pending",
34
+ RUNNING: "running",
35
+ COMPLETED: "completed",
36
+ FAILED: "failed",
37
+ SKIPPED: "skipped",
38
+ };
39
+
40
+ export class CLIAutonomousAgent extends EventEmitter {
41
+ constructor() {
42
+ super();
43
+ this._goals = new Map();
44
+ this._llmChat = null;
45
+ this._toolExecutor = null;
46
+ this._hookManager = null;
47
+ this._initialized = false;
48
+ this._maxIterations = 20;
49
+ this._maxRetries = 3;
50
+ }
51
+
52
+ /**
53
+ * Initialize with required dependencies.
54
+ */
55
+ initialize({ llmChat, toolExecutor, hookManager, maxIterations } = {}) {
56
+ this._llmChat = llmChat || null;
57
+ this._toolExecutor = toolExecutor || null;
58
+ this._hookManager = hookManager || null;
59
+ if (maxIterations) this._maxIterations = maxIterations;
60
+ this._initialized = true;
61
+ }
62
+
63
+ /**
64
+ * Submit a goal for autonomous execution.
65
+ * @param {string} description - Natural language goal
66
+ * @param {object} [options]
67
+ * @param {number} [options.tokenBudget=50000] - Advisory token budget
68
+ * @returns {{ goalId: string }}
69
+ */
70
+ async submitGoal(description, { tokenBudget = 50000 } = {}) {
71
+ if (!this._initialized) throw new Error("Agent not initialized");
72
+ if (!description) throw new Error("Goal description required");
73
+
74
+ const goalId = `goal-${_deps.Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
75
+
76
+ const goal = {
77
+ id: goalId,
78
+ description,
79
+ status: GoalStatus.PENDING,
80
+ tokenBudget,
81
+ tokensUsed: 0,
82
+ steps: [],
83
+ iterations: 0,
84
+ errors: [],
85
+ result: null,
86
+ createdAt: new Date().toISOString(),
87
+ updatedAt: new Date().toISOString(),
88
+ };
89
+
90
+ this._goals.set(goalId, goal);
91
+ this.emit("goal:submitted", { goalId, description });
92
+
93
+ // Start the ReAct loop asynchronously
94
+ this._runReActLoop(goal).catch((err) => {
95
+ goal.status = GoalStatus.FAILED;
96
+ goal.errors.push(err.message);
97
+ this.emit("goal:failed", { goalId, error: err.message });
98
+ });
99
+
100
+ return { goalId };
101
+ }
102
+
103
+ /**
104
+ * Pause a running goal.
105
+ */
106
+ pauseGoal(goalId) {
107
+ const goal = this._goals.get(goalId);
108
+ if (!goal) return { error: "Goal not found" };
109
+ if (goal.status !== GoalStatus.RUNNING)
110
+ return { error: "Goal is not running" };
111
+
112
+ goal.status = GoalStatus.PAUSED;
113
+ goal.updatedAt = new Date().toISOString();
114
+ this.emit("goal:paused", { goalId });
115
+ return { success: true };
116
+ }
117
+
118
+ /**
119
+ * Resume a paused goal.
120
+ */
121
+ resumeGoal(goalId) {
122
+ const goal = this._goals.get(goalId);
123
+ if (!goal) return { error: "Goal not found" };
124
+ if (goal.status !== GoalStatus.PAUSED)
125
+ return { error: "Goal is not paused" };
126
+
127
+ goal.status = GoalStatus.RUNNING;
128
+ goal.updatedAt = new Date().toISOString();
129
+ this.emit("goal:resumed", { goalId });
130
+
131
+ // Continue the loop
132
+ this._runReActLoop(goal).catch((err) => {
133
+ goal.status = GoalStatus.FAILED;
134
+ goal.errors.push(err.message);
135
+ });
136
+
137
+ return { success: true };
138
+ }
139
+
140
+ /**
141
+ * Cancel a goal.
142
+ */
143
+ cancelGoal(goalId) {
144
+ const goal = this._goals.get(goalId);
145
+ if (!goal) return { error: "Goal not found" };
146
+
147
+ goal.status = GoalStatus.CANCELLED;
148
+ goal.updatedAt = new Date().toISOString();
149
+ this.emit("goal:cancelled", { goalId });
150
+ return { success: true };
151
+ }
152
+
153
+ /**
154
+ * Get goal status with steps.
155
+ */
156
+ getGoalStatus(goalId) {
157
+ const goal = this._goals.get(goalId);
158
+ if (!goal) return null;
159
+
160
+ return {
161
+ id: goal.id,
162
+ description: goal.description,
163
+ status: goal.status,
164
+ steps: goal.steps.map((s) => ({
165
+ description: s.description,
166
+ status: s.status,
167
+ tool: s.tool,
168
+ result: s.result ? String(s.result).substring(0, 200) : null,
169
+ error: s.error,
170
+ })),
171
+ iterations: goal.iterations,
172
+ errors: goal.errors,
173
+ result: goal.result,
174
+ tokensUsed: goal.tokensUsed,
175
+ };
176
+ }
177
+
178
+ /**
179
+ * List all goals.
180
+ */
181
+ listGoals() {
182
+ return [...this._goals.values()].map((g) => ({
183
+ id: g.id,
184
+ description: g.description.substring(0, 80),
185
+ status: g.status,
186
+ steps: g.steps.length,
187
+ iterations: g.iterations,
188
+ }));
189
+ }
190
+
191
+ // ─── ReAct Loop ─────────────────────────────────────────────
192
+
193
+ async _runReActLoop(goal) {
194
+ goal.status = GoalStatus.RUNNING;
195
+ this.emit("goal:started", { goalId: goal.id });
196
+
197
+ // Decompose goal into initial steps
198
+ if (goal.steps.length === 0) {
199
+ goal.steps = await this._decomposeGoal(goal);
200
+ this.emit("goal:planned", {
201
+ goalId: goal.id,
202
+ stepCount: goal.steps.length,
203
+ });
204
+ }
205
+
206
+ while (
207
+ goal.status === GoalStatus.RUNNING &&
208
+ goal.iterations < this._maxIterations
209
+ ) {
210
+ goal.iterations++;
211
+
212
+ // Find next pending step
213
+ const nextStep = goal.steps.find((s) => s.status === StepStatus.PENDING);
214
+ if (!nextStep) {
215
+ // All steps done or no pending steps
216
+ const allDone = goal.steps.every(
217
+ (s) =>
218
+ s.status === StepStatus.COMPLETED ||
219
+ s.status === StepStatus.SKIPPED,
220
+ );
221
+ if (allDone) {
222
+ goal.status = GoalStatus.COMPLETED;
223
+ goal.result = this._summarizeResults(goal);
224
+ this.emit("goal:completed", { goalId: goal.id, result: goal.result });
225
+ } else {
226
+ goal.status = GoalStatus.FAILED;
227
+ goal.errors.push("Not all steps completed");
228
+ this.emit("goal:failed", {
229
+ goalId: goal.id,
230
+ error: "Not all steps completed",
231
+ });
232
+ }
233
+ break;
234
+ }
235
+
236
+ // Execute step
237
+ nextStep.status = StepStatus.RUNNING;
238
+ this.emit("step:started", {
239
+ goalId: goal.id,
240
+ step: nextStep.description,
241
+ });
242
+
243
+ try {
244
+ const result = await this._executeStep(nextStep);
245
+ nextStep.status = StepStatus.COMPLETED;
246
+ nextStep.result = result;
247
+ this.emit("step:completed", {
248
+ goalId: goal.id,
249
+ step: nextStep.description,
250
+ });
251
+ } catch (err) {
252
+ nextStep.error = err.message;
253
+
254
+ // Self-correction: try to replan
255
+ if (nextStep.retries < this._maxRetries) {
256
+ nextStep.retries++;
257
+ this.emit("step:retrying", {
258
+ goalId: goal.id,
259
+ step: nextStep.description,
260
+ error: err.message,
261
+ });
262
+
263
+ const corrected = await this._selfCorrect(goal, err);
264
+ if (corrected) {
265
+ nextStep.status = StepStatus.PENDING; // Retry
266
+ continue;
267
+ }
268
+ }
269
+
270
+ nextStep.status = StepStatus.FAILED;
271
+ this.emit("step:failed", {
272
+ goalId: goal.id,
273
+ step: nextStep.description,
274
+ error: err.message,
275
+ });
276
+
277
+ // Check if failure is fatal
278
+ if (nextStep.critical !== false) {
279
+ goal.status = GoalStatus.FAILED;
280
+ goal.errors.push(
281
+ `Step failed: ${nextStep.description} — ${err.message}`,
282
+ );
283
+ this.emit("goal:failed", { goalId: goal.id, error: err.message });
284
+ break;
285
+ }
286
+ }
287
+
288
+ goal.updatedAt = new Date().toISOString();
289
+ }
290
+
291
+ if (
292
+ goal.iterations >= this._maxIterations &&
293
+ goal.status === GoalStatus.RUNNING
294
+ ) {
295
+ goal.status = GoalStatus.FAILED;
296
+ goal.errors.push("Max iterations reached");
297
+ this.emit("goal:failed", {
298
+ goalId: goal.id,
299
+ error: "Max iterations reached",
300
+ });
301
+ }
302
+ }
303
+
304
+ /**
305
+ * Decompose a goal into executable steps using LLM.
306
+ */
307
+ async _decomposeGoal(goal) {
308
+ if (!this._llmChat) {
309
+ // No LLM — create a single step
310
+ return [
311
+ {
312
+ description: goal.description,
313
+ tool: null,
314
+ params: {},
315
+ status: StepStatus.PENDING,
316
+ retries: 0,
317
+ critical: true,
318
+ result: null,
319
+ error: null,
320
+ },
321
+ ];
322
+ }
323
+
324
+ try {
325
+ const prompt = `Break down this goal into 2-6 concrete, executable steps. Each step should use one tool.
326
+
327
+ Goal: ${goal.description}
328
+
329
+ Available tools: read_file, write_file, edit_file, run_shell, search_files, list_dir, run_skill
330
+
331
+ Return a JSON array of steps, each with: { "description": "...", "tool": "tool_name", "params": {...} }
332
+ Only return the JSON array, no other text.`;
333
+
334
+ const response = await this._llmChat(
335
+ [{ role: "user", content: prompt }],
336
+ { maxTokens: 1024 },
337
+ );
338
+
339
+ // Parse steps from LLM response
340
+ const parsed = this._parseSteps(response);
341
+ return parsed.map((s) => ({
342
+ description: s.description || "Step",
343
+ tool: s.tool || null,
344
+ params: s.params || {},
345
+ status: StepStatus.PENDING,
346
+ retries: 0,
347
+ critical: s.critical !== false,
348
+ result: null,
349
+ error: null,
350
+ }));
351
+ } catch (_err) {
352
+ // Fallback: single step
353
+ return [
354
+ {
355
+ description: goal.description,
356
+ tool: null,
357
+ params: {},
358
+ status: StepStatus.PENDING,
359
+ retries: 0,
360
+ critical: true,
361
+ result: null,
362
+ error: null,
363
+ },
364
+ ];
365
+ }
366
+ }
367
+
368
+ /**
369
+ * Execute a single step using the tool executor.
370
+ */
371
+ async _executeStep(step) {
372
+ if (!step.tool || !this._toolExecutor) {
373
+ // No tool specified or no executor — skip as informational
374
+ return "No tool action required";
375
+ }
376
+
377
+ return await this._toolExecutor(step.tool, step.params);
378
+ }
379
+
380
+ /**
381
+ * Self-correct after a step failure.
382
+ * Returns true if a correction was applied.
383
+ */
384
+ async _selfCorrect(goal, error) {
385
+ if (!this._llmChat) return false;
386
+
387
+ try {
388
+ const context = goal.steps.map((s) => ({
389
+ description: s.description,
390
+ status: s.status,
391
+ error: s.error,
392
+ }));
393
+
394
+ const prompt = `A step in my plan failed. Help me fix it.
395
+
396
+ Goal: ${goal.description}
397
+ Steps so far: ${JSON.stringify(context)}
398
+ Error: ${error.message}
399
+
400
+ Should I:
401
+ 1. Retry the same step with different params
402
+ 2. Add a new prerequisite step
403
+ 3. Skip this step and continue
404
+
405
+ Reply with a JSON object: { "action": "retry|add_step|skip", "newParams": {...}, "newStep": {...} }`;
406
+
407
+ const response = await this._llmChat(
408
+ [{ role: "user", content: prompt }],
409
+ { maxTokens: 512 },
410
+ );
411
+
412
+ const correction = this._parseJSON(response);
413
+ if (!correction) return false;
414
+
415
+ if (correction.action === "skip") {
416
+ const failedStep = goal.steps.find(
417
+ (s) => s.status === StepStatus.RUNNING,
418
+ );
419
+ if (failedStep) failedStep.status = StepStatus.SKIPPED;
420
+ return true;
421
+ }
422
+
423
+ if (correction.action === "add_step" && correction.newStep) {
424
+ const failedIdx = goal.steps.findIndex(
425
+ (s) => s.status === StepStatus.RUNNING,
426
+ );
427
+ if (failedIdx >= 0) {
428
+ goal.steps.splice(failedIdx, 0, {
429
+ description: correction.newStep.description || "Corrective step",
430
+ tool: correction.newStep.tool || null,
431
+ params: correction.newStep.params || {},
432
+ status: StepStatus.PENDING,
433
+ retries: 0,
434
+ critical: false,
435
+ result: null,
436
+ error: null,
437
+ });
438
+ }
439
+ return true;
440
+ }
441
+
442
+ if (correction.action === "retry" && correction.newParams) {
443
+ const failedStep = goal.steps.find(
444
+ (s) => s.status === StepStatus.RUNNING,
445
+ );
446
+ if (failedStep) {
447
+ Object.assign(failedStep.params, correction.newParams);
448
+ }
449
+ return true;
450
+ }
451
+
452
+ return false;
453
+ } catch (_err) {
454
+ return false;
455
+ }
456
+ }
457
+
458
+ _summarizeResults(goal) {
459
+ const completed = goal.steps.filter(
460
+ (s) => s.status === StepStatus.COMPLETED,
461
+ );
462
+ return `Completed ${completed.length}/${goal.steps.length} steps for: ${goal.description}`;
463
+ }
464
+
465
+ _parseSteps(text) {
466
+ try {
467
+ // Extract JSON array from response
468
+ const match = text.match(/\[[\s\S]*\]/);
469
+ if (match) {
470
+ return JSON.parse(match[0]);
471
+ }
472
+ } catch (_err) {
473
+ // Parse failure
474
+ }
475
+ return [{ description: "Execute goal", tool: null, params: {} }];
476
+ }
477
+
478
+ _parseJSON(text) {
479
+ try {
480
+ const match = text.match(/\{[\s\S]*\}/);
481
+ if (match) return JSON.parse(match[0]);
482
+ } catch (_err) {
483
+ // Parse failure
484
+ }
485
+ return null;
486
+ }
487
+ }