nebulon-escrow-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/bin/nebulon.js +3 -0
- package/idl/nebulon.json +4320 -0
- package/package.json +33 -0
- package/src/capsules.js +154 -0
- package/src/cli.js +292 -0
- package/src/commands/capsule.js +46 -0
- package/src/commands/config.js +445 -0
- package/src/commands/contract.js +4895 -0
- package/src/commands/hosted.js +90 -0
- package/src/commands/init.js +458 -0
- package/src/commands/invites.js +345 -0
- package/src/commands/login.js +320 -0
- package/src/commands/logout.js +22 -0
- package/src/commands/reset.js +102 -0
- package/src/commands/status.js +72 -0
- package/src/commands/tee.js +169 -0
- package/src/commands/wallet.js +166 -0
- package/src/config.js +80 -0
- package/src/constants.js +70 -0
- package/src/hosted.js +288 -0
- package/src/nebulon.js +121 -0
- package/src/paths.js +24 -0
- package/src/privacy.js +117 -0
- package/src/session.js +131 -0
- package/src/solana.js +196 -0
- package/src/ui.js +36 -0
- package/src/wallets.js +85 -0
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nebulon-escrow-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Nebulon CLI",
|
|
5
|
+
"author": "northbyt3 <northbyt3@gmail.com>",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/northbyt3/nebulon-public.git"
|
|
10
|
+
},
|
|
11
|
+
"private": false,
|
|
12
|
+
"bin": {
|
|
13
|
+
"nebulon": "bin/nebulon.js"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"start": "node bin/nebulon.js"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=18"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@solana/spl-token": "^0.4.14",
|
|
23
|
+
"@solana/web3.js": "^1.95.5",
|
|
24
|
+
"@coral-xyz/anchor": "^0.30.1",
|
|
25
|
+
"@magicblock-labs/gum-sdk": "^3.0.10",
|
|
26
|
+
"@magicblock-labs/ephemeral-rollups-sdk": "^0.8.0",
|
|
27
|
+
"bs58": "^6.0.0",
|
|
28
|
+
"chalk": "^4.1.2",
|
|
29
|
+
"commander": "^12.1.0",
|
|
30
|
+
"enquirer": "^2.4.1",
|
|
31
|
+
"tweetnacl": "^1.0.3"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/capsules.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const {
|
|
3
|
+
nebulonHome,
|
|
4
|
+
legacyConfigPath,
|
|
5
|
+
legacyWalletsDir,
|
|
6
|
+
capsulesDir,
|
|
7
|
+
activeCapsulePath,
|
|
8
|
+
capsuleRoot,
|
|
9
|
+
capsuleConfigPath,
|
|
10
|
+
capsuleWalletsDir,
|
|
11
|
+
} = require("./paths");
|
|
12
|
+
|
|
13
|
+
const CAPSULE_NAME_RE = /^[a-zA-Z0-9_-]+$/;
|
|
14
|
+
|
|
15
|
+
const ensureBaseDirs = () => {
|
|
16
|
+
const home = nebulonHome();
|
|
17
|
+
if (!fs.existsSync(home)) {
|
|
18
|
+
fs.mkdirSync(home, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
const capsuleRootDir = capsulesDir();
|
|
21
|
+
if (!fs.existsSync(capsuleRootDir)) {
|
|
22
|
+
fs.mkdirSync(capsuleRootDir, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const readActiveState = () => {
|
|
27
|
+
ensureBaseDirs();
|
|
28
|
+
const statePath = activeCapsulePath();
|
|
29
|
+
if (!fs.existsSync(statePath)) {
|
|
30
|
+
return { lastUsed: null, sessions: {} };
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const parsed = JSON.parse(fs.readFileSync(statePath, "utf8"));
|
|
34
|
+
return {
|
|
35
|
+
lastUsed: parsed.lastUsed || null,
|
|
36
|
+
sessions: parsed.sessions || {},
|
|
37
|
+
};
|
|
38
|
+
} catch (error) {
|
|
39
|
+
return { lastUsed: null, sessions: {} };
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const writeActiveState = (state) => {
|
|
44
|
+
ensureBaseDirs();
|
|
45
|
+
fs.writeFileSync(activeCapsulePath(), JSON.stringify(state, null, 2));
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const getSessionId = () => String(process.ppid || process.pid);
|
|
49
|
+
|
|
50
|
+
const isValidCapsuleName = (name) =>
|
|
51
|
+
typeof name === "string" && CAPSULE_NAME_RE.test(name.trim());
|
|
52
|
+
|
|
53
|
+
const ensureCapsuleDirs = (name) => {
|
|
54
|
+
ensureBaseDirs();
|
|
55
|
+
const root = capsuleRoot(name);
|
|
56
|
+
if (!fs.existsSync(root)) {
|
|
57
|
+
fs.mkdirSync(root, { recursive: true });
|
|
58
|
+
}
|
|
59
|
+
const wallets = capsuleWalletsDir(name);
|
|
60
|
+
if (!fs.existsSync(wallets)) {
|
|
61
|
+
fs.mkdirSync(wallets, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const listCapsules = () => {
|
|
66
|
+
ensureBaseDirs();
|
|
67
|
+
const root = capsulesDir();
|
|
68
|
+
if (!fs.existsSync(root)) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
return fs
|
|
72
|
+
.readdirSync(root, { withFileTypes: true })
|
|
73
|
+
.filter((entry) => entry.isDirectory())
|
|
74
|
+
.map((entry) => entry.name)
|
|
75
|
+
.sort((a, b) => a.localeCompare(b));
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const migrateLegacyIfNeeded = () => {
|
|
79
|
+
if (!fs.existsSync(legacyConfigPath())) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
if (listCapsules().length > 0) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
ensureCapsuleDirs("1");
|
|
86
|
+
try {
|
|
87
|
+
fs.renameSync(legacyConfigPath(), capsuleConfigPath("1"));
|
|
88
|
+
} catch (error) {
|
|
89
|
+
fs.copyFileSync(legacyConfigPath(), capsuleConfigPath("1"));
|
|
90
|
+
fs.rmSync(legacyConfigPath(), { force: true });
|
|
91
|
+
}
|
|
92
|
+
if (fs.existsSync(legacyWalletsDir())) {
|
|
93
|
+
try {
|
|
94
|
+
fs.renameSync(legacyWalletsDir(), capsuleWalletsDir("1"));
|
|
95
|
+
} catch (error) {
|
|
96
|
+
fs.cpSync(legacyWalletsDir(), capsuleWalletsDir("1"), {
|
|
97
|
+
recursive: true,
|
|
98
|
+
});
|
|
99
|
+
fs.rmSync(legacyWalletsDir(), { recursive: true, force: true });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const state = readActiveState();
|
|
103
|
+
state.lastUsed = "1";
|
|
104
|
+
state.sessions[getSessionId()] = "1";
|
|
105
|
+
writeActiveState(state);
|
|
106
|
+
return true;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const getActiveCapsule = (preferred) => {
|
|
110
|
+
migrateLegacyIfNeeded();
|
|
111
|
+
const state = readActiveState();
|
|
112
|
+
const sessionId = getSessionId();
|
|
113
|
+
let capsule =
|
|
114
|
+
(preferred && preferred.trim()) ||
|
|
115
|
+
state.sessions[sessionId] ||
|
|
116
|
+
state.lastUsed ||
|
|
117
|
+
"1";
|
|
118
|
+
if (!isValidCapsuleName(capsule)) {
|
|
119
|
+
capsule = "1";
|
|
120
|
+
}
|
|
121
|
+
ensureCapsuleDirs(capsule);
|
|
122
|
+
if (state.sessions[sessionId] !== capsule || state.lastUsed !== capsule) {
|
|
123
|
+
state.sessions[sessionId] = capsule;
|
|
124
|
+
state.lastUsed = capsule;
|
|
125
|
+
writeActiveState(state);
|
|
126
|
+
}
|
|
127
|
+
return capsule;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const setActiveCapsule = (name) => {
|
|
131
|
+
if (!isValidCapsuleName(name)) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
"Invalid capsule name. Use letters, numbers, dashes, or underscores."
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
ensureCapsuleDirs(name.trim());
|
|
137
|
+
const state = readActiveState();
|
|
138
|
+
const sessionId = getSessionId();
|
|
139
|
+
state.sessions[sessionId] = name.trim();
|
|
140
|
+
state.lastUsed = name.trim();
|
|
141
|
+
writeActiveState(state);
|
|
142
|
+
return name.trim();
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
module.exports = {
|
|
146
|
+
ensureCapsuleDirs,
|
|
147
|
+
getActiveCapsule,
|
|
148
|
+
isValidCapsuleName,
|
|
149
|
+
listCapsules,
|
|
150
|
+
migrateLegacyIfNeeded,
|
|
151
|
+
readActiveState,
|
|
152
|
+
setActiveCapsule,
|
|
153
|
+
writeActiveState,
|
|
154
|
+
};
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
const { Command } = require("commander");
|
|
2
|
+
const { runInit } = require("./commands/init");
|
|
3
|
+
const { runConfigGet, runConfigSummary, runConfigSet } = require("./commands/config");
|
|
4
|
+
const { runStatus } = require("./commands/status");
|
|
5
|
+
const { runLogin } = require("./commands/login");
|
|
6
|
+
const { runLogout } = require("./commands/logout");
|
|
7
|
+
const { runReset } = require("./commands/reset");
|
|
8
|
+
const { runCapsuleList, runCapsuleUse } = require("./commands/capsule");
|
|
9
|
+
const { runContractCommand } = require("./commands/contract");
|
|
10
|
+
const { runInviteList, runInviteAction } = require("./commands/invites");
|
|
11
|
+
const { runHostedMe, runHostedFaucet } = require("./commands/hosted");
|
|
12
|
+
const { runWalletShow, runWalletBalance, runWalletExport } = require("./commands/wallet");
|
|
13
|
+
const { runTestTee } = require("./commands/tee");
|
|
14
|
+
const { errorMessage } = require("./ui");
|
|
15
|
+
|
|
16
|
+
const VERSION = "0.1.0";
|
|
17
|
+
const program = new Command();
|
|
18
|
+
let hasFatalError = false;
|
|
19
|
+
|
|
20
|
+
const formatError = (error) => {
|
|
21
|
+
if (!error) {
|
|
22
|
+
return "Action failed.";
|
|
23
|
+
}
|
|
24
|
+
if (typeof error === "string") {
|
|
25
|
+
return error;
|
|
26
|
+
}
|
|
27
|
+
if (error.message) {
|
|
28
|
+
return error.message;
|
|
29
|
+
}
|
|
30
|
+
return "Action failed.";
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
process.on("uncaughtException", (error) => {
|
|
34
|
+
hasFatalError = true;
|
|
35
|
+
errorMessage(formatError(error));
|
|
36
|
+
process.exit(1);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
process.on("unhandledRejection", (error) => {
|
|
40
|
+
hasFatalError = true;
|
|
41
|
+
errorMessage(formatError(error));
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
process.on("exit", (code) => {
|
|
46
|
+
if (!hasFatalError && code && code !== 0) {
|
|
47
|
+
errorMessage("Action failed.");
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
program
|
|
52
|
+
.name("nebulon")
|
|
53
|
+
.description("Nebulon CLI")
|
|
54
|
+
.version(VERSION)
|
|
55
|
+
.configureHelp({
|
|
56
|
+
formatHelp: () => {
|
|
57
|
+
return [
|
|
58
|
+
"Nebulon CLI - help",
|
|
59
|
+
"",
|
|
60
|
+
"Options:",
|
|
61
|
+
" -v, -V, --version output the version number",
|
|
62
|
+
"",
|
|
63
|
+
"Commands:",
|
|
64
|
+
" nebulon init Initializes the Nebulon setup",
|
|
65
|
+
" nebulon init capsule <name> Initializes a specific capsule",
|
|
66
|
+
" nebulon status Show account summary",
|
|
67
|
+
" nebulon login Login in hosted mode",
|
|
68
|
+
" nebulon logout Logout of hosted mode",
|
|
69
|
+
" nebulon reset Reset the current capsule",
|
|
70
|
+
" nebulon reset capsules Reset all capsules",
|
|
71
|
+
" nebulon capsule list List capsules",
|
|
72
|
+
" nebulon capsule use Switch capsules",
|
|
73
|
+
" nebulon contract Contract commands (create, list, show, disputed, <id> ...)",
|
|
74
|
+
" nebulon contract <id> sync Sync PER status to on-chain flags",
|
|
75
|
+
" nebulon contract <id> milestone list Show milestone status",
|
|
76
|
+
" nebulon contract <id> milestone <n> status Show milestone status",
|
|
77
|
+
" nebulon contract <id> milestone <n> ready Mark milestone as ready",
|
|
78
|
+
" nebulon contract <id> milestone <n> confirm Confirm milestone",
|
|
79
|
+
" nebulon contract <id> term list Show deadline/payment terms",
|
|
80
|
+
" nebulon contract <id> details Show full contract details",
|
|
81
|
+
" nebulon contract <id> status Show contract summary",
|
|
82
|
+
" nebulon contract <id> isFunded Show funding status",
|
|
83
|
+
" nebulon contract <id> whoami Show your role for this contract",
|
|
84
|
+
" nebulon contract <id> nowwhat Show the next expected action",
|
|
85
|
+
" nebulon contract <id> rate <1-5> Rate the other party (completed only)",
|
|
86
|
+
" nebulon invite list Show pending invites",
|
|
87
|
+
" nebulon invite list --show-all Show accepted/canceled history",
|
|
88
|
+
" nebulon invite list sent Show sent invites only",
|
|
89
|
+
" nebulon invite list received Show received invites only",
|
|
90
|
+
" nebulon invite <id|idx> View or respond to an invite",
|
|
91
|
+
" nebulon address Show connected wallet address",
|
|
92
|
+
" nebulon balance Show SOL + USDC balance",
|
|
93
|
+
" nebulon wallet export Export active wallet to C:\\Nebulon\\Wallets",
|
|
94
|
+
" nebulon config Show and edit configuration",
|
|
95
|
+
" nebulon config [key] [value] Change a configuration value directly",
|
|
96
|
+
" nebulon test-tee Validate TEE auth + RPC connectivity",
|
|
97
|
+
" nebulon whoami Show hosted profile",
|
|
98
|
+
" nebulon request-usdc Request test USDC from backend faucet",
|
|
99
|
+
" nebulon help Shows this menu",
|
|
100
|
+
].join("\n");
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
program.helpCommand("help");
|
|
105
|
+
|
|
106
|
+
program
|
|
107
|
+
.command("init")
|
|
108
|
+
.description("Initialize Nebulon CLI")
|
|
109
|
+
.argument("[arg1]", "capsule or keyword")
|
|
110
|
+
.argument("[arg2]", "capsule name")
|
|
111
|
+
.option("--no-banner", "hide the banner")
|
|
112
|
+
.action(async (arg1, arg2, options) => {
|
|
113
|
+
let capsule = null;
|
|
114
|
+
if (arg1 === "capsule") {
|
|
115
|
+
if (!arg2) {
|
|
116
|
+
console.log("Usage: nebulon init capsule <name>");
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
capsule = arg2;
|
|
120
|
+
} else {
|
|
121
|
+
if (arg2) {
|
|
122
|
+
console.log("Usage: nebulon init [capsule] | nebulon init capsule <name>");
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
capsule = arg1 || null;
|
|
126
|
+
}
|
|
127
|
+
await runInit(options, capsule);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
program
|
|
131
|
+
.command("status")
|
|
132
|
+
.description("Show account summary")
|
|
133
|
+
.action(async () => {
|
|
134
|
+
await runStatus();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
program
|
|
138
|
+
.command("login")
|
|
139
|
+
.description("Login in hosted mode")
|
|
140
|
+
.option("--handle <handle>", "request a Nebulon handle on login")
|
|
141
|
+
.option("--debug", "enable login debug logging")
|
|
142
|
+
.action(async (options) => {
|
|
143
|
+
await runLogin(options);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
program
|
|
147
|
+
.command("logout")
|
|
148
|
+
.description("Logout of hosted mode")
|
|
149
|
+
.action(async () => {
|
|
150
|
+
await runLogout();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
program
|
|
154
|
+
.command("reset")
|
|
155
|
+
.description("Reset the current capsule")
|
|
156
|
+
.argument("[scope]", "capsules")
|
|
157
|
+
.action(async (scope) => {
|
|
158
|
+
await runReset(scope);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const capsule = program
|
|
162
|
+
.command("capsule")
|
|
163
|
+
.description("Capsule commands");
|
|
164
|
+
|
|
165
|
+
capsule
|
|
166
|
+
.command("list")
|
|
167
|
+
.description("List capsules")
|
|
168
|
+
.action(async () => {
|
|
169
|
+
runCapsuleList();
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
capsule
|
|
173
|
+
.command("use")
|
|
174
|
+
.description("Switch capsules")
|
|
175
|
+
.argument("<name>", "capsule name")
|
|
176
|
+
.action(async (name) => {
|
|
177
|
+
runCapsuleUse(name);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
program
|
|
181
|
+
.command("contract")
|
|
182
|
+
.description("Contract commands")
|
|
183
|
+
.argument("[target]", "create | list | show | <id|index>")
|
|
184
|
+
.argument("[rest...]", "contract sub-commands")
|
|
185
|
+
.option("--confirm", "skip confirmation prompts")
|
|
186
|
+
.option("--full-fields", "show full list fields without truncation")
|
|
187
|
+
.action(async (target, rest, options) => {
|
|
188
|
+
const args = [];
|
|
189
|
+
if (target) {
|
|
190
|
+
args.push(target);
|
|
191
|
+
}
|
|
192
|
+
if (Array.isArray(rest) && rest.length) {
|
|
193
|
+
args.push(...rest);
|
|
194
|
+
}
|
|
195
|
+
await runContractCommand(args, options);
|
|
196
|
+
})
|
|
197
|
+
.alias("contracts");
|
|
198
|
+
|
|
199
|
+
const invite = program
|
|
200
|
+
.command("invite")
|
|
201
|
+
.description("Invite commands")
|
|
202
|
+
.argument("[target]", "list | index | contractId")
|
|
203
|
+
.argument("[action]", "accept | deny")
|
|
204
|
+
.option("--show-all", "show accepted/canceled invites too")
|
|
205
|
+
.action(async (target, action, options) => {
|
|
206
|
+
if (!target || target === "list") {
|
|
207
|
+
await runInviteList(action, options);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
await runInviteAction(target, action);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
invite
|
|
214
|
+
.command("list")
|
|
215
|
+
.description("List invites")
|
|
216
|
+
.argument("[filter]", "sent | received")
|
|
217
|
+
.option("--show-all", "show accepted/canceled invites too")
|
|
218
|
+
.action(async (filter, options) => {
|
|
219
|
+
await runInviteList(filter, options);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
program
|
|
223
|
+
.command("config")
|
|
224
|
+
.description("Manage config")
|
|
225
|
+
.argument("[key]", "config key")
|
|
226
|
+
.argument("[value]", "config value")
|
|
227
|
+
.action(async (key, value) => {
|
|
228
|
+
if (!key) {
|
|
229
|
+
await runConfigSummary();
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
if (typeof value === "undefined") {
|
|
233
|
+
runConfigGet(key);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
await runConfigSet(key, value);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
program
|
|
240
|
+
.command("whoami")
|
|
241
|
+
.description("Show hosted profile")
|
|
242
|
+
.action(async () => {
|
|
243
|
+
await runHostedMe();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
program
|
|
247
|
+
.command("address")
|
|
248
|
+
.description("Show connected wallet address")
|
|
249
|
+
.action(() => {
|
|
250
|
+
runWalletShow();
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
program
|
|
254
|
+
.command("balance")
|
|
255
|
+
.description("Show SOL + USDC balance")
|
|
256
|
+
.action(async () => {
|
|
257
|
+
await runWalletBalance();
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
program
|
|
261
|
+
.command("wallet")
|
|
262
|
+
.description("Wallet commands")
|
|
263
|
+
.argument("[action]", "export")
|
|
264
|
+
.action(async (action) => {
|
|
265
|
+
if (action === "export") {
|
|
266
|
+
await runWalletExport();
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
console.log("Usage: nebulon wallet export");
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
program
|
|
273
|
+
.command("request-usdc")
|
|
274
|
+
.description("Request test USDC from backend faucet")
|
|
275
|
+
.action(async () => {
|
|
276
|
+
await runHostedFaucet();
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
program
|
|
280
|
+
.command("test-tee")
|
|
281
|
+
.description("Validate TEE auth + RPC connectivity")
|
|
282
|
+
.option("--debug", "print extra diagnostic output")
|
|
283
|
+
.action(async (options) => {
|
|
284
|
+
await runTestTee(options);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
if (process.argv.includes("-v") && !process.argv.includes("-V")) {
|
|
288
|
+
console.log(VERSION);
|
|
289
|
+
process.exit(0);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
program.parseAsync(process.argv);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const {
|
|
2
|
+
listCapsules,
|
|
3
|
+
migrateLegacyIfNeeded,
|
|
4
|
+
readActiveState,
|
|
5
|
+
setActiveCapsule,
|
|
6
|
+
} = require("../capsules");
|
|
7
|
+
|
|
8
|
+
const runCapsuleList = () => {
|
|
9
|
+
migrateLegacyIfNeeded();
|
|
10
|
+
const capsules = listCapsules();
|
|
11
|
+
if (!capsules.length) {
|
|
12
|
+
console.log("No capsules found. Run `nebulon init` to create one.");
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const state = readActiveState();
|
|
17
|
+
const sessionId = String(process.ppid || process.pid);
|
|
18
|
+
const active = state.sessions && state.sessions[sessionId]
|
|
19
|
+
? state.sessions[sessionId]
|
|
20
|
+
: state.lastUsed;
|
|
21
|
+
|
|
22
|
+
console.log("Capsules");
|
|
23
|
+
capsules.forEach((name) => {
|
|
24
|
+
const marker = name === active ? "*" : " ";
|
|
25
|
+
console.log(`${marker} ${name}`);
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const runCapsuleUse = (name) => {
|
|
30
|
+
if (!name) {
|
|
31
|
+
console.log("Usage: nebulon capsule use <name>");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const capsule = setActiveCapsule(name);
|
|
36
|
+
console.log(`Capsule active: ${capsule}`);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error(error.message);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
module.exports = {
|
|
44
|
+
runCapsuleList,
|
|
45
|
+
runCapsuleUse,
|
|
46
|
+
};
|