@hardkas/cli 0.2.2-alpha.1 → 0.4.0-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/dist/accounts-keystore-runners-QYSNZMZV.js +155 -0
  2. package/dist/{artifact-lineage-runner-RJWQ3R3X.js → artifact-lineage-runner-TY4YTE6H.js} +6 -2
  3. package/dist/bridge-local-runner-E3LICYYX.js +174 -0
  4. package/dist/{chunk-AQWQW5ZG.js → chunk-K7XPWWIO.js} +45 -1
  5. package/dist/chunk-KA5CAWI2.js +163 -0
  6. package/dist/chunk-ZM2NBOAE.js +37 -0
  7. package/dist/{dag-runners-YQDHD7U6.js → dag-runners-NLBYR7I7.js} +2 -2
  8. package/dist/deployment-runners-GEICABEH.js +15 -0
  9. package/dist/dev-doctor-runner-LTSENPQ3.js +145 -0
  10. package/dist/dev-server-runner-IM5DCDD3.js +45 -0
  11. package/dist/index.js +2145 -560
  12. package/dist/kaspa-doctor-runner-F2ISPABM.js +81 -0
  13. package/dist/kaspa-wallet-runner-ORJ5YFKU.js +179 -0
  14. package/dist/local-wizard-runner-GCAWGZ6D.js +144 -0
  15. package/dist/metamask-runner-PRIOW4J3.js +132 -0
  16. package/dist/replay-verify-runner-Y3RARVD7.js +50 -0
  17. package/dist/{rpc-doctor-runner-ERWXOXSE.js → rpc-doctor-runner-V7H7AAX4.js} +1 -1
  18. package/dist/session-runner-LDSGDP47.js +118 -0
  19. package/dist/{snapshot-restore-runner-QNAADGBX.js → snapshot-restore-runner-KIJNPLDV.js} +1 -1
  20. package/dist/{snapshot-verify-runner-BWRW3NUW.js → snapshot-verify-runner-PGMADWLN.js} +1 -1
  21. package/dist/{tx-verify-runner-Z5M2JDRI.js → tx-verify-runner-6EGY5ZN4.js} +11 -2
  22. package/dist/ui-SUYOHGGP.js +10 -0
  23. package/package.json +26 -15
  24. package/dist/accounts-keystore-runners-MCJIAGZ4.js +0 -112
  25. package/dist/replay-verify-runner-UMYALHNT.js +0 -37
  26. package/dist/ui-OVK5PX6H.js +0 -8
@@ -0,0 +1,155 @@
1
+ import {
2
+ acquirePassword,
3
+ acquirePrivateKey
4
+ } from "./chunk-ZM2NBOAE.js";
5
+ import {
6
+ UI
7
+ } from "./chunk-K7XPWWIO.js";
8
+
9
+ // src/runners/accounts-keystore-runners.ts
10
+ import fs from "fs";
11
+ import path from "path";
12
+ import { KeystoreManager, loadOrCreateRealAccountStore, saveRealAccountStore, importRealDevAccount } from "@hardkas/accounts";
13
+ async function runAccountsKeystoreImport(options) {
14
+ const name = options.name || "default";
15
+ const address = options.address;
16
+ if (options.unsafePlaintext) {
17
+ UI.warning("LEGACY MODE: Storing private keys in plaintext is unsafe and discouraged.");
18
+ if (!options.yes) {
19
+ const confirmed = await UI.confirm("Are you sure you want to store this key in plaintext?");
20
+ if (!confirmed) throw new Error("Import cancelled by user.");
21
+ }
22
+ } else {
23
+ UI.info("HardKAS: Encrypted keystore is for local developer workflows, not institutional custody.");
24
+ UI.info("Do not import mainnet keys unless you fully understand the risks.");
25
+ }
26
+ if (!address) {
27
+ throw new Error("Address is required for import.");
28
+ }
29
+ let privateKeyUsedAsArg = false;
30
+ let finalKey;
31
+ if (options.privateKeyStdin || options.privateKeyEnv) {
32
+ finalKey = await acquirePrivateKey({
33
+ stdin: !!options.privateKeyStdin,
34
+ env: options.privateKeyEnv,
35
+ message: `Enter private key for account '${name}':`
36
+ });
37
+ } else if (options.privateKey) {
38
+ finalKey = options.privateKey;
39
+ privateKeyUsedAsArg = true;
40
+ } else {
41
+ finalKey = await acquirePrivateKey({
42
+ message: `Enter private key for account '${name}':`
43
+ });
44
+ }
45
+ if (privateKeyUsedAsArg) {
46
+ const warningMsg = "--private-key may be recorded in shell history, process lists, CI logs, or terminal scrollback.";
47
+ const suggestion = "Use --private-key-stdin or --private-key-env instead.";
48
+ if (!options.json) {
49
+ UI.securityWarning("PRIVATE_KEY_ARG_DEPRECATED", warningMsg, suggestion);
50
+ }
51
+ }
52
+ if (!finalKey) {
53
+ throw new Error("Private key is required for import.");
54
+ }
55
+ let keystoreRef;
56
+ if (!options.unsafePlaintext) {
57
+ const password = await acquirePassword({
58
+ stdin: !!options.passwordStdin,
59
+ env: options.passwordEnv,
60
+ message: `Enter new keystore password for account '${name}':`
61
+ });
62
+ if (!password) {
63
+ throw new Error("Password cannot be empty for encrypted storage.");
64
+ }
65
+ const keystore = await KeystoreManager.createEncryptedKeystore(
66
+ {
67
+ address,
68
+ privateKey: finalKey,
69
+ network: address.startsWith("kaspa:") ? "mainnet" : "devnet"
70
+ },
71
+ password,
72
+ {
73
+ label: name,
74
+ network: address.startsWith("kaspa:") ? "mainnet" : "devnet"
75
+ }
76
+ );
77
+ const keystoreDir = path.join(process.cwd(), ".hardkas", "keystore");
78
+ const filePath = path.join(keystoreDir, `${name}.json`);
79
+ await KeystoreManager.saveEncryptedKeystore(filePath, keystore);
80
+ keystoreRef = `.hardkas/keystore/${name}.json`;
81
+ }
82
+ let store = await loadOrCreateRealAccountStore();
83
+ store = importRealDevAccount(store, {
84
+ name,
85
+ address,
86
+ ...options.unsafePlaintext ? { privateKey: finalKey } : {},
87
+ ...keystoreRef ? { keystoreRef } : {}
88
+ });
89
+ await saveRealAccountStore(store);
90
+ const warnings = [];
91
+ if (privateKeyUsedAsArg) {
92
+ warnings.push({
93
+ code: "PRIVATE_KEY_ARG_DEPRECATED",
94
+ severity: "warning",
95
+ message: "--private-key is deprecated and unsafe. Use --private-key-stdin or --private-key-env."
96
+ });
97
+ }
98
+ return {
99
+ success: true,
100
+ name,
101
+ encrypted: !options.unsafePlaintext,
102
+ warnings,
103
+ formatted: options.unsafePlaintext ? `\u2713 Successfully imported account '${name}' (UNSAFE PLAINTEXT)` : `\u2713 Successfully imported and encrypted account '${name}'`
104
+ };
105
+ }
106
+ async function runAccountsSessionOpen(options) {
107
+ const { name } = options;
108
+ const filePath = path.join(process.cwd(), ".hardkas", "keystore", `${name}.json`);
109
+ if (!fs.existsSync(filePath)) {
110
+ throw new Error(`Keystore for account '${name}' not found at ${filePath}`);
111
+ }
112
+ const keystore = await KeystoreManager.loadEncryptedKeystore(filePath);
113
+ const password = await acquirePassword({
114
+ stdin: !!options.passwordStdin,
115
+ env: options.passwordEnv,
116
+ message: `Enter password for account '${name}':`
117
+ });
118
+ const result = await KeystoreManager.decryptEncryptedKeystore(keystore, password);
119
+ if (result.success) {
120
+ UI.success(`Access to account '${name}' verified.`);
121
+ UI.info("Note: This does not create a production wallet session or daemon.");
122
+ UI.info("Decrypted key material is process-local and will not be persisted.");
123
+ } else {
124
+ throw new Error(result.error || "Failed to unlock keystore.");
125
+ }
126
+ }
127
+ async function runAccountsKeystoreChangePassword(options) {
128
+ const { name } = options;
129
+ const filePath = path.join(process.cwd(), ".hardkas", "keystore", `${name}.json`);
130
+ const keystore = await KeystoreManager.loadEncryptedKeystore(filePath);
131
+ const oldPassword = await acquirePassword({
132
+ message: "Enter current password:"
133
+ });
134
+ const newPassword = await acquirePassword({
135
+ message: "Enter new password:"
136
+ });
137
+ const confirm = await acquirePassword({
138
+ message: "Confirm new password:"
139
+ });
140
+ if (newPassword !== confirm) {
141
+ throw new Error("New passwords do not match.");
142
+ }
143
+ const updatedKeystore = await KeystoreManager.changeKeystorePassword(
144
+ keystore,
145
+ oldPassword,
146
+ newPassword
147
+ );
148
+ await KeystoreManager.saveEncryptedKeystore(filePath, updatedKeystore);
149
+ UI.success(`Successfully changed password for account '${name}'.`);
150
+ }
151
+ export {
152
+ runAccountsKeystoreChangePassword,
153
+ runAccountsKeystoreImport,
154
+ runAccountsSessionOpen
155
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  UI
3
- } from "./chunk-AQWQW5ZG.js";
3
+ } from "./chunk-K7XPWWIO.js";
4
4
 
5
5
  // src/runners/artifact-lineage-runner.ts
6
6
  import {
@@ -49,7 +49,11 @@ async function runArtifactLineage(options) {
49
49
  const result = verifyLineage(artifact);
50
50
  if (!result.ok) {
51
51
  console.log("\nLineage Violations:");
52
- result.issues.forEach((i) => console.log(` \u2717 [${i.code}] ${i.message}`));
52
+ result.issues.forEach((i) => {
53
+ const prefix = i.severity === "error" ? "\u2717" : "\u26A0";
54
+ console.log(` ${prefix} [${i.code}] ${i.message}`);
55
+ });
56
+ process.exitCode = 1;
53
57
  } else {
54
58
  console.log("\n\u2713 Internal lineage structure is consistent.");
55
59
  }
@@ -0,0 +1,174 @@
1
+ import {
2
+ handleError
3
+ } from "./chunk-K7XPWWIO.js";
4
+
5
+ // src/runners/bridge-local-runner.ts
6
+ import pc from "picocolors";
7
+ import { loadHardkasConfig } from "@hardkas/config";
8
+ async function runBridgeLocalPlan(options) {
9
+ try {
10
+ const config = await loadHardkasConfig();
11
+ const { planBridgeEntry, resolveBridgeLocalContext } = await import("@hardkas/bridge-local");
12
+ const { MockKaspaRpcClient } = await import("@hardkas/kaspa-rpc");
13
+ const ctx = await resolveBridgeLocalContext({
14
+ config,
15
+ sessionName: options.session,
16
+ from: options.from,
17
+ toIgra: options.toIgra
18
+ });
19
+ const amountSompi = BigInt(Math.floor(parseFloat(options.amount) * 1e8));
20
+ const rpc = new MockKaspaRpcClient();
21
+ rpc.setUtxos(ctx.l1.address, [
22
+ {
23
+ outpoint: { transactionId: "mock-utxo", index: 0 },
24
+ address: ctx.l1.address,
25
+ amountSompi: 100000000000n,
26
+ // 1000 KAS
27
+ scriptPublicKey: "mock-script"
28
+ }
29
+ ]);
30
+ const utxos = await rpc.getUtxosByAddress(ctx.l1.address);
31
+ const plan = planBridgeEntry({
32
+ fromAddress: ctx.l1.address,
33
+ targetEvmAddress: ctx.l2.address,
34
+ amountSompi,
35
+ networkId: config.config.networkId || config.config.defaultNetwork || "simnet",
36
+ availableUtxos: utxos.map((u) => ({ ...u, scriptPublicKey: "", blockDaaScore: u.blockDaaScore ? BigInt(u.blockDaaScore) : void 0 }))
37
+ });
38
+ if (options.json) {
39
+ console.log(JSON.stringify({
40
+ schema: "hardkas.bridgeLocalSessionPlan.v1",
41
+ session: {
42
+ source: ctx.source,
43
+ name: ctx.sessionName || null
44
+ },
45
+ l1: {
46
+ wallet: ctx.l1.walletName,
47
+ address: ctx.l1.address
48
+ },
49
+ l2: {
50
+ account: ctx.l2.accountName || null,
51
+ address: ctx.l2.address
52
+ },
53
+ bridge: {
54
+ mode: ctx.bridgeMode,
55
+ amount: options.amount,
56
+ payload: plan.serializedPayload
57
+ },
58
+ plan
59
+ }, (k, v) => typeof v === "bigint" ? v.toString() : v, 2));
60
+ return;
61
+ }
62
+ printBridgeContext(ctx, options.amount, plan.serializedPayload);
63
+ console.log(pc.bold("Local Bridge Entry Plan"));
64
+ console.log(pc.dim("----------------------------------------"));
65
+ console.log(`Fee (est): ${pc.yellow(Number(plan.estimatedFeeSompi) / 1e8)} KAS`);
66
+ console.log(`Mass: ${plan.estimatedMass}`);
67
+ console.log(pc.dim("----------------------------------------\n"));
68
+ } catch (e) {
69
+ handleError(e);
70
+ }
71
+ }
72
+ async function runBridgeLocalSimulate(options) {
73
+ try {
74
+ const config = await loadHardkasConfig();
75
+ const { planBridgeEntry, simulatePrefixMining, resolveBridgeLocalContext } = await import("@hardkas/bridge-local");
76
+ const { MockKaspaRpcClient } = await import("@hardkas/kaspa-rpc");
77
+ const ctx = await resolveBridgeLocalContext({
78
+ config,
79
+ sessionName: options.session,
80
+ from: options.from,
81
+ toIgra: options.toIgra
82
+ });
83
+ const amountSompi = BigInt(Math.floor(parseFloat(options.amount) * 1e8));
84
+ const rpc = new MockKaspaRpcClient();
85
+ rpc.setUtxos(ctx.l1.address, [
86
+ {
87
+ outpoint: { transactionId: "mock-utxo", index: 0 },
88
+ address: ctx.l1.address,
89
+ amountSompi: 100000000000n,
90
+ // 1000 KAS
91
+ scriptPublicKey: "mock-script"
92
+ }
93
+ ]);
94
+ const utxos = await rpc.getUtxosByAddress(ctx.l1.address);
95
+ const plan = planBridgeEntry({
96
+ fromAddress: ctx.l1.address,
97
+ targetEvmAddress: ctx.l2.address,
98
+ amountSompi,
99
+ networkId: config.config.networkId || config.config.defaultNetwork || "simnet",
100
+ availableUtxos: utxos.map((u) => ({ ...u, scriptPublicKey: "", blockDaaScore: u.blockDaaScore ? BigInt(u.blockDaaScore) : void 0 }))
101
+ });
102
+ if (!options.json) {
103
+ printBridgeContext(ctx, options.amount, plan.serializedPayload);
104
+ console.log(pc.bold("Bridge Entry Simulation"));
105
+ console.log(`${pc.cyan("Step 1:")} Planning entry transaction... OK`);
106
+ console.log(`${pc.cyan("Step 2:")} Simulating prefix mining for prefix "${pc.white(options.prefix)}"...`);
107
+ }
108
+ const miningResult = simulatePrefixMining(plan.bridgePayload, options.prefix);
109
+ if (options.json) {
110
+ console.log(JSON.stringify({
111
+ schema: "hardkas.bridgeLocalSessionSimulation.v1",
112
+ status: "success",
113
+ session: {
114
+ source: ctx.source,
115
+ name: ctx.sessionName || null
116
+ },
117
+ l1: {
118
+ wallet: ctx.l1.walletName,
119
+ address: ctx.l1.address
120
+ },
121
+ l2: {
122
+ account: ctx.l2.accountName || null,
123
+ address: ctx.l2.address
124
+ },
125
+ miningResult,
126
+ plan
127
+ }, (k, v) => typeof v === "bigint" ? v.toString() : v, 2));
128
+ return;
129
+ }
130
+ console.log(` ${pc.green("\u2713")} Target found at nonce: ${pc.white(miningResult.nonce)}`);
131
+ console.log(` ${pc.green("\u2713")} Attempts: ${miningResult.attempts}`);
132
+ console.log(` ${pc.green("\u2713")} Simulated Hash: ${pc.dim(miningResult.hash)}`);
133
+ console.log(`
134
+ ${pc.bold(pc.green("SUCCESS"))}: Local bridge entry simulated.`);
135
+ console.log(pc.yellow(pc.bold("\n\u26A0\uFE0F SIMULATION DISCLAIMER:")));
136
+ console.log(` - ${pc.white("NO actual bridge settlement")} occurred on L1.`);
137
+ console.log(` - ${pc.white("NO L2 minting")} or state change occurred on Igra.`);
138
+ console.log(` - ${pc.white("NO real bridge validation")} or relayer action was involved.`);
139
+ console.log(` - This is a ${pc.bold("deterministic local proof")} for development workflows only.
140
+ `);
141
+ } catch (e) {
142
+ handleError(e);
143
+ }
144
+ }
145
+ async function runBridgeLocalInspect(txid, options) {
146
+ try {
147
+ console.log(pc.bold(`
148
+ Inspecting Local Bridge Transaction: ${txid}`));
149
+ console.log(pc.dim("Feature limited in alpha: no local tx store yet."));
150
+ } catch (e) {
151
+ handleError(e);
152
+ }
153
+ }
154
+ function printBridgeContext(ctx, amount, payload) {
155
+ console.log(pc.bold("\nSession"));
156
+ console.log(` Source: ${pc.white(ctx.source)}`);
157
+ console.log(` Name: ${pc.white(ctx.sessionName || "none")}`);
158
+ console.log(pc.bold("\nKaspa L1"));
159
+ console.log(` Wallet: ${pc.white(ctx.l1.walletName)}`);
160
+ console.log(` Address: ${pc.dim(ctx.l1.address)}`);
161
+ console.log(pc.bold("\nIgra L2"));
162
+ console.log(` Account: ${pc.white(ctx.l2.accountName || "explicit")}`);
163
+ console.log(` Address: ${pc.dim(ctx.l2.address)}`);
164
+ console.log(pc.bold("\nBridge"));
165
+ console.log(` Mode: ${pc.white(ctx.bridgeMode)}`);
166
+ console.log(` Amount: ${pc.green(amount)} KAS`);
167
+ console.log(` Payload: ${pc.dim(payload)}`);
168
+ console.log("");
169
+ }
170
+ export {
171
+ runBridgeLocalInspect,
172
+ runBridgeLocalPlan,
173
+ runBridgeLocalSimulate
174
+ };
@@ -32,6 +32,17 @@ var UI = {
32
32
  \u26A0\uFE0F WARNING:`));
33
33
  console.log(pc.yellow(` ${masked}`));
34
34
  },
35
+ securityWarning(code, message, suggestion) {
36
+ console.log(pc.yellow(`
37
+ \u26A0\uFE0F SECURITY WARNING [${code}]:`));
38
+ console.log(pc.yellow(` ${message}`));
39
+ if (suggestion) {
40
+ console.log(pc.cyan(`
41
+ \u{1F4A1} Suggestion:`));
42
+ console.log(pc.cyan(` ${suggestion}`));
43
+ }
44
+ console.log("");
45
+ },
35
46
  error(msg, suggestion) {
36
47
  const maskedMsg = maskSecrets(msg);
37
48
  const maskedSuggestion = suggestion ? maskSecrets(suggestion) : void 0;
@@ -114,8 +125,41 @@ Suggestion:
114
125
  }
115
126
  UI.error(context ? `${context}: ${msg}` : msg, suggestion);
116
127
  }
128
+ function handleLockError(e) {
129
+ const code = e.code || "UNKNOWN_ERROR";
130
+ const meta = e.cause;
131
+ if (code === "LOCK_HELD" || code === "LOCK_TIMEOUT" || code === "STALE_LOCK") {
132
+ const title = code === "STALE_LOCK" ? "Stale Workspace Lock Detected" : "Workspace is locked by another HardKAS process";
133
+ console.error(pc.red(`
134
+ \u2717 ${pc.bold(title)}`));
135
+ console.error(pc.red(` ${"\u2500".repeat(title.length + 4)}`));
136
+ if (meta) {
137
+ console.error(` ${pc.dim("Lock:")} ${pc.white(meta.name)}`);
138
+ console.error(` ${pc.dim("PID:")} ${pc.white(meta.pid)}`);
139
+ console.error(` ${pc.dim("Command:")} ${pc.white(meta.command)}`);
140
+ console.error(` ${pc.dim("Created:")} ${pc.white(meta.createdAt)}`);
141
+ if (meta.path) console.error(` ${pc.dim("Path:")} ${pc.white(meta.path)}`);
142
+ }
143
+ console.error(pc.cyan(`
144
+ \u{1F4A1} Suggestion:`));
145
+ if (code === "STALE_LOCK") {
146
+ console.error(` The process (PID ${meta?.pid}) appears to be dead.`);
147
+ console.error(` Run 'hardkas lock clear ${meta?.name} --if-dead' to release it safely.`);
148
+ } else {
149
+ console.error(` Wait for the process to finish, or run:`);
150
+ console.error(` hardkas lock doctor`);
151
+ console.error(`
152
+ If you believe the process is dead:`);
153
+ console.error(` hardkas lock clear ${meta?.name} --if-dead`);
154
+ }
155
+ console.error("");
156
+ return;
157
+ }
158
+ handleError(e);
159
+ }
117
160
 
118
161
  export {
119
162
  UI,
120
- handleError
163
+ handleError,
164
+ handleLockError
121
165
  };
@@ -0,0 +1,163 @@
1
+ import {
2
+ UI
3
+ } from "./chunk-K7XPWWIO.js";
4
+
5
+ // src/runners/deployment-runners.ts
6
+ import { withLock } from "@hardkas/core";
7
+ import {
8
+ saveDeployment,
9
+ loadDeployment,
10
+ listDeployments,
11
+ createDeploymentRecord,
12
+ updateDeploymentStatus
13
+ } from "@hardkas/artifacts";
14
+ import { loadHardkasConfig, resolveNetworkTarget } from "@hardkas/config";
15
+ import { JsonWrpcKaspaClient } from "@hardkas/kaspa-rpc";
16
+ async function trackDeployment(opts) {
17
+ const rootDir = process.cwd();
18
+ await withLock({ rootDir, name: "artifacts", command: "hardkas deploy track" }, async () => {
19
+ const existing = await loadDeployment(rootDir, opts.network, opts.label);
20
+ if (existing) {
21
+ throw new Error(`Deployment '${opts.label}' already exists on network '${opts.network}'.`);
22
+ }
23
+ const record = createDeploymentRecord({
24
+ label: opts.label,
25
+ networkId: opts.network,
26
+ ...opts.txId ? { txId: opts.txId } : {},
27
+ ...opts.plan ? { planArtifactId: opts.plan } : {},
28
+ ...opts.receipt ? { receiptArtifactId: opts.receipt } : {},
29
+ status: opts.status || "sent",
30
+ ...opts.notes ? { notes: opts.notes } : {}
31
+ });
32
+ await saveDeployment(rootDir, record);
33
+ UI.success(`Tracked deployment: ${opts.label} (${opts.network})`);
34
+ });
35
+ }
36
+ async function listAllDeployments(opts) {
37
+ const rootDir = process.cwd();
38
+ const deployments = await listDeployments(rootDir, opts.network);
39
+ const filtered = opts.status ? deployments.filter((d) => d.status === opts.status) : deployments;
40
+ if (opts.json) {
41
+ console.log(JSON.stringify(filtered, null, 2));
42
+ return;
43
+ }
44
+ if (filtered.length === 0) {
45
+ UI.info("No deployments found.");
46
+ return;
47
+ }
48
+ UI.header("Deployments");
49
+ const byNetwork = {};
50
+ for (const d of filtered) {
51
+ const net = d.networkId || "unknown";
52
+ if (!byNetwork[net]) byNetwork[net] = [];
53
+ byNetwork[net].push(d);
54
+ }
55
+ let total = 0;
56
+ for (const [net, items] of Object.entries(byNetwork)) {
57
+ console.log(`
58
+ ${net}`);
59
+ for (const d of items) {
60
+ const statusIcon = d.status === "confirmed" ? "\u2705" : d.status === "failed" ? "\u274C" : "\u23F3";
61
+ const txIdShort = d.txId ? d.txId.slice(0, 12) + "..." : "(none)";
62
+ const ago = formatAgo(d.deployedAt);
63
+ console.log(` ${statusIcon} ${d.label.padEnd(20)} ${d.status.padEnd(10)} ${txIdShort.padEnd(16)} ${ago}`);
64
+ total++;
65
+ }
66
+ }
67
+ console.log(`
68
+ Total: ${total} deployments across ${Object.keys(byNetwork).length} networks`);
69
+ }
70
+ async function inspectDeployment(opts) {
71
+ const rootDir = process.cwd();
72
+ const record = await loadDeployment(rootDir, opts.network, opts.label);
73
+ if (!record) {
74
+ throw new Error(`Deployment '${opts.label}' not found on network '${opts.network}'.`);
75
+ }
76
+ if (opts.json) {
77
+ console.log(JSON.stringify(record, null, 2));
78
+ return;
79
+ }
80
+ UI.header(`Deployment: ${record.label}`);
81
+ console.log(` Network: ${record.networkId}`);
82
+ console.log(` Status: ${record.status}`);
83
+ console.log(` TxId: ${record.txId || "(none)"}`);
84
+ console.log(` Plan artifact: ${record.planArtifactId || "(none)"}`);
85
+ console.log(` Receipt: ${record.receiptArtifactId || "(none)"}`);
86
+ console.log(` Deployed at: ${record.deployedAt}`);
87
+ console.log(` Content hash: ${record.contentHash}`);
88
+ if (record.notes) console.log(` Notes: ${record.notes}`);
89
+ }
90
+ async function verifyDeploymentStatus(opts) {
91
+ const rootDir = process.cwd();
92
+ const record = await loadDeployment(rootDir, opts.network, opts.label);
93
+ if (!record) {
94
+ throw new Error(`Deployment '${opts.label}' not found on network '${opts.network}'.`);
95
+ }
96
+ if (!opts.verify) {
97
+ if (opts.json) console.log(JSON.stringify({ label: record.label, status: record.status }, null, 2));
98
+ else console.log(`Current status: ${record.status}`);
99
+ return;
100
+ }
101
+ if (!record.txId) {
102
+ throw new Error(`Cannot verify deployment '${opts.label}' without a transaction ID.`);
103
+ }
104
+ UI.info(`Checking ${record.label} on ${record.networkId}...`);
105
+ const { config } = await loadHardkasConfig();
106
+ const netTarget = resolveNetworkTarget({ config, network: record.networkId });
107
+ const rpcUrl = netTarget.target.rpcUrl;
108
+ console.log(` RPC: ${rpcUrl || "simulated"}`);
109
+ console.log(` TxId: ${record.txId}`);
110
+ if (record.networkId === "simnet") {
111
+ UI.info(" Simnet deployment \u2014 status preserved.");
112
+ } else if (!rpcUrl) {
113
+ UI.error(" No RPC URL configured for this network.");
114
+ } else {
115
+ try {
116
+ const client = new JsonWrpcKaspaClient({ rpcUrl });
117
+ const tx = await client.getTransaction(record.txId);
118
+ let newStatus = record.status;
119
+ if (tx) {
120
+ const isAccepted = tx.isAccepted || tx.transaction && tx.transaction.block_hash;
121
+ if (isAccepted) newStatus = "confirmed";
122
+ } else {
123
+ }
124
+ if (newStatus !== record.status) {
125
+ await withLock({ rootDir, name: "artifacts", command: "hardkas deploy status" }, async () => {
126
+ const updated = updateDeploymentStatus(record, newStatus);
127
+ await saveDeployment(rootDir, updated);
128
+ UI.success(` Status updated: ${newStatus}`);
129
+ });
130
+ } else {
131
+ UI.info(` Status remains: ${record.status}`);
132
+ }
133
+ await client.close();
134
+ } catch (e) {
135
+ UI.error(` RPC check failed: ${e.message}`);
136
+ }
137
+ }
138
+ }
139
+ async function showDeploymentHistory(opts) {
140
+ const options = {
141
+ ...opts.json !== void 0 ? { json: opts.json } : {}
142
+ };
143
+ await listAllDeployments(options);
144
+ }
145
+ function formatAgo(dateStr) {
146
+ const date = new Date(dateStr);
147
+ const now = /* @__PURE__ */ new Date();
148
+ const diffMs = now.getTime() - date.getTime();
149
+ const diffMin = Math.floor(diffMs / 6e4);
150
+ if (diffMin < 1) return "just now";
151
+ if (diffMin < 60) return `${diffMin} min ago`;
152
+ const diffHour = Math.floor(diffMin / 60);
153
+ if (diffHour < 24) return `${diffHour} hours ago`;
154
+ return `${Math.floor(diffHour / 24)} days ago`;
155
+ }
156
+
157
+ export {
158
+ trackDeployment,
159
+ listAllDeployments,
160
+ inspectDeployment,
161
+ verifyDeploymentStatus,
162
+ showDeploymentHistory
163
+ };
@@ -0,0 +1,37 @@
1
+ // src/runners/secrets.ts
2
+ import enquirer from "enquirer";
3
+ var { Password } = enquirer;
4
+ async function acquirePassword(options = {}) {
5
+ if (options.env && process.env[options.env]) {
6
+ return process.env[options.env];
7
+ }
8
+ if (options.stdin) {
9
+ return new Promise((resolve, reject) => {
10
+ let data = "";
11
+ process.stdin.setEncoding("utf8");
12
+ process.stdin.on("data", (chunk) => {
13
+ data += chunk;
14
+ });
15
+ process.stdin.on("end", () => {
16
+ resolve(data.trim());
17
+ });
18
+ process.stdin.on("error", reject);
19
+ });
20
+ }
21
+ const prompt = new Password({
22
+ name: "password",
23
+ message: options.message || "Enter password:"
24
+ });
25
+ return await prompt.run();
26
+ }
27
+ async function acquirePrivateKey(options = {}) {
28
+ return acquirePassword({
29
+ ...options,
30
+ message: options.message || "Enter private key (hex):"
31
+ });
32
+ }
33
+
34
+ export {
35
+ acquirePassword,
36
+ acquirePrivateKey
37
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  UI
3
- } from "./chunk-AQWQW5ZG.js";
3
+ } from "./chunk-K7XPWWIO.js";
4
4
 
5
5
  // src/runners/dag-runners.ts
6
6
  import {
@@ -49,7 +49,7 @@ async function runDagSimulateReorg(options) {
49
49
  if (!forkPointId) throw new Error("Could not find fork point in current path.");
50
50
  const forkPoint = state.dag.blocks[forkPointId];
51
51
  if (!forkPoint) throw new Error(`Fork point block ${forkPointId} not found in state.`);
52
- const sideBlockId = `reorg_side_${Date.now().toString(36)}`;
52
+ const sideBlockId = `reorg_side_${forkPointId}_0`;
53
53
  state.dag.blocks[sideBlockId] = {
54
54
  id: sideBlockId,
55
55
  parents: [forkPointId],
@@ -0,0 +1,15 @@
1
+ import {
2
+ inspectDeployment,
3
+ listAllDeployments,
4
+ showDeploymentHistory,
5
+ trackDeployment,
6
+ verifyDeploymentStatus
7
+ } from "./chunk-KA5CAWI2.js";
8
+ import "./chunk-K7XPWWIO.js";
9
+ export {
10
+ inspectDeployment,
11
+ listAllDeployments,
12
+ showDeploymentHistory,
13
+ trackDeployment,
14
+ verifyDeploymentStatus
15
+ };