chainlesschain 0.66.0 → 0.81.0

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.
@@ -12,6 +12,22 @@ import {
12
12
  createWorkspace,
13
13
  planRun,
14
14
  listRuns,
15
+ // V2
16
+ RUN_STATUS_V2,
17
+ RUN_TYPE_V2,
18
+ WORKSPACE_STATUS_V2,
19
+ TERRAFORM_DEFAULT_MAX_CONCURRENT,
20
+ setMaxConcurrentRuns,
21
+ getMaxConcurrentRuns,
22
+ createWorkspaceV2,
23
+ setWorkspaceStatus,
24
+ archiveWorkspace,
25
+ planRunV2,
26
+ setRunStatus,
27
+ cancelRun,
28
+ failRun,
29
+ getActiveRunCount,
30
+ getTerraformStatsV2,
15
31
  } from "../lib/terraform-manager.js";
16
32
 
17
33
  export function registerTerraformCommand(program) {
@@ -145,4 +161,233 @@ export function registerTerraformCommand(program) {
145
161
  process.exit(1);
146
162
  }
147
163
  });
164
+
165
+ /* ── V2 Subcommands (Phase 56) ──────────────────────────── */
166
+
167
+ const withDb = async (fn) => {
168
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
169
+ if (!ctx.db) {
170
+ logger.error("Database not available");
171
+ process.exit(1);
172
+ }
173
+ try {
174
+ const db = ctx.db.getDatabase();
175
+ ensureTerraformTables(db);
176
+ return await fn(db);
177
+ } finally {
178
+ await shutdown();
179
+ }
180
+ };
181
+
182
+ terraform
183
+ .command("run-statuses")
184
+ .description("List RUN_STATUS_V2 enum values")
185
+ .action(() => {
186
+ console.log(JSON.stringify(Object.values(RUN_STATUS_V2), null, 2));
187
+ });
188
+
189
+ terraform
190
+ .command("run-types")
191
+ .description("List RUN_TYPE_V2 enum values")
192
+ .action(() => {
193
+ console.log(JSON.stringify(Object.values(RUN_TYPE_V2), null, 2));
194
+ });
195
+
196
+ terraform
197
+ .command("workspace-statuses")
198
+ .description("List WORKSPACE_STATUS_V2 enum values")
199
+ .action(() => {
200
+ console.log(JSON.stringify(Object.values(WORKSPACE_STATUS_V2), null, 2));
201
+ });
202
+
203
+ terraform
204
+ .command("default-max-concurrent")
205
+ .description("Show TERRAFORM_DEFAULT_MAX_CONCURRENT")
206
+ .action(() => {
207
+ console.log(TERRAFORM_DEFAULT_MAX_CONCURRENT);
208
+ });
209
+
210
+ terraform
211
+ .command("active-run-count")
212
+ .description("Show current active (non-terminal) run count")
213
+ .action(() => {
214
+ console.log(getActiveRunCount());
215
+ });
216
+
217
+ terraform
218
+ .command("set-max-concurrent <n>")
219
+ .description("Set max concurrent runs")
220
+ .action(async (n) => {
221
+ try {
222
+ const value = setMaxConcurrentRuns(Number(n));
223
+ logger.success(`maxConcurrentRuns = ${value}`);
224
+ } catch (err) {
225
+ logger.error(`Failed: ${err.message}`);
226
+ process.exit(1);
227
+ }
228
+ });
229
+
230
+ terraform
231
+ .command("max-concurrent")
232
+ .description("Show current max concurrent runs")
233
+ .action(() => {
234
+ console.log(getMaxConcurrentRuns());
235
+ });
236
+
237
+ terraform
238
+ .command("create-workspace-v2 <name>")
239
+ .description("Create workspace (V2, unique-name enforced)")
240
+ .option("-d, --description <text>", "Workspace description")
241
+ .option("--tf-version <version>", "Terraform version")
242
+ .option("--auto-apply", "Enable auto-apply")
243
+ .option("--providers <list>", "Comma-separated providers")
244
+ .action(async (name, options) => {
245
+ await withDb(async (db) => {
246
+ try {
247
+ const ws = createWorkspaceV2(db, {
248
+ name,
249
+ description: options.description,
250
+ terraformVersion: options.tfVersion,
251
+ autoApply: options.autoApply,
252
+ providers: options.providers
253
+ ? options.providers.split(",").map((s) => s.trim())
254
+ : undefined,
255
+ });
256
+ logger.success("Workspace created (V2)");
257
+ logger.log(` ID: ${chalk.cyan(ws.id)}`);
258
+ logger.log(` Name: ${ws.name}`);
259
+ logger.log(` Status: ${ws.status}`);
260
+ } catch (err) {
261
+ logger.error(`Failed: ${err.message}`);
262
+ process.exit(1);
263
+ }
264
+ });
265
+ });
266
+
267
+ terraform
268
+ .command("set-workspace-status <workspace-id> <status>")
269
+ .description("Set workspace status (state-machine guarded)")
270
+ .action(async (workspaceId, status) => {
271
+ await withDb(async (db) => {
272
+ try {
273
+ const result = setWorkspaceStatus(db, workspaceId, status);
274
+ logger.success(
275
+ `Workspace ${workspaceId.slice(0, 8)} → ${result.status}`,
276
+ );
277
+ } catch (err) {
278
+ logger.error(`Failed: ${err.message}`);
279
+ process.exit(1);
280
+ }
281
+ });
282
+ });
283
+
284
+ terraform
285
+ .command("archive-workspace <workspace-id>")
286
+ .description("Archive a workspace (shortcut)")
287
+ .action(async (workspaceId) => {
288
+ await withDb(async (db) => {
289
+ try {
290
+ const result = archiveWorkspace(db, workspaceId);
291
+ logger.success(`Workspace archived: ${result.status}`);
292
+ } catch (err) {
293
+ logger.error(`Failed: ${err.message}`);
294
+ process.exit(1);
295
+ }
296
+ });
297
+ });
298
+
299
+ terraform
300
+ .command("plan-run-v2 <workspace-id>")
301
+ .description("Create a V2 run (pending state, concurrency-limited)")
302
+ .option("-t, --run-type <type>", "Run type: plan|apply|destroy", "plan")
303
+ .option("--triggered-by <who>", "Who triggered the run")
304
+ .action(async (workspaceId, options) => {
305
+ await withDb(async (db) => {
306
+ try {
307
+ const run = planRunV2(db, {
308
+ workspaceId,
309
+ runType: options.runType,
310
+ triggeredBy: options.triggeredBy,
311
+ });
312
+ logger.success("Run created (V2)");
313
+ logger.log(` ID: ${chalk.cyan(run.id)}`);
314
+ logger.log(` Type: ${run.runType}`);
315
+ logger.log(` Status: ${run.status}`);
316
+ } catch (err) {
317
+ logger.error(`Failed: ${err.message}`);
318
+ process.exit(1);
319
+ }
320
+ });
321
+ });
322
+
323
+ terraform
324
+ .command("set-run-status <run-id> <status>")
325
+ .description("Set run status (state-machine guarded)")
326
+ .option("--plan-output <text>", "Plan output summary")
327
+ .option("--apply-output <text>", "Apply output summary")
328
+ .option("--resources-added <n>", "Resources added count")
329
+ .option("--resources-changed <n>", "Resources changed count")
330
+ .option("--resources-destroyed <n>", "Resources destroyed count")
331
+ .option("--error-message <text>", "Error message")
332
+ .action(async (runId, status, options) => {
333
+ await withDb(async (db) => {
334
+ try {
335
+ const patch = {};
336
+ if (options.planOutput) patch.planOutput = options.planOutput;
337
+ if (options.applyOutput) patch.applyOutput = options.applyOutput;
338
+ if (options.resourcesAdded !== undefined)
339
+ patch.resourcesAdded = Number(options.resourcesAdded);
340
+ if (options.resourcesChanged !== undefined)
341
+ patch.resourcesChanged = Number(options.resourcesChanged);
342
+ if (options.resourcesDestroyed !== undefined)
343
+ patch.resourcesDestroyed = Number(options.resourcesDestroyed);
344
+ if (options.errorMessage) patch.errorMessage = options.errorMessage;
345
+ const run = setRunStatus(db, runId, status, patch);
346
+ logger.success(`Run ${runId.slice(0, 8)} → ${run.status}`);
347
+ } catch (err) {
348
+ logger.error(`Failed: ${err.message}`);
349
+ process.exit(1);
350
+ }
351
+ });
352
+ });
353
+
354
+ terraform
355
+ .command("cancel-run <run-id>")
356
+ .description("Cancel a run (shortcut)")
357
+ .action(async (runId) => {
358
+ await withDb(async (db) => {
359
+ try {
360
+ const run = cancelRun(db, runId);
361
+ logger.success(`Run cancelled: ${run.status}`);
362
+ } catch (err) {
363
+ logger.error(`Failed: ${err.message}`);
364
+ process.exit(1);
365
+ }
366
+ });
367
+ });
368
+
369
+ terraform
370
+ .command("fail-run <run-id> <error-message>")
371
+ .description("Mark a run as errored (shortcut)")
372
+ .action(async (runId, errorMessage) => {
373
+ await withDb(async (db) => {
374
+ try {
375
+ const run = failRun(db, runId, errorMessage);
376
+ logger.success(`Run errored: ${run.errorMessage}`);
377
+ } catch (err) {
378
+ logger.error(`Failed: ${err.message}`);
379
+ process.exit(1);
380
+ }
381
+ });
382
+ });
383
+
384
+ terraform
385
+ .command("stats-v2")
386
+ .description("Show V2 terraform stats")
387
+ .action(async () => {
388
+ await withDb(async () => {
389
+ const stats = getTerraformStatsV2();
390
+ console.log(JSON.stringify(stats, null, 2));
391
+ });
392
+ });
148
393
  }
@@ -22,6 +22,26 @@ import {
22
22
  registerCredential,
23
23
  selectiveDisclose,
24
24
  listCredentials,
25
+ // V2 — Phase 88
26
+ PROOF_SCHEME_V2,
27
+ CIRCUIT_STATUS_V2,
28
+ PROOF_STATUS_V2,
29
+ ZKP_DEFAULT_MAX_CIRCUITS_PER_CREATOR,
30
+ ZKP_DEFAULT_PROOF_EXPIRY_MS,
31
+ setMaxCircuitsPerCreator,
32
+ getMaxCircuitsPerCreator,
33
+ getCircuitCountByCreator,
34
+ setProofExpiryMs,
35
+ getProofExpiryMs,
36
+ compileCircuitV2,
37
+ setCircuitStatusV2,
38
+ generateProofV2,
39
+ verifyProofV2,
40
+ failProof,
41
+ setProofStatus,
42
+ autoExpireProofs,
43
+ selectiveDiscloseV2,
44
+ getZKPStatsV2,
25
45
  } from "../lib/zkp-engine.js";
26
46
 
27
47
  export function registerZkpCommand(program) {
@@ -500,4 +520,319 @@ export function registerZkpCommand(program) {
500
520
  process.exit(1);
501
521
  }
502
522
  });
523
+
524
+ /* ── V2 — Phase 88 ──────────────────────────────────────── */
525
+
526
+ // Enum dumps
527
+ zkp
528
+ .command("proof-schemes-v2")
529
+ .description("List V2 proof schemes")
530
+ .action(() => {
531
+ console.log(JSON.stringify(PROOF_SCHEME_V2, null, 2));
532
+ });
533
+
534
+ zkp
535
+ .command("circuit-statuses-v2")
536
+ .description("List V2 circuit statuses")
537
+ .action(() => {
538
+ console.log(JSON.stringify(CIRCUIT_STATUS_V2, null, 2));
539
+ });
540
+
541
+ zkp
542
+ .command("proof-statuses-v2")
543
+ .description("List V2 proof statuses (pending/verified/invalid/expired)")
544
+ .action(() => {
545
+ console.log(JSON.stringify(PROOF_STATUS_V2, null, 2));
546
+ });
547
+
548
+ zkp
549
+ .command("default-max-circuits-per-creator")
550
+ .description("Show default max circuits per creator")
551
+ .action(() => {
552
+ console.log(ZKP_DEFAULT_MAX_CIRCUITS_PER_CREATOR);
553
+ });
554
+
555
+ zkp
556
+ .command("max-circuits-per-creator")
557
+ .description("Show current max circuits per creator")
558
+ .action(() => {
559
+ console.log(getMaxCircuitsPerCreator());
560
+ });
561
+
562
+ zkp
563
+ .command("set-max-circuits-per-creator <n>")
564
+ .description("Set max circuits per creator (positive integer)")
565
+ .action((n) => {
566
+ try {
567
+ setMaxCircuitsPerCreator(Number(n));
568
+ logger.success(
569
+ `Max circuits per creator = ${getMaxCircuitsPerCreator()}`,
570
+ );
571
+ } catch (err) {
572
+ logger.error(`Failed: ${err.message}`);
573
+ process.exit(1);
574
+ }
575
+ });
576
+
577
+ zkp
578
+ .command("circuit-count-by-creator <creator>")
579
+ .description("Count circuits owned by a creator")
580
+ .action((creator) => {
581
+ console.log(getCircuitCountByCreator(creator));
582
+ });
583
+
584
+ zkp
585
+ .command("default-proof-expiry-ms")
586
+ .description("Show default proof expiry (ms)")
587
+ .action(() => {
588
+ console.log(ZKP_DEFAULT_PROOF_EXPIRY_MS);
589
+ });
590
+
591
+ zkp
592
+ .command("proof-expiry-ms")
593
+ .description("Show current proof expiry (ms)")
594
+ .action(() => {
595
+ console.log(getProofExpiryMs());
596
+ });
597
+
598
+ zkp
599
+ .command("set-proof-expiry-ms <ms>")
600
+ .description("Set proof expiry in ms")
601
+ .action((ms) => {
602
+ try {
603
+ setProofExpiryMs(Number(ms));
604
+ logger.success(`Proof expiry = ${getProofExpiryMs()}ms`);
605
+ } catch (err) {
606
+ logger.error(`Failed: ${err.message}`);
607
+ process.exit(1);
608
+ }
609
+ });
610
+
611
+ zkp
612
+ .command("compile-v2 <name>")
613
+ .description("Compile circuit (V2 — creator cap enforced)")
614
+ .option("-d, --definition <json>", "Circuit definition as JSON")
615
+ .option("-c, --creator <did>", "Creator DID")
616
+ .action(async (name, options) => {
617
+ try {
618
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
619
+ if (!ctx.db) {
620
+ logger.error("Database not available");
621
+ process.exit(1);
622
+ }
623
+ const db = ctx.db.getDatabase();
624
+ ensureZKPTables(db);
625
+ const def = options.definition ? JSON.parse(options.definition) : {};
626
+ const circuit = compileCircuitV2(db, {
627
+ name,
628
+ definition: def,
629
+ creator: options.creator,
630
+ });
631
+ logger.success(`Circuit compiled (V2): ${chalk.cyan(name)}`);
632
+ logger.log(` ${chalk.bold("ID:")} ${chalk.cyan(circuit.id)}`);
633
+ if (circuit.creator) {
634
+ logger.log(` ${chalk.bold("Creator:")} ${circuit.creator}`);
635
+ }
636
+ await shutdown();
637
+ } catch (err) {
638
+ logger.error(`Failed: ${err.message}`);
639
+ process.exit(1);
640
+ }
641
+ });
642
+
643
+ zkp
644
+ .command("set-circuit-status-v2 <circuit-id> <status>")
645
+ .description("Set circuit status (state-machine guarded)")
646
+ .option("-e, --error-message <msg>", "Error message (for failed status)")
647
+ .action(async (circuitId, status, options) => {
648
+ try {
649
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
650
+ const db = ctx.db.getDatabase();
651
+ ensureZKPTables(db);
652
+ const patch = {};
653
+ if (options.errorMessage !== undefined) {
654
+ patch.errorMessage = options.errorMessage;
655
+ }
656
+ const updated = setCircuitStatusV2(db, circuitId, status, patch);
657
+ logger.success(`Circuit ${circuitId} → ${updated.status}`);
658
+ await shutdown();
659
+ } catch (err) {
660
+ logger.error(`Failed: ${err.message}`);
661
+ process.exit(1);
662
+ }
663
+ });
664
+
665
+ zkp
666
+ .command("prove-v2 <circuit-id>")
667
+ .description("Generate proof (V2 — stamps pending + expiresAt)")
668
+ .option("--private <json>", "Private inputs JSON", "{}")
669
+ .option("--public <json>", "Public inputs JSON", "[]")
670
+ .option("-s, --scheme <scheme>", "Proof scheme")
671
+ .action(async (circuitId, options) => {
672
+ try {
673
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
674
+ const db = ctx.db.getDatabase();
675
+ ensureZKPTables(db);
676
+ const proof = generateProofV2(db, {
677
+ circuitId,
678
+ privateInputs: JSON.parse(options.private),
679
+ publicInputs: JSON.parse(options.public),
680
+ scheme: options.scheme,
681
+ });
682
+ logger.success("Proof generated (V2)");
683
+ logger.log(` ${chalk.bold("ID:")} ${chalk.cyan(proof.id)}`);
684
+ logger.log(` ${chalk.bold("Status:")} ${proof.status}`);
685
+ logger.log(
686
+ ` ${chalk.bold("ExpiresAt:")} ${new Date(proof.expiresAt).toISOString()}`,
687
+ );
688
+ await shutdown();
689
+ } catch (err) {
690
+ logger.error(`Failed: ${err.message}`);
691
+ process.exit(1);
692
+ }
693
+ });
694
+
695
+ zkp
696
+ .command("verify-v2 <proof-id>")
697
+ .description("Verify proof (V2 — auto-expire past deadline)")
698
+ .action(async (proofId) => {
699
+ try {
700
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
701
+ const db = ctx.db.getDatabase();
702
+ ensureZKPTables(db);
703
+ const result = verifyProofV2(db, proofId);
704
+ if (result.valid) {
705
+ logger.success(`Proof ${proofId} VERIFIED`);
706
+ } else {
707
+ logger.error(
708
+ `Proof ${proofId} INVALID (reason: ${result.reason || result.status})`,
709
+ );
710
+ }
711
+ await shutdown();
712
+ } catch (err) {
713
+ logger.error(`Failed: ${err.message}`);
714
+ process.exit(1);
715
+ }
716
+ });
717
+
718
+ zkp
719
+ .command("fail-proof <proof-id>")
720
+ .description("Mark proof as invalid")
721
+ .option("-r, --reason <reason>", "Failure reason")
722
+ .action(async (proofId, options) => {
723
+ try {
724
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
725
+ const db = ctx.db.getDatabase();
726
+ ensureZKPTables(db);
727
+ failProof(db, proofId, { reason: options.reason });
728
+ logger.success(`Proof ${proofId} → invalid`);
729
+ await shutdown();
730
+ } catch (err) {
731
+ logger.error(`Failed: ${err.message}`);
732
+ process.exit(1);
733
+ }
734
+ });
735
+
736
+ zkp
737
+ .command("set-proof-status <proof-id> <status>")
738
+ .description("Set proof status (state-machine guarded)")
739
+ .option("-e, --error-message <msg>", "Error message")
740
+ .action(async (proofId, status, options) => {
741
+ try {
742
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
743
+ const db = ctx.db.getDatabase();
744
+ ensureZKPTables(db);
745
+ const patch = {};
746
+ if (options.errorMessage !== undefined) {
747
+ patch.errorMessage = options.errorMessage;
748
+ }
749
+ const updated = setProofStatus(db, proofId, status, patch);
750
+ logger.success(`Proof ${proofId} → ${updated.status}`);
751
+ await shutdown();
752
+ } catch (err) {
753
+ logger.error(`Failed: ${err.message}`);
754
+ process.exit(1);
755
+ }
756
+ });
757
+
758
+ zkp
759
+ .command("auto-expire-proofs")
760
+ .description("Bulk-expire proofs past their deadline")
761
+ .action(async () => {
762
+ try {
763
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
764
+ const db = ctx.db.getDatabase();
765
+ ensureZKPTables(db);
766
+ const expired = autoExpireProofs(db);
767
+ logger.success(`Expired ${expired.length} proofs`);
768
+ await shutdown();
769
+ } catch (err) {
770
+ logger.error(`Failed: ${err.message}`);
771
+ process.exit(1);
772
+ }
773
+ });
774
+
775
+ zkp
776
+ .command("selective-disclose-v2 <credential-id>")
777
+ .description(
778
+ "Selectively disclose credential fields (requiredFields enforced)",
779
+ )
780
+ .option(
781
+ "-d, --disclosed <fields>",
782
+ "Comma-separated fields to disclose",
783
+ "",
784
+ )
785
+ .option(
786
+ "-r, --required <fields>",
787
+ "Comma-separated fields REQUIRED in disclosure",
788
+ "",
789
+ )
790
+ .option("--recipient <did>", "Recipient DID")
791
+ .action(async (credentialId, options) => {
792
+ try {
793
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
794
+ const db = ctx.db.getDatabase();
795
+ ensureZKPTables(db);
796
+ const disclosedFields = options.disclosed
797
+ ? options.disclosed
798
+ .split(",")
799
+ .map((s) => s.trim())
800
+ .filter(Boolean)
801
+ : [];
802
+ const requiredFields = options.required
803
+ ? options.required
804
+ .split(",")
805
+ .map((s) => s.trim())
806
+ .filter(Boolean)
807
+ : undefined;
808
+ const result = selectiveDiscloseV2(db, {
809
+ credentialId,
810
+ disclosedFields,
811
+ requiredFields,
812
+ recipientDid: options.recipient,
813
+ });
814
+ console.log(JSON.stringify(result, null, 2));
815
+ await shutdown();
816
+ } catch (err) {
817
+ logger.error(`Failed: ${err.message}`);
818
+ process.exit(1);
819
+ }
820
+ });
821
+
822
+ zkp
823
+ .command("stats-v2")
824
+ .description("V2 stats (all-enum-key zero init)")
825
+ .action(async () => {
826
+ try {
827
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
828
+ const db = ctx.db.getDatabase();
829
+ ensureZKPTables(db);
830
+ const stats = getZKPStatsV2();
831
+ console.log(JSON.stringify(stats, null, 2));
832
+ await shutdown();
833
+ } catch (err) {
834
+ logger.error(`Failed: ${err.message}`);
835
+ process.exit(1);
836
+ }
837
+ });
503
838
  }