flyspace-cli 0.1.29 → 0.1.30

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.
Files changed (2) hide show
  1. package/dist/cli.js +80 -40
  2. package/package.json +7 -2
package/dist/cli.js CHANGED
@@ -1835,7 +1835,7 @@ async function runAuthCmd(args) {
1835
1835
  }
1836
1836
 
1837
1837
  // ../api/src/version.ts
1838
- var CLI_VERSION = true ? "0.1.29" : null;
1838
+ var CLI_VERSION = true ? "0.1.30" : null;
1839
1839
  function isOlderVersion(a, b) {
1840
1840
  const parse = (v) => v.replace(/^v/, "").split("-")[0].split(".").map(Number);
1841
1841
  const [pa, pb] = [parse(a), parse(b)];
@@ -2108,11 +2108,11 @@ async function serverReachable() {
2108
2108
  return err.cause ? String(err.cause) : err.message;
2109
2109
  }
2110
2110
  }
2111
- function checkService(name, installed, file, running, fix) {
2111
+ function checkService(name, installed, file, running2, fix) {
2112
2112
  if (!installed) bad2(`${name} not installed`, `run: ${fix}`);
2113
2113
  else if (serviceBinaryMissing(file))
2114
2114
  bad2(`${name} points at a CLI that no longer exists`, `run: ${fix}`);
2115
- else if (!running) bad2(`${name} not running`, `logs: ${tilde3(paths.LOG_DIR)}`);
2115
+ else if (!running2) bad2(`${name} not running`, `logs: ${tilde3(paths.LOG_DIR)}`);
2116
2116
  else ok2(`${name} running`);
2117
2117
  }
2118
2118
  async function runDoctor(args) {
@@ -2418,7 +2418,7 @@ function npmEnv() {
2418
2418
  return home2 ? { ...process.env, PATH: `${join11(home2, "node", "bin")}:${process.env.PATH ?? ""}` } : process.env;
2419
2419
  }
2420
2420
  async function runUpgrade() {
2421
- const current = "0.1.29";
2421
+ const current = "0.1.30";
2422
2422
  console.log(`Current version: ${current}`);
2423
2423
  console.log("Checking for updates...\n");
2424
2424
  try {
@@ -6348,10 +6348,10 @@ async function runMcpCmd(args) {
6348
6348
  }
6349
6349
 
6350
6350
  // src/commands/dashboard.ts
6351
- import { spawn as spawn7, spawnSync } from "child_process";
6351
+ import { spawn as spawn8, spawnSync } from "child_process";
6352
6352
  import { existsSync as existsSync32 } from "fs";
6353
6353
  import { platform as platform7 } from "os";
6354
- import { join as join28 } from "path";
6354
+ import { join as join29 } from "path";
6355
6355
 
6356
6356
  // src/reconcile.ts
6357
6357
  import { existsSync as existsSync14, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
@@ -7398,8 +7398,8 @@ var inFlight = /* @__PURE__ */ new Map();
7398
7398
  async function readOrCreateTranslation(input2) {
7399
7399
  const contentHash = translationHash(input2.title, input2.content);
7400
7400
  const key = `${input2.shareId}:${contentHash}:${input2.lang}`;
7401
- const running = inFlight.get(key);
7402
- if (running) return running;
7401
+ const running2 = inFlight.get(key);
7402
+ if (running2) return running2;
7403
7403
  const job = (async () => {
7404
7404
  const cached = await getDocShareTranslation(input2.shareId, input2.lang, contentHash);
7405
7405
  if (cached) return cached;
@@ -8805,6 +8805,9 @@ async function verifyTurnstileToken(token) {
8805
8805
  return data.action === void 0 || data.action === "login";
8806
8806
  }
8807
8807
 
8808
+ // ../api/src/dashboard/onboarding-routes.ts
8809
+ import { Hono as Hono7 } from "hono";
8810
+
8808
8811
  // ../api/src/store/device-store.ts
8809
8812
  import { createHash as createHash7, createPublicKey as createPublicKey2, randomBytes as randomBytes4, randomInt } from "crypto";
8810
8813
  var DEVICE_CODE_TTL_MS = 10 * 6e4;
@@ -9031,9 +9034,6 @@ async function userEmail(userId) {
9031
9034
  return data.user?.email ?? null;
9032
9035
  }
9033
9036
 
9034
- // ../api/src/dashboard/onboarding-routes.ts
9035
- import { Hono as Hono7 } from "hono";
9036
-
9037
9037
  // ../api/src/dashboard/agent-bridge-data.ts
9038
9038
  import { randomBytes as randomBytes5, randomUUID as randomUUID2, verify as verifyRaw } from "crypto";
9039
9039
  import { WebSocket, WebSocketServer } from "ws";
@@ -9207,6 +9207,11 @@ var CHANNEL_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
9207
9207
  function isWorkspaceOwner(ctx) {
9208
9208
  return ctx?.role === "admin" && !ctx.isSupport;
9209
9209
  }
9210
+ async function isHostOwner(ctx) {
9211
+ if (ctx.role !== "admin") return false;
9212
+ if (ctx.isSupport) return true;
9213
+ return (await listWorkspaceDevices(ctx.workspaceId)).some((d) => d.userId === ctx.userId);
9214
+ }
9210
9215
  function hostUnavailable(c, agent, method) {
9211
9216
  return c.json({ error: "host offline", reason: agent.getHostCallFailure?.(method) ?? "offline" }, 503);
9212
9217
  }
@@ -9389,7 +9394,7 @@ function createAuthRouter() {
9389
9394
  owner: isWorkspaceOwner(ctx),
9390
9395
  // Only the Host's owner can run `flyspace upgrade` on it, so other
9391
9396
  // admins never see the upgrade banner. Support staff can tell them to.
9392
- hostOwner: ctx.role === "admin" && (ctx.isSupport === true || (await listWorkspaceDevices(ctx.workspaceId)).some((d) => d.userId === ctx.userId))
9397
+ hostOwner: await isHostOwner(ctx)
9393
9398
  });
9394
9399
  });
9395
9400
  auth.patch("/handle", async (c) => {
@@ -10057,8 +10062,8 @@ async function translateThread(threadId, lang, messages) {
10057
10062
  if (messages.length === 0) return [];
10058
10063
  const shape = createHash8("sha256").update(messages.map((m) => translationHash2(m.author, m.body)).join("\n")).digest("hex");
10059
10064
  const key = `${threadId}:${lang}:${shape}`;
10060
- const running = inFlight4.get(key);
10061
- if (running) return running;
10065
+ const running2 = inFlight4.get(key);
10066
+ if (running2) return running2;
10062
10067
  const job = (async () => {
10063
10068
  const hashes = messages.map((m) => ({
10064
10069
  replyId: m.id,
@@ -13701,6 +13706,7 @@ async function resolveThreadLinks(sessions2) {
13701
13706
  }
13702
13707
 
13703
13708
  // ../api/src/dashboard/data-api.ts
13709
+ var SELF_UPGRADE_MIN_VERSION = "0.1.30";
13704
13710
  function registerDataRoutes(api, agent = {}) {
13705
13711
  api.get("/profile", (c) => c.json({ profile: getProfile() }));
13706
13712
  api.get("/host/status", async (c) => {
@@ -13714,7 +13720,20 @@ function registerDataRoutes(api, agent = {}) {
13714
13720
  const cliVersion = agent.getHostCliVersion?.(getProfile()) ?? null;
13715
13721
  const latest2 = cliVersion ? await latestCliVersion() : null;
13716
13722
  const outdated = !!(cliVersion && latest2 && isOlderVersion(cliVersion, latest2));
13717
- return c.json({ online: !paused, cliVersion, ...outdated ? { latestCliVersion: latest2 } : {} });
13723
+ const selfUpgrade = !!cliVersion && !isOlderVersion(cliVersion, SELF_UPGRADE_MIN_VERSION);
13724
+ return c.json({
13725
+ online: !paused,
13726
+ cliVersion,
13727
+ selfUpgrade,
13728
+ ...outdated ? { latestCliVersion: latest2 } : {}
13729
+ });
13730
+ });
13731
+ api.post("/host/upgrade", async (c) => {
13732
+ const auth = c.get("auth");
13733
+ if (!await isHostOwner(auth)) return c.json({ error: "only the Host owner can upgrade it" }, 403);
13734
+ const res = await agent.upgradeHost?.();
13735
+ if (!res) return c.json({ error: "Host is offline" }, 503);
13736
+ return c.json(res, 202);
13718
13737
  });
13719
13738
  api.get("/channels", async (c) => {
13720
13739
  const auth = c.get("auth");
@@ -13902,9 +13921,9 @@ function registerDataRoutes(api, agent = {}) {
13902
13921
  void broadcastHostStatusChange();
13903
13922
  let cancelled = 0;
13904
13923
  if (body.paused) {
13905
- const running = await agent.listAgentRuns?.() ?? [];
13906
- if (running.length > 0) {
13907
- const { data } = await getSupabaseClient().from("threads").select("id, channel_id").in("id", running);
13924
+ const running2 = await agent.listAgentRuns?.() ?? [];
13925
+ if (running2.length > 0) {
13926
+ const { data } = await getSupabaseClient().from("threads").select("id, channel_id").in("id", running2);
13908
13927
  const profile = getProfile();
13909
13928
  for (const t of data ?? []) {
13910
13929
  if (findOwningProfile(t.channel_id) !== profile) continue;
@@ -13922,7 +13941,7 @@ function registerDataRoutes(api, agent = {}) {
13922
13941
  const host = trustedHost(c);
13923
13942
  const known = await listKnownWorkspaces();
13924
13943
  const hostProfile = profileFromHost(host, known);
13925
- const running = new Set(await agent.listRunningProfiles?.() ?? []);
13944
+ const running2 = new Set(await agent.listRunningProfiles?.() ?? []);
13926
13945
  const auth = c.get("auth");
13927
13946
  const [{ data: memberships }, workspaces] = await Promise.all([
13928
13947
  getSupabaseClient().from("memberships").select("workspace_id").eq("user_id", auth.userId),
@@ -13939,7 +13958,7 @@ function registerDataRoutes(api, agent = {}) {
13939
13958
  return {
13940
13959
  name,
13941
13960
  active: name === active,
13942
- running: running.has(name),
13961
+ running: running2.has(name),
13943
13962
  displayName: branding.displayName,
13944
13963
  logo: branding.logo,
13945
13964
  hostname: (hostProfile ? workspaceHostname(host, name) : null) ?? void 0
@@ -14313,16 +14332,16 @@ function installSkillSync(profiles, options = {}) {
14313
14332
  if (!databaseReachable()) return () => {
14314
14333
  };
14315
14334
  const { intervalMs = SYNC_INTERVAL_MS, onError = (e) => console.error("[skill-sync]", e) } = options;
14316
- let running = false;
14335
+ let running2 = false;
14317
14336
  const tick = async () => {
14318
- if (running) return;
14319
- running = true;
14337
+ if (running2) return;
14338
+ running2 = true;
14320
14339
  try {
14321
14340
  for (const profile of profiles) {
14322
14341
  await runWithProfile(profile, () => pushSkillScopes()).catch(onError);
14323
14342
  }
14324
14343
  } finally {
14325
- running = false;
14344
+ running2 = false;
14326
14345
  }
14327
14346
  };
14328
14347
  void tick();
@@ -14874,8 +14893,8 @@ var inFlight5 = /* @__PURE__ */ new Map();
14874
14893
  async function readOrCreateDocTranslation(input2) {
14875
14894
  const contentHash = translationHash(input2.title, input2.content);
14876
14895
  const key = `${input2.channelId}:${input2.sourcePath}:${contentHash}:${input2.lang}`;
14877
- const running = inFlight5.get(key);
14878
- if (running) return running;
14896
+ const running2 = inFlight5.get(key);
14897
+ if (running2) return running2;
14879
14898
  const job = (async () => {
14880
14899
  const cached = await getDocTranslation(input2.channelId, input2.sourcePath, input2.lang, contentHash);
14881
14900
  if (cached) return cached;
@@ -18832,6 +18851,26 @@ function readDocShareBundle({ cwd, sourcePath }) {
18832
18851
  return { status: "ok", kind, title, content: content + renderAttachments(attachments), assets };
18833
18852
  }
18834
18853
 
18854
+ // src/dashboard/host-upgrade.ts
18855
+ import { spawn as spawn7 } from "child_process";
18856
+ import { mkdirSync as mkdirSync13, openSync as openSync3 } from "fs";
18857
+ import { join as join27 } from "path";
18858
+ var running = false;
18859
+ function startHostUpgrade() {
18860
+ if (running) return { started: false };
18861
+ mkdirSync13(paths.LOG_DIR, { recursive: true });
18862
+ const log5 = openSync3(join27(paths.LOG_DIR, "host-upgrade.log"), "a");
18863
+ const child = spawn7(process.execPath, [process.argv[1] ?? "", "upgrade"], {
18864
+ detached: true,
18865
+ stdio: ["ignore", log5, log5]
18866
+ });
18867
+ running = true;
18868
+ child.on("exit", () => running = false);
18869
+ child.on("error", () => running = false);
18870
+ child.unref();
18871
+ return { started: true };
18872
+ }
18873
+
18835
18874
  // src/dashboard/agent-bridge-host.ts
18836
18875
  var HOSTED_DATA_SOCKET_ORIGIN = "wss://flyspace-api.fly.dev";
18837
18876
  function dataSocketUrl() {
@@ -18872,6 +18911,7 @@ function localAgentCallbacks(chatAgent) {
18872
18911
  docsRequest: (req) => handleDocsRequest(req),
18873
18912
  hostRequest: (req) => handleHostRequest(req),
18874
18913
  listSessions: () => listLocalSessions(),
18914
+ upgradeHost: () => startHostUpgrade(),
18875
18915
  scanOnboarding: (slug) => scanOnboarding(slug),
18876
18916
  linkProjectFolders: (slug, items) => linkProjectFolders(slug, items),
18877
18917
  isHostOnline: () => true
@@ -19129,7 +19169,7 @@ function startPushWatcher() {
19129
19169
 
19130
19170
  // src/dashboard/machine-server.ts
19131
19171
  import { existsSync as existsSync31 } from "fs";
19132
- import { join as join27 } from "path";
19172
+ import { join as join28 } from "path";
19133
19173
  import { serveStatic } from "@hono/node-server/serve-static";
19134
19174
 
19135
19175
  // src/dashboard/app-icon-routes.ts
@@ -19211,7 +19251,7 @@ function pngResponse(c, png) {
19211
19251
  }
19212
19252
 
19213
19253
  // src/dashboard/machine-server.ts
19214
- var WEB_DIST = join27(paths.WEB_ROOT, "dist");
19254
+ var WEB_DIST = join28(paths.WEB_ROOT, "dist");
19215
19255
  async function bootMachine() {
19216
19256
  await reconcileAll().catch(
19217
19257
  (err) => console.error("[dashboard] reconcileAll failed:", err.message)
@@ -19231,14 +19271,14 @@ async function bootMachine() {
19231
19271
  function mountSpa(app) {
19232
19272
  app.route("/share", createPublicShareAssetRouter(WEB_DIST));
19233
19273
  app.route("/", createAppIconRouter());
19234
- if (existsSync31(WEB_DIST) || existsSync31(join27(paths.WEB_ROOT, "package.json"))) {
19274
+ if (existsSync31(WEB_DIST) || existsSync31(join28(paths.WEB_ROOT, "package.json"))) {
19235
19275
  app.use("/*", serveStatic({ root: WEB_DIST }));
19236
19276
  }
19237
19277
  app.get("/assets/*", (c) => c.text("stale asset \u2014 reload for the current build", 404));
19238
- const spaFallback = serveStatic({ path: join27(WEB_DIST, "index.html") });
19278
+ const spaFallback = serveStatic({ path: join28(WEB_DIST, "index.html") });
19239
19279
  app.get("*", async (c, next) => {
19240
- if (!existsSync31(join27(WEB_DIST, "index.html"))) {
19241
- const isCheckout = existsSync31(join27(paths.WEB_ROOT, "package.json"));
19280
+ if (!existsSync31(join28(WEB_DIST, "index.html"))) {
19281
+ const isCheckout = existsSync31(join28(paths.WEB_ROOT, "package.json"));
19242
19282
  return c.text(
19243
19283
  isCheckout ? `Workspace UI build missing (${WEB_DIST}).
19244
19284
  Run \`pnpm build:web\` from the repo root.
@@ -19367,13 +19407,13 @@ function flagValue(args, name) {
19367
19407
  function openBrowser2(url) {
19368
19408
  const cmd = platform7() === "darwin" ? "open" : platform7() === "win32" ? "start" : "xdg-open";
19369
19409
  try {
19370
- spawn7(cmd, [url], { stdio: "ignore", detached: true }).unref();
19410
+ spawn8(cmd, [url], { stdio: "ignore", detached: true }).unref();
19371
19411
  } catch {
19372
19412
  }
19373
19413
  }
19374
19414
  function ensureWebBuild() {
19375
- if (existsSync32(join28(paths.WEB_ROOT, "dist", "index.html"))) return;
19376
- if (!existsSync32(join28(paths.WEB_ROOT, "package.json"))) return;
19415
+ if (existsSync32(join29(paths.WEB_ROOT, "dist", "index.html"))) return;
19416
+ if (!existsSync32(join29(paths.WEB_ROOT, "package.json"))) return;
19377
19417
  console.log(" packages/ui/dist missing, building the dashboard UI...");
19378
19418
  const result = spawnSync("pnpm", ["build"], {
19379
19419
  cwd: paths.WEB_ROOT,
@@ -19423,7 +19463,7 @@ async function runDashboard(args) {
19423
19463
  }
19424
19464
 
19425
19465
  // src/commands/workspace.ts
19426
- import { existsSync as existsSync33, mkdirSync as mkdirSync13, writeFileSync as writeFileSync13 } from "fs";
19466
+ import { existsSync as existsSync33, mkdirSync as mkdirSync14, writeFileSync as writeFileSync13 } from "fs";
19427
19467
  var USAGE7 = `
19428
19468
  Usage: flyspace workspace <subcommand> [options]
19429
19469
 
@@ -19527,7 +19567,7 @@ async function provisionChannels(specs) {
19527
19567
  }
19528
19568
  const cwd = expandPath(spec.cwd);
19529
19569
  if (!existsSync33(cwd)) {
19530
- mkdirSync13(cwd, { recursive: true });
19570
+ mkdirSync14(cwd, { recursive: true });
19531
19571
  console.log(` created cwd ${cwd}`);
19532
19572
  }
19533
19573
  await createChannel({ name: spec.name, cwd, position: index });
@@ -19604,10 +19644,10 @@ async function runReconcileCmd(args) {
19604
19644
  }
19605
19645
 
19606
19646
  // src/cli.ts
19607
- import { join as join29 } from "path";
19647
+ import { join as join30 } from "path";
19608
19648
  var home = flyspaceHome();
19609
19649
  if (home) {
19610
- const bin = join29(home, "bin");
19650
+ const bin = join30(home, "bin");
19611
19651
  const path = process.env.PATH ?? "";
19612
19652
  if (!path.split(":").includes(bin)) process.env.PATH = path ? `${bin}:${path}` : bin;
19613
19653
  }
@@ -19745,7 +19785,7 @@ async function main() {
19745
19785
  break;
19746
19786
  case "-v":
19747
19787
  case "--version":
19748
- printRaw("0.1.29");
19788
+ printRaw("0.1.30");
19749
19789
  break;
19750
19790
  case "-h":
19751
19791
  case "--help":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flyspace-cli",
3
- "version": "0.1.29",
3
+ "version": "0.1.30",
4
4
  "description": "AI-native headless community OS",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "private": false,
@@ -29,7 +29,7 @@
29
29
  "build:cli": "FLYSPACE_PUBLIC_BUILD=1 tsup",
30
30
  "start": "node dist/cli.js start",
31
31
  "prepublishOnly": "pnpm run build:cli",
32
- "release": "pnpm version patch && npm publish && git push --follow-tags"
32
+ "release": "pnpm version patch && git push --follow-tags"
33
33
  },
34
34
  "dependencies": {
35
35
  "@anthropic-ai/sandbox-runtime": "0.0.77",
@@ -71,5 +71,10 @@
71
71
  "@types/web-push": "^3.6.4",
72
72
  "@types/ws": "^8.18.1",
73
73
  "playwright": "^1.58.2"
74
+ },
75
+ "repository": {
76
+ "type": "git",
77
+ "url": "git+https://github.com/flycoder-io/flyspace.git",
78
+ "directory": "packages/host"
74
79
  }
75
80
  }