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.
- package/package.json +3 -2
- package/src/commands/agent.js +7 -1
- package/src/commands/ask.js +24 -9
- package/src/commands/chat.js +7 -1
- package/src/commands/cli-anything.js +266 -0
- package/src/commands/compliance.js +216 -0
- package/src/commands/dao.js +312 -0
- package/src/commands/dlp.js +278 -0
- package/src/commands/evomap.js +558 -0
- package/src/commands/hardening.js +230 -0
- package/src/commands/matrix.js +168 -0
- package/src/commands/nostr.js +185 -0
- package/src/commands/pqc.js +162 -0
- package/src/commands/scim.js +218 -0
- package/src/commands/serve.js +109 -0
- package/src/commands/siem.js +156 -0
- package/src/commands/social.js +480 -0
- package/src/commands/terraform.js +148 -0
- package/src/constants.js +1 -0
- package/src/index.js +60 -0
- package/src/lib/autonomous-agent.js +487 -0
- package/src/lib/cli-anything-bridge.js +379 -0
- package/src/lib/cli-context-engineering.js +472 -0
- package/src/lib/compliance-manager.js +290 -0
- package/src/lib/content-recommender.js +205 -0
- package/src/lib/dao-governance.js +296 -0
- package/src/lib/dlp-engine.js +304 -0
- package/src/lib/evomap-client.js +135 -0
- package/src/lib/evomap-federation.js +240 -0
- package/src/lib/evomap-governance.js +250 -0
- package/src/lib/evomap-manager.js +227 -0
- package/src/lib/git-integration.js +1 -1
- package/src/lib/hardening-manager.js +275 -0
- package/src/lib/llm-providers.js +14 -1
- package/src/lib/matrix-bridge.js +196 -0
- package/src/lib/nostr-bridge.js +195 -0
- package/src/lib/permanent-memory.js +370 -0
- package/src/lib/plan-mode.js +211 -0
- package/src/lib/pqc-manager.js +196 -0
- package/src/lib/scim-manager.js +212 -0
- package/src/lib/session-manager.js +38 -0
- package/src/lib/siem-exporter.js +137 -0
- package/src/lib/social-manager.js +283 -0
- package/src/lib/task-model-selector.js +232 -0
- package/src/lib/terraform-manager.js +201 -0
- package/src/lib/ws-server.js +474 -0
- package/src/repl/agent-repl.js +796 -41
- package/src/repl/chat-repl.js +14 -6
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EvoMap commands — gene exchange protocol client
|
|
3
|
+
* chainlesschain evomap search|publish|download|list|hubs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { logger } from "../lib/logger.js";
|
|
9
|
+
import { bootstrap, shutdown } from "../runtime/bootstrap.js";
|
|
10
|
+
import { EvoMapClient } from "../lib/evomap-client.js";
|
|
11
|
+
import { EvoMapManager } from "../lib/evomap-manager.js";
|
|
12
|
+
import {
|
|
13
|
+
ensureEvoMapFederationTables,
|
|
14
|
+
listFederatedHubs,
|
|
15
|
+
addFederatedHub,
|
|
16
|
+
syncGenes,
|
|
17
|
+
getPressureReport,
|
|
18
|
+
recombineGenes,
|
|
19
|
+
getLineage,
|
|
20
|
+
} from "../lib/evomap-federation.js";
|
|
21
|
+
import {
|
|
22
|
+
ensureEvoMapGovernanceTables,
|
|
23
|
+
registerOwnership,
|
|
24
|
+
traceOwnership,
|
|
25
|
+
createGovernanceProposal,
|
|
26
|
+
voteOnGovernanceProposal,
|
|
27
|
+
getGovernanceDashboard,
|
|
28
|
+
} from "../lib/evomap-governance.js";
|
|
29
|
+
|
|
30
|
+
export function registerEvoMapCommand(program) {
|
|
31
|
+
const evomap = program
|
|
32
|
+
.command("evomap")
|
|
33
|
+
.description("EvoMap — gene exchange protocol for agent capabilities");
|
|
34
|
+
|
|
35
|
+
// evomap search
|
|
36
|
+
evomap
|
|
37
|
+
.command("search <query>")
|
|
38
|
+
.description("Search for genes on the hub")
|
|
39
|
+
.option("-c, --category <cat>", "Filter by category")
|
|
40
|
+
.option("-n, --limit <n>", "Max results", "20")
|
|
41
|
+
.action(async (query, opts) => {
|
|
42
|
+
try {
|
|
43
|
+
const client = new EvoMapClient();
|
|
44
|
+
logger.info(`Searching for "${query}"...`);
|
|
45
|
+
const results = await client.search(query, {
|
|
46
|
+
category: opts.category,
|
|
47
|
+
limit: parseInt(opts.limit) || 20,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (results.length === 0) {
|
|
51
|
+
logger.info("No genes found.");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
for (const gene of results) {
|
|
56
|
+
logger.log(
|
|
57
|
+
` ${chalk.cyan(gene.name || gene.id)} v${gene.version || "?"} by ${gene.author || "unknown"}`,
|
|
58
|
+
);
|
|
59
|
+
if (gene.description) {
|
|
60
|
+
logger.log(` ${chalk.gray(gene.description.substring(0, 80))}`);
|
|
61
|
+
}
|
|
62
|
+
logger.log(
|
|
63
|
+
` ${chalk.gray(`downloads: ${gene.downloads || 0} rating: ${gene.rating || "N/A"}`)}`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
logger.log(`\n${results.length} gene(s) found.`);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
logger.error(`Search failed: ${err.message}`);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// evomap download
|
|
73
|
+
evomap
|
|
74
|
+
.command("download <geneId>")
|
|
75
|
+
.description("Download a gene from the hub")
|
|
76
|
+
.action(async (geneId) => {
|
|
77
|
+
try {
|
|
78
|
+
const client = new EvoMapClient();
|
|
79
|
+
const ctx = await bootstrap({ verbose: false }).catch(() => ({}));
|
|
80
|
+
const dataDir = process.env.CHAINLESSCHAIN_DATA_DIR || process.cwd();
|
|
81
|
+
const manager = new EvoMapManager({
|
|
82
|
+
genesDir: path.join(dataDir, "evomap", "genes"),
|
|
83
|
+
db: ctx.db || null,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
logger.info(`Downloading gene ${geneId}...`);
|
|
87
|
+
const data = await client.download(geneId);
|
|
88
|
+
manager.saveGene(data.gene || data, data.content || "");
|
|
89
|
+
logger.success(`Gene ${geneId} installed.`);
|
|
90
|
+
|
|
91
|
+
await shutdown().catch(() => {});
|
|
92
|
+
} catch (err) {
|
|
93
|
+
logger.error(`Download failed: ${err.message}`);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// evomap publish
|
|
98
|
+
evomap
|
|
99
|
+
.command("publish")
|
|
100
|
+
.description("Publish a gene to the hub")
|
|
101
|
+
.requiredOption("--name <name>", "Gene name")
|
|
102
|
+
.option("--description <desc>", "Gene description")
|
|
103
|
+
.option("--category <cat>", "Gene category")
|
|
104
|
+
.option("--content <content>", "Gene content (or pipe stdin)")
|
|
105
|
+
.option("--author <author>", "Author name")
|
|
106
|
+
.action(async (opts) => {
|
|
107
|
+
try {
|
|
108
|
+
const client = new EvoMapClient();
|
|
109
|
+
const manager = new EvoMapManager({ genesDir: "" });
|
|
110
|
+
|
|
111
|
+
const gene = manager.packageGene({
|
|
112
|
+
name: opts.name,
|
|
113
|
+
description: opts.description,
|
|
114
|
+
category: opts.category,
|
|
115
|
+
content: opts.content || "",
|
|
116
|
+
author: opts.author,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
logger.info(`Publishing gene "${opts.name}"...`);
|
|
120
|
+
await client.publish(gene);
|
|
121
|
+
logger.success(`Gene ${gene.id} published.`);
|
|
122
|
+
} catch (err) {
|
|
123
|
+
logger.error(`Publish failed: ${err.message}`);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// evomap list
|
|
128
|
+
evomap
|
|
129
|
+
.command("list")
|
|
130
|
+
.description("List locally installed genes")
|
|
131
|
+
.action(async () => {
|
|
132
|
+
try {
|
|
133
|
+
const ctx = await bootstrap({ verbose: false }).catch(() => ({}));
|
|
134
|
+
const dataDir = process.env.CHAINLESSCHAIN_DATA_DIR || process.cwd();
|
|
135
|
+
const manager = new EvoMapManager({
|
|
136
|
+
genesDir: path.join(dataDir, "evomap", "genes"),
|
|
137
|
+
db: ctx.db || null,
|
|
138
|
+
});
|
|
139
|
+
manager.initialize();
|
|
140
|
+
|
|
141
|
+
const genes = manager.listGenes();
|
|
142
|
+
if (genes.length === 0) {
|
|
143
|
+
logger.info(
|
|
144
|
+
"No genes installed. Use `evomap download <id>` to install.",
|
|
145
|
+
);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
for (const gene of genes) {
|
|
150
|
+
logger.log(
|
|
151
|
+
` ${chalk.cyan(gene.name || gene.id)} v${gene.version || "?"} [${gene.category || "general"}]`,
|
|
152
|
+
);
|
|
153
|
+
if (gene.description) {
|
|
154
|
+
logger.log(` ${chalk.gray(gene.description.substring(0, 80))}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
logger.log(`\n${genes.length} gene(s) installed.`);
|
|
158
|
+
|
|
159
|
+
await shutdown().catch(() => {});
|
|
160
|
+
} catch (err) {
|
|
161
|
+
logger.error(`List failed: ${err.message}`);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// evomap hubs
|
|
166
|
+
evomap
|
|
167
|
+
.command("hubs")
|
|
168
|
+
.description("List configured EvoMap hubs")
|
|
169
|
+
.action(async () => {
|
|
170
|
+
try {
|
|
171
|
+
const client = new EvoMapClient();
|
|
172
|
+
const hubs = await client.listHubs();
|
|
173
|
+
for (const hub of hubs) {
|
|
174
|
+
logger.log(
|
|
175
|
+
` ${chalk.cyan(hub.url)} — ${hub.status || hub.name || "active"}`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
} catch (err) {
|
|
179
|
+
logger.error(`Hub list failed: ${err.message}`);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// ── Federation subcommands ──────────────────────────────────
|
|
184
|
+
|
|
185
|
+
const federation = evomap
|
|
186
|
+
.command("federation")
|
|
187
|
+
.description("Federated hub management and gene syncing");
|
|
188
|
+
|
|
189
|
+
federation
|
|
190
|
+
.command("list-hubs")
|
|
191
|
+
.description("List federated hubs")
|
|
192
|
+
.option("--status <status>", "Filter by status")
|
|
193
|
+
.option("--region <region>", "Filter by region")
|
|
194
|
+
.option("--json", "Output as JSON")
|
|
195
|
+
.action(async (options) => {
|
|
196
|
+
try {
|
|
197
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
198
|
+
if (!ctx.db) {
|
|
199
|
+
logger.error("Database not available");
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
const db = ctx.db.getDatabase();
|
|
203
|
+
ensureEvoMapFederationTables(db);
|
|
204
|
+
|
|
205
|
+
const hubs = listFederatedHubs(db, {
|
|
206
|
+
status: options.status,
|
|
207
|
+
region: options.region,
|
|
208
|
+
});
|
|
209
|
+
if (options.json) {
|
|
210
|
+
console.log(JSON.stringify(hubs, null, 2));
|
|
211
|
+
} else if (hubs.length === 0) {
|
|
212
|
+
logger.info(
|
|
213
|
+
"No federated hubs. Use `evomap federation add-hub` to add one.",
|
|
214
|
+
);
|
|
215
|
+
} else {
|
|
216
|
+
for (const h of hubs) {
|
|
217
|
+
logger.log(
|
|
218
|
+
` ${chalk.cyan(h.id.slice(0, 8))} ${h.hubUrl} [${h.status}] region=${h.region} genes=${h.geneCount} trust=${h.trustScore.toFixed(2)}`,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
await shutdown();
|
|
224
|
+
} catch (err) {
|
|
225
|
+
logger.error(`Failed: ${err.message}`);
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
federation
|
|
231
|
+
.command("add-hub <url>")
|
|
232
|
+
.description("Add a federated hub")
|
|
233
|
+
.option("-n, --name <name>", "Hub name")
|
|
234
|
+
.option("-r, --region <region>", "Hub region", "global")
|
|
235
|
+
.action(async (url, options) => {
|
|
236
|
+
try {
|
|
237
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
238
|
+
if (!ctx.db) {
|
|
239
|
+
logger.error("Database not available");
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
const db = ctx.db.getDatabase();
|
|
243
|
+
ensureEvoMapFederationTables(db);
|
|
244
|
+
|
|
245
|
+
const hub = addFederatedHub(db, url, options.name, options.region);
|
|
246
|
+
logger.success("Hub added");
|
|
247
|
+
logger.log(` ${chalk.bold("ID:")} ${chalk.cyan(hub.id)}`);
|
|
248
|
+
logger.log(` ${chalk.bold("URL:")} ${hub.hubUrl}`);
|
|
249
|
+
logger.log(` ${chalk.bold("Region:")} ${hub.region}`);
|
|
250
|
+
|
|
251
|
+
await shutdown();
|
|
252
|
+
} catch (err) {
|
|
253
|
+
logger.error(`Failed: ${err.message}`);
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
federation
|
|
259
|
+
.command("sync <hub-id>")
|
|
260
|
+
.description("Sync genes with a federated hub")
|
|
261
|
+
.option("--gene-ids <ids>", "Comma-separated gene IDs to sync")
|
|
262
|
+
.action(async (hubId, options) => {
|
|
263
|
+
try {
|
|
264
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
265
|
+
if (!ctx.db) {
|
|
266
|
+
logger.error("Database not available");
|
|
267
|
+
process.exit(1);
|
|
268
|
+
}
|
|
269
|
+
const db = ctx.db.getDatabase();
|
|
270
|
+
ensureEvoMapFederationTables(db);
|
|
271
|
+
|
|
272
|
+
const geneIds = options.geneIds
|
|
273
|
+
? options.geneIds.split(",").map((s) => s.trim())
|
|
274
|
+
: [];
|
|
275
|
+
const result = syncGenes(db, hubId, geneIds);
|
|
276
|
+
logger.success(
|
|
277
|
+
`Synced ${result.synced} gene(s) with hub ${chalk.cyan(hubId.slice(0, 8))}`,
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
await shutdown();
|
|
281
|
+
} catch (err) {
|
|
282
|
+
logger.error(`Failed: ${err.message}`);
|
|
283
|
+
process.exit(1);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
federation
|
|
288
|
+
.command("pressure")
|
|
289
|
+
.description("Show evolutionary pressure report")
|
|
290
|
+
.option("--json", "Output as JSON")
|
|
291
|
+
.action(async (options) => {
|
|
292
|
+
try {
|
|
293
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
294
|
+
if (!ctx.db) {
|
|
295
|
+
logger.error("Database not available");
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
const db = ctx.db.getDatabase();
|
|
299
|
+
ensureEvoMapFederationTables(db);
|
|
300
|
+
|
|
301
|
+
const report = getPressureReport();
|
|
302
|
+
if (options.json) {
|
|
303
|
+
console.log(JSON.stringify(report, null, 2));
|
|
304
|
+
} else {
|
|
305
|
+
logger.log(` ${chalk.bold("Total Genes:")} ${report.totalGenes}`);
|
|
306
|
+
logger.log(
|
|
307
|
+
` ${chalk.bold("Avg Fitness:")} ${report.avgFitness.toFixed(3)}`,
|
|
308
|
+
);
|
|
309
|
+
logger.log(
|
|
310
|
+
` ${chalk.bold("Max Generation:")} ${report.maxGeneration}`,
|
|
311
|
+
);
|
|
312
|
+
logger.log(` ${chalk.bold("Mutations:")} ${report.mutations}`);
|
|
313
|
+
logger.log(
|
|
314
|
+
` ${chalk.bold("Recombinations:")} ${report.recombinations}`,
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
await shutdown();
|
|
319
|
+
} catch (err) {
|
|
320
|
+
logger.error(`Failed: ${err.message}`);
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
federation
|
|
326
|
+
.command("recombine <gene-id-1> <gene-id-2>")
|
|
327
|
+
.description("Recombine two genes to create offspring")
|
|
328
|
+
.action(async (geneId1, geneId2) => {
|
|
329
|
+
try {
|
|
330
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
331
|
+
if (!ctx.db) {
|
|
332
|
+
logger.error("Database not available");
|
|
333
|
+
process.exit(1);
|
|
334
|
+
}
|
|
335
|
+
const db = ctx.db.getDatabase();
|
|
336
|
+
ensureEvoMapFederationTables(db);
|
|
337
|
+
|
|
338
|
+
const entry = recombineGenes(db, geneId1, geneId2);
|
|
339
|
+
logger.success("Genes recombined");
|
|
340
|
+
logger.log(
|
|
341
|
+
` ${chalk.bold("Child Gene:")} ${chalk.cyan(entry.geneId)}`,
|
|
342
|
+
);
|
|
343
|
+
logger.log(` ${chalk.bold("Parent 1:")} ${entry.parentGeneId}`);
|
|
344
|
+
logger.log(
|
|
345
|
+
` ${chalk.bold("Parent 2:")} ${entry.recombinationSource}`,
|
|
346
|
+
);
|
|
347
|
+
logger.log(` ${chalk.bold("Generation:")} ${entry.generation}`);
|
|
348
|
+
logger.log(
|
|
349
|
+
` ${chalk.bold("Fitness:")} ${entry.fitnessScore.toFixed(3)}`,
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
await shutdown();
|
|
353
|
+
} catch (err) {
|
|
354
|
+
logger.error(`Failed: ${err.message}`);
|
|
355
|
+
process.exit(1);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
federation
|
|
360
|
+
.command("lineage <gene-id>")
|
|
361
|
+
.description("Show gene lineage and ancestry")
|
|
362
|
+
.option("--json", "Output as JSON")
|
|
363
|
+
.action(async (geneId, options) => {
|
|
364
|
+
try {
|
|
365
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
366
|
+
if (!ctx.db) {
|
|
367
|
+
logger.error("Database not available");
|
|
368
|
+
process.exit(1);
|
|
369
|
+
}
|
|
370
|
+
const db = ctx.db.getDatabase();
|
|
371
|
+
ensureEvoMapFederationTables(db);
|
|
372
|
+
|
|
373
|
+
const entries = getLineage(geneId);
|
|
374
|
+
if (options.json) {
|
|
375
|
+
console.log(JSON.stringify(entries, null, 2));
|
|
376
|
+
} else if (entries.length === 0) {
|
|
377
|
+
logger.info("No lineage found for this gene.");
|
|
378
|
+
} else {
|
|
379
|
+
for (const e of entries) {
|
|
380
|
+
logger.log(
|
|
381
|
+
` ${chalk.cyan(e.id.slice(0, 8))} gene=${e.geneId.slice(0, 8)} gen=${e.generation} fitness=${e.fitnessScore.toFixed(2)} type=${e.mutationType}`,
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
await shutdown();
|
|
387
|
+
} catch (err) {
|
|
388
|
+
logger.error(`Failed: ${err.message}`);
|
|
389
|
+
process.exit(1);
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// ── Governance subcommands ──────────────────────────────────
|
|
394
|
+
|
|
395
|
+
const gov = evomap
|
|
396
|
+
.command("gov")
|
|
397
|
+
.description("EvoMap governance — ownership, proposals, voting");
|
|
398
|
+
|
|
399
|
+
gov
|
|
400
|
+
.command("ownership-register <gene-id> <owner-did>")
|
|
401
|
+
.description("Register gene ownership")
|
|
402
|
+
.action(async (geneId, ownerDid) => {
|
|
403
|
+
try {
|
|
404
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
405
|
+
if (!ctx.db) {
|
|
406
|
+
logger.error("Database not available");
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
const db = ctx.db.getDatabase();
|
|
410
|
+
ensureEvoMapGovernanceTables(db);
|
|
411
|
+
|
|
412
|
+
const result = registerOwnership(db, geneId, ownerDid);
|
|
413
|
+
logger.success("Ownership registered");
|
|
414
|
+
logger.log(` ${chalk.bold("ID:")} ${chalk.cyan(result.id)}`);
|
|
415
|
+
logger.log(` ${chalk.bold("Gene:")} ${result.geneId}`);
|
|
416
|
+
logger.log(` ${chalk.bold("Owner:")} ${result.ownerDid}`);
|
|
417
|
+
|
|
418
|
+
await shutdown();
|
|
419
|
+
} catch (err) {
|
|
420
|
+
logger.error(`Failed: ${err.message}`);
|
|
421
|
+
process.exit(1);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
gov
|
|
426
|
+
.command("ownership-trace <gene-id>")
|
|
427
|
+
.description("Trace gene ownership and contributions")
|
|
428
|
+
.option("--json", "Output as JSON")
|
|
429
|
+
.action(async (geneId, options) => {
|
|
430
|
+
try {
|
|
431
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
432
|
+
if (!ctx.db) {
|
|
433
|
+
logger.error("Database not available");
|
|
434
|
+
process.exit(1);
|
|
435
|
+
}
|
|
436
|
+
const db = ctx.db.getDatabase();
|
|
437
|
+
ensureEvoMapGovernanceTables(db);
|
|
438
|
+
|
|
439
|
+
const result = traceOwnership(geneId);
|
|
440
|
+
if (options.json) {
|
|
441
|
+
console.log(JSON.stringify(result, null, 2));
|
|
442
|
+
} else {
|
|
443
|
+
logger.log(` ${chalk.bold("Gene:")} ${result.geneId}`);
|
|
444
|
+
logger.log(
|
|
445
|
+
` ${chalk.bold("Owner:")} ${result.owner || "N/A"}`,
|
|
446
|
+
);
|
|
447
|
+
logger.log(
|
|
448
|
+
` ${chalk.bold("Contributors:")} ${result.contributors.join(", ") || "N/A"}`,
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
await shutdown();
|
|
453
|
+
} catch (err) {
|
|
454
|
+
logger.error(`Failed: ${err.message}`);
|
|
455
|
+
process.exit(1);
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
gov
|
|
460
|
+
.command("propose <title>")
|
|
461
|
+
.description("Create a governance proposal")
|
|
462
|
+
.option("-d, --description <text>", "Proposal description")
|
|
463
|
+
.option("-p, --proposer <did>", "Proposer DID", "cli-user")
|
|
464
|
+
.action(async (title, options) => {
|
|
465
|
+
try {
|
|
466
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
467
|
+
if (!ctx.db) {
|
|
468
|
+
logger.error("Database not available");
|
|
469
|
+
process.exit(1);
|
|
470
|
+
}
|
|
471
|
+
const db = ctx.db.getDatabase();
|
|
472
|
+
ensureEvoMapGovernanceTables(db);
|
|
473
|
+
|
|
474
|
+
const result = createGovernanceProposal(
|
|
475
|
+
db,
|
|
476
|
+
title,
|
|
477
|
+
options.description,
|
|
478
|
+
options.proposer,
|
|
479
|
+
);
|
|
480
|
+
logger.success("Proposal created");
|
|
481
|
+
logger.log(` ${chalk.bold("ID:")} ${chalk.cyan(result.id)}`);
|
|
482
|
+
logger.log(` ${chalk.bold("Title:")} ${result.title}`);
|
|
483
|
+
logger.log(` ${chalk.bold("Status:")} ${result.status}`);
|
|
484
|
+
|
|
485
|
+
await shutdown();
|
|
486
|
+
} catch (err) {
|
|
487
|
+
logger.error(`Failed: ${err.message}`);
|
|
488
|
+
process.exit(1);
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
gov
|
|
493
|
+
.command("vote <proposal-id> <direction>")
|
|
494
|
+
.description('Vote on a governance proposal ("for" or "against")')
|
|
495
|
+
.option("-v, --voter <did>", "Voter DID", "cli-user")
|
|
496
|
+
.action(async (proposalId, direction, options) => {
|
|
497
|
+
try {
|
|
498
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
499
|
+
if (!ctx.db) {
|
|
500
|
+
logger.error("Database not available");
|
|
501
|
+
process.exit(1);
|
|
502
|
+
}
|
|
503
|
+
const db = ctx.db.getDatabase();
|
|
504
|
+
ensureEvoMapGovernanceTables(db);
|
|
505
|
+
|
|
506
|
+
const result = voteOnGovernanceProposal(
|
|
507
|
+
db,
|
|
508
|
+
proposalId,
|
|
509
|
+
options.voter,
|
|
510
|
+
direction,
|
|
511
|
+
);
|
|
512
|
+
logger.success("Vote recorded");
|
|
513
|
+
logger.log(` ${chalk.bold("Proposal:")} ${result.proposalId}`);
|
|
514
|
+
logger.log(` ${chalk.bold("Direction:")} ${result.vote}`);
|
|
515
|
+
logger.log(` ${chalk.bold("Total Votes:")} ${result.totalVotes}`);
|
|
516
|
+
logger.log(` ${chalk.bold("Status:")} ${result.status}`);
|
|
517
|
+
|
|
518
|
+
await shutdown();
|
|
519
|
+
} catch (err) {
|
|
520
|
+
logger.error(`Failed: ${err.message}`);
|
|
521
|
+
process.exit(1);
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
gov
|
|
526
|
+
.command("dashboard")
|
|
527
|
+
.description("Show governance dashboard")
|
|
528
|
+
.option("--json", "Output as JSON")
|
|
529
|
+
.action(async (options) => {
|
|
530
|
+
try {
|
|
531
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
532
|
+
if (!ctx.db) {
|
|
533
|
+
logger.error("Database not available");
|
|
534
|
+
process.exit(1);
|
|
535
|
+
}
|
|
536
|
+
const db = ctx.db.getDatabase();
|
|
537
|
+
ensureEvoMapGovernanceTables(db);
|
|
538
|
+
|
|
539
|
+
const result = getGovernanceDashboard();
|
|
540
|
+
if (options.json) {
|
|
541
|
+
console.log(JSON.stringify(result, null, 2));
|
|
542
|
+
} else {
|
|
543
|
+
logger.log(
|
|
544
|
+
` ${chalk.bold("Total Proposals:")} ${result.totalProposals}`,
|
|
545
|
+
);
|
|
546
|
+
logger.log(` ${chalk.bold("Active:")} ${result.active}`);
|
|
547
|
+
logger.log(` ${chalk.bold("Passed:")} ${result.passed}`);
|
|
548
|
+
logger.log(` ${chalk.bold("Rejected:")} ${result.rejected}`);
|
|
549
|
+
logger.log(` ${chalk.bold("Executed:")} ${result.executed}`);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
await shutdown();
|
|
553
|
+
} catch (err) {
|
|
554
|
+
logger.error(`Failed: ${err.message}`);
|
|
555
|
+
process.exit(1);
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
}
|