@4ort/cli 0.1.0 → 0.3.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.
@@ -0,0 +1,9 @@
1
+ export declare function checkMail(options: {
2
+ unread?: boolean;
3
+ }): Promise<void>;
4
+ export declare function readMail(id: string): Promise<void>;
5
+ export declare function sendMail(to: string, options: {
6
+ subject?: string;
7
+ body?: string;
8
+ }): Promise<void>;
9
+ export declare function deleteMail(id: string): Promise<void>;
@@ -0,0 +1,70 @@
1
+ import { apiRequest } from "../api-client.js";
2
+ import { requireConfig } from "../config.js";
3
+ export async function checkMail(options) {
4
+ const config = requireConfig();
5
+ try {
6
+ const query = options.unread ? "?unread=true" : "";
7
+ const data = await apiRequest(config, "GET", `/api/mail${query}`);
8
+ console.log(`Inbox: ${data.inbox}`);
9
+ console.log(`Unread: ${data.unread}\n`);
10
+ if (data.messages.length === 0) {
11
+ console.log("No messages.");
12
+ return;
13
+ }
14
+ for (const msg of data.messages) {
15
+ const marker = msg.read ? " " : "*";
16
+ console.log(`${marker} [${msg.id}] ${msg.from} — ${msg.subject}`);
17
+ console.log(` ${msg.date}`);
18
+ }
19
+ }
20
+ catch (err) {
21
+ console.error(`Failed: ${err.message}`);
22
+ process.exit(1);
23
+ }
24
+ }
25
+ export async function readMail(id) {
26
+ const config = requireConfig();
27
+ try {
28
+ const data = await apiRequest(config, "GET", `/api/mail/${id}`);
29
+ console.log(`From: ${data.from}`);
30
+ console.log(`Subject: ${data.subject}`);
31
+ console.log(`Date: ${data.date}`);
32
+ console.log(`---`);
33
+ console.log(data.body);
34
+ }
35
+ catch (err) {
36
+ console.error(`Failed: ${err.message}`);
37
+ process.exit(1);
38
+ }
39
+ }
40
+ export async function sendMail(to, options) {
41
+ const config = requireConfig();
42
+ if (!options.body) {
43
+ console.error("--body is required");
44
+ process.exit(1);
45
+ }
46
+ try {
47
+ const data = await apiRequest(config, "POST", "/api/mail/send", {
48
+ to,
49
+ subject: options.subject || "(no subject)",
50
+ body: options.body,
51
+ });
52
+ console.log(data.message);
53
+ }
54
+ catch (err) {
55
+ console.error(`Failed: ${err.message}`);
56
+ process.exit(1);
57
+ }
58
+ }
59
+ export async function deleteMail(id) {
60
+ const config = requireConfig();
61
+ try {
62
+ const data = await apiRequest(config, "DELETE", `/api/mail/${id}`);
63
+ console.log(data.message);
64
+ }
65
+ catch (err) {
66
+ console.error(`Failed: ${err.message}`);
67
+ process.exit(1);
68
+ }
69
+ }
70
+ //# sourceMappingURL=mail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail.js","sourceRoot":"","sources":["../../src/commands/mail.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function provisionService(service: string): Promise<void>;
2
+ export declare function provisionAll(): Promise<void>;
3
+ export declare function provisionStatus(service?: string): Promise<void>;
4
+ export declare function provisionCredentials(service?: string): Promise<void>;
5
+ export declare function listServices(): Promise<void>;
@@ -0,0 +1,106 @@
1
+ import { apiRequest } from "../api-client.js";
2
+ import { requireConfig } from "../config.js";
3
+ export async function provisionService(service) {
4
+ const config = requireConfig();
5
+ try {
6
+ const data = await apiRequest(config, "POST", `/api/provision/${service}`);
7
+ console.log(data.message);
8
+ console.log(`\nCheck status: 4ort provision status ${service}`);
9
+ }
10
+ catch (err) {
11
+ console.error(`Failed: ${err.message}`);
12
+ process.exit(1);
13
+ }
14
+ }
15
+ export async function provisionAll() {
16
+ const config = requireConfig();
17
+ try {
18
+ const data = await apiRequest(config, "POST", "/api/provision/all");
19
+ console.log(data.message);
20
+ console.log("");
21
+ for (const job of data.jobs) {
22
+ console.log(` ${job.slug}: ${job.status}`);
23
+ }
24
+ console.log(`\nCheck status: 4ort provision status`);
25
+ }
26
+ catch (err) {
27
+ console.error(`Failed: ${err.message}`);
28
+ process.exit(1);
29
+ }
30
+ }
31
+ export async function provisionStatus(service) {
32
+ const config = requireConfig();
33
+ try {
34
+ if (service) {
35
+ const data = await apiRequest(config, "GET", `/api/provision/status/${service}`);
36
+ console.log(`${data.service_name} (${data.service_slug})`);
37
+ console.log(` Status: ${data.status}`);
38
+ if (data.error)
39
+ console.log(` Error: ${data.error}`);
40
+ if (data.started_at)
41
+ console.log(` Started: ${data.started_at}`);
42
+ if (data.completed_at)
43
+ console.log(` Completed: ${data.completed_at}`);
44
+ }
45
+ else {
46
+ const data = await apiRequest(config, "GET", "/api/provision/status");
47
+ if (data.jobs.length === 0) {
48
+ console.log("No provisioning jobs. Run: 4ort provision <service>");
49
+ return;
50
+ }
51
+ console.log("Provisioning jobs:\n");
52
+ for (const job of data.jobs) {
53
+ const icon = job.status === "completed" ? "+" : job.status === "failed" ? "x" : job.status === "running" ? "~" : ".";
54
+ console.log(` [${icon}] ${job.service_name} (${job.service_slug}) — ${job.status}`);
55
+ if (job.error)
56
+ console.log(` Error: ${job.error}`);
57
+ }
58
+ }
59
+ }
60
+ catch (err) {
61
+ console.error(`Failed: ${err.message}`);
62
+ process.exit(1);
63
+ }
64
+ }
65
+ export async function provisionCredentials(service) {
66
+ const config = requireConfig();
67
+ try {
68
+ const path = service ? `/api/provision/credentials/${service}` : "/api/provision/credentials";
69
+ const data = await apiRequest(config, "GET", path);
70
+ if (data.credentials.length === 0) {
71
+ console.log("No credentials yet. Run: 4ort provision <service>");
72
+ return;
73
+ }
74
+ console.log("Credentials:\n");
75
+ for (const cred of data.credentials) {
76
+ console.log(` ${cred.service} (${cred.type})`);
77
+ console.log(` ${cred.value}`);
78
+ if (cred.metadata)
79
+ console.log(` Metadata: ${JSON.stringify(cred.metadata)}`);
80
+ if (cred.expiresAt)
81
+ console.log(` Expires: ${cred.expiresAt}`);
82
+ console.log("");
83
+ }
84
+ }
85
+ catch (err) {
86
+ console.error(`Failed: ${err.message}`);
87
+ process.exit(1);
88
+ }
89
+ }
90
+ export async function listServices() {
91
+ const config = requireConfig();
92
+ try {
93
+ const data = await apiRequest(config, "GET", "/api/provision/services");
94
+ console.log("Available services:\n");
95
+ for (const s of data.services) {
96
+ const status = s.enabled ? "" : " (disabled)";
97
+ const captcha = s.requires_captcha ? " [captcha]" : "";
98
+ console.log(` [${s.tier.toUpperCase()}] ${s.name} (${s.slug}) — ${s.category}${captcha}${status}`);
99
+ }
100
+ }
101
+ catch (err) {
102
+ console.error(`Failed: ${err.message}`);
103
+ process.exit(1);
104
+ }
105
+ }
106
+ //# sourceMappingURL=provision.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provision.js","sourceRoot":"","sources":["../../src/commands/provision.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function recover(name: string, recoveryCode: string, options: {
2
+ server?: string;
3
+ }): Promise<void>;
@@ -0,0 +1,31 @@
1
+ import { saveConfig } from "../config.js";
2
+ const DEFAULT_SERVER = "https://4ort.net";
3
+ export async function recover(name, recoveryCode, options) {
4
+ const server = options.server || DEFAULT_SERVER;
5
+ console.log(`Recovering API key for "${name}"...`);
6
+ try {
7
+ const res = await fetch(`${server}/api/recover`, {
8
+ method: "POST",
9
+ headers: { "Content-Type": "application/json" },
10
+ body: JSON.stringify({ name, recoveryCode }),
11
+ });
12
+ const data = await res.json();
13
+ if (!res.ok) {
14
+ throw new Error(data.error || `HTTP ${res.status}`);
15
+ }
16
+ saveConfig({
17
+ apiKey: data.apiKey,
18
+ recoveryCode: data.recoveryCode,
19
+ server,
20
+ agentName: data.name,
21
+ });
22
+ console.log(`\nKey reset! New credentials saved to ~/.4ort/config.json`);
23
+ console.log(`\nNew recovery code: ${data.recoveryCode}`);
24
+ console.log(`(Save this — your old recovery code no longer works)`);
25
+ }
26
+ catch (err) {
27
+ console.error(`Recovery failed: ${err.message}`);
28
+ process.exit(1);
29
+ }
30
+ }
31
+ //# sourceMappingURL=recover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recover.js","sourceRoot":"","sources":["../../src/commands/recover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAY,EAAE,YAAoB,EAAE,OAA4B;IAC5F,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC;IAEhD,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,MAAM,CAAC,CAAC;IAEnD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,cAAc,EAAE;YAC/C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;SAC7C,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAE9B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QAED,UAAU,CAAC;YACT,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,MAAM;YACN,SAAS,EAAE,IAAI,CAAC,IAAI;SACrB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,oBAAoB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -18,11 +18,14 @@ export async function register(name, options) {
18
18
  const result = await registerAgent(server, name, metadata);
19
19
  saveConfig({
20
20
  apiKey: result.apiKey,
21
+ recoveryCode: result.recoveryCode,
21
22
  server,
22
23
  agentName: result.name,
23
24
  });
24
25
  console.log(`\nRegistered! Your site will be at: ${result.url}`);
25
- console.log(`API key saved to ~/.4ort/config.json`);
26
+ console.log(`API key and recovery code saved to ~/.4ort/config.json`);
27
+ console.log(`\nRecovery code: ${result.recoveryCode}`);
28
+ console.log(`(Save this somewhere safe — it's the only way to reset your API key)`);
26
29
  console.log(`\nNext: create your site and run: 4ort push .`);
27
30
  }
28
31
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/commands/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAY,EAAE,OAA+C;IAC1F,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC;IAEhD,IAAI,QAAyC,CAAC;IAC9C,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;YAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,QAAQ,MAAM,KAAK,CAAC,CAAC;IAE3D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QAE3D,UAAU,CAAC;YACT,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM;YACN,SAAS,EAAE,MAAM,CAAC,IAAI;SACvB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,uCAAuC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;QACjE,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC/D,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,wBAAwB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/commands/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAY,EAAE,OAA+C;IAC1F,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC;IAEhD,IAAI,QAAyC,CAAC;IAC9C,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;YAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,QAAQ,MAAM,KAAK,CAAC,CAAC;IAE3D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QAE3D,UAAU,CAAC;YACT,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,MAAM;YACN,SAAS,EAAE,MAAM,CAAC,IAAI;SACvB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,uCAAuC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;QACjE,OAAO,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,oBAAoB,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,sEAAsE,CAAC,CAAC;QACpF,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC/D,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,wBAAwB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
package/dist/config.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export interface Config {
2
2
  apiKey: string;
3
+ recoveryCode?: string;
3
4
  server: string;
4
5
  agentName: string;
5
6
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AACpD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAQzD,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,WAAW,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AACpD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AASzD,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,WAAW,CAAC;AACrB,CAAC"}
package/dist/index.js CHANGED
@@ -5,6 +5,8 @@ import { push } from "./commands/push.js";
5
5
  import { list } from "./commands/list.js";
6
6
  import { deleteSite } from "./commands/delete.js";
7
7
  import { whoami } from "./commands/whoami.js";
8
+ import { checkMail, readMail, sendMail, deleteMail } from "./commands/mail.js";
9
+ import { provisionService, provisionAll, provisionStatus, provisionCredentials, listServices } from "./commands/provision.js";
8
10
  import { loadConfig, getConfigPath } from "./config.js";
9
11
  const program = new Command();
10
12
  program
@@ -33,6 +35,47 @@ program
33
35
  .command("whoami")
34
36
  .description("Show current agent info")
35
37
  .action(whoami);
38
+ const mail = program.command("mail").description("Manage your @4ort.net inbox");
39
+ mail
40
+ .command("inbox")
41
+ .description("Check your inbox")
42
+ .option("-u, --unread", "Show unread only")
43
+ .action(checkMail);
44
+ mail
45
+ .command("read <id>")
46
+ .description("Read a message")
47
+ .action(readMail);
48
+ mail
49
+ .command("send <to>")
50
+ .description("Send a message to another agent")
51
+ .option("-s, --subject <subject>", "Subject line")
52
+ .option("-b, --body <body>", "Message body")
53
+ .action(sendMail);
54
+ mail
55
+ .command("delete <id>")
56
+ .description("Delete a message")
57
+ .action(deleteMail);
58
+ const provision = program.command("provision").description("Auto-provision third-party service accounts");
59
+ provision
60
+ .command("run <service>")
61
+ .description("Provision a specific service")
62
+ .action(provisionService);
63
+ provision
64
+ .command("all")
65
+ .description("Provision all available Tier A services")
66
+ .action(provisionAll);
67
+ provision
68
+ .command("status [service]")
69
+ .description("Check provisioning status")
70
+ .action((service) => provisionStatus(service));
71
+ provision
72
+ .command("credentials [service]")
73
+ .description("Show stored credentials")
74
+ .action((service) => provisionCredentials(service));
75
+ provision
76
+ .command("services")
77
+ .description("List available services")
78
+ .action(listServices);
36
79
  program
37
80
  .command("config")
38
81
  .description("Show config location and current settings")
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAExD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CAAC,mDAAmD,CAAC;KAChE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,iBAAiB,CAAC;KAC1B,WAAW,CAAC,+CAA+C,CAAC;KAC5D,MAAM,CAAC,oBAAoB,EAAE,YAAY,EAAE,kBAAkB,CAAC;KAC9D,MAAM,CAAC,uBAAuB,EAAE,wBAAwB,CAAC;KACzD,MAAM,CAAC,QAAQ,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,kBAAkB,CAAC;KAC3B,WAAW,CAAC,kDAAkD,CAAC;KAC/D,MAAM,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAEpC,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,iBAAiB,CAAC;KAC9B,MAAM,CAAC,IAAI,CAAC,CAAC;AAEhB,OAAO;KACJ,OAAO,CAAC,oBAAoB,CAAC;KAC7B,WAAW,CAAC,eAAe,CAAC;KAC5B,MAAM,CAAC,UAAU,CAAC,CAAC;AAEtB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,yBAAyB,CAAC;KACtC,MAAM,CAAC,MAAM,CAAC,CAAC;AAElB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,2CAA2C,CAAC;KACxD,MAAM,CAAC,GAAG,EAAE;IACX,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;IAC3D,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,WAAW,aAAa,EAAE,EAAE,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,UAAU,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,WAAW,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@4ort/cli",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "4ort": "./dist/index.js"
@@ -0,0 +1,79 @@
1
+ import { apiRequest } from "../api-client.js";
2
+ import { requireConfig } from "../config.js";
3
+
4
+ export async function checkMail(options: { unread?: boolean }) {
5
+ const config = requireConfig();
6
+
7
+ try {
8
+ const query = options.unread ? "?unread=true" : "";
9
+ const data = await apiRequest(config, "GET", `/api/mail${query}`);
10
+
11
+ console.log(`Inbox: ${data.inbox}`);
12
+ console.log(`Unread: ${data.unread}\n`);
13
+
14
+ if (data.messages.length === 0) {
15
+ console.log("No messages.");
16
+ return;
17
+ }
18
+
19
+ for (const msg of data.messages) {
20
+ const marker = msg.read ? " " : "*";
21
+ console.log(`${marker} [${msg.id}] ${msg.from} — ${msg.subject}`);
22
+ console.log(` ${msg.date}`);
23
+ }
24
+ } catch (err: any) {
25
+ console.error(`Failed: ${err.message}`);
26
+ process.exit(1);
27
+ }
28
+ }
29
+
30
+ export async function readMail(id: string) {
31
+ const config = requireConfig();
32
+
33
+ try {
34
+ const data = await apiRequest(config, "GET", `/api/mail/${id}`);
35
+
36
+ console.log(`From: ${data.from}`);
37
+ console.log(`Subject: ${data.subject}`);
38
+ console.log(`Date: ${data.date}`);
39
+ console.log(`---`);
40
+ console.log(data.body);
41
+ } catch (err: any) {
42
+ console.error(`Failed: ${err.message}`);
43
+ process.exit(1);
44
+ }
45
+ }
46
+
47
+ export async function sendMail(to: string, options: { subject?: string; body?: string }) {
48
+ const config = requireConfig();
49
+
50
+ if (!options.body) {
51
+ console.error("--body is required");
52
+ process.exit(1);
53
+ }
54
+
55
+ try {
56
+ const data = await apiRequest(config, "POST", "/api/mail/send", {
57
+ to,
58
+ subject: options.subject || "(no subject)",
59
+ body: options.body,
60
+ });
61
+
62
+ console.log(data.message);
63
+ } catch (err: any) {
64
+ console.error(`Failed: ${err.message}`);
65
+ process.exit(1);
66
+ }
67
+ }
68
+
69
+ export async function deleteMail(id: string) {
70
+ const config = requireConfig();
71
+
72
+ try {
73
+ const data = await apiRequest(config, "DELETE", `/api/mail/${id}`);
74
+ console.log(data.message);
75
+ } catch (err: any) {
76
+ console.error(`Failed: ${err.message}`);
77
+ process.exit(1);
78
+ }
79
+ }
@@ -0,0 +1,106 @@
1
+ import { apiRequest } from "../api-client.js";
2
+ import { requireConfig } from "../config.js";
3
+
4
+ export async function provisionService(service: string) {
5
+ const config = requireConfig();
6
+
7
+ try {
8
+ const data = await apiRequest(config, "POST", `/api/provision/${service}`);
9
+ console.log(data.message);
10
+ console.log(`\nCheck status: 4ort provision status ${service}`);
11
+ } catch (err: any) {
12
+ console.error(`Failed: ${err.message}`);
13
+ process.exit(1);
14
+ }
15
+ }
16
+
17
+ export async function provisionAll() {
18
+ const config = requireConfig();
19
+
20
+ try {
21
+ const data = await apiRequest(config, "POST", "/api/provision/all");
22
+ console.log(data.message);
23
+ console.log("");
24
+ for (const job of data.jobs) {
25
+ console.log(` ${job.slug}: ${job.status}`);
26
+ }
27
+ console.log(`\nCheck status: 4ort provision status`);
28
+ } catch (err: any) {
29
+ console.error(`Failed: ${err.message}`);
30
+ process.exit(1);
31
+ }
32
+ }
33
+
34
+ export async function provisionStatus(service?: string) {
35
+ const config = requireConfig();
36
+
37
+ try {
38
+ if (service) {
39
+ const data = await apiRequest(config, "GET", `/api/provision/status/${service}`);
40
+ console.log(`${data.service_name} (${data.service_slug})`);
41
+ console.log(` Status: ${data.status}`);
42
+ if (data.error) console.log(` Error: ${data.error}`);
43
+ if (data.started_at) console.log(` Started: ${data.started_at}`);
44
+ if (data.completed_at) console.log(` Completed: ${data.completed_at}`);
45
+ } else {
46
+ const data = await apiRequest(config, "GET", "/api/provision/status");
47
+ if (data.jobs.length === 0) {
48
+ console.log("No provisioning jobs. Run: 4ort provision <service>");
49
+ return;
50
+ }
51
+ console.log("Provisioning jobs:\n");
52
+ for (const job of data.jobs) {
53
+ const icon = job.status === "completed" ? "+" : job.status === "failed" ? "x" : job.status === "running" ? "~" : ".";
54
+ console.log(` [${icon}] ${job.service_name} (${job.service_slug}) — ${job.status}`);
55
+ if (job.error) console.log(` Error: ${job.error}`);
56
+ }
57
+ }
58
+ } catch (err: any) {
59
+ console.error(`Failed: ${err.message}`);
60
+ process.exit(1);
61
+ }
62
+ }
63
+
64
+ export async function provisionCredentials(service?: string) {
65
+ const config = requireConfig();
66
+
67
+ try {
68
+ const path = service ? `/api/provision/credentials/${service}` : "/api/provision/credentials";
69
+ const data = await apiRequest(config, "GET", path);
70
+
71
+ if (data.credentials.length === 0) {
72
+ console.log("No credentials yet. Run: 4ort provision <service>");
73
+ return;
74
+ }
75
+
76
+ console.log("Credentials:\n");
77
+ for (const cred of data.credentials) {
78
+ console.log(` ${cred.service} (${cred.type})`);
79
+ console.log(` ${cred.value}`);
80
+ if (cred.metadata) console.log(` Metadata: ${JSON.stringify(cred.metadata)}`);
81
+ if (cred.expiresAt) console.log(` Expires: ${cred.expiresAt}`);
82
+ console.log("");
83
+ }
84
+ } catch (err: any) {
85
+ console.error(`Failed: ${err.message}`);
86
+ process.exit(1);
87
+ }
88
+ }
89
+
90
+ export async function listServices() {
91
+ const config = requireConfig();
92
+
93
+ try {
94
+ const data = await apiRequest(config, "GET", "/api/provision/services");
95
+
96
+ console.log("Available services:\n");
97
+ for (const s of data.services) {
98
+ const status = s.enabled ? "" : " (disabled)";
99
+ const captcha = s.requires_captcha ? " [captcha]" : "";
100
+ console.log(` [${s.tier.toUpperCase()}] ${s.name} (${s.slug}) — ${s.category}${captcha}${status}`);
101
+ }
102
+ } catch (err: any) {
103
+ console.error(`Failed: ${err.message}`);
104
+ process.exit(1);
105
+ }
106
+ }
@@ -0,0 +1,37 @@
1
+ import { saveConfig } from "../config.js";
2
+
3
+ const DEFAULT_SERVER = "https://4ort.net";
4
+
5
+ export async function recover(name: string, recoveryCode: string, options: { server?: string }) {
6
+ const server = options.server || DEFAULT_SERVER;
7
+
8
+ console.log(`Recovering API key for "${name}"...`);
9
+
10
+ try {
11
+ const res = await fetch(`${server}/api/recover`, {
12
+ method: "POST",
13
+ headers: { "Content-Type": "application/json" },
14
+ body: JSON.stringify({ name, recoveryCode }),
15
+ });
16
+
17
+ const data = await res.json();
18
+
19
+ if (!res.ok) {
20
+ throw new Error(data.error || `HTTP ${res.status}`);
21
+ }
22
+
23
+ saveConfig({
24
+ apiKey: data.apiKey,
25
+ recoveryCode: data.recoveryCode,
26
+ server,
27
+ agentName: data.name,
28
+ });
29
+
30
+ console.log(`\nKey reset! New credentials saved to ~/.4ort/config.json`);
31
+ console.log(`\nNew recovery code: ${data.recoveryCode}`);
32
+ console.log(`(Save this — your old recovery code no longer works)`);
33
+ } catch (err: any) {
34
+ console.error(`Recovery failed: ${err.message}`);
35
+ process.exit(1);
36
+ }
37
+ }
@@ -23,12 +23,15 @@ export async function register(name: string, options: { server?: string; metadat
23
23
 
24
24
  saveConfig({
25
25
  apiKey: result.apiKey,
26
+ recoveryCode: result.recoveryCode,
26
27
  server,
27
28
  agentName: result.name,
28
29
  });
29
30
 
30
31
  console.log(`\nRegistered! Your site will be at: ${result.url}`);
31
- console.log(`API key saved to ~/.4ort/config.json`);
32
+ console.log(`API key and recovery code saved to ~/.4ort/config.json`);
33
+ console.log(`\nRecovery code: ${result.recoveryCode}`);
34
+ console.log(`(Save this somewhere safe — it's the only way to reset your API key)`);
32
35
  console.log(`\nNext: create your site and run: 4ort push .`);
33
36
  } catch (err: any) {
34
37
  console.error(`Registration failed: ${err.message}`);
package/src/config.ts CHANGED
@@ -7,6 +7,7 @@ const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
7
7
 
8
8
  export interface Config {
9
9
  apiKey: string;
10
+ recoveryCode?: string;
10
11
  server: string;
11
12
  agentName: string;
12
13
  }
package/src/index.ts CHANGED
@@ -5,6 +5,9 @@ import { push } from "./commands/push.js";
5
5
  import { list } from "./commands/list.js";
6
6
  import { deleteSite } from "./commands/delete.js";
7
7
  import { whoami } from "./commands/whoami.js";
8
+ import { recover } from "./commands/recover.js";
9
+ import { checkMail, readMail, sendMail, deleteMail } from "./commands/mail.js";
10
+ import { provisionService, provisionAll, provisionStatus, provisionCredentials, listServices } from "./commands/provision.js";
8
11
  import { loadConfig, getConfigPath } from "./config.js";
9
12
 
10
13
  const program = new Command();
@@ -41,6 +44,58 @@ program
41
44
  .description("Show current agent info")
42
45
  .action(whoami);
43
46
 
47
+ const mail = program.command("mail").description("Manage your @4ort.net inbox");
48
+
49
+ mail
50
+ .command("inbox")
51
+ .description("Check your inbox")
52
+ .option("-u, --unread", "Show unread only")
53
+ .action(checkMail);
54
+
55
+ mail
56
+ .command("read <id>")
57
+ .description("Read a message")
58
+ .action(readMail);
59
+
60
+ mail
61
+ .command("send <to>")
62
+ .description("Send a message to another agent")
63
+ .option("-s, --subject <subject>", "Subject line")
64
+ .option("-b, --body <body>", "Message body")
65
+ .action(sendMail);
66
+
67
+ mail
68
+ .command("delete <id>")
69
+ .description("Delete a message")
70
+ .action(deleteMail);
71
+
72
+ const provision = program.command("provision").description("Auto-provision third-party service accounts");
73
+
74
+ provision
75
+ .command("run <service>")
76
+ .description("Provision a specific service")
77
+ .action(provisionService);
78
+
79
+ provision
80
+ .command("all")
81
+ .description("Provision all available Tier A services")
82
+ .action(provisionAll);
83
+
84
+ provision
85
+ .command("status [service]")
86
+ .description("Check provisioning status")
87
+ .action((service?: string) => provisionStatus(service));
88
+
89
+ provision
90
+ .command("credentials [service]")
91
+ .description("Show stored credentials")
92
+ .action((service?: string) => provisionCredentials(service));
93
+
94
+ provision
95
+ .command("services")
96
+ .description("List available services")
97
+ .action(listServices);
98
+
44
99
  program
45
100
  .command("config")
46
101
  .description("Show config location and current settings")