chainlesschain 0.37.8 → 0.37.10

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 (59) hide show
  1. package/README.md +403 -8
  2. package/bin/chainlesschain.js +4 -0
  3. package/package.json +7 -2
  4. package/src/commands/agent.js +30 -0
  5. package/src/commands/ask.js +114 -0
  6. package/src/commands/audit.js +286 -0
  7. package/src/commands/auth.js +387 -0
  8. package/src/commands/browse.js +184 -0
  9. package/src/commands/chat.js +35 -0
  10. package/src/commands/db.js +152 -0
  11. package/src/commands/did.js +376 -0
  12. package/src/commands/encrypt.js +233 -0
  13. package/src/commands/export.js +125 -0
  14. package/src/commands/git.js +215 -0
  15. package/src/commands/import.js +259 -0
  16. package/src/commands/instinct.js +202 -0
  17. package/src/commands/llm.js +288 -0
  18. package/src/commands/mcp.js +302 -0
  19. package/src/commands/memory.js +282 -0
  20. package/src/commands/note.js +489 -0
  21. package/src/commands/org.js +505 -0
  22. package/src/commands/p2p.js +274 -0
  23. package/src/commands/plugin.js +398 -0
  24. package/src/commands/search.js +237 -0
  25. package/src/commands/session.js +238 -0
  26. package/src/commands/skill.js +479 -0
  27. package/src/commands/sync.js +249 -0
  28. package/src/commands/tokens.js +214 -0
  29. package/src/commands/wallet.js +416 -0
  30. package/src/index.js +65 -0
  31. package/src/lib/audit-logger.js +364 -0
  32. package/src/lib/bm25-search.js +322 -0
  33. package/src/lib/browser-automation.js +216 -0
  34. package/src/lib/crypto-manager.js +246 -0
  35. package/src/lib/did-manager.js +270 -0
  36. package/src/lib/ensure-utf8.js +59 -0
  37. package/src/lib/git-integration.js +220 -0
  38. package/src/lib/instinct-manager.js +190 -0
  39. package/src/lib/knowledge-exporter.js +302 -0
  40. package/src/lib/knowledge-importer.js +293 -0
  41. package/src/lib/llm-providers.js +325 -0
  42. package/src/lib/mcp-client.js +413 -0
  43. package/src/lib/memory-manager.js +211 -0
  44. package/src/lib/note-versioning.js +244 -0
  45. package/src/lib/org-manager.js +424 -0
  46. package/src/lib/p2p-manager.js +317 -0
  47. package/src/lib/pdf-parser.js +96 -0
  48. package/src/lib/permission-engine.js +374 -0
  49. package/src/lib/plan-mode.js +333 -0
  50. package/src/lib/platform.js +15 -0
  51. package/src/lib/plugin-manager.js +312 -0
  52. package/src/lib/response-cache.js +156 -0
  53. package/src/lib/session-manager.js +189 -0
  54. package/src/lib/sync-manager.js +347 -0
  55. package/src/lib/token-tracker.js +200 -0
  56. package/src/lib/wallet-manager.js +348 -0
  57. package/src/repl/agent-repl.js +912 -0
  58. package/src/repl/chat-repl.js +262 -0
  59. package/src/runtime/bootstrap.js +159 -0
@@ -0,0 +1,505 @@
1
+ /**
2
+ * Organization & team commands
3
+ * chainlesschain org create|list|show|update|delete|invite|members|team|approval
4
+ */
5
+
6
+ import chalk from "chalk";
7
+ import { logger } from "../lib/logger.js";
8
+ import { bootstrap, shutdown } from "../runtime/bootstrap.js";
9
+ import {
10
+ createOrg,
11
+ getOrg,
12
+ listOrgs,
13
+ updateOrg,
14
+ deleteOrg,
15
+ inviteMember,
16
+ acceptInvite,
17
+ getMembers,
18
+ updateMemberRole,
19
+ removeMember,
20
+ createTeam,
21
+ listTeams,
22
+ addTeamMember,
23
+ getTeamMembers,
24
+ removeTeamMember,
25
+ deleteTeam,
26
+ submitApproval,
27
+ approveRequest,
28
+ rejectRequest,
29
+ getApprovals,
30
+ getOrgSummary,
31
+ } from "../lib/org-manager.js";
32
+
33
+ export function registerOrgCommand(program) {
34
+ const org = program
35
+ .command("org")
36
+ .description("Organization, team, and approval management");
37
+
38
+ // org create
39
+ org
40
+ .command("create")
41
+ .description("Create a new organization")
42
+ .argument("<name>", "Organization name")
43
+ .option("--owner <id>", "Owner user ID", "cli-user")
44
+ .option("--description <desc>", "Organization description")
45
+ .option("--json", "Output as JSON")
46
+ .action(async (name, options) => {
47
+ try {
48
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
49
+ if (!ctx.db) {
50
+ logger.error("Database not available");
51
+ process.exit(1);
52
+ }
53
+ const db = ctx.db.getDatabase();
54
+ const result = createOrg(db, name, options.owner, options.description);
55
+
56
+ if (options.json) {
57
+ console.log(JSON.stringify(result, null, 2));
58
+ } else {
59
+ logger.success("Organization created");
60
+ logger.log(` ${chalk.bold("ID:")} ${chalk.cyan(result.id)}`);
61
+ logger.log(` ${chalk.bold("Name:")} ${result.name}`);
62
+ logger.log(` ${chalk.bold("Owner:")} ${result.ownerId}`);
63
+ }
64
+
65
+ await shutdown();
66
+ } catch (err) {
67
+ logger.error(`Failed: ${err.message}`);
68
+ process.exit(1);
69
+ }
70
+ });
71
+
72
+ // org list
73
+ org
74
+ .command("list", { isDefault: true })
75
+ .description("List all organizations")
76
+ .option("--json", "Output as JSON")
77
+ .action(async (options) => {
78
+ try {
79
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
80
+ if (!ctx.db) {
81
+ logger.error("Database not available");
82
+ process.exit(1);
83
+ }
84
+ const db = ctx.db.getDatabase();
85
+ const orgs = listOrgs(db);
86
+
87
+ if (options.json) {
88
+ console.log(JSON.stringify(orgs, null, 2));
89
+ } else if (orgs.length === 0) {
90
+ logger.info(
91
+ 'No organizations. Create one with "chainlesschain org create <name>"',
92
+ );
93
+ } else {
94
+ logger.log(chalk.bold(`Organizations (${orgs.length}):\n`));
95
+ for (const o of orgs) {
96
+ const status =
97
+ o.status === "active"
98
+ ? chalk.green("active")
99
+ : chalk.gray(o.status);
100
+ logger.log(` ${chalk.cyan(o.id)} - ${o.name} [${status}]`);
101
+ }
102
+ }
103
+
104
+ await shutdown();
105
+ } catch (err) {
106
+ logger.error(`Failed: ${err.message}`);
107
+ process.exit(1);
108
+ }
109
+ });
110
+
111
+ // org show
112
+ org
113
+ .command("show")
114
+ .description("Show organization details")
115
+ .argument("<org-id>", "Organization ID")
116
+ .option("--json", "Output as JSON")
117
+ .action(async (orgId, options) => {
118
+ try {
119
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
120
+ if (!ctx.db) {
121
+ logger.error("Database not available");
122
+ process.exit(1);
123
+ }
124
+ const db = ctx.db.getDatabase();
125
+ const orgData = getOrg(db, orgId);
126
+
127
+ if (!orgData) {
128
+ logger.error(`Organization not found: ${orgId}`);
129
+ process.exit(1);
130
+ }
131
+
132
+ const summary = getOrgSummary(db, orgId);
133
+
134
+ if (options.json) {
135
+ console.log(JSON.stringify({ ...orgData, ...summary }, null, 2));
136
+ } else {
137
+ logger.log(chalk.bold("Organization:\n"));
138
+ logger.log(
139
+ ` ${chalk.bold("ID:")} ${chalk.cyan(orgData.id)}`,
140
+ );
141
+ logger.log(` ${chalk.bold("Name:")} ${orgData.name}`);
142
+ logger.log(
143
+ ` ${chalk.bold("Description:")} ${orgData.description || chalk.gray("(none)")}`,
144
+ );
145
+ logger.log(` ${chalk.bold("Owner:")} ${orgData.owner_id}`);
146
+ logger.log(` ${chalk.bold("Members:")} ${summary.memberCount}`);
147
+ logger.log(` ${chalk.bold("Teams:")} ${summary.teamCount}`);
148
+ logger.log(
149
+ ` ${chalk.bold("Pending:")} ${summary.pendingApprovals}`,
150
+ );
151
+ }
152
+
153
+ await shutdown();
154
+ } catch (err) {
155
+ logger.error(`Failed: ${err.message}`);
156
+ process.exit(1);
157
+ }
158
+ });
159
+
160
+ // org delete
161
+ org
162
+ .command("delete")
163
+ .description("Delete an organization")
164
+ .argument("<org-id>", "Organization ID")
165
+ .option("--force", "Skip confirmation")
166
+ .action(async (orgId, options) => {
167
+ try {
168
+ if (!options.force) {
169
+ const { confirm } = await import("@inquirer/prompts");
170
+ const ok = await confirm({
171
+ message: "Delete this organization and all its data?",
172
+ });
173
+ if (!ok) {
174
+ logger.info("Cancelled");
175
+ return;
176
+ }
177
+ }
178
+
179
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
180
+ if (!ctx.db) {
181
+ logger.error("Database not available");
182
+ process.exit(1);
183
+ }
184
+ const db = ctx.db.getDatabase();
185
+ const ok = deleteOrg(db, orgId);
186
+
187
+ if (ok) {
188
+ logger.success("Organization deleted");
189
+ } else {
190
+ logger.error(`Organization not found: ${orgId}`);
191
+ }
192
+
193
+ await shutdown();
194
+ } catch (err) {
195
+ logger.error(`Failed: ${err.message}`);
196
+ process.exit(1);
197
+ }
198
+ });
199
+
200
+ // org invite
201
+ org
202
+ .command("invite")
203
+ .description("Invite a member to an organization")
204
+ .argument("<org-id>", "Organization ID")
205
+ .argument("<user-id>", "User ID to invite")
206
+ .option("--name <name>", "Display name")
207
+ .option("--role <role>", "Role (admin/member/viewer)", "member")
208
+ .action(async (orgId, userId, options) => {
209
+ try {
210
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
211
+ if (!ctx.db) {
212
+ logger.error("Database not available");
213
+ process.exit(1);
214
+ }
215
+ const db = ctx.db.getDatabase();
216
+ const result = inviteMember(
217
+ db,
218
+ orgId,
219
+ userId,
220
+ options.name,
221
+ options.role,
222
+ );
223
+ logger.success(`Invited ${userId} as ${result.role}`);
224
+ await shutdown();
225
+ } catch (err) {
226
+ logger.error(`Failed: ${err.message}`);
227
+ process.exit(1);
228
+ }
229
+ });
230
+
231
+ // org members
232
+ org
233
+ .command("members")
234
+ .description("List organization members")
235
+ .argument("<org-id>", "Organization ID")
236
+ .option("--json", "Output as JSON")
237
+ .action(async (orgId, options) => {
238
+ try {
239
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
240
+ if (!ctx.db) {
241
+ logger.error("Database not available");
242
+ process.exit(1);
243
+ }
244
+ const db = ctx.db.getDatabase();
245
+ const members = getMembers(db, orgId);
246
+
247
+ if (options.json) {
248
+ console.log(JSON.stringify(members, null, 2));
249
+ } else if (members.length === 0) {
250
+ logger.info("No members");
251
+ } else {
252
+ logger.log(chalk.bold(`Members (${members.length}):\n`));
253
+ for (const m of members) {
254
+ const role =
255
+ m.role === "admin" ? chalk.yellow(m.role) : chalk.gray(m.role);
256
+ const status =
257
+ m.status === "active"
258
+ ? chalk.green("active")
259
+ : chalk.gray(m.status);
260
+ logger.log(` ${m.user_id} [${role}] ${status}`);
261
+ }
262
+ }
263
+
264
+ await shutdown();
265
+ } catch (err) {
266
+ logger.error(`Failed: ${err.message}`);
267
+ process.exit(1);
268
+ }
269
+ });
270
+
271
+ // org team create
272
+ org
273
+ .command("team-create")
274
+ .description("Create a team")
275
+ .argument("<org-id>", "Organization ID")
276
+ .argument("<team-name>", "Team name")
277
+ .option("--description <desc>", "Team description")
278
+ .option("--lead <id>", "Team lead user ID")
279
+ .option("--json", "Output as JSON")
280
+ .action(async (orgId, teamName, options) => {
281
+ try {
282
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
283
+ if (!ctx.db) {
284
+ logger.error("Database not available");
285
+ process.exit(1);
286
+ }
287
+ const db = ctx.db.getDatabase();
288
+ const team = createTeam(
289
+ db,
290
+ orgId,
291
+ teamName,
292
+ options.description,
293
+ options.lead,
294
+ );
295
+
296
+ if (options.json) {
297
+ console.log(JSON.stringify(team, null, 2));
298
+ } else {
299
+ logger.success("Team created");
300
+ logger.log(` ${chalk.bold("ID:")} ${chalk.cyan(team.id)}`);
301
+ logger.log(` ${chalk.bold("Name:")} ${team.name}`);
302
+ }
303
+
304
+ await shutdown();
305
+ } catch (err) {
306
+ logger.error(`Failed: ${err.message}`);
307
+ process.exit(1);
308
+ }
309
+ });
310
+
311
+ // org teams
312
+ org
313
+ .command("teams")
314
+ .description("List teams in an organization")
315
+ .argument("<org-id>", "Organization ID")
316
+ .option("--json", "Output as JSON")
317
+ .action(async (orgId, options) => {
318
+ try {
319
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
320
+ if (!ctx.db) {
321
+ logger.error("Database not available");
322
+ process.exit(1);
323
+ }
324
+ const db = ctx.db.getDatabase();
325
+ const teams = listTeams(db, orgId);
326
+
327
+ if (options.json) {
328
+ console.log(JSON.stringify(teams, null, 2));
329
+ } else if (teams.length === 0) {
330
+ logger.info("No teams");
331
+ } else {
332
+ logger.log(chalk.bold(`Teams (${teams.length}):\n`));
333
+ for (const t of teams) {
334
+ logger.log(` ${chalk.cyan(t.id)} - ${t.name}`);
335
+ if (t.description) logger.log(` ${chalk.gray(t.description)}`);
336
+ }
337
+ }
338
+
339
+ await shutdown();
340
+ } catch (err) {
341
+ logger.error(`Failed: ${err.message}`);
342
+ process.exit(1);
343
+ }
344
+ });
345
+
346
+ // org approval submit
347
+ org
348
+ .command("approval-submit")
349
+ .description("Submit an approval request")
350
+ .argument("<org-id>", "Organization ID")
351
+ .argument("<title>", "Request title")
352
+ .option("--type <type>", "Request type", "general")
353
+ .option("--description <desc>", "Request description")
354
+ .option("--requester <id>", "Requester ID", "cli-user")
355
+ .option("--json", "Output as JSON")
356
+ .action(async (orgId, title, options) => {
357
+ try {
358
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
359
+ if (!ctx.db) {
360
+ logger.error("Database not available");
361
+ process.exit(1);
362
+ }
363
+ const db = ctx.db.getDatabase();
364
+ const result = submitApproval(
365
+ db,
366
+ orgId,
367
+ options.requester,
368
+ options.type,
369
+ title,
370
+ options.description,
371
+ );
372
+
373
+ if (options.json) {
374
+ console.log(JSON.stringify(result, null, 2));
375
+ } else {
376
+ logger.success("Approval request submitted");
377
+ logger.log(` ${chalk.bold("ID:")} ${chalk.cyan(result.id)}`);
378
+ logger.log(
379
+ ` ${chalk.bold("Status:")} ${chalk.yellow(result.status)}`,
380
+ );
381
+ }
382
+
383
+ await shutdown();
384
+ } catch (err) {
385
+ logger.error(`Failed: ${err.message}`);
386
+ process.exit(1);
387
+ }
388
+ });
389
+
390
+ // org approval list
391
+ org
392
+ .command("approvals")
393
+ .description("List approval requests")
394
+ .option("--org <id>", "Filter by organization")
395
+ .option("--status <status>", "Filter by status (pending/approved/rejected)")
396
+ .option("--json", "Output as JSON")
397
+ .action(async (options) => {
398
+ try {
399
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
400
+ if (!ctx.db) {
401
+ logger.error("Database not available");
402
+ process.exit(1);
403
+ }
404
+ const db = ctx.db.getDatabase();
405
+ const approvals = getApprovals(db, {
406
+ orgId: options.org,
407
+ status: options.status,
408
+ });
409
+
410
+ if (options.json) {
411
+ console.log(JSON.stringify(approvals, null, 2));
412
+ } else if (approvals.length === 0) {
413
+ logger.info("No approval requests");
414
+ } else {
415
+ logger.log(chalk.bold(`Approvals (${approvals.length}):\n`));
416
+ for (const a of approvals) {
417
+ const statusColor =
418
+ a.status === "approved"
419
+ ? chalk.green
420
+ : a.status === "rejected"
421
+ ? chalk.red
422
+ : chalk.yellow;
423
+ logger.log(
424
+ ` ${chalk.cyan(a.id)} ${a.title} [${statusColor(a.status)}]`,
425
+ );
426
+ }
427
+ }
428
+
429
+ await shutdown();
430
+ } catch (err) {
431
+ logger.error(`Failed: ${err.message}`);
432
+ process.exit(1);
433
+ }
434
+ });
435
+
436
+ // org approval approve
437
+ org
438
+ .command("approve")
439
+ .description("Approve a request")
440
+ .argument("<approval-id>", "Approval request ID")
441
+ .option("--approver <id>", "Approver ID", "cli-user")
442
+ .option("--note <note>", "Decision note")
443
+ .action(async (approvalId, options) => {
444
+ try {
445
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
446
+ if (!ctx.db) {
447
+ logger.error("Database not available");
448
+ process.exit(1);
449
+ }
450
+ const db = ctx.db.getDatabase();
451
+ const ok = approveRequest(
452
+ db,
453
+ approvalId,
454
+ options.approver,
455
+ options.note,
456
+ );
457
+
458
+ if (ok) {
459
+ logger.success("Request approved");
460
+ } else {
461
+ logger.error(`Request not found: ${approvalId}`);
462
+ }
463
+
464
+ await shutdown();
465
+ } catch (err) {
466
+ logger.error(`Failed: ${err.message}`);
467
+ process.exit(1);
468
+ }
469
+ });
470
+
471
+ // org approval reject
472
+ org
473
+ .command("reject")
474
+ .description("Reject a request")
475
+ .argument("<approval-id>", "Approval request ID")
476
+ .option("--approver <id>", "Approver ID", "cli-user")
477
+ .option("--note <note>", "Decision note")
478
+ .action(async (approvalId, options) => {
479
+ try {
480
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
481
+ if (!ctx.db) {
482
+ logger.error("Database not available");
483
+ process.exit(1);
484
+ }
485
+ const db = ctx.db.getDatabase();
486
+ const ok = rejectRequest(
487
+ db,
488
+ approvalId,
489
+ options.approver,
490
+ options.note,
491
+ );
492
+
493
+ if (ok) {
494
+ logger.success("Request rejected");
495
+ } else {
496
+ logger.error(`Request not found: ${approvalId}`);
497
+ }
498
+
499
+ await shutdown();
500
+ } catch (err) {
501
+ logger.error(`Failed: ${err.message}`);
502
+ process.exit(1);
503
+ }
504
+ });
505
+ }