airterm 1.0.0 → 1.0.2
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/cli.js +78 -52
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -83,7 +83,7 @@ function resetAll() {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
// src/components/Welcome.tsx
|
|
86
|
-
import { useState } from "react";
|
|
86
|
+
import { useState, useEffect } from "react";
|
|
87
87
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
88
88
|
import TextInput from "ink-text-input";
|
|
89
89
|
|
|
@@ -94,10 +94,50 @@ function Header() {
|
|
|
94
94
|
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx(Box, { borderStyle: "round", paddingX: 2, children: /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "AirTerm" }) }) });
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
// src/lib/api.ts
|
|
98
|
+
var API_BASE = process.env.AIRCLAW_API_URL || "https://app.airclaw.com";
|
|
99
|
+
async function redeemCode(code) {
|
|
100
|
+
const res = await fetch(`${API_BASE}/api/airterm/redeem`, {
|
|
101
|
+
method: "POST",
|
|
102
|
+
headers: { "Content-Type": "application/json" },
|
|
103
|
+
body: JSON.stringify({ code })
|
|
104
|
+
});
|
|
105
|
+
const data = await res.json();
|
|
106
|
+
if (!res.ok) {
|
|
107
|
+
return { error: data.error || `HTTP ${res.status}` };
|
|
108
|
+
}
|
|
109
|
+
return data;
|
|
110
|
+
}
|
|
111
|
+
function isRedeemError(result) {
|
|
112
|
+
return "error" in result;
|
|
113
|
+
}
|
|
114
|
+
async function downloadKey(url) {
|
|
115
|
+
const res = await fetch(url);
|
|
116
|
+
if (!res.ok) {
|
|
117
|
+
throw new Error(`Failed to download key: HTTP ${res.status}`);
|
|
118
|
+
}
|
|
119
|
+
return await res.text();
|
|
120
|
+
}
|
|
121
|
+
async function fetchInfo() {
|
|
122
|
+
try {
|
|
123
|
+
const res = await fetch(`${API_BASE}/api/airterm/info`);
|
|
124
|
+
if (!res.ok) return null;
|
|
125
|
+
return await res.json();
|
|
126
|
+
} catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
97
131
|
// src/components/Welcome.tsx
|
|
98
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
132
|
+
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
99
133
|
function Welcome({ onSubmitCode }) {
|
|
100
134
|
const [code, setCode] = useState("");
|
|
135
|
+
const [phone, setPhone] = useState(null);
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
fetchInfo().then((info) => {
|
|
138
|
+
if (info?.phone) setPhone(info.phone);
|
|
139
|
+
});
|
|
140
|
+
}, []);
|
|
101
141
|
return /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", children: [
|
|
102
142
|
/* @__PURE__ */ jsx2(Header, {}),
|
|
103
143
|
/* @__PURE__ */ jsx2(Box2, { marginBottom: 1, children: /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "No saved connections." }) }),
|
|
@@ -117,11 +157,14 @@ function Welcome({ onSubmitCode }) {
|
|
|
117
157
|
}
|
|
118
158
|
)
|
|
119
159
|
] }),
|
|
120
|
-
/* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsxs(
|
|
121
|
-
"Don't have one? Text your AirClaw:",
|
|
122
|
-
"
|
|
123
|
-
|
|
124
|
-
|
|
160
|
+
/* @__PURE__ */ jsx2(Box2, { marginTop: 1, flexDirection: "column", children: phone ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
161
|
+
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Don't have one? Text your AirClaw:" }),
|
|
162
|
+
/* @__PURE__ */ jsxs(Text2, { color: "cyan", children: [
|
|
163
|
+
"\u2192 sms:",
|
|
164
|
+
phone,
|
|
165
|
+
"&body=Give%20me%20terminal%20access"
|
|
166
|
+
] })
|
|
167
|
+
] }) : /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Don't have one? Text your AirClaw and ask for terminal access." }) })
|
|
125
168
|
] });
|
|
126
169
|
}
|
|
127
170
|
|
|
@@ -232,53 +275,32 @@ function SelectMachine({
|
|
|
232
275
|
}
|
|
233
276
|
|
|
234
277
|
// src/components/Connecting.tsx
|
|
235
|
-
import { useEffect, useState as useState4 } from "react";
|
|
278
|
+
import { useEffect as useEffect2, useState as useState4 } from "react";
|
|
236
279
|
import { Box as Box5, Text as Text5, useApp as useApp2 } from "ink";
|
|
237
280
|
import Spinner from "ink-spinner";
|
|
238
281
|
|
|
239
|
-
// src/lib/api.ts
|
|
240
|
-
var API_BASE = process.env.AIRCLAW_API_URL || "https://app.airclaw.com";
|
|
241
|
-
async function redeemCode(code) {
|
|
242
|
-
const res = await fetch(`${API_BASE}/api/airterm/redeem`, {
|
|
243
|
-
method: "POST",
|
|
244
|
-
headers: { "Content-Type": "application/json" },
|
|
245
|
-
body: JSON.stringify({ code })
|
|
246
|
-
});
|
|
247
|
-
const data = await res.json();
|
|
248
|
-
if (!res.ok) {
|
|
249
|
-
return { error: data.error || `HTTP ${res.status}` };
|
|
250
|
-
}
|
|
251
|
-
return data;
|
|
252
|
-
}
|
|
253
|
-
function isRedeemError(result) {
|
|
254
|
-
return "error" in result;
|
|
255
|
-
}
|
|
256
|
-
async function downloadKey(url) {
|
|
257
|
-
const res = await fetch(url);
|
|
258
|
-
if (!res.ok) {
|
|
259
|
-
throw new Error(`Failed to download key: HTTP ${res.status}`);
|
|
260
|
-
}
|
|
261
|
-
return await res.text();
|
|
262
|
-
}
|
|
263
|
-
|
|
264
282
|
// src/lib/ssh.ts
|
|
265
283
|
import { spawnSync } from "child_process";
|
|
266
284
|
function connectSSH(conn) {
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
285
|
+
const needsTls = conn.hostname.endsWith(".fly.dev");
|
|
286
|
+
const args = [
|
|
287
|
+
"-i",
|
|
288
|
+
conn.keyPath,
|
|
289
|
+
"-p",
|
|
290
|
+
String(conn.port),
|
|
291
|
+
"-o",
|
|
292
|
+
"StrictHostKeyChecking=accept-new",
|
|
293
|
+
"-o",
|
|
294
|
+
"UserKnownHostsFile=~/.airterm/known_hosts"
|
|
295
|
+
];
|
|
296
|
+
if (needsTls) {
|
|
297
|
+
args.push(
|
|
274
298
|
"-o",
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
{ stdio: "inherit" }
|
|
281
|
-
);
|
|
299
|
+
`ProxyCommand openssl s_client -connect %h:%p -quiet 2>/dev/null`
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
args.push(`${conn.username}@${conn.hostname}`);
|
|
303
|
+
const result = spawnSync("ssh", args, { stdio: "inherit" });
|
|
282
304
|
return result.status ?? 1;
|
|
283
305
|
}
|
|
284
306
|
|
|
@@ -289,7 +311,7 @@ function Connecting({ code, connection, onError }) {
|
|
|
289
311
|
code ? "Redeeming access code..." : "Connecting..."
|
|
290
312
|
);
|
|
291
313
|
const { exit } = useApp2();
|
|
292
|
-
|
|
314
|
+
useEffect2(() => {
|
|
293
315
|
let cancelled = false;
|
|
294
316
|
async function run() {
|
|
295
317
|
let conn = connection;
|
|
@@ -438,10 +460,14 @@ function App({ initialCode: initialCode2, initialScreen: initialScreen2 }) {
|
|
|
438
460
|
|
|
439
461
|
// src/cli.tsx
|
|
440
462
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
463
|
+
if (process.argv.includes("-h")) {
|
|
464
|
+
process.argv[process.argv.indexOf("-h")] = "--help";
|
|
465
|
+
}
|
|
466
|
+
if (process.argv.includes("-v")) {
|
|
467
|
+
process.argv[process.argv.indexOf("-v")] = "--version";
|
|
468
|
+
}
|
|
441
469
|
var cli = meow(
|
|
442
470
|
`
|
|
443
|
-
AirTerm \u2014 SSH into your AirClaw machine
|
|
444
|
-
|
|
445
471
|
Usage:
|
|
446
472
|
airterm Connect to your machine
|
|
447
473
|
airterm <code> Redeem an access code and connect
|
|
@@ -485,14 +511,14 @@ if (command === "add") {
|
|
|
485
511
|
} else {
|
|
486
512
|
initialScreen = "add";
|
|
487
513
|
}
|
|
488
|
-
} else if (command === "list") {
|
|
514
|
+
} else if (command === "list" || command === "ls") {
|
|
489
515
|
const connections = getConnections();
|
|
490
516
|
if (connections.length === 0) {
|
|
491
517
|
console.log("No saved connections. Run `airterm add` to set up.");
|
|
492
518
|
process.exit(0);
|
|
493
519
|
}
|
|
494
520
|
initialScreen = "list";
|
|
495
|
-
} else if (command && !["add", "list", "help", "reset"].includes(command)) {
|
|
521
|
+
} else if (command && !["add", "list", "ls", "help", "reset"].includes(command)) {
|
|
496
522
|
if (/^[A-Za-z0-9_-]{10,}$/.test(command)) {
|
|
497
523
|
initialCode = command;
|
|
498
524
|
} else {
|