@hardkas/cli 0.2.1-alpha → 0.2.2-alpha.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/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  UI,
4
4
  handleError
5
- } from "./chunk-M54KNJEH.js";
5
+ } from "./chunk-AQWQW5ZG.js";
6
6
 
7
7
  // src/index.ts
8
8
  import { Command } from "commander";
@@ -70,19 +70,19 @@ async function runUp() {
70
70
 
71
71
  // src/commands/init.ts
72
72
  function registerInitCommands(program) {
73
- program.command("init").description("Initialize a new HardKAS project").argument("[name]", "Project name or directory").option("--force", "Overwrite existing hardkas.config.ts", false).action(async (name, options) => {
73
+ program.command("init").description(`Initialize a new HardKAS project ${UI.maturity("stable")}`).argument("[name]", "Project name or directory").option("--force", "Overwrite existing hardkas.config.ts", false).action(async (name, options) => {
74
74
  try {
75
75
  const fs10 = await import("fs");
76
- const path11 = await import("path");
76
+ const path12 = await import("path");
77
77
  let targetDir = process.cwd();
78
78
  if (name) {
79
- targetDir = path11.join(process.cwd(), name);
79
+ targetDir = path12.join(process.cwd(), name);
80
80
  if (!fs10.existsSync(targetDir)) {
81
81
  fs10.mkdirSync(targetDir, { recursive: true });
82
82
  }
83
83
  }
84
- const configFile = path11.join(targetDir, "hardkas.config.ts");
85
- const pkgFile = path11.join(targetDir, "package.json");
84
+ const configFile = path12.join(targetDir, "hardkas.config.ts");
85
+ const pkgFile = path12.join(targetDir, "package.json");
86
86
  if (fs10.existsSync(configFile) && !options.force) {
87
87
  UI.warning(`hardkas.config.ts already exists in ${name || "current directory"}. Use --force to overwrite.`);
88
88
  return;
@@ -102,7 +102,7 @@ function registerInitCommands(program) {
102
102
  const template = `import { defineHardkasConfig } from "@hardkas/sdk";
103
103
 
104
104
  export default defineHardkasConfig({
105
- // HardKAS v0.2-alpha Configuration
105
+ // HardKAS v0.2.2-alpha Configuration
106
106
  defaultNetwork: "simnet",
107
107
 
108
108
  networks: {
@@ -120,16 +120,28 @@ export default defineHardkasConfig({
120
120
  accounts: {
121
121
  alice: {
122
122
  kind: "simulated",
123
- address: "kaspasim:sim_alice"
123
+ address: "kaspa:sim_alice"
124
124
  },
125
125
  bob: {
126
126
  kind: "simulated",
127
- address: "kaspasim:sim_bob"
127
+ address: "kaspa:sim_bob"
128
128
  }
129
129
  }
130
130
  });
131
131
  `;
132
132
  fs10.writeFileSync(configFile, template, "utf-8");
133
+ const gitIgnoreFile = path12.join(targetDir, ".gitignore");
134
+ const gitIgnoreEntry = "\n# HardKAS local storage\n.hardkas/\n";
135
+ if (!fs10.existsSync(gitIgnoreFile)) {
136
+ fs10.writeFileSync(gitIgnoreFile, gitIgnoreEntry, "utf-8");
137
+ UI.info("Created: .gitignore");
138
+ } else {
139
+ const content = fs10.readFileSync(gitIgnoreFile, "utf-8");
140
+ if (!content.includes(".hardkas/")) {
141
+ fs10.appendFileSync(gitIgnoreFile, gitIgnoreEntry, "utf-8");
142
+ UI.info("Updated: .gitignore (added .hardkas/)");
143
+ }
144
+ }
133
145
  UI.success(`HardKAS project '${name || "current"}' initialized successfully.`);
134
146
  if (name) UI.info(`Project folder: ${targetDir}`);
135
147
  UI.info(`Created: hardkas.config.ts (v0.2-alpha)`);
@@ -139,7 +151,7 @@ export default defineHardkasConfig({
139
151
  process.exitCode = 1;
140
152
  }
141
153
  });
142
- program.command("up").description("Boot or validate the HardKAS developer runtime environment").action(async () => {
154
+ program.command("up").description(`Boot or validate the HardKAS developer runtime environment ${UI.maturity("stable")}`).action(async () => {
143
155
  try {
144
156
  await runUp();
145
157
  } catch (e) {
@@ -234,8 +246,8 @@ async function runTxPlan(input) {
234
246
  const { target, name } = resolveNetworkTarget({ config, network: networkId });
235
247
  resolvedNetwork = name;
236
248
  if (target.kind === "simulated") {
237
- const { loadOrCreateLocalnetState: loadOrCreateLocalnetState3, getSpendableUtxos } = await import("@hardkas/localnet");
238
- const localState = await loadOrCreateLocalnetState3();
249
+ const { loadOrCreateLocalnetState: loadOrCreateLocalnetState4, getSpendableUtxos } = await import("@hardkas/localnet");
250
+ const localState = await loadOrCreateLocalnetState4();
239
251
  const unspent = getSpendableUtxos(localState, fromAddress);
240
252
  availableUtxos = unspent.map((u) => ({
241
253
  outpoint: {
@@ -248,17 +260,17 @@ async function runTxPlan(input) {
248
260
  }));
249
261
  mode = "simulated";
250
262
  } else if (target.kind === "kaspa-node" || target.kind === "kaspa-rpc") {
251
- const { JsonWrpcKaspaClient: JsonWrpcKaspaClient4 } = await import("@hardkas/kaspa-rpc");
252
- const { resolveRuntimeConfig } = await import("@hardkas/node-orchestrator");
263
+ const { JsonWrpcKaspaClient: JsonWrpcKaspaClient5 } = await import("@hardkas/kaspa-rpc");
264
+ const { resolveRuntimeConfig: resolveRuntimeConfig2 } = await import("@hardkas/node-orchestrator");
253
265
  rpcUrl = url || target.rpcUrl;
254
266
  if (!rpcUrl && target.kind === "kaspa-node") {
255
- rpcUrl = resolveRuntimeConfig({
267
+ rpcUrl = resolveRuntimeConfig2({
256
268
  network: target.network,
257
269
  ...target.dataDir ? { dataDir: target.dataDir } : {}
258
270
  }).rpcUrl;
259
271
  }
260
272
  if (!rpcUrl) throw new Error("Could not resolve RPC URL");
261
- const client = new JsonWrpcKaspaClient4({ rpcUrl });
273
+ const client = new JsonWrpcKaspaClient5({ rpcUrl });
262
274
  const rpcUtxos = await client.getUtxosByAddress(fromAddress);
263
275
  await client.close();
264
276
  availableUtxos = rpcUtxos.map((u) => ({
@@ -271,13 +283,13 @@ async function runTxPlan(input) {
271
283
  }
272
284
  } catch (e) {
273
285
  if (url || networkId !== "simnet") {
274
- const { JsonWrpcKaspaClient: JsonWrpcKaspaClient4 } = await import("@hardkas/kaspa-rpc");
275
- const { resolveRuntimeConfig } = await import("@hardkas/node-orchestrator");
286
+ const { JsonWrpcKaspaClient: JsonWrpcKaspaClient5 } = await import("@hardkas/kaspa-rpc");
287
+ const { resolveRuntimeConfig: resolveRuntimeConfig2 } = await import("@hardkas/node-orchestrator");
276
288
  rpcUrl = url;
277
289
  if (!rpcUrl) {
278
- rpcUrl = resolveRuntimeConfig({ network: networkId }).rpcUrl;
290
+ rpcUrl = resolveRuntimeConfig2({ network: networkId }).rpcUrl;
279
291
  }
280
- const client = new JsonWrpcKaspaClient4({ rpcUrl });
292
+ const client = new JsonWrpcKaspaClient5({ rpcUrl });
281
293
  const rpcUtxos = await client.getUtxosByAddress(fromAddress);
282
294
  await client.close();
283
295
  availableUtxos = rpcUtxos.map((u) => ({
@@ -413,6 +425,7 @@ async function runTxSend(input) {
413
425
  schema: ARTIFACT_SCHEMAS.TX_RECEIPT,
414
426
  hardkasVersion: HARDKAS_VERSION,
415
427
  version: ARTIFACT_VERSION,
428
+ hashVersion: "sha256-canonical",
416
429
  networkId: resolvedName,
417
430
  mode: "simulated",
418
431
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -432,6 +445,7 @@ async function runTxSend(input) {
432
445
  schema: ARTIFACT_SCHEMAS.TX_TRACE,
433
446
  hardkasVersion: HARDKAS_VERSION,
434
447
  version: ARTIFACT_VERSION,
448
+ hashVersion: "sha256-canonical",
435
449
  createdAt: receipt.createdAt,
436
450
  txId: receipt.txId,
437
451
  mode: "simulated",
@@ -471,6 +485,7 @@ Receipt: ${receiptPath}`
471
485
  schema: ARTIFACT_SCHEMAS.TX_RECEIPT,
472
486
  hardkasVersion: HARDKAS_VERSION,
473
487
  version: ARTIFACT_VERSION,
488
+ hashVersion: "sha256-canonical",
474
489
  networkId: resolvedName,
475
490
  mode: "real",
476
491
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -666,19 +681,19 @@ async function runTxReceipt(input) {
666
681
  // src/commands/tx.ts
667
682
  function registerTxCommands(program) {
668
683
  const tx = program.command("tx").description("L1 Transaction commands");
669
- tx.command("profile <path>").description("Show detailed mass and fee breakdown for a transaction plan").action(async (path11) => {
684
+ tx.command("profile <path>").description("Show detailed mass and fee breakdown for a transaction plan").action(async (path12) => {
670
685
  try {
671
- await runTxProfile({ path: path11 });
686
+ await runTxProfile({ path: path12 });
672
687
  } catch (e) {
673
688
  handleError(e);
674
689
  process.exitCode = 1;
675
690
  }
676
691
  });
677
- tx.command("plan").description("Build a transaction plan artifact").option("--from <accountOrAddress>", "Sender account name or address").option("--to <address>", "Recipient address").option("--amount <kas>", "Amount in KAS").option("--network <name>", "Kaspa network name", "simnet").option("--fee-rate <sompiPerMass>", "Fee rate in sompi per mass", "1").option("--url <url>", "RPC URL (optional override)").option("--out <path>", "Save plan as artifact JSON").option("--json", "Output as JSON", false).action(async (options) => {
692
+ tx.command("plan").description(`Build a transaction plan artifact ${UI.maturity("stable")}`).option("--from <accountOrAddress>", "Sender account name or address").option("--to <address>", "Recipient address").option("--amount <kas>", "Amount in KAS").option("--network <name>", "Kaspa network name", "simnet").option("--fee-rate <sompiPerMass>", "Fee rate in sompi per mass", "1").option("--url <url>", "RPC URL (optional override)").option("--out <path>", "Save plan as artifact JSON").option("--json", "Output as JSON", false).action(async (options) => {
678
693
  try {
679
- const { loadHardkasConfig: loadHardkasConfig3 } = await import("@hardkas/config");
694
+ const { loadHardkasConfig: loadHardkasConfig5 } = await import("@hardkas/config");
680
695
  const { writeArtifact: writeArtifact4, formatTxPlanArtifact } = await import("@hardkas/artifacts");
681
- const loaded = await loadHardkasConfig3();
696
+ const loaded = await loadHardkasConfig5();
682
697
  const artifact = await runTxPlan({
683
698
  from: options.from || "alice",
684
699
  to: options.to || "bob",
@@ -700,12 +715,12 @@ Artifact saved to: ${options.out}`);
700
715
  process.exitCode = 1;
701
716
  }
702
717
  });
703
- tx.command("sign <planPath>").description("Sign a transaction plan artifact").option("--account <name>", "Account name to sign with").option("--out <path>", "Save signed artifact JSON").option("--allow-mainnet-signing", "Allow signing for mainnet", false).option("--json", "Output as JSON", false).action(async (planPath, options) => {
718
+ tx.command("sign <planPath>").description(`Sign a transaction plan artifact ${UI.maturity("stable")}`).option("--account <name>", "Account name to sign with").option("--out <path>", "Save signed artifact JSON").option("--allow-mainnet-signing", "Allow signing for mainnet", false).option("--json", "Output as JSON", false).action(async (planPath, options) => {
704
719
  try {
705
720
  const { readTxPlanArtifact, writeArtifact: writeArtifact4, formatSignedTxArtifact } = await import("@hardkas/artifacts");
706
- const { loadHardkasConfig: loadHardkasConfig3 } = await import("@hardkas/config");
721
+ const { loadHardkasConfig: loadHardkasConfig5 } = await import("@hardkas/config");
707
722
  const planArtifact = await readTxPlanArtifact(planPath);
708
- const loaded = await loadHardkasConfig3();
723
+ const loaded = await loadHardkasConfig5();
709
724
  const signedArtifact = await runTxSign({
710
725
  planArtifact,
711
726
  ...options.account ? { accountName: options.account } : {},
@@ -724,10 +739,10 @@ Signed artifact saved to: ${options.out}`);
724
739
  process.exitCode = 1;
725
740
  }
726
741
  });
727
- tx.command("send [signedPath]").description("Broadcast a signed transaction or send directly (simulated)").option("--from <accountOrAddress>", "Sender (shortcut mode)").option("--to <address>", "Recipient (shortcut mode)").option("--amount <kas>", "Amount in KAS (shortcut mode)").option("--network <name>", "Network name", "simnet").option("--url <url>", "RPC URL (optional override)").option("--yes", "Confirm broadcast", false).option("--json", "Output as JSON", false).action(async (signedPath, options) => {
742
+ tx.command("send [signedPath]").description(`Broadcast a signed transaction or send directly ${UI.maturity("stable")}`).option("--from <accountOrAddress>", "Sender (shortcut mode)").option("--to <address>", "Recipient (shortcut mode)").option("--amount <kas>", "Amount in KAS (shortcut mode)").option("--network <name>", "Network name", "simnet").option("--url <url>", "RPC URL (optional override)").option("--yes", "Confirm broadcast", false).option("--json", "Output as JSON", false).action(async (signedPath, options) => {
728
743
  try {
729
- const { loadHardkasConfig: loadHardkasConfig3 } = await import("@hardkas/config");
730
- const loaded = await loadHardkasConfig3();
744
+ const { loadHardkasConfig: loadHardkasConfig5 } = await import("@hardkas/config");
745
+ const loaded = await loadHardkasConfig5();
731
746
  if (signedPath) {
732
747
  const { readSignedTxArtifact } = await import("@hardkas/artifacts");
733
748
  const signedArtifact = await readSignedTxArtifact(signedPath);
@@ -777,12 +792,12 @@ Signed artifact saved to: ${options.out}`);
777
792
  process.exitCode = 1;
778
793
  }
779
794
  });
780
- tx.command("verify <path>").description("Perform deep semantic verification of a transaction plan").option("--json", "Output as JSON", false).action(async (path11, options) => {
781
- const { runTxVerify } = await import("./tx-verify-runner-GPPVBQIF.js");
782
- await runTxVerify({ path: path11, ...options });
795
+ tx.command("verify <path>").description(`Perform deep semantic verification of a transaction plan ${UI.maturity("preview")}`).option("--json", "Output as JSON", false).action(async (path12, options) => {
796
+ const { runTxVerify } = await import("./tx-verify-runner-Z5M2JDRI.js");
797
+ await runTxVerify({ path: path12, ...options });
783
798
  });
784
- tx.command("trace <txId>").description("Reconstruct the full operational trace of a transaction").action(async (txId) => {
785
- const { UI: UI2 } = await import("./ui-DXULTF7Q.js");
799
+ tx.command("trace <txId>").description(`Reconstruct the full operational trace of a transaction ${UI.maturity("research")}`).action(async (txId) => {
800
+ const { UI: UI2 } = await import("./ui-OVK5PX6H.js");
786
801
  UI2.error("Tracing is temporarily disabled while the query API stabilizes.");
787
802
  process.exitCode = 1;
788
803
  });
@@ -984,26 +999,26 @@ async function runArtifactExplain(options) {
984
999
  // src/commands/artifact.ts
985
1000
  function registerArtifactCommands(program) {
986
1001
  const artifactCmd = program.command("artifact").description("Manage HardKAS artifacts");
987
- artifactCmd.command("verify <path>").description("Verify an artifact's integrity and schema").option("--json", "Output results as JSON", false).option("--recursive", "Recursively verify all artifacts in a directory", false).option("--strict", "Perform deep semantic and operational safety verification", false).action(async (path11, options) => {
1002
+ artifactCmd.command("verify <path>").description(`Verify an artifact's integrity and schema ${UI.maturity("stable")}`).option("--json", "Output results as JSON", false).option("--recursive", "Recursively verify all artifacts in a directory", false).option("--strict", "Perform deep semantic and operational safety verification", false).action(async (path12, options) => {
988
1003
  try {
989
- await runArtifactVerify({ path: path11, ...options });
1004
+ await runArtifactVerify({ path: path12, ...options });
990
1005
  } catch (e) {
991
1006
  handleError(e);
992
1007
  process.exitCode = 1;
993
1008
  }
994
1009
  });
995
- artifactCmd.command("explain <path>").description("Provide a human-readable operational summary of an artifact").action(async (path11) => {
1010
+ artifactCmd.command("explain <path>").description(`Provide a human-readable operational summary of an artifact ${UI.maturity("preview")}`).action(async (path12) => {
996
1011
  try {
997
- await runArtifactExplain({ path: path11 });
1012
+ await runArtifactExplain({ path: path12 });
998
1013
  } catch (e) {
999
1014
  handleError(e);
1000
1015
  process.exitCode = 1;
1001
1016
  }
1002
1017
  });
1003
- artifactCmd.command("lineage <path>").description("Show the provenance and operational history of an artifact").action(async (path11) => {
1018
+ artifactCmd.command("lineage <path>").description(`Show the provenance and operational history of an artifact ${UI.maturity("preview")}`).action(async (path12) => {
1004
1019
  try {
1005
- const { runArtifactLineage } = await import("./artifact-lineage-runner-EPT6ABS2.js");
1006
- await runArtifactLineage({ path: path11 });
1020
+ const { runArtifactLineage } = await import("./artifact-lineage-runner-RJWQ3R3X.js");
1021
+ await runArtifactLineage({ path: path12 });
1007
1022
  } catch (e) {
1008
1023
  handleError(e);
1009
1024
  process.exitCode = 1;
@@ -1014,9 +1029,9 @@ function registerArtifactCommands(program) {
1014
1029
  // src/commands/replay.ts
1015
1030
  function registerReplayCommands(program) {
1016
1031
  const replayCmd = program.command("replay").description("Manage HardKAS transaction replays");
1017
- replayCmd.command("verify <path>").description("Verify replay invariants for a directory of artifacts").action(async (path11) => {
1018
- const { runReplayVerify } = await import("./replay-verify-runner-WBK2FCWC.js");
1019
- await runReplayVerify({ path: path11 });
1032
+ replayCmd.command("verify <path>").description("Verify replay invariants for a directory of artifacts").action(async (path12) => {
1033
+ const { runReplayVerify } = await import("./replay-verify-runner-UMYALHNT.js");
1034
+ await runReplayVerify({ path: path12 });
1020
1035
  });
1021
1036
  }
1022
1037
 
@@ -1024,11 +1039,11 @@ function registerReplayCommands(program) {
1024
1039
  function registerSnapshotCommands(program) {
1025
1040
  const snapshotCmd = program.command("snapshot").description("Manage HardKAS localnet snapshots");
1026
1041
  snapshotCmd.command("verify <idOrName>").description("Verify the integrity of a snapshot").action(async (idOrName) => {
1027
- const { runSnapshotVerify } = await import("./snapshot-verify-runner-UYTXXQ7A.js");
1042
+ const { runSnapshotVerify } = await import("./snapshot-verify-runner-BWRW3NUW.js");
1028
1043
  await runSnapshotVerify({ idOrName });
1029
1044
  });
1030
1045
  snapshotCmd.command("restore <idOrName>").description("Restore localnet state from a snapshot").action(async (idOrName) => {
1031
- const { runSnapshotRestore } = await import("./snapshot-restore-runner-P26HDE74.js");
1046
+ const { runSnapshotRestore } = await import("./snapshot-restore-runner-QNAADGBX.js");
1032
1047
  await runSnapshotRestore({ idOrName });
1033
1048
  });
1034
1049
  }
@@ -1215,7 +1230,7 @@ function registerRpcCommands(program) {
1215
1230
  }
1216
1231
  });
1217
1232
  rpcCmd.command("doctor").description("Run comprehensive RPC diagnostics").option("--endpoints <urls...>", "Specific endpoints to audit").action(async (options) => {
1218
- const { runRpcDoctor } = await import("./rpc-doctor-runner-RKGKFGMM.js");
1233
+ const { runRpcDoctor } = await import("./rpc-doctor-runner-ERWXOXSE.js");
1219
1234
  try {
1220
1235
  await runRpcDoctor(options);
1221
1236
  } catch (e) {
@@ -1250,7 +1265,7 @@ function registerDagCommands(program) {
1250
1265
  const dagCmd = program.command("dag").description("Simulate blockDAG operations (Localnet only)");
1251
1266
  dagCmd.command("status").description("View current DAG status").action(async () => {
1252
1267
  try {
1253
- const { runDagStatus } = await import("./dag-runners-BQAKJ6DM.js");
1268
+ const { runDagStatus } = await import("./dag-runners-YQDHD7U6.js");
1254
1269
  await runDagStatus();
1255
1270
  } catch (e) {
1256
1271
  handleError(e);
@@ -1259,7 +1274,7 @@ function registerDagCommands(program) {
1259
1274
  });
1260
1275
  dagCmd.command("simulate-reorg").description("Simulate a DAG reorg").option("--depth <n>", "Reorg depth", "1").action(async (options) => {
1261
1276
  try {
1262
- const { runDagSimulateReorg } = await import("./dag-runners-BQAKJ6DM.js");
1277
+ const { runDagSimulateReorg } = await import("./dag-runners-YQDHD7U6.js");
1263
1278
  await runDagSimulateReorg({ depth: parseInt(options.depth) });
1264
1279
  } catch (e) {
1265
1280
  handleError(e);
@@ -1340,14 +1355,99 @@ async function runAccountsRealGenerate(options = {}) {
1340
1355
  };
1341
1356
  }
1342
1357
 
1358
+ // src/runners/accounts-balance-runner.ts
1359
+ import {
1360
+ loadHardkasConfig as loadHardkasConfig2
1361
+ } from "@hardkas/config";
1362
+ import {
1363
+ loadRealAccountStore as loadRealAccountStore2,
1364
+ getRealDevAccount
1365
+ } from "@hardkas/accounts";
1366
+ import { JsonWrpcKaspaClient as JsonWrpcKaspaClient3 } from "@hardkas/kaspa-rpc";
1367
+ import { resolveRuntimeConfig } from "@hardkas/node-orchestrator";
1368
+ async function runAccountsBalance(options) {
1369
+ let address = options.identifier;
1370
+ let name = "Unknown";
1371
+ const loadedConfig = await loadHardkasConfig2({});
1372
+ const projectAccount = loadedConfig.config.accounts?.[options.identifier];
1373
+ if (projectAccount) {
1374
+ address = projectAccount.address ?? "";
1375
+ name = options.identifier;
1376
+ } else {
1377
+ const store = await loadRealAccountStore2();
1378
+ const realAccount = store ? getRealDevAccount(store, options.identifier) : null;
1379
+ if (realAccount) {
1380
+ address = realAccount.address ?? "";
1381
+ name = realAccount.name;
1382
+ }
1383
+ }
1384
+ const network = options.network ?? loadedConfig.config.defaultNetwork ?? "simnet";
1385
+ let rpcUrl = options.url;
1386
+ if (!rpcUrl) {
1387
+ rpcUrl = resolveRuntimeConfig({ network }).rpcUrl;
1388
+ }
1389
+ const client = new JsonWrpcKaspaClient3({ rpcUrl });
1390
+ try {
1391
+ const balance = await client.getBalanceByAddress(address);
1392
+ const utxos = await client.getUtxosByAddress(address);
1393
+ return {
1394
+ name,
1395
+ address,
1396
+ balanceSompi: balance.balanceSompi,
1397
+ utxoCount: utxos.length,
1398
+ network
1399
+ };
1400
+ } finally {
1401
+ await client.close();
1402
+ }
1403
+ }
1404
+
1405
+ // src/runners/accounts-fund-runner.ts
1406
+ import { loadHardkasConfig as loadHardkasConfig3 } from "@hardkas/config";
1407
+ import { resolveHardkasAccountAddress as resolveHardkasAccountAddress2 } from "@hardkas/accounts";
1408
+ import {
1409
+ loadOrCreateLocalnetState as loadOrCreateLocalnetState2,
1410
+ saveLocalnetState as saveLocalnetState2,
1411
+ fundAddress
1412
+ } from "@hardkas/localnet";
1413
+ async function runAccountsFund(options) {
1414
+ const loadedConfig = await loadHardkasConfig3({});
1415
+ const address = resolveHardkasAccountAddress2(options.identifier, loadedConfig.config);
1416
+ const networkId = loadedConfig.config.defaultNetwork || "simnet";
1417
+ const allowedNetworks = ["simnet", "localnet", "dev", "simulated"];
1418
+ if (!allowedNetworks.includes(networkId)) {
1419
+ throw new Error(`Faucet/Funding is only allowed on development networks (${allowedNetworks.join(", ")}). Current network is: ${networkId}`);
1420
+ }
1421
+ if (networkId === "simulated" || networkId === "localnet") {
1422
+ const state = await loadOrCreateLocalnetState2();
1423
+ const amount = options.amountSompi || 1000n * 100000000n;
1424
+ const newState = fundAddress(state, { address, amountSompi: amount });
1425
+ await saveLocalnetState2(newState);
1426
+ return {
1427
+ success: true,
1428
+ address,
1429
+ amountSompi: amount,
1430
+ mode: "simulated",
1431
+ formatted: `Successfully funded ${options.identifier} (${address}) with ${Number(amount) / 1e8} KAS (Simulated)`
1432
+ };
1433
+ }
1434
+ if (networkId === "simnet" || networkId === "dev") {
1435
+ throw new Error(
1436
+ `Funding for real simnet (Docker) via faucet requires a miner account.
1437
+ Hint: Start your node with 'hardkas node start --miningaddr ${address}' to mine coins directly to this account.`
1438
+ );
1439
+ }
1440
+ throw new Error(`Unsupported network for funding: ${networkId}`);
1441
+ }
1442
+
1343
1443
  // src/commands/accounts.ts
1344
1444
  function registerAccountsCommands(program) {
1345
1445
  const accountsCmd = program.command("accounts").description("Manage HardKAS accounts");
1346
1446
  accountsCmd.command("list").description("List available HardKAS accounts").option("--config <path>", "Path to config file").option("--json", "Output as JSON", false).action(async (options) => {
1347
- const { loadHardkasConfig: loadHardkasConfig3 } = await import("@hardkas/config");
1447
+ const { loadHardkasConfig: loadHardkasConfig5 } = await import("@hardkas/config");
1348
1448
  const { listHardkasAccounts: listHardkasAccounts2, describeAccount } = await import("@hardkas/accounts");
1349
1449
  try {
1350
- const loaded = await loadHardkasConfig3(options.config ? { configPath: options.config } : {});
1450
+ const loaded = await loadHardkasConfig5(options.config ? { configPath: options.config } : {});
1351
1451
  const accounts = listHardkasAccounts2(loaded.config);
1352
1452
  if (options.json) {
1353
1453
  console.log(JSON.stringify(accounts.map((a) => describeAccount(a)), null, 2));
@@ -1377,7 +1477,7 @@ function registerAccountsCommands(program) {
1377
1477
  });
1378
1478
  realAccountsCmd.command("import").description("Import an account into the persistent store").option("--name <name>", "Account name").option("--address <address>", "Kaspa address").option("--private-key <hex>", "Private key (plaintext, discouraged)").option("--encrypted", "Import as encrypted keystore (recommended)", false).option("--json", "Output as JSON", false).action(async (options) => {
1379
1479
  try {
1380
- const { runAccountsKeystoreImport } = await import("./accounts-keystore-runners-CVRE6NVM.js");
1480
+ const { runAccountsKeystoreImport } = await import("./accounts-keystore-runners-MCJIAGZ4.js");
1381
1481
  const result = await runAccountsKeystoreImport(options);
1382
1482
  if (options.json) console.log(JSON.stringify(result, null, 2));
1383
1483
  else console.log(result.formatted);
@@ -1386,26 +1486,28 @@ function registerAccountsCommands(program) {
1386
1486
  process.exitCode = 1;
1387
1487
  }
1388
1488
  });
1389
- realAccountsCmd.command("unlock <name>").description("Verify password for an encrypted account").action(async (name) => {
1489
+ realAccountsCmd.command("unlock <name>").description(`Verify keystore access ${UI.maturity("internal")}`).action(async (name) => {
1390
1490
  try {
1391
- const { runAccountsKeystoreUnlock } = await import("./accounts-keystore-runners-CVRE6NVM.js");
1491
+ const { runAccountsKeystoreUnlock } = await import("./accounts-keystore-runners-MCJIAGZ4.js");
1392
1492
  await runAccountsKeystoreUnlock({ name });
1493
+ console.log(`
1494
+ \u2713 Access to account '${name}' verified.`);
1495
+ console.log(` (Note: HardKAS CLI is stateless. Password will be required again for signing operations.)
1496
+ `);
1393
1497
  } catch (e) {
1394
1498
  handleError(e);
1395
1499
  process.exitCode = 1;
1396
1500
  }
1397
1501
  });
1398
- realAccountsCmd.command("lock <name>").description("Lock an account (clear session)").action(async (name) => {
1399
- try {
1400
- console.log(`Account '${name}' is now locked. (Session cleared)`);
1401
- } catch (e) {
1402
- handleError(e);
1403
- process.exitCode = 1;
1404
- }
1502
+ realAccountsCmd.command("lock <name>").description(`[DEPRECATED] Lock an account ${UI.maturity("internal")}`).action(async (name) => {
1503
+ console.log(`
1504
+ \u2139 Account '${name}' session clear (redundant).`);
1505
+ console.log(` The CLI is already stateless. No secrets are stored in memory between commands.
1506
+ `);
1405
1507
  });
1406
1508
  realAccountsCmd.command("change-password <name>").description("Change password for an encrypted account").action(async (name) => {
1407
1509
  try {
1408
- const { runAccountsKeystoreChangePassword } = await import("./accounts-keystore-runners-CVRE6NVM.js");
1510
+ const { runAccountsKeystoreChangePassword } = await import("./accounts-keystore-runners-MCJIAGZ4.js");
1409
1511
  await runAccountsKeystoreChangePassword({ name });
1410
1512
  } catch (e) {
1411
1513
  handleError(e);
@@ -1426,6 +1528,34 @@ function registerAccountsCommands(program) {
1426
1528
  process.exitCode = 1;
1427
1529
  }
1428
1530
  });
1531
+ accountsCmd.command("balance <identifier>").description("Show account balance").option("--network <name>", "Network name (simnet, localnet, etc.)").option("--url <rpc-url>", "Explicit RPC URL").option("--json", "Output as JSON", false).action(async (identifier, options) => {
1532
+ try {
1533
+ const result = await runAccountsBalance({ identifier, network: options.network ?? "simnet", url: options.url ?? "" });
1534
+ if (options.json) {
1535
+ console.log(JSON.stringify(result, null, 2));
1536
+ } else {
1537
+ console.log(`
1538
+ Account: ${result.name}`);
1539
+ console.log(`Address: ${result.address}`);
1540
+ console.log(`Balance: ${Number(result.balanceSompi) / 1e8} KAS`);
1541
+ console.log(`UTXOs: ${result.utxoCount}`);
1542
+ console.log(`Network: ${result.network}`);
1543
+ }
1544
+ } catch (e) {
1545
+ handleError(e);
1546
+ process.exitCode = 1;
1547
+ }
1548
+ });
1549
+ accountsCmd.command("fund <identifier>").description("Fund an account (Faucet)").option("--amount <kas>", "Amount in KAS to fund", "1000").action(async (identifier, options) => {
1550
+ try {
1551
+ const amountSompi = BigInt(parseFloat(options.amount) * 1e8);
1552
+ const result = await runAccountsFund({ identifier, amountSompi });
1553
+ console.log(result.formatted);
1554
+ } catch (e) {
1555
+ handleError(e);
1556
+ process.exitCode = 1;
1557
+ }
1558
+ });
1429
1559
  }
1430
1560
 
1431
1561
  // src/runners/l2-networks-runner.ts
@@ -1523,10 +1653,11 @@ import {
1523
1653
  createIgraSignedId,
1524
1654
  assertValidIgraTxReceiptArtifact,
1525
1655
  listIgraTxReceiptArtifacts,
1526
- loadIgraTxReceiptArtifact
1656
+ loadIgraTxReceiptArtifact,
1657
+ calculateContentHash
1527
1658
  } from "@hardkas/artifacts";
1528
1659
  import {
1529
- loadRealAccountStore as loadRealAccountStore2,
1660
+ loadRealAccountStore as loadRealAccountStore3,
1530
1661
  resolveRealAccountOrAddress
1531
1662
  } from "@hardkas/accounts";
1532
1663
  async function runL2TxBuild(options) {
@@ -1569,14 +1700,14 @@ async function runL2TxBuild(options) {
1569
1700
  gasLimit = g.toString();
1570
1701
  }
1571
1702
  const estimatedFeeWei = (BigInt(gasLimit) * BigInt(gasPrice)).toString();
1572
- const planId = createIgraPlanId();
1573
1703
  const artifact = {
1574
1704
  schema: ARTIFACT_SCHEMAS2.IGRA_TX_PLAN,
1575
1705
  hardkasVersion: HARDKAS_VERSION2,
1576
1706
  networkId: profile.name,
1577
1707
  mode: "l2-rpc",
1578
1708
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1579
- planId,
1709
+ planId: "",
1710
+ // Placeholder
1580
1711
  l2Network: profile.name,
1581
1712
  chainId,
1582
1713
  request: {
@@ -1592,6 +1723,10 @@ async function runL2TxBuild(options) {
1592
1723
  estimatedFeeWei,
1593
1724
  status: "built"
1594
1725
  };
1726
+ const hash = calculateContentHash(artifact);
1727
+ const planId = createIgraPlanId(hash);
1728
+ artifact.planId = planId;
1729
+ artifact.contentHash = hash;
1595
1730
  assertValidIgraTxPlanArtifact(artifact);
1596
1731
  const outDir = options.outDir || "plans";
1597
1732
  const sanitizedDir = path6.normalize(outDir).replace(/^(\.\.[\/\\])+/, "");
@@ -1647,7 +1782,7 @@ async function runL2TxSign(options) {
1647
1782
  }
1648
1783
  let accountInfo;
1649
1784
  if (options.account) {
1650
- const store = await loadRealAccountStore2();
1785
+ const store = await loadRealAccountStore3();
1651
1786
  const accountData = resolveRealAccountOrAddress(store, options.account);
1652
1787
  if (plan.request.from && plan.request.from.toLowerCase() !== accountData.address.toLowerCase()) {
1653
1788
  throw new Error(`Account address mismatch: plan specifies '${plan.request.from}' but resolved account '${accountData.name ?? accountData.address}' is '${accountData.address}'`);
@@ -1686,14 +1821,14 @@ async function runL2TxSign(options) {
1686
1821
  }
1687
1822
  throw e;
1688
1823
  }
1689
- const signedId = createIgraSignedId();
1690
1824
  const artifact = {
1691
1825
  schema: ARTIFACT_SCHEMAS2.IGRA_SIGNED_TX,
1692
1826
  hardkasVersion: HARDKAS_VERSION2,
1693
1827
  networkId: plan.networkId,
1694
1828
  mode: "l2-rpc",
1695
1829
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1696
- signedId,
1830
+ signedId: "",
1831
+ // Placeholder
1697
1832
  sourcePlanId: plan.planId,
1698
1833
  sourcePlanPath: options.planPath,
1699
1834
  l2Network: plan.l2Network,
@@ -1702,6 +1837,10 @@ async function runL2TxSign(options) {
1702
1837
  txHash: result.txHash || "unknown",
1703
1838
  status: "signed"
1704
1839
  };
1840
+ const hash = calculateContentHash(artifact);
1841
+ const signedId = createIgraSignedId(hash);
1842
+ artifact.signedId = signedId;
1843
+ artifact.contentHash = hash;
1705
1844
  assertValidIgraSignedTxArtifact(artifact);
1706
1845
  const outDir = options.outDir || "signed";
1707
1846
  const sanitizedDir = path6.normalize(outDir).replace(/^(\.\.[\/\\])+/, "");
@@ -1954,7 +2093,8 @@ import {
1954
2093
  writeArtifact as writeArtifact3,
1955
2094
  HARDKAS_VERSION as HARDKAS_VERSION3,
1956
2095
  ARTIFACT_SCHEMAS as ARTIFACT_SCHEMAS3,
1957
- createIgraDeployPlanId
2096
+ createIgraDeployPlanId,
2097
+ calculateContentHash as calculateContentHash2
1958
2098
  } from "@hardkas/artifacts";
1959
2099
  async function runL2ContractDeployPlan(options) {
1960
2100
  const networkName = options.network ?? "igra";
@@ -1999,14 +2139,14 @@ async function runL2ContractDeployPlan(options) {
1999
2139
  gasLimit = g.toString();
2000
2140
  }
2001
2141
  const estimatedFeeWei = (BigInt(gasLimit) * BigInt(gasPrice)).toString();
2002
- const planId = createIgraDeployPlanId();
2003
2142
  const artifact = {
2004
2143
  schema: ARTIFACT_SCHEMAS3.IGRA_TX_PLAN,
2005
2144
  hardkasVersion: HARDKAS_VERSION3,
2006
2145
  networkId: profile.name,
2007
2146
  mode: "l2-rpc",
2008
2147
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2009
- planId,
2148
+ planId: "",
2149
+ // Placeholder
2010
2150
  l2Network: profile.name,
2011
2151
  chainId,
2012
2152
  txType: "contract-deploy",
@@ -2022,6 +2162,10 @@ async function runL2ContractDeployPlan(options) {
2022
2162
  estimatedFeeWei,
2023
2163
  status: "built"
2024
2164
  };
2165
+ const hash = calculateContentHash2(artifact);
2166
+ const planId = createIgraDeployPlanId(hash);
2167
+ artifact.planId = planId;
2168
+ artifact.contentHash = hash;
2025
2169
  assertValidIgraTxPlanArtifact2(artifact);
2026
2170
  const outDir = options.outDir || "plans";
2027
2171
  const sanitizedDir = path7.normalize(outDir).replace(/^(\.\.[\/\\])+/, "");
@@ -2402,10 +2546,49 @@ async function runNodeStatus(input) {
2402
2546
  };
2403
2547
  }
2404
2548
 
2549
+ // src/runners/node-stop-runner.ts
2550
+ import { DockerKaspadRunner as DockerKaspadRunner3 } from "@hardkas/node-runner";
2551
+ async function runNodeStop(input) {
2552
+ const runner = new DockerKaspadRunner3(input.containerName ? { containerName: input.containerName } : {});
2553
+ return runner.stop();
2554
+ }
2555
+
2556
+ // src/runners/node-restart-runner.ts
2557
+ import { DockerKaspadRunner as DockerKaspadRunner4 } from "@hardkas/node-runner";
2558
+ async function runNodeRestart(input) {
2559
+ const runner = new DockerKaspadRunner4({
2560
+ ...input.containerName ? { containerName: input.containerName } : {},
2561
+ ...input.image ? { image: input.image } : {}
2562
+ });
2563
+ const status = await runner.restart();
2564
+ return {
2565
+ status,
2566
+ formatted: `Kaspa node restarted (Container: ${status.containerName})`
2567
+ };
2568
+ }
2569
+
2570
+ // src/runners/node-reset-runner.ts
2571
+ import { DockerKaspadRunner as DockerKaspadRunner5 } from "@hardkas/node-runner";
2572
+ async function runNodeReset(input) {
2573
+ const runner = new DockerKaspadRunner5(input.containerName ? { containerName: input.containerName } : {});
2574
+ const status = await runner.reset({ removeData: input.removeData !== false });
2575
+ return {
2576
+ status,
2577
+ formatted: `Kaspa node reset complete. Data removed: ${input.removeData !== false}. Node is currently ${status.running ? "running" : "stopped"}.`
2578
+ };
2579
+ }
2580
+
2581
+ // src/runners/node-logs-runner.ts
2582
+ import { DockerKaspadRunner as DockerKaspadRunner6 } from "@hardkas/node-runner";
2583
+ async function runNodeLogs(input) {
2584
+ const runner = new DockerKaspadRunner6(input.containerName ? { containerName: input.containerName } : {});
2585
+ return await runner.logs(input.tail ? { tail: input.tail } : {}) ?? "";
2586
+ }
2587
+
2405
2588
  // src/commands/node.ts
2406
2589
  function registerNodeCommands(program) {
2407
2590
  const nodeCmd = program.command("node").description("Kaspa node management (Docker)");
2408
- nodeCmd.command("start").description("Start local node").option("--image <image>", "Docker image").action(async (options) => {
2591
+ nodeCmd.command("start").description(`Start local node ${UI.maturity("stable")}`).option("--image <image>", "Docker image").action(async (options) => {
2409
2592
  try {
2410
2593
  const result = await runNodeStart(options);
2411
2594
  console.log(result.formatted);
@@ -2413,6 +2596,42 @@ function registerNodeCommands(program) {
2413
2596
  handleError(e);
2414
2597
  }
2415
2598
  });
2599
+ nodeCmd.command("stop").description(`Stop local node ${UI.maturity("stable")}`).action(async () => {
2600
+ try {
2601
+ const result = await runNodeStop({});
2602
+ UI.success(`Node stopped (Container: ${result.containerName})`);
2603
+ } catch (e) {
2604
+ handleError(e);
2605
+ }
2606
+ });
2607
+ nodeCmd.command("restart").description(`Restart local node ${UI.maturity("stable")}`).action(async () => {
2608
+ try {
2609
+ const result = await runNodeRestart({});
2610
+ console.log(result.formatted);
2611
+ } catch (e) {
2612
+ handleError(e);
2613
+ }
2614
+ });
2615
+ nodeCmd.command("reset").description(`Stop node and remove all local chain data ${UI.maturity("preview")}`).option("--start", "Restart the node after reset", false).option("--yes", "Skip confirmation prompt", false).action(async (options) => {
2616
+ try {
2617
+ if (!options.yes) {
2618
+ const confirmed = await UI.confirm("This will delete all local chain data. Are you sure?");
2619
+ if (!confirmed) {
2620
+ console.log(" Aborted.");
2621
+ return;
2622
+ }
2623
+ }
2624
+ const result = await runNodeReset({ removeData: true });
2625
+ UI.success(result.formatted);
2626
+ if (options.start) {
2627
+ UI.info("Starting node...");
2628
+ const startResult = await runNodeStart({});
2629
+ console.log(startResult.formatted);
2630
+ }
2631
+ } catch (e) {
2632
+ handleError(e);
2633
+ }
2634
+ });
2416
2635
  nodeCmd.command("status").description("Check node status").action(async () => {
2417
2636
  try {
2418
2637
  const result = await runNodeStatus({});
@@ -2421,15 +2640,25 @@ function registerNodeCommands(program) {
2421
2640
  handleError(e);
2422
2641
  }
2423
2642
  });
2643
+ nodeCmd.command("logs").description(`View node logs ${UI.maturity("preview")}`).option("--tail <n>", "Number of lines to show", "100").option("--follow", "Follow log output", false).action(async (options) => {
2644
+ try {
2645
+ const result = await runNodeLogs({
2646
+ tail: parseInt(options.tail, 10)
2647
+ });
2648
+ if (result) console.log(result);
2649
+ } catch (e) {
2650
+ handleError(e);
2651
+ }
2652
+ });
2424
2653
  }
2425
2654
 
2426
2655
  // src/commands/config.ts
2427
2656
  function registerConfigCommands(program) {
2428
2657
  const configCmd = program.command("config").description("Manage HardKAS configuration");
2429
2658
  configCmd.command("show").description("Show the current HardKAS configuration").option("--config <path>", "Path to config file").option("--json", "Output as JSON", false).action(async (options) => {
2430
- const { loadHardkasConfig: loadHardkasConfig3 } = await import("@hardkas/config");
2659
+ const { loadHardkasConfig: loadHardkasConfig5 } = await import("@hardkas/config");
2431
2660
  try {
2432
- const loaded = await loadHardkasConfig3(options.config ? { configPath: options.config } : {});
2661
+ const loaded = await loadHardkasConfig5(options.config ? { configPath: options.config } : {});
2433
2662
  if (options.json) {
2434
2663
  console.log(JSON.stringify(loaded, null, 2));
2435
2664
  return;
@@ -2459,7 +2688,7 @@ function registerConfigCommands(program) {
2459
2688
  }
2460
2689
 
2461
2690
  // src/commands/misc.ts
2462
- import { loadOrCreateLocalnetState as loadOrCreateLocalnetState2 } from "@hardkas/localnet";
2691
+ import { loadOrCreateLocalnetState as loadOrCreateLocalnetState3 } from "@hardkas/localnet";
2463
2692
 
2464
2693
  // src/runners/example-list-runner.ts
2465
2694
  import fs7 from "fs/promises";
@@ -2566,7 +2795,7 @@ function registerMiscCommands(program) {
2566
2795
  });
2567
2796
  program.command("dev").description("Start development environment").option("--mode <mode>", "simulated or node", "simulated").action(async (options) => {
2568
2797
  if (options.mode === "simulated") {
2569
- const state = await loadOrCreateLocalnetState2();
2798
+ const state = await loadOrCreateLocalnetState3();
2570
2799
  UI.success("Local HardKAS devnet (simulated) is ready.");
2571
2800
  UI.info(`Network: ${state.networkId}`);
2572
2801
  UI.info(`Accounts: ${state.accounts.length}`);
@@ -2579,11 +2808,50 @@ function registerMiscCommands(program) {
2579
2808
  // src/commands/query.ts
2580
2809
  function registerQueryCommands(program) {
2581
2810
  const queryCmd = program.command("query").description("Query and introspect HardKAS artifacts, lineage, and workflows");
2582
- const artifactsCmd = queryCmd.command("artifacts").description("Query artifact store");
2811
+ const artifactsCmd = queryCmd.command("artifacts").description(`Query artifact store ${UI.maturity("stable")}`);
2812
+ const storeCmd = queryCmd.command("store").description(`Manage query store index ${UI.maturity("alpha")}`);
2813
+ storeCmd.command("doctor").description("Integrity and freshness check of the query store index").action(async () => {
2814
+ try {
2815
+ const engine = await getQueryEngine();
2816
+ const report = await engine.backend.doctor();
2817
+ console.log("\n \u2550\u2550\u2550 Query Store Doctor \u2550\u2550\u2550\n");
2818
+ console.log(` Backend: ${engine.backend.kind()}`);
2819
+ console.log(` Overall: ${report.ok ? "\u2713 HEALTHY" : "\u2717 STALE / ISSUES"}`);
2820
+ console.log(` Last Indexed: ${report.lastIndexedAt || "never"}`);
2821
+ console.log(` Stale Rows: ${report.staleArtifacts || 0}`);
2822
+ console.log(` Zombie Rows: ${report.zombieArtifacts || 0}`);
2823
+ console.log(` Orphan Edges: ${report.orphanEdges || 0}`);
2824
+ if (report.corruptedFiles?.length > 0) {
2825
+ console.log("\n Corrupted Files:");
2826
+ for (const f of report.corruptedFiles) console.log(` \u2717 ${f}`);
2827
+ }
2828
+ if (!report.ok) {
2829
+ console.log("\n Recommendation: Run 'hardkas query store rebuild' to fix issues.\n");
2830
+ } else {
2831
+ console.log("\n Everything looks good.\n");
2832
+ }
2833
+ } catch (e) {
2834
+ handleError(e);
2835
+ process.exitCode = 1;
2836
+ }
2837
+ });
2838
+ storeCmd.command("rebuild").description("Force a complete rebuild of the query store index").action(async () => {
2839
+ try {
2840
+ console.log("\n Rebuilding query store index...");
2841
+ const engine = await getQueryEngine();
2842
+ const start = Date.now();
2843
+ await engine.backend.rebuild();
2844
+ console.log(` \u2713 Index rebuilt successfully in ${Date.now() - start}ms.
2845
+ `);
2846
+ } catch (e) {
2847
+ handleError(e);
2848
+ process.exitCode = 1;
2849
+ }
2850
+ });
2583
2851
  artifactsCmd.command("list").description("List artifacts matching filters").option("--schema <schema>", "Filter by artifact schema (e.g. txPlan, signedTx)").option("--network <network>", "Filter by network ID").option("--mode <mode>", "Filter by mode (simulated/real)").option("--from <address>", "Filter by sender address").option("--to <address>", "Filter by recipient address").option("--sort <field:dir>", "Sort field and direction (e.g. createdAt:desc)").option("--limit <n>", "Max results", "100").option("--json", "Output as deterministic JSON", false).option("--explain [level]", "Attach explain chains (brief|full)").action(async (options) => {
2584
2852
  try {
2585
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2586
- const engine = new QueryEngine({ artifactDir: process.cwd() });
2853
+ const { createQueryRequest } = await import("@hardkas/query");
2854
+ const engine = await getQueryEngine();
2587
2855
  const filters = [];
2588
2856
  if (options.schema) filters.push({ field: "schema", op: "eq", value: `hardkas.${options.schema}` });
2589
2857
  if (options.network) filters.push({ field: "networkId", op: "eq", value: options.network });
@@ -2617,8 +2885,8 @@ function registerQueryCommands(program) {
2617
2885
  });
2618
2886
  artifactsCmd.command("inspect <target>").description("Deep structural analysis of an artifact (path or contentHash)").option("--json", "Output as JSON", false).option("--explain [level]", "Attach explain chains (brief|full)").action(async (target, options) => {
2619
2887
  try {
2620
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2621
- const engine = new QueryEngine({ artifactDir: process.cwd() });
2888
+ const { createQueryRequest } = await import("@hardkas/query");
2889
+ const engine = await getQueryEngine();
2622
2890
  const request = createQueryRequest({
2623
2891
  domain: "artifacts",
2624
2892
  op: "inspect",
@@ -2639,8 +2907,8 @@ function registerQueryCommands(program) {
2639
2907
  });
2640
2908
  artifactsCmd.command("diff <left> <right>").description("Semantic diff between two artifacts").option("--json", "Output as JSON", false).action(async (left, right, options) => {
2641
2909
  try {
2642
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2643
- const engine = new QueryEngine({ artifactDir: process.cwd() });
2910
+ const { createQueryRequest } = await import("@hardkas/query");
2911
+ const engine = await getQueryEngine();
2644
2912
  const request = createQueryRequest({
2645
2913
  domain: "artifacts",
2646
2914
  op: "diff",
@@ -2658,11 +2926,11 @@ function registerQueryCommands(program) {
2658
2926
  process.exitCode = 1;
2659
2927
  }
2660
2928
  });
2661
- const lineageCmd = queryCmd.command("lineage").description("Traverse artifact lineage");
2929
+ const lineageCmd = queryCmd.command("lineage").description(`Traverse artifact lineage ${UI.maturity("preview")}`);
2662
2930
  lineageCmd.command("chain <anchor>").description("Reconstruct lineage chain from an artifact (contentHash or artifactId)").option("--direction <dir>", "Traversal direction: ancestors or descendants", "ancestors").option("--json", "Output as JSON", false).option("--explain [level]", "Attach explain chains (brief|full)").option("--why", "Shorthand for --explain full").action(async (anchor, options) => {
2663
2931
  try {
2664
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2665
- const engine = new QueryEngine({ artifactDir: process.cwd() });
2932
+ const { createQueryRequest } = await import("@hardkas/query");
2933
+ const engine = await getQueryEngine();
2666
2934
  const explain = options.why ? "full" : options.explain === true ? "brief" : options.explain || false;
2667
2935
  const request = createQueryRequest({
2668
2936
  domain: "lineage",
@@ -2684,8 +2952,8 @@ function registerQueryCommands(program) {
2684
2952
  });
2685
2953
  lineageCmd.command("transitions").description("List all lineage transitions").option("--root <hash>", "Filter by root artifact ID").option("--json", "Output as JSON", false).option("--explain [level]", "Attach explain chains (brief|full)").option("--why", "Shorthand for --explain full").action(async (options) => {
2686
2954
  try {
2687
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2688
- const engine = new QueryEngine({ artifactDir: process.cwd() });
2955
+ const { createQueryRequest } = await import("@hardkas/query");
2956
+ const engine = await getQueryEngine();
2689
2957
  const explain = options.why ? "full" : options.explain === true ? "brief" : options.explain || false;
2690
2958
  const request = createQueryRequest({
2691
2959
  domain: "lineage",
@@ -2707,8 +2975,8 @@ function registerQueryCommands(program) {
2707
2975
  });
2708
2976
  lineageCmd.command("orphans").description("Find artifacts with broken lineage references").option("--json", "Output as JSON", false).option("--explain [level]", "Attach explain chains (brief|full)").action(async (options) => {
2709
2977
  try {
2710
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2711
- const engine = new QueryEngine({ artifactDir: process.cwd() });
2978
+ const { createQueryRequest } = await import("@hardkas/query");
2979
+ const engine = await getQueryEngine();
2712
2980
  const request = createQueryRequest({
2713
2981
  domain: "lineage",
2714
2982
  op: "orphans",
@@ -2726,11 +2994,11 @@ function registerQueryCommands(program) {
2726
2994
  process.exitCode = 1;
2727
2995
  }
2728
2996
  });
2729
- const replayCmd = queryCmd.command("replay").description("Inspect replay history and divergence");
2997
+ const replayCmd = queryCmd.command("replay").description(`Inspect replay history and divergence ${UI.maturity("preview")}`);
2730
2998
  replayCmd.command("list").description("List all stored receipts").option("--status <status>", "Filter by status").option("--json", "Output as JSON", false).option("--limit <n>", "Max results", "100").action(async (options) => {
2731
2999
  try {
2732
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2733
- const engine = new QueryEngine({ artifactDir: process.cwd() });
3000
+ const { createQueryRequest } = await import("@hardkas/query");
3001
+ const engine = await getQueryEngine();
2734
3002
  const filters = [];
2735
3003
  if (options.status) filters.push({ field: "status", op: "eq", value: options.status });
2736
3004
  const request = createQueryRequest({ domain: "replay", op: "list", filters, limit: parseInt(options.limit, 10) });
@@ -2748,8 +3016,8 @@ function registerQueryCommands(program) {
2748
3016
  });
2749
3017
  replayCmd.command("summary <txId>").description("Detailed receipt + trace summary for a transaction").option("--json", "Output as JSON", false).action(async (txId, options) => {
2750
3018
  try {
2751
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2752
- const engine = new QueryEngine({ artifactDir: process.cwd() });
3019
+ const { createQueryRequest } = await import("@hardkas/query");
3020
+ const engine = await getQueryEngine();
2753
3021
  const request = createQueryRequest({ domain: "replay", op: "summary", params: { txId } });
2754
3022
  const result = await engine.execute(request);
2755
3023
  if (options.json) {
@@ -2765,8 +3033,8 @@ function registerQueryCommands(program) {
2765
3033
  });
2766
3034
  replayCmd.command("divergences").description("Detect receipts with replay divergence indicators").option("--json", "Output as JSON", false).option("--explain [level]", "Attach explain chains (brief|full)").action(async (options) => {
2767
3035
  try {
2768
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2769
- const engine = new QueryEngine({ artifactDir: process.cwd() });
3036
+ const { createQueryRequest } = await import("@hardkas/query");
3037
+ const engine = await getQueryEngine();
2770
3038
  const request = createQueryRequest({
2771
3039
  domain: "replay",
2772
3040
  op: "divergences",
@@ -2786,8 +3054,8 @@ function registerQueryCommands(program) {
2786
3054
  });
2787
3055
  replayCmd.command("invariants <txId>").description("Check replay invariants for a specific transaction").option("--json", "Output as JSON", false).option("--explain [level]", "Attach explain chains (brief|full)").action(async (txId, options) => {
2788
3056
  try {
2789
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2790
- const engine = new QueryEngine({ artifactDir: process.cwd() });
3057
+ const { createQueryRequest } = await import("@hardkas/query");
3058
+ const engine = await getQueryEngine();
2791
3059
  const request = createQueryRequest({
2792
3060
  domain: "replay",
2793
3061
  op: "invariants",
@@ -2806,11 +3074,11 @@ function registerQueryCommands(program) {
2806
3074
  process.exitCode = 1;
2807
3075
  }
2808
3076
  });
2809
- const dagCmd = queryCmd.command("dag").description("Query simulated DAG state (deterministic-light-model, NOT GHOSTDAG)");
3077
+ const dagCmd = queryCmd.command("dag").description(`Query simulated DAG state ${UI.maturity("research")}`);
2810
3078
  dagCmd.command("conflicts").description("Show double-spend conflict analysis").option("--json", "Output as JSON", false).option("--explain [level]", "Attach explain chains (brief|full)").option("--why", "Shorthand for --explain full").action(async (options) => {
2811
3079
  try {
2812
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2813
- const engine = new QueryEngine({ artifactDir: process.cwd() });
3080
+ const { createQueryRequest } = await import("@hardkas/query");
3081
+ const engine = await getQueryEngine();
2814
3082
  const explain = options.why ? "full" : options.explain === true ? "brief" : options.explain || false;
2815
3083
  const request = createQueryRequest({ domain: "dag", op: "conflicts", explain });
2816
3084
  const result = await engine.execute(request);
@@ -2827,8 +3095,8 @@ function registerQueryCommands(program) {
2827
3095
  });
2828
3096
  dagCmd.command("displaced").description("Show displaced transactions").option("--json", "Output as JSON", false).option("--explain [level]", "Attach explain chains (brief|full)").action(async (options) => {
2829
3097
  try {
2830
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2831
- const engine = new QueryEngine({ artifactDir: process.cwd() });
3098
+ const { createQueryRequest } = await import("@hardkas/query");
3099
+ const engine = await getQueryEngine();
2832
3100
  const explain = options.explain === true ? "brief" : options.explain || false;
2833
3101
  const request = createQueryRequest({ domain: "dag", op: "displaced", explain });
2834
3102
  const result = await engine.execute(request);
@@ -2845,8 +3113,8 @@ function registerQueryCommands(program) {
2845
3113
  });
2846
3114
  dagCmd.command("history <txId>").description("Full lifecycle of a transaction through the DAG").option("--json", "Output as JSON", false).option("--explain [level]", "Attach explain chains (brief|full)").option("--why", "Shorthand for --explain full").action(async (txId, options) => {
2847
3115
  try {
2848
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2849
- const engine = new QueryEngine({ artifactDir: process.cwd() });
3116
+ const { createQueryRequest } = await import("@hardkas/query");
3117
+ const engine = await getQueryEngine();
2850
3118
  const explain = options.why ? "full" : options.explain === true ? "brief" : options.explain || false;
2851
3119
  const request = createQueryRequest({ domain: "dag", op: "history", params: { txId }, explain });
2852
3120
  const result = await engine.execute(request);
@@ -2863,8 +3131,8 @@ function registerQueryCommands(program) {
2863
3131
  });
2864
3132
  dagCmd.command("sink-path").description("Show current selected path from genesis to sink").option("--json", "Output as JSON", false).action(async (options) => {
2865
3133
  try {
2866
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2867
- const engine = new QueryEngine({ artifactDir: process.cwd() });
3134
+ const { createQueryRequest } = await import("@hardkas/query");
3135
+ const engine = await getQueryEngine();
2868
3136
  const request = createQueryRequest({ domain: "dag", op: "sink-path" });
2869
3137
  const result = await engine.execute(request);
2870
3138
  if (options.json) {
@@ -2880,8 +3148,8 @@ function registerQueryCommands(program) {
2880
3148
  });
2881
3149
  dagCmd.command("anomalies").description("Find transactions or blocks in unexpected states").option("--json", "Output as JSON", false).option("--explain [level]", "Attach explain chains (brief|full)").action(async (options) => {
2882
3150
  try {
2883
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2884
- const engine = new QueryEngine({ artifactDir: process.cwd() });
3151
+ const { createQueryRequest } = await import("@hardkas/query");
3152
+ const engine = await getQueryEngine();
2885
3153
  const explain = options.explain === true ? "brief" : options.explain || false;
2886
3154
  const request = createQueryRequest({ domain: "dag", op: "anomalies", explain });
2887
3155
  const result = await engine.execute(request);
@@ -2898,8 +3166,8 @@ function registerQueryCommands(program) {
2898
3166
  });
2899
3167
  queryCmd.command("events").description("Query event log").option("--tx <txId>", "Filter events by transaction ID").option("--domain <domain>", "Filter by event domain").option("--kind <kind>", "Filter by event kind").option("--workflow <workflowId>", "Filter by workflow ID").option("--limit <n>", "Max results", "100").option("--json", "Output as deterministic JSON", false).option("--explain [level]", "Attach explain metadata (brief|full)").action(async (options) => {
2900
3168
  try {
2901
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2902
- const engine = new QueryEngine({ artifactDir: process.cwd() });
3169
+ const { createQueryRequest } = await import("@hardkas/query");
3170
+ const engine = await getQueryEngine();
2903
3171
  const filters = [];
2904
3172
  if (options.domain) filters.push({ field: "domain", op: "eq", value: options.domain });
2905
3173
  if (options.kind) filters.push({ field: "kind", op: "eq", value: options.kind });
@@ -2926,10 +3194,10 @@ function registerQueryCommands(program) {
2926
3194
  process.exitCode = 1;
2927
3195
  }
2928
3196
  });
2929
- queryCmd.command("tx <txId>").description("Aggregate all data for a transaction").option("--json", "Output as deterministic JSON", false).option("--explain [level]", "Attach explain metadata (brief|full)").action(async (txId, options) => {
3197
+ queryCmd.command("tx <txId>").description(`Aggregate all data for a transaction ${UI.maturity("stable")}`).option("--json", "Output as deterministic JSON", false).option("--explain [level]", "Attach explain metadata (brief|full)").action(async (txId, options) => {
2930
3198
  try {
2931
- const { QueryEngine, createQueryRequest } = await import("@hardkas/query");
2932
- const engine = new QueryEngine({ artifactDir: process.cwd() });
3199
+ const { createQueryRequest } = await import("@hardkas/query");
3200
+ const engine = await getQueryEngine();
2933
3201
  const request = createQueryRequest({
2934
3202
  domain: "tx",
2935
3203
  op: "aggregate",
@@ -2960,9 +3228,12 @@ function printArtifactList(result) {
2960
3228
  }
2961
3229
  console.log(`
2962
3230
  queryHash: ${result.queryHash.slice(0, 16)}...`);
2963
- console.log(` ${result.annotations.executionMs}ms | ${result.annotations.filesScanned ?? 0} files scanned
3231
+ const backend = result.annotations.backendUsed || "unknown";
3232
+ const freshness = result.annotations.freshness ? ` | ${result.annotations.freshness}` : "";
3233
+ console.log(` ${result.annotations.executionMs}ms | backend:${backend}${freshness} | ${result.annotations.filesScanned ?? 0} files scanned
2964
3234
  `);
2965
- if (result.explain) printExplainChains(result.explain);
3235
+ printExplain(result.explain);
3236
+ printWhy(result.why);
2966
3237
  }
2967
3238
  function printInspectResult(result) {
2968
3239
  const item = result.items[0];
@@ -2988,7 +3259,8 @@ function printInspectResult(result) {
2988
3259
  for (const err of item.integrity.errors) console.log(` \u2717 ${err}`);
2989
3260
  }
2990
3261
  console.log("");
2991
- if (result.explain) printExplainChains(result.explain);
3262
+ printExplain(result.explain);
3263
+ printWhy(result.why);
2992
3264
  }
2993
3265
  function printDiffResult(result) {
2994
3266
  const diff = result.items[0];
@@ -3029,7 +3301,8 @@ function printLineageChain(result) {
3029
3301
  console.log(`${prefix} ${node.schema} [${node.contentHash.slice(0, 12)}...] ${node.networkId}/${node.mode}`);
3030
3302
  }
3031
3303
  console.log("");
3032
- if (result.explain) printExplainChains(result.explain);
3304
+ printExplain(result.explain);
3305
+ printWhy(result.why);
3033
3306
  }
3034
3307
  function printTransitions(result) {
3035
3308
  console.log(`
@@ -3040,7 +3313,8 @@ function printTransitions(result) {
3040
3313
  console.log(` ${marker} ${t.from.schema} \u2192 ${t.to.schema} [${t.rule}]`);
3041
3314
  }
3042
3315
  console.log("");
3043
- if (result.explain) printExplainChains(result.explain);
3316
+ printExplain(result.explain);
3317
+ printWhy(result.why);
3044
3318
  }
3045
3319
  function printOrphans(result) {
3046
3320
  if (result.total === 0) {
@@ -3056,7 +3330,8 @@ function printOrphans(result) {
3056
3330
  console.log(` Reason: ${o.reason}
3057
3331
  `);
3058
3332
  }
3059
- if (result.explain) printExplainChains(result.explain);
3333
+ printExplain(result.explain);
3334
+ printWhy(result.why);
3060
3335
  }
3061
3336
  function printReplayList(result) {
3062
3337
  console.log(`
@@ -3101,7 +3376,8 @@ function printDivergences(result) {
3101
3376
  console.log(` Actual: ${d.actual.slice(0, 60)}
3102
3377
  `);
3103
3378
  }
3104
- if (result.explain) printExplainChains(result.explain);
3379
+ printExplain(result.explain);
3380
+ printWhy(result.why);
3105
3381
  }
3106
3382
  function printInvariants(result) {
3107
3383
  const inv = result.items[0];
@@ -3121,7 +3397,8 @@ function printInvariants(result) {
3121
3397
  for (const i of inv.issues) console.log(` \u2717 ${i}`);
3122
3398
  }
3123
3399
  console.log("");
3124
- if (result.explain) printExplainChains(result.explain);
3400
+ printExplain(result.explain);
3401
+ printWhy(result.why);
3125
3402
  }
3126
3403
  function printDagConflicts(result) {
3127
3404
  console.log("\n \u26A0 DAG model: deterministic-light-model (NOT GHOSTDAG)\n");
@@ -3137,7 +3414,8 @@ function printDagConflicts(result) {
3137
3414
  for (const l of c.loserTxIds) console.log(` \u2514\u2500 LOSER: ${l.slice(0, 24)}...`);
3138
3415
  console.log("");
3139
3416
  }
3140
- if (result.explain) printExplainChains(result.explain);
3417
+ printExplain(result.explain);
3418
+ printWhy(result.why);
3141
3419
  }
3142
3420
  function printDagDisplaced(result) {
3143
3421
  console.log("\n \u26A0 DAG model: deterministic-light-model (NOT GHOSTDAG)\n");
@@ -3153,7 +3431,8 @@ function printDagDisplaced(result) {
3153
3431
  console.log(` ${d.reason}
3154
3432
  `);
3155
3433
  }
3156
- if (result.explain) printExplainChains(result.explain);
3434
+ printExplain(result.explain);
3435
+ printWhy(result.why);
3157
3436
  }
3158
3437
  function printDagHistory(result) {
3159
3438
  console.log("\n \u26A0 DAG model: deterministic-light-model (NOT GHOSTDAG)\n");
@@ -3169,7 +3448,8 @@ function printDagHistory(result) {
3169
3448
  console.log(` ${status.padEnd(10)} block:${e.blockId.slice(0, 12)}... daa:${e.daaScore} ${sinkPath}`);
3170
3449
  }
3171
3450
  console.log("");
3172
- if (result.explain) printExplainChains(result.explain);
3451
+ printExplain(result.explain);
3452
+ printWhy(result.why);
3173
3453
  }
3174
3454
  function printSinkPath(result) {
3175
3455
  console.log("\n \u26A0 DAG model: deterministic-light-model (NOT GHOSTDAG)\n");
@@ -3202,19 +3482,39 @@ function printDagAnomalies(result) {
3202
3482
  console.log(` \u2717 [${a.kind}] ${a.description}
3203
3483
  `);
3204
3484
  }
3205
- if (result.explain) printExplainChains(result.explain);
3485
+ if (result.explain) printExplain(result.explain);
3486
+ }
3487
+ function printExplain(explain) {
3488
+ if (!explain) return;
3489
+ console.log(" \u2500\u2500\u2500 Explain: Technical Diagnostics \u2500\u2500\u2500\n");
3490
+ console.log(` Backend: ${explain.backend}`);
3491
+ console.log(` Freshness: ${explain.freshness}`);
3492
+ console.log(` Rows Read: ${explain.rowsRead}`);
3493
+ console.log(` Files Scan: ${explain.scannedFiles}`);
3494
+ if (explain.executionPlan && explain.executionPlan.length > 0) {
3495
+ console.log(` Plan: ${explain.executionPlan.join(" \u2192 ")}`);
3496
+ }
3497
+ if (explain.warnings && explain.warnings.length > 0) {
3498
+ console.log(` Warnings:`);
3499
+ for (const w of explain.warnings) console.log(` \u26A0 ${w}`);
3500
+ }
3501
+ console.log("");
3206
3502
  }
3207
- function printExplainChains(chains) {
3208
- console.log(" \u2500\u2500\u2500 Explain \u2500\u2500\u2500\n");
3209
- for (const chain of chains) {
3210
- console.log(` Q: ${chain.question}`);
3211
- for (const step of chain.steps) {
3503
+ function printWhy(why) {
3504
+ if (!why || why.length === 0) return;
3505
+ console.log(" \u2500\u2500\u2500 Why: Causal Analysis \u2500\u2500\u2500\n");
3506
+ for (const block of why) {
3507
+ console.log(` Q: ${block.question}`);
3508
+ console.log(` A: ${block.answer}`);
3509
+ for (const step of block.causalChain) {
3212
3510
  console.log(` ${step.order}. ${step.assertion}`);
3213
- if (step.rule) console.log(` Rule: ${step.rule}`);
3511
+ console.log(` Evidence: ${step.evidence}`);
3512
+ if (step.rule) console.log(` Rule: ${step.rule}`);
3214
3513
  }
3215
- console.log(` \u2192 ${chain.conclusion}`);
3216
- console.log(` [model: ${chain.model}, confidence: ${chain.confidence}]
3217
- `);
3514
+ if (block.evidence && block.evidence.length > 0) {
3515
+ console.log(` Evidence Refs: ${block.evidence.map((e) => `${e.type}:${e.value.slice(0, 12)}...`).join(", ")}`);
3516
+ }
3517
+ console.log("");
3218
3518
  }
3219
3519
  }
3220
3520
  function printEventList(result) {
@@ -3229,7 +3529,8 @@ function printEventList(result) {
3229
3529
  queryHash: ${result.queryHash.slice(0, 16)}...`);
3230
3530
  console.log(` ${result.annotations.executionMs}ms
3231
3531
  `);
3232
- if (result.explain) printExplainChains(result.explain);
3532
+ printExplain(result.explain);
3533
+ printWhy(result.why);
3233
3534
  }
3234
3535
  function printTxAggregate(result) {
3235
3536
  const agg = result.items[0];
@@ -3264,32 +3565,79 @@ function printTxAggregate(result) {
3264
3565
  }
3265
3566
  }
3266
3567
  console.log("");
3267
- if (result.explain) printExplainChains(result.explain);
3568
+ if (result.explain) printExplain(result.explain);
3569
+ }
3570
+ async function getQueryEngine() {
3571
+ const { QueryEngine } = await import("@hardkas/query");
3572
+ return QueryEngine.create({
3573
+ artifactDir: process.cwd()
3574
+ });
3268
3575
  }
3269
3576
 
3270
- // src/commands/test.ts
3577
+ // src/runners/test-runner.ts
3271
3578
  import { Hardkas } from "@hardkas/sdk";
3272
- function registerTestCommands(program) {
3273
- program.command("test [files...]").description("Run HardKAS tests against localnet").option("--network <network>", "Network to test against", "simnet").action(async (files, options) => {
3274
- try {
3275
- console.log(`Starting HardKAS Test Runner...`);
3276
- console.log(`Network: ${options.network}`);
3277
- const hardkas = await Hardkas.open(".");
3278
- if (options.network === "simnet") {
3279
- console.log(`Initializing deterministic localnet...`);
3280
- await hardkas.localnet.start();
3579
+ async function runTest(options) {
3580
+ const { files, network, watch, json, reporter } = options;
3581
+ if (!json) {
3582
+ UI.header("HardKAS Test Runner");
3583
+ UI.info(`Network: ${network}`);
3584
+ }
3585
+ let hardkas;
3586
+ try {
3587
+ hardkas = await Hardkas.open(".");
3588
+ } catch (e) {
3589
+ throw new Error("Could not find a valid HardKAS project in this directory.");
3590
+ }
3591
+ const searchPatterns = files.length > 0 ? files : ["test/**/*.test.ts", "tests/**/*.test.ts"];
3592
+ if (!json) {
3593
+ UI.info(`Searching for tests: ${searchPatterns.join(", ")}`);
3594
+ }
3595
+ try {
3596
+ const { startVitest } = await import("vitest/node");
3597
+ const vitestOptions = {
3598
+ run: !watch,
3599
+ watch: !!watch,
3600
+ reporter: json ? "json" : reporter || "default",
3601
+ globals: true,
3602
+ environment: "node",
3603
+ include: searchPatterns,
3604
+ exclude: ["**/node_modules/**", "**/dist/**", "**/.hardkas/**"],
3605
+ // Injected environment variables for tests to consume
3606
+ env: {
3607
+ HARDKAS_NETWORK: network,
3608
+ HARDKAS_CWD: process.cwd()
3281
3609
  }
3282
- const targetFiles = files.length > 0 ? files : ["test/**/*.test.ts"];
3283
- console.log(`
3284
- Discovered ${targetFiles.length} test files.`);
3285
- console.log(`
3286
- [RUNNING] ${targetFiles[0] || "test/example.test.ts"}`);
3287
- console.log(` \u2713 should perform deterministic tx`);
3288
- console.log(` \u2713 should reject double spend`);
3289
- console.log(`
3290
- \u2705 2 passing (1.5s)`);
3610
+ };
3611
+ const vitest = await startVitest("test", searchPatterns, vitestOptions);
3612
+ if (!vitest) {
3613
+ throw new Error("Failed to initialize test engine.");
3614
+ }
3615
+ } catch (e) {
3616
+ const error = e;
3617
+ if (error.code === "ERR_MODULE_NOT_FOUND" || error.message?.includes("vitest")) {
3618
+ UI.warning("Vitest is not installed in this project.");
3619
+ UI.info("Run 'pnpm add -D vitest' to enable real test execution.");
3620
+ UI.divider();
3621
+ UI.info("Fallback: No real tests were executed because the engine is missing.");
3622
+ process.exit(1);
3623
+ }
3624
+ throw e;
3625
+ }
3626
+ }
3627
+
3628
+ // src/commands/test.ts
3629
+ function registerTestCommands(program) {
3630
+ program.command("test [files...]").description(`Run HardKAS tests against localnet ${UI.maturity("stable")}`).option("--network <network>", "Network to test against", "simnet").option("--watch", "Watch for changes", false).option("--json", "Output results as JSON", false).option("--reporter <reporter>", "Reporter to use", "default").action(async (files, options) => {
3631
+ try {
3632
+ await runTest({
3633
+ files,
3634
+ network: options.network,
3635
+ watch: options.watch,
3636
+ json: options.json,
3637
+ reporter: options.reporter
3638
+ });
3291
3639
  } catch (e) {
3292
- console.error("Test execution failed:", e instanceof Error ? e.message : e);
3640
+ handleError(e, "Test execution failed");
3293
3641
  process.exit(1);
3294
3642
  }
3295
3643
  });
@@ -3300,8 +3648,8 @@ import os from "os";
3300
3648
  import path10 from "path";
3301
3649
  import fs9 from "fs/promises";
3302
3650
  import pc from "picocolors";
3303
- import { loadHardkasConfig as loadHardkasConfig2 } from "@hardkas/config";
3304
- import { JsonWrpcKaspaClient as JsonWrpcKaspaClient3 } from "@hardkas/kaspa-rpc";
3651
+ import { loadHardkasConfig as loadHardkasConfig4 } from "@hardkas/config";
3652
+ import { JsonWrpcKaspaClient as JsonWrpcKaspaClient4 } from "@hardkas/kaspa-rpc";
3305
3653
  import { HardkasStore } from "@hardkas/query-store";
3306
3654
  function registerDoctorCommand(program) {
3307
3655
  program.command("doctor").description("Perform a full system diagnostic and health report").action(async () => {
@@ -3321,7 +3669,7 @@ async function runDoctor() {
3321
3669
  UI.divider();
3322
3670
  UI.header("Configuration Analysis");
3323
3671
  try {
3324
- const loaded = await loadHardkasConfig2({ cwd: process.cwd() });
3672
+ const loaded = await loadHardkasConfig4({ cwd: process.cwd() });
3325
3673
  UI.success(`Config found: ${pc.cyan(path10.basename(loaded.path || "unknown"))}`);
3326
3674
  UI.field("Default Network", loaded.config.defaultNetwork || "simnet");
3327
3675
  } catch (e) {
@@ -3330,15 +3678,15 @@ async function runDoctor() {
3330
3678
  UI.divider();
3331
3679
  UI.header("RPC Connectivity & Health");
3332
3680
  try {
3333
- const loaded = await loadHardkasConfig2({ cwd: process.cwd() });
3681
+ const loaded = await loadHardkasConfig4({ cwd: process.cwd() });
3334
3682
  const networkId = loaded.config.defaultNetwork || "simnet";
3335
3683
  const target = loaded.config.networks?.[networkId];
3336
3684
  let rpcUrl = "ws://127.0.0.1:18210";
3337
3685
  if (target?.rpcUrl) rpcUrl = target.rpcUrl;
3338
3686
  UI.info(`Connecting to ${pc.cyan(rpcUrl)}...`);
3339
- const rpc = new JsonWrpcKaspaClient3({ rpcUrl });
3687
+ const rpc = new JsonWrpcKaspaClient4({ rpcUrl });
3340
3688
  const info = await rpc.getInfo();
3341
- UI.success(`RPC Alive: ${pc.bold(info.networkId)}`);
3689
+ UI.success(`RPC Alive: ${pc.bold(info.networkId || "active")}`);
3342
3690
  UI.field("Synced", info.isSynced ? pc.green("YES") : pc.yellow("NO"));
3343
3691
  if (info.serverVersion) UI.field("Version", info.serverVersion);
3344
3692
  } catch (e) {
@@ -3366,28 +3714,49 @@ async function runDoctor() {
3366
3714
  }
3367
3715
  UI.divider();
3368
3716
  UI.header("Query Store (SQLite) Status");
3369
- const dbPath = path10.join(hardkasDir, "query.db");
3717
+ const dbPath = path10.join(hardkasDir, "store.db");
3370
3718
  try {
3371
3719
  const store = new HardkasStore({ dbPath });
3372
3720
  store.connect();
3373
3721
  const db = store.getDatabase();
3374
3722
  const artCount = db.prepare("SELECT COUNT(*) as count FROM artifacts").get().count;
3375
3723
  const eventCount = db.prepare("SELECT COUNT(*) as count FROM events").get().count;
3376
- UI.success("Relational index (query.db) is healthy");
3724
+ UI.success("Relational index (store.db) is healthy");
3377
3725
  UI.field("Indexed Artifacts", artCount);
3378
3726
  UI.field("Indexed Events", eventCount);
3379
3727
  if (artCount === 0 && eventCount === 0) {
3380
- UI.warning("Database is empty. Run 'hardkas query store index' to populate.");
3728
+ UI.warning("Database is empty. Run 'hardkas query store rebuild' to populate.");
3381
3729
  }
3382
3730
  store.disconnect();
3383
3731
  } catch (e) {
3384
- UI.error("Query Store Issues", "The SQLite database might be corrupt or inaccessible.");
3732
+ UI.error("Query Store Issues", "The SQLite database might be corrupt or inaccessible. Run 'hardkas query store rebuild' to repair.");
3385
3733
  }
3386
3734
  UI.footer("Use 'hardkas query' for deep operational introspection.");
3387
3735
  }
3388
3736
 
3737
+ // src/commands/faucet.ts
3738
+ function registerFaucetCommand(program) {
3739
+ program.command("faucet <identifier>").description(`Fund an account with KAS (Local only) ${UI.maturity("stable")}`).option("--amount <kas>", "Amount in KAS to fund", "1000").action(async (identifier, options) => {
3740
+ try {
3741
+ const amountSompi = BigInt(parseFloat(options.amount) * 1e8);
3742
+ const result = await runAccountsFund({ identifier, amountSompi });
3743
+ console.log(result.formatted);
3744
+ } catch (e) {
3745
+ handleError(e);
3746
+ process.exitCode = 1;
3747
+ }
3748
+ });
3749
+ }
3750
+
3389
3751
  // src/index.ts
3390
- var HARDKAS_VERSION4 = "0.2.0-alpha";
3752
+ import { readFileSync } from "fs";
3753
+ import { fileURLToPath } from "url";
3754
+ import path11 from "path";
3755
+ var packageJsonPath = path11.resolve(
3756
+ path11.dirname(fileURLToPath(import.meta.url)),
3757
+ "../package.json"
3758
+ );
3759
+ var { version: HARDKAS_VERSION4 } = JSON.parse(readFileSync(packageJsonPath, "utf8"));
3391
3760
  async function main() {
3392
3761
  const program = new Command();
3393
3762
  program.name("hardkas").description("HardKAS: Kaspa-native developer operating environment").version(HARDKAS_VERSION4);
@@ -3406,15 +3775,21 @@ async function main() {
3406
3775
  registerQueryCommands(program);
3407
3776
  registerTestCommands(program);
3408
3777
  registerDoctorCommand(program);
3778
+ registerFaucetCommand(program);
3409
3779
  try {
3410
3780
  await program.parseAsync(process.argv);
3411
3781
  } catch (err) {
3782
+ const { maskSecrets } = await import("@hardkas/core");
3412
3783
  console.error(`
3413
- Error: ${err.message}`);
3784
+ Error: ${maskSecrets(err.message || String(err))}`);
3414
3785
  process.exit(1);
3415
3786
  }
3416
3787
  }
3417
- main().catch((err) => {
3418
- console.error("Fatal error:", err);
3788
+ main().catch(async (err) => {
3789
+ const { maskSecrets } = await import("@hardkas/core");
3790
+ console.error("Fatal error:", maskSecrets(err.message || String(err)));
3791
+ if (err.stack) {
3792
+ console.error(maskSecrets(err.stack));
3793
+ }
3419
3794
  process.exit(1);
3420
3795
  });