@knowsuchagency/fulcrum 5.5.1 → 5.6.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/bin/fulcrum.js +285 -10
- package/dist/assets/{index-Dqp_1iXi.js → index-D-jR9IJB.js} +139 -139
- package/dist/index.html +1 -1
- package/package.json +1 -1
- package/server/index.js +228 -60
package/bin/fulcrum.js
CHANGED
|
@@ -1136,6 +1136,19 @@ class FulcrumClient {
|
|
|
1136
1136
|
body: JSON.stringify({ title, message })
|
|
1137
1137
|
});
|
|
1138
1138
|
}
|
|
1139
|
+
async getServerExpose() {
|
|
1140
|
+
return this.fetch("/api/server/expose");
|
|
1141
|
+
}
|
|
1142
|
+
async createServerExpose(input) {
|
|
1143
|
+
return this.fetch("/api/server/expose", {
|
|
1144
|
+
method: "POST",
|
|
1145
|
+
body: JSON.stringify(input)
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
async deleteServerExpose(removeTunnel) {
|
|
1149
|
+
const query = removeTunnel ? "?removeTunnel=true" : "";
|
|
1150
|
+
return this.fetch(`/api/server/expose${query}`, { method: "DELETE" });
|
|
1151
|
+
}
|
|
1139
1152
|
async getDeveloperMode() {
|
|
1140
1153
|
return this.fetch("/api/config/developer-mode");
|
|
1141
1154
|
}
|
|
@@ -31923,7 +31936,7 @@ __export(exports_regexes2, {
|
|
|
31923
31936
|
integer: () => integer2,
|
|
31924
31937
|
idnEmail: () => idnEmail,
|
|
31925
31938
|
html5Email: () => html5Email,
|
|
31926
|
-
hostname: () =>
|
|
31939
|
+
hostname: () => hostname2,
|
|
31927
31940
|
hex: () => hex,
|
|
31928
31941
|
guid: () => guid2,
|
|
31929
31942
|
extendedDuration: () => extendedDuration,
|
|
@@ -31975,7 +31988,7 @@ var cuid3, cuid22, ulid2, xid2, ksuid2, nanoid2, duration3, extendedDuration, gu
|
|
|
31975
31988
|
if (!version2)
|
|
31976
31989
|
return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/;
|
|
31977
31990
|
return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version2}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`);
|
|
31978
|
-
}, uuid4, uuid6, uuid7, email2, html5Email, rfc5322Email, unicodeEmail, idnEmail, browserEmail, _emoji3 = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`, ipv42, ipv62, cidrv42, cidrv62, base642, base64url2,
|
|
31991
|
+
}, uuid4, uuid6, uuid7, email2, html5Email, rfc5322Email, unicodeEmail, idnEmail, browserEmail, _emoji3 = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`, ipv42, ipv62, cidrv42, cidrv62, base642, base64url2, hostname2, domain, e1642, dateSource2 = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`, date4, string4 = (params) => {
|
|
31979
31992
|
const regex2 = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`;
|
|
31980
31993
|
return new RegExp(`^${regex2}$`);
|
|
31981
31994
|
}, bigint3, integer2, number4, boolean4, _null4, _undefined3, lowercase2, uppercase2, hex, md5_hex, md5_base64, md5_base64url, sha1_hex, sha1_base64, sha1_base64url, sha256_hex, sha256_base64, sha256_base64url, sha384_hex, sha384_base64, sha384_base64url, sha512_hex, sha512_base64, sha512_base64url;
|
|
@@ -32004,7 +32017,7 @@ var init_regexes2 = __esm(() => {
|
|
|
32004
32017
|
cidrv62 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/;
|
|
32005
32018
|
base642 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/;
|
|
32006
32019
|
base64url2 = /^[A-Za-z0-9_-]*$/;
|
|
32007
|
-
|
|
32020
|
+
hostname2 = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
|
|
32008
32021
|
domain = /^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
32009
32022
|
e1642 = /^\+(?:[0-9]){6,14}[0-9]$/;
|
|
32010
32023
|
date4 = /* @__PURE__ */ new RegExp(`^${dateSource2}$`);
|
|
@@ -33115,7 +33128,7 @@ var init_schemas4 = __esm(() => {
|
|
|
33115
33128
|
code: "invalid_format",
|
|
33116
33129
|
format: "url",
|
|
33117
33130
|
note: "Invalid hostname",
|
|
33118
|
-
pattern:
|
|
33131
|
+
pattern: hostname2.source,
|
|
33119
33132
|
input: payload.value,
|
|
33120
33133
|
inst,
|
|
33121
33134
|
continue: !def.abort
|
|
@@ -42389,7 +42402,7 @@ function jwt(params) {
|
|
|
42389
42402
|
function stringFormat(format, fnOrRegex, _params = {}) {
|
|
42390
42403
|
return _stringFormat2(ZodCustomStringFormat, format, fnOrRegex, _params);
|
|
42391
42404
|
}
|
|
42392
|
-
function
|
|
42405
|
+
function hostname3(_params) {
|
|
42393
42406
|
return _stringFormat2(ZodCustomStringFormat, "hostname", exports_regexes2.hostname, _params);
|
|
42394
42407
|
}
|
|
42395
42408
|
function hex2(_params) {
|
|
@@ -43453,7 +43466,7 @@ __export(exports_external, {
|
|
|
43453
43466
|
instanceof: () => _instanceof,
|
|
43454
43467
|
includes: () => _includes2,
|
|
43455
43468
|
httpUrl: () => httpUrl,
|
|
43456
|
-
hostname: () =>
|
|
43469
|
+
hostname: () => hostname3,
|
|
43457
43470
|
hex: () => hex2,
|
|
43458
43471
|
hash: () => hash,
|
|
43459
43472
|
guid: () => guid3,
|
|
@@ -46838,7 +46851,7 @@ async function runMcpServer(urlOverride, portOverride) {
|
|
|
46838
46851
|
const client = new FulcrumClient(urlOverride, portOverride);
|
|
46839
46852
|
const server = new McpServer({
|
|
46840
46853
|
name: "fulcrum",
|
|
46841
|
-
version: "5.
|
|
46854
|
+
version: "5.6.0"
|
|
46842
46855
|
});
|
|
46843
46856
|
registerTools(server, client);
|
|
46844
46857
|
const transport = new StdioServerTransport;
|
|
@@ -49187,7 +49200,7 @@ var marketplace_default = `{
|
|
|
49187
49200
|
"name": "fulcrum",
|
|
49188
49201
|
"source": "./",
|
|
49189
49202
|
"description": "Task orchestration for Claude Code",
|
|
49190
|
-
"version": "5.
|
|
49203
|
+
"version": "5.6.0",
|
|
49191
49204
|
"skills": [
|
|
49192
49205
|
"./skills/fulcrum"
|
|
49193
49206
|
],
|
|
@@ -49210,7 +49223,7 @@ var marketplace_default = `{
|
|
|
49210
49223
|
var plugin_default = `{
|
|
49211
49224
|
"name": "fulcrum",
|
|
49212
49225
|
"description": "Fulcrum task orchestration for Claude Code",
|
|
49213
|
-
"version": "5.
|
|
49226
|
+
"version": "5.6.0",
|
|
49214
49227
|
"author": {
|
|
49215
49228
|
"name": "Fulcrum"
|
|
49216
49229
|
},
|
|
@@ -50227,7 +50240,7 @@ function compareVersions(v1, v2) {
|
|
|
50227
50240
|
var package_default = {
|
|
50228
50241
|
name: "@knowsuchagency/fulcrum",
|
|
50229
50242
|
private: true,
|
|
50230
|
-
version: "5.
|
|
50243
|
+
version: "5.6.0",
|
|
50231
50244
|
description: "Harness Attention. Orchestrate Agents. Ship.",
|
|
50232
50245
|
license: "PolyForm-Perimeter-1.0.0",
|
|
50233
50246
|
type: "module",
|
|
@@ -50768,6 +50781,267 @@ var downCommand = defineCommand({
|
|
|
50768
50781
|
}
|
|
50769
50782
|
});
|
|
50770
50783
|
|
|
50784
|
+
// cli/src/commands/expose.ts
|
|
50785
|
+
init_client();
|
|
50786
|
+
init_errors();
|
|
50787
|
+
import { execSync as execSync4, spawnSync as spawnSync4 } from "child_process";
|
|
50788
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync6, writeFileSync as writeFileSync5, chmodSync as chmodSync2, unlinkSync as unlinkSync3 } from "fs";
|
|
50789
|
+
import { homedir as homedir4, hostname, platform as platform2 } from "os";
|
|
50790
|
+
import { dirname as dirname5, join as join7 } from "path";
|
|
50791
|
+
var SYSTEMD_SERVICE_TEMPLATE = `[Unit]
|
|
50792
|
+
Description=Fulcrum Cloudflare Tunnel
|
|
50793
|
+
Documentation=https://github.com/knowsuchagency/fulcrum
|
|
50794
|
+
After=network-online.target
|
|
50795
|
+
Wants=network-online.target
|
|
50796
|
+
|
|
50797
|
+
[Service]
|
|
50798
|
+
Type=notify
|
|
50799
|
+
ExecStart=/usr/bin/env cloudflared --no-autoupdate tunnel --token __TUNNEL_TOKEN__ run
|
|
50800
|
+
Restart=on-failure
|
|
50801
|
+
RestartSec=5s
|
|
50802
|
+
TimeoutStopSec=20
|
|
50803
|
+
|
|
50804
|
+
[Install]
|
|
50805
|
+
WantedBy=default.target
|
|
50806
|
+
`;
|
|
50807
|
+
var LAUNCHD_PLIST_TEMPLATE = `<?xml version="1.0" encoding="UTF-8"?>
|
|
50808
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
50809
|
+
<plist version="1.0">
|
|
50810
|
+
<dict>
|
|
50811
|
+
<key>Label</key>
|
|
50812
|
+
<string>com.fulcrum.tunnel</string>
|
|
50813
|
+
<key>ProgramArguments</key>
|
|
50814
|
+
<array>
|
|
50815
|
+
<string>__CLOUDFLARED_PATH__</string>
|
|
50816
|
+
<string>--no-autoupdate</string>
|
|
50817
|
+
<string>tunnel</string>
|
|
50818
|
+
<string>--token</string>
|
|
50819
|
+
<string>__TUNNEL_TOKEN__</string>
|
|
50820
|
+
<string>run</string>
|
|
50821
|
+
</array>
|
|
50822
|
+
<key>RunAtLoad</key>
|
|
50823
|
+
<true/>
|
|
50824
|
+
<key>KeepAlive</key>
|
|
50825
|
+
<true/>
|
|
50826
|
+
<key>StandardErrorPath</key>
|
|
50827
|
+
<string>__LOG_PATH__</string>
|
|
50828
|
+
<key>StandardOutPath</key>
|
|
50829
|
+
<string>__LOG_PATH__</string>
|
|
50830
|
+
</dict>
|
|
50831
|
+
</plist>
|
|
50832
|
+
`;
|
|
50833
|
+
function isCloudflaredInstalled() {
|
|
50834
|
+
try {
|
|
50835
|
+
execSync4("which cloudflared", { stdio: "ignore" });
|
|
50836
|
+
return true;
|
|
50837
|
+
} catch {
|
|
50838
|
+
return false;
|
|
50839
|
+
}
|
|
50840
|
+
}
|
|
50841
|
+
function whichCloudflared() {
|
|
50842
|
+
return execSync4("which cloudflared", { encoding: "utf-8" }).trim();
|
|
50843
|
+
}
|
|
50844
|
+
var LINUX_SERVICE_NAME = "fulcrum-tunnel";
|
|
50845
|
+
var MACOS_LABEL = "com.fulcrum.tunnel";
|
|
50846
|
+
function linuxUnitPath() {
|
|
50847
|
+
return join7(homedir4(), ".config", "systemd", "user", `${LINUX_SERVICE_NAME}.service`);
|
|
50848
|
+
}
|
|
50849
|
+
function macosPlistPath() {
|
|
50850
|
+
return join7(homedir4(), "Library", "LaunchAgents", `${MACOS_LABEL}.plist`);
|
|
50851
|
+
}
|
|
50852
|
+
function macosLogPath() {
|
|
50853
|
+
return join7(homedir4(), "Library", "Logs", "fulcrum-tunnel.log");
|
|
50854
|
+
}
|
|
50855
|
+
function installService(tunnelToken) {
|
|
50856
|
+
if (platform2() === "darwin") {
|
|
50857
|
+
const cloudflaredPath = whichCloudflared();
|
|
50858
|
+
const plist = LAUNCHD_PLIST_TEMPLATE.replace("__CLOUDFLARED_PATH__", cloudflaredPath).replace("__TUNNEL_TOKEN__", tunnelToken).replace(/__LOG_PATH__/g, macosLogPath());
|
|
50859
|
+
const dest2 = macosPlistPath();
|
|
50860
|
+
mkdirSync6(dirname5(dest2), { recursive: true });
|
|
50861
|
+
writeFileSync5(dest2, plist, "utf-8");
|
|
50862
|
+
chmodSync2(dest2, 420);
|
|
50863
|
+
spawnSync4("launchctl", ["unload", dest2], { stdio: "ignore" });
|
|
50864
|
+
const load = spawnSync4("launchctl", ["load", dest2], { stdio: "inherit" });
|
|
50865
|
+
if (load.status !== 0) {
|
|
50866
|
+
throw new CliError("LAUNCHCTL_LOAD_FAILED", "launchctl load failed", ExitCodes.ERROR);
|
|
50867
|
+
}
|
|
50868
|
+
return { path: dest2, how: "launchd" };
|
|
50869
|
+
}
|
|
50870
|
+
const unit = SYSTEMD_SERVICE_TEMPLATE.replace("__TUNNEL_TOKEN__", tunnelToken);
|
|
50871
|
+
const dest = linuxUnitPath();
|
|
50872
|
+
mkdirSync6(dirname5(dest), { recursive: true });
|
|
50873
|
+
writeFileSync5(dest, unit, "utf-8");
|
|
50874
|
+
chmodSync2(dest, 420);
|
|
50875
|
+
for (const args of [
|
|
50876
|
+
["--user", "daemon-reload"],
|
|
50877
|
+
["--user", "enable", LINUX_SERVICE_NAME],
|
|
50878
|
+
["--user", "restart", LINUX_SERVICE_NAME]
|
|
50879
|
+
]) {
|
|
50880
|
+
const r3 = spawnSync4("systemctl", args, { stdio: "inherit" });
|
|
50881
|
+
if (r3.status !== 0) {
|
|
50882
|
+
throw new CliError("SYSTEMCTL_FAILED", `systemctl ${args.join(" ")} failed (exit ${r3.status})`, ExitCodes.ERROR);
|
|
50883
|
+
}
|
|
50884
|
+
}
|
|
50885
|
+
return { path: dest, how: "systemd" };
|
|
50886
|
+
}
|
|
50887
|
+
function uninstallService() {
|
|
50888
|
+
if (platform2() === "darwin") {
|
|
50889
|
+
const dest2 = macosPlistPath();
|
|
50890
|
+
if (!existsSync7(dest2))
|
|
50891
|
+
return { stopped: false, removed: false };
|
|
50892
|
+
spawnSync4("launchctl", ["unload", dest2], { stdio: "ignore" });
|
|
50893
|
+
unlinkSync3(dest2);
|
|
50894
|
+
return { stopped: true, removed: true };
|
|
50895
|
+
}
|
|
50896
|
+
const dest = linuxUnitPath();
|
|
50897
|
+
if (!existsSync7(dest))
|
|
50898
|
+
return { stopped: false, removed: false };
|
|
50899
|
+
spawnSync4("systemctl", ["--user", "stop", LINUX_SERVICE_NAME], { stdio: "ignore" });
|
|
50900
|
+
spawnSync4("systemctl", ["--user", "disable", LINUX_SERVICE_NAME], { stdio: "ignore" });
|
|
50901
|
+
unlinkSync3(dest);
|
|
50902
|
+
spawnSync4("systemctl", ["--user", "daemon-reload"], { stdio: "ignore" });
|
|
50903
|
+
return { stopped: true, removed: true };
|
|
50904
|
+
}
|
|
50905
|
+
function serviceStatus() {
|
|
50906
|
+
if (platform2() === "darwin") {
|
|
50907
|
+
const r4 = spawnSync4("launchctl", ["list", MACOS_LABEL], { encoding: "utf-8" });
|
|
50908
|
+
if (r4.status === 0) {
|
|
50909
|
+
const match = r4.stdout.match(/"PID"\s*=\s*(\d+);/);
|
|
50910
|
+
return match ? `running (pid ${match[1]})` : "loaded";
|
|
50911
|
+
}
|
|
50912
|
+
return "not loaded";
|
|
50913
|
+
}
|
|
50914
|
+
const r3 = spawnSync4("systemctl", ["--user", "is-active", LINUX_SERVICE_NAME], { encoding: "utf-8" });
|
|
50915
|
+
return (r3.stdout || r3.stderr).trim() || "unknown";
|
|
50916
|
+
}
|
|
50917
|
+
async function handleExpose(args) {
|
|
50918
|
+
const { positional, flags } = args;
|
|
50919
|
+
const subdomain = positional[0]?.trim() || hostname().split(".")[0];
|
|
50920
|
+
const domain = flags.domain?.trim();
|
|
50921
|
+
if (!domain) {
|
|
50922
|
+
throw new CliError("MISSING_DOMAIN", "Required: --domain <zone> (e.g. --domain fulcrum.example.com)", ExitCodes.INVALID_ARGS);
|
|
50923
|
+
}
|
|
50924
|
+
const skipService = flags["no-service"] === "true";
|
|
50925
|
+
const autoYes = flags.yes === "true" || flags.y === "true";
|
|
50926
|
+
if (!skipService && !isCloudflaredInstalled()) {
|
|
50927
|
+
console.error("cloudflared is not installed.");
|
|
50928
|
+
console.error("Install it from https://github.com/cloudflare/cloudflared/releases or via your package manager.");
|
|
50929
|
+
if (!autoYes) {
|
|
50930
|
+
const proceed = await confirm("Continue without installing the system service? (the tunnel will be created but not running)");
|
|
50931
|
+
if (!proceed)
|
|
50932
|
+
throw new CliError("CLOUDFLARED_MISSING", "cloudflared required to start tunnel", ExitCodes.ERROR);
|
|
50933
|
+
}
|
|
50934
|
+
}
|
|
50935
|
+
const client = new FulcrumClient(flags.url, flags.port);
|
|
50936
|
+
const result = await client.createServerExpose({ subdomain, domain });
|
|
50937
|
+
console.error(`Tunnel ready: ${result.publicDomain} (${result.reusedExisting ? "reused" : "created"})`);
|
|
50938
|
+
console.error(`Tunnel ID: ${result.tunnelId}`);
|
|
50939
|
+
let serviceInfo = null;
|
|
50940
|
+
if (skipService) {
|
|
50941
|
+
console.error("Skipping system service installation (--no-service).");
|
|
50942
|
+
} else if (!result.tunnelToken) {
|
|
50943
|
+
console.error("Existing tunnel reused; the tunnel token was not returned by Cloudflare.");
|
|
50944
|
+
console.error("Keep the existing system service running, or rotate the token via the Cloudflare dashboard.");
|
|
50945
|
+
} else if (!isCloudflaredInstalled()) {
|
|
50946
|
+
console.error("Skipping service install: cloudflared not on PATH.");
|
|
50947
|
+
} else {
|
|
50948
|
+
const installed = installService(result.tunnelToken);
|
|
50949
|
+
serviceInfo = { path: installed.path, how: installed.how };
|
|
50950
|
+
console.error(`Installed and started ${installed.how} service: ${installed.path}`);
|
|
50951
|
+
}
|
|
50952
|
+
console.error("");
|
|
50953
|
+
console.error("Next steps:");
|
|
50954
|
+
console.error(` 1. Visit ${result.accessSetupUrl} and create a Cloudflare Access policy for *.${domain}.`);
|
|
50955
|
+
console.error(` 2. Open https://${result.publicDomain} in your browser.`);
|
|
50956
|
+
if (isJsonOutput()) {
|
|
50957
|
+
output({
|
|
50958
|
+
publicDomain: result.publicDomain,
|
|
50959
|
+
tunnelId: result.tunnelId,
|
|
50960
|
+
reusedExisting: result.reusedExisting,
|
|
50961
|
+
service: serviceInfo
|
|
50962
|
+
});
|
|
50963
|
+
}
|
|
50964
|
+
}
|
|
50965
|
+
async function handleStatus(flags) {
|
|
50966
|
+
const client = new FulcrumClient(flags.url, flags.port);
|
|
50967
|
+
const status = await client.getServerExpose();
|
|
50968
|
+
const svc = serviceStatus();
|
|
50969
|
+
if (isJsonOutput()) {
|
|
50970
|
+
output({ ...status, serviceStatus: svc });
|
|
50971
|
+
return;
|
|
50972
|
+
}
|
|
50973
|
+
console.log(`Public domain: ${status.publicDomain ?? "(not set)"}`);
|
|
50974
|
+
console.log(`Tailscale hostname: ${status.tailscaleHostname ?? "(not set)"}`);
|
|
50975
|
+
console.log(`Detected tailnet: ${status.detectedTailscaleHostname ?? "(not detected)"}`);
|
|
50976
|
+
console.log(`Cloudflare ready: ${status.tunnelAvailable ? "yes" : "no"}`);
|
|
50977
|
+
console.log(`Tunnel ID: ${status.tunnelId ?? "(none)"}`);
|
|
50978
|
+
console.log(`Tunnel status: ${status.tunnelStatus ?? "(unknown)"}`);
|
|
50979
|
+
console.log(`Local service: ${svc}`);
|
|
50980
|
+
}
|
|
50981
|
+
async function handleDown(flags) {
|
|
50982
|
+
const removeTunnel = flags["remove-tunnel"] === "true";
|
|
50983
|
+
const autoYes = flags.yes === "true" || flags.y === "true";
|
|
50984
|
+
if (removeTunnel && !autoYes) {
|
|
50985
|
+
const ok = await confirm("Permanently delete the Cloudflare Tunnel from your account?");
|
|
50986
|
+
if (!ok) {
|
|
50987
|
+
console.error("Aborted.");
|
|
50988
|
+
return;
|
|
50989
|
+
}
|
|
50990
|
+
}
|
|
50991
|
+
const svc = uninstallService();
|
|
50992
|
+
if (svc.removed) {
|
|
50993
|
+
console.error("Stopped and removed the local cloudflared service.");
|
|
50994
|
+
}
|
|
50995
|
+
const client = new FulcrumClient(flags.url, flags.port);
|
|
50996
|
+
const result = await client.deleteServerExpose(removeTunnel);
|
|
50997
|
+
if (result.tunnelDeleted)
|
|
50998
|
+
console.error("Deleted the Cloudflare Tunnel from your account.");
|
|
50999
|
+
console.error("Cleared server.publicDomain.");
|
|
51000
|
+
if (isJsonOutput()) {
|
|
51001
|
+
output({ success: true, serviceRemoved: svc.removed, tunnelDeleted: !!result.tunnelDeleted });
|
|
51002
|
+
}
|
|
51003
|
+
}
|
|
51004
|
+
var exposeCommand = defineCommand({
|
|
51005
|
+
meta: {
|
|
51006
|
+
name: "expose",
|
|
51007
|
+
description: "Expose this Fulcrum server publicly via a Cloudflare Tunnel"
|
|
51008
|
+
},
|
|
51009
|
+
args: {
|
|
51010
|
+
...globalArgs,
|
|
51011
|
+
domain: { type: "string", description: "Cloudflare zone for the public hostname (e.g. fulcrum.example.com)" },
|
|
51012
|
+
"no-service": { type: "boolean", description: "Create the tunnel but do not install/start the system service" },
|
|
51013
|
+
"remove-tunnel": { type: "boolean", description: "For `down`: also delete the tunnel from Cloudflare" },
|
|
51014
|
+
yes: { type: "boolean", alias: "y", description: "Auto-answer yes to prompts" }
|
|
51015
|
+
},
|
|
51016
|
+
subCommands: {
|
|
51017
|
+
status: defineCommand({
|
|
51018
|
+
meta: { name: "status", description: "Show current expose state and service status" },
|
|
51019
|
+
args: { ...globalArgs },
|
|
51020
|
+
async run({ args }) {
|
|
51021
|
+
setupJsonOutput(args);
|
|
51022
|
+
await handleStatus(toFlags(args));
|
|
51023
|
+
}
|
|
51024
|
+
}),
|
|
51025
|
+
down: defineCommand({
|
|
51026
|
+
meta: { name: "down", description: "Stop the local tunnel service and clear publicDomain" },
|
|
51027
|
+
args: {
|
|
51028
|
+
...globalArgs,
|
|
51029
|
+
"remove-tunnel": { type: "boolean", description: "Also delete the tunnel from Cloudflare" },
|
|
51030
|
+
yes: { type: "boolean", alias: "y", description: "Auto-answer yes to prompts" }
|
|
51031
|
+
},
|
|
51032
|
+
async run({ args }) {
|
|
51033
|
+
setupJsonOutput(args);
|
|
51034
|
+
await handleDown(toFlags(args));
|
|
51035
|
+
}
|
|
51036
|
+
})
|
|
51037
|
+
},
|
|
51038
|
+
async run({ args, rawArgs }) {
|
|
51039
|
+
setupJsonOutput(args);
|
|
51040
|
+
const positional = args._ ?? rawArgs.filter((a2) => !a2.startsWith("-"));
|
|
51041
|
+
await handleExpose({ positional, flags: toFlags(args) });
|
|
51042
|
+
}
|
|
51043
|
+
});
|
|
51044
|
+
|
|
50771
51045
|
// cli/src/commands/status.ts
|
|
50772
51046
|
init_server();
|
|
50773
51047
|
async function handleStatusCommand(flags) {
|
|
@@ -51071,6 +51345,7 @@ var main = defineCommand({
|
|
|
51071
51345
|
notify: notifyCommand,
|
|
51072
51346
|
up: upCommand,
|
|
51073
51347
|
down: downCommand,
|
|
51348
|
+
expose: exposeCommand,
|
|
51074
51349
|
status: statusCommand,
|
|
51075
51350
|
doctor: doctorCommand,
|
|
51076
51351
|
dev: devCommand,
|