@archildata/just-bash 0.8.18 → 0.8.19

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/shell.js DELETED
@@ -1,313 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // bin/shell.ts
4
- import * as readline from "readline";
5
- import { Command } from "commander";
6
- import { ArchilClient } from "@archildata/native";
7
- import { Archil } from "disk";
8
- import { Bash } from "just-bash";
9
- import { ArchilFs, createArchilCommand } from "@archildata/just-bash";
10
- var program = new Command();
11
- program.name("archil-shell").description("Interactive bash shell with Archil filesystem").version("0.1.0").argument("[target]", "S3 bucket (s3://bucket) or region (e.g., aws-us-east-1)").argument("[disk]", "Disk name (e.g., myaccount/mydisk) - only when target is region").option("-r, --region <region>", "Region identifier (e.g., aws-us-east-1)").option("-d, --disk <disk>", "Disk name (e.g., myaccount/mydisk)").option("-k, --api-key <key>", "API key for disk management (required for S3 bucket mode)").option("-t, --token <token>", "Auth token for direct connection (defaults to IAM)").option("-l, --log-level <level>", "Log level: trace, debug, info, warn, error").option("--bucket-region <region>", "AWS region for the S3 bucket (default: us-east-1)").option("--bucket-prefix <prefix>", "Path prefix within the bucket").addHelpText("after", `
12
- Quick Start (S3 bucket mode):
13
- Connect directly to an S3 bucket - creates a disk if needed:
14
- $ npx @archildata/just-bash s3://my-bucket --api-key adt_xxx
15
- $ npx @archildata/just-bash s3://my-bucket --api-key adt_xxx --bucket-region us-west-2
16
-
17
- AWS credentials are read from environment:
18
- $ AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx npx @archildata/just-bash s3://my-bucket -k adt_xxx
19
-
20
- Traditional usage (direct connection):
21
- $ npx @archildata/just-bash aws-us-east-1 myaccount/mydisk
22
- $ npx @archildata/just-bash --region aws-us-east-1 --disk myaccount/mydisk
23
- $ ARCHIL_DISK_TOKEN=xxx npx @archildata/just-bash aws-us-east-1 myaccount/mydisk
24
-
25
- Subdirectory mounting (mount a subdirectory as the root):
26
- $ npx @archildata/just-bash aws-us-east-1 myaccount/mydisk:/data/project
27
-
28
- Environment variables:
29
- ARCHIL_API_KEY API key for disk management
30
- ARCHIL_REGION Fallback for --region
31
- ARCHIL_DISK Fallback for --disk
32
- ARCHIL_DISK_TOKEN Fallback for --token (recommended for secrets)
33
- ARCHIL_LOG_LEVEL Fallback for --log-level
34
- AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY S3 credentials for bucket mode
35
- `);
36
- program.parse();
37
- var opts = program.opts();
38
- var args = program.args;
39
- var isS3Bucket = args[0]?.startsWith("s3://");
40
- function parseS3Url(url) {
41
- const match = url.match(/^s3:\/\/([^/]+)(\/.*)?$/);
42
- if (!match) {
43
- throw new Error(`Invalid S3 URL: ${url}`);
44
- }
45
- return {
46
- bucket: match[1],
47
- prefix: match[2]?.slice(1) || void 0
48
- // Remove leading /
49
- };
50
- }
51
- function diskNameFromBucket(bucket) {
52
- return `s3-${bucket.replace(/[^a-zA-Z0-9-]/g, "-")}`;
53
- }
54
- function findDiskForBucket(disks, bucketName) {
55
- return disks.find(
56
- (disk) => disk.mounts?.some(
57
- (mount) => mount.type === "s3" && mount.config?.bucketName === bucketName
58
- )
59
- );
60
- }
61
- async function runS3BucketMode() {
62
- const s3Url = args[0];
63
- const logLevel = opts.logLevel || process.env.ARCHIL_LOG_LEVEL;
64
- const region = opts.region || process.env.ARCHIL_REGION || "aws-us-east-1";
65
- const bucketRegion = opts.bucketRegion || "us-east-1";
66
- const awsAccessKeyId = process.env.AWS_ACCESS_KEY_ID;
67
- const awsSecretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
68
- if (!awsAccessKeyId || !awsSecretAccessKey) {
69
- console.error("Error: AWS credentials required for S3 bucket mode");
70
- console.error("");
71
- console.error("Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables:");
72
- console.error(" AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx npx @archildata/just-bash s3://my-bucket -k adt_xxx");
73
- process.exit(1);
74
- }
75
- const { bucket, prefix } = parseS3Url(s3Url);
76
- const combinedPrefix = opts.bucketPrefix ? opts.bucketPrefix + (prefix ? "/" + prefix : "") : prefix;
77
- console.log("Archil S3 Quick Start");
78
- console.log("=====================");
79
- console.log(` Bucket: ${bucket}`);
80
- if (combinedPrefix) {
81
- console.log(` Prefix: ${combinedPrefix}`);
82
- }
83
- console.log(` Region: ${region}`);
84
- console.log(` Bucket Region: ${bucketRegion}`);
85
- console.log("");
86
- let archil;
87
- try {
88
- archil = new Archil({
89
- apiKey: opts.apiKey,
90
- region
91
- });
92
- } catch (err) {
93
- console.error(err instanceof Error ? err.message : err);
94
- console.error("");
95
- console.error("Usage:");
96
- console.error(" npx @archildata/just-bash s3://my-bucket --api-key adt_xxx");
97
- console.error("");
98
- console.error("Or set ARCHIL_API_KEY environment variable:");
99
- console.error(" ARCHIL_API_KEY=adt_xxx npx @archildata/just-bash s3://my-bucket");
100
- process.exit(1);
101
- }
102
- console.log("Checking for existing disk...");
103
- let disk;
104
- let mountToken;
105
- try {
106
- const disks = await archil.disks.list();
107
- disk = findDiskForBucket(disks, bucket);
108
- if (disk) {
109
- console.log(`Found existing disk: ${disk.name} (${disk.id})`);
110
- }
111
- } catch (err) {
112
- console.error("Failed to list disks:", err instanceof Error ? err.message : err);
113
- process.exit(1);
114
- }
115
- if (!disk) {
116
- const diskName = diskNameFromBucket(bucket);
117
- console.log(`Creating new disk: ${diskName}`);
118
- try {
119
- const result = await archil.disks.create({
120
- name: diskName,
121
- mounts: [
122
- {
123
- type: "s3",
124
- bucketName: bucket,
125
- bucketPrefix: combinedPrefix,
126
- accessKeyId: awsAccessKeyId,
127
- secretAccessKey: awsSecretAccessKey
128
- }
129
- ]
130
- });
131
- disk = result.disk;
132
- mountToken = result.token ?? void 0;
133
- console.log(`Created disk: ${disk.name} (${disk.id})`);
134
- } catch (err) {
135
- console.error("Failed to create disk:", err instanceof Error ? err.message : err);
136
- process.exit(1);
137
- }
138
- }
139
- if (!mountToken) {
140
- try {
141
- const { token } = await disk.createToken("just-bash");
142
- mountToken = token;
143
- } catch (err) {
144
- console.error("Failed to create mount token:", err instanceof Error ? err.message : err);
145
- process.exit(1);
146
- }
147
- }
148
- console.log("Connecting...");
149
- let client;
150
- try {
151
- client = await disk.mount({ authToken: mountToken, logLevel });
152
- console.log("Connected!");
153
- } catch (err) {
154
- console.error("Failed to connect:", err instanceof Error ? err.message : err);
155
- process.exit(1);
156
- }
157
- return { client, diskName: disk.name, subdirectory: void 0 };
158
- }
159
- async function runDirectMode() {
160
- const region = args[0] || opts.region || process.env.ARCHIL_REGION;
161
- const rawDisk = args[1] || opts.disk || process.env.ARCHIL_DISK;
162
- const authToken = opts.token || process.env.ARCHIL_DISK_TOKEN;
163
- const logLevel = opts.logLevel || process.env.ARCHIL_LOG_LEVEL;
164
- let diskName;
165
- let subdirectory;
166
- if (rawDisk) {
167
- const colonIdx = rawDisk.indexOf(":/");
168
- if (colonIdx !== -1) {
169
- diskName = rawDisk.substring(0, colonIdx);
170
- const subdir = rawDisk.substring(colonIdx + 1).replace(/^\/+|\/+$/g, "");
171
- if (subdir) {
172
- subdirectory = subdir;
173
- }
174
- } else {
175
- diskName = rawDisk;
176
- }
177
- }
178
- if (!region || !diskName) {
179
- console.error("Error: region and disk are required\n");
180
- console.error("Usage:");
181
- console.error(" npx @archildata/just-bash <region> <disk>");
182
- console.error(" npx @archildata/just-bash --region <region> --disk <disk>");
183
- console.error("\nQuick start with S3 bucket:");
184
- console.error(" npx @archildata/just-bash s3://my-bucket --api-key adt_xxx");
185
- console.error("\nExamples:");
186
- console.error(" npx @archildata/just-bash aws-us-east-1 myaccount/mydisk");
187
- console.error(" ARCHIL_DISK_TOKEN=xxx npx @archildata/just-bash aws-us-east-1 myaccount/mydisk");
188
- console.error("\nRun with --help for more options.");
189
- process.exit(1);
190
- }
191
- console.log("Connecting to Archil...");
192
- console.log(` Region: ${region}`);
193
- console.log(` Disk: ${diskName}`);
194
- if (subdirectory) {
195
- console.log(` Subdirectory: ${subdirectory}`);
196
- }
197
- console.log(` Auth: ${authToken ? "token" : "IAM"}`);
198
- if (logLevel) {
199
- console.log(` Log level: ${logLevel}`);
200
- }
201
- console.log("");
202
- let client;
203
- try {
204
- client = await ArchilClient.connect({
205
- region,
206
- diskName,
207
- authToken: authToken || void 0,
208
- logLevel
209
- });
210
- console.log("Connected!");
211
- } catch (err) {
212
- console.error("Failed to connect:", err instanceof Error ? err.message : err);
213
- process.exit(1);
214
- }
215
- return { client, diskName, subdirectory };
216
- }
217
- async function main() {
218
- const { client, diskName, subdirectory } = isS3Bucket ? await runS3BucketMode() : await runDirectMode();
219
- const fs = await ArchilFs.create(client, { subdirectory });
220
- const bash = new Bash({ fs, customCommands: [createArchilCommand(client, fs)] });
221
- let cleaningUp = false;
222
- const cleanup = async (signal) => {
223
- if (cleaningUp) return;
224
- cleaningUp = true;
225
- if (signal) {
226
- console.log(`
227
- Received ${signal}, cleaning up...`);
228
- } else {
229
- console.log("\nGoodbye!");
230
- }
231
- try {
232
- const released = await client.close();
233
- if (released > 0) {
234
- console.log(`Released ${released} delegation${released > 1 ? "s" : ""}`);
235
- }
236
- } catch (err) {
237
- console.error("Error during cleanup:", err instanceof Error ? err.message : err);
238
- }
239
- process.exit(0);
240
- };
241
- process.on("SIGINT", () => cleanup("SIGINT"));
242
- process.on("SIGTERM", () => cleanup("SIGTERM"));
243
- process.on("SIGHUP", () => cleanup("SIGHUP"));
244
- console.log("");
245
- console.log("=== Archil just-bash shell ===");
246
- console.log(`Connected to: ${diskName}${subdirectory ? ":" + subdirectory : ""}`);
247
- console.log("");
248
- console.log("Type bash commands to interact with the filesystem.");
249
- console.log("Special commands:");
250
- console.log(" archil checkout [--force] <path> - Acquire write delegation");
251
- console.log(" archil checkin <path> - Release write delegation");
252
- console.log(" archil list-delegations - Show held delegations");
253
- console.log(" archil help - Show archil commands");
254
- console.log("Type 'exit' or Ctrl+D to quit.");
255
- console.log("");
256
- const rl = readline.createInterface({
257
- input: process.stdin,
258
- output: process.stdout,
259
- prompt: "archil$ "
260
- });
261
- let cwd = "/";
262
- const prompt = () => {
263
- rl.setPrompt(`archil:${cwd}$ `);
264
- rl.prompt();
265
- };
266
- prompt();
267
- rl.on("line", async (line) => {
268
- const trimmed = line.trim();
269
- if (trimmed === "exit" || trimmed === "quit") {
270
- await cleanup();
271
- return;
272
- }
273
- if (!trimmed) {
274
- prompt();
275
- return;
276
- }
277
- rl.pause();
278
- try {
279
- const result = await bash.exec(trimmed, {
280
- cwd,
281
- env: {
282
- HOME: "/",
283
- USER: "archil",
284
- PWD: cwd
285
- }
286
- });
287
- if (result.stdout) {
288
- process.stdout.write(result.stdout);
289
- if (!result.stdout.endsWith("\n")) {
290
- console.log("");
291
- }
292
- }
293
- if (result.stderr) {
294
- process.stderr.write(result.stderr);
295
- if (!result.stderr.endsWith("\n")) {
296
- console.error("");
297
- }
298
- }
299
- if (result.env?.PWD && result.env.PWD !== cwd) {
300
- cwd = result.env.PWD;
301
- }
302
- } catch (err) {
303
- console.error("Error:", err instanceof Error ? err.message : err);
304
- }
305
- rl.resume();
306
- prompt();
307
- });
308
- rl.on("close", () => cleanup());
309
- }
310
- main().catch((err) => {
311
- console.error("Fatal error:", err);
312
- process.exit(1);
313
- });