flyspace-cli 0.1.16 → 0.1.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.
@@ -1,6 +1,28 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // src/profile.ts
3
+ // ../api/src/store/supabase-client.ts
4
+ var client;
5
+ var factory;
6
+ function setSupabaseClient(replacement) {
7
+ client = replacement;
8
+ }
9
+ function setSupabaseClientFactory(create) {
10
+ factory = create;
11
+ }
12
+ function hasSupabaseCredentials() {
13
+ return !!process.env["SUPABASE_URL"] && !!process.env["SUPABASE_SECRET_KEY"];
14
+ }
15
+ function databaseReachable() {
16
+ return !!client || !!factory && hasSupabaseCredentials();
17
+ }
18
+ function getSupabaseClient() {
19
+ if (client) return client;
20
+ if (!factory) throw new Error("No Supabase client installed in this process");
21
+ client = factory();
22
+ return client;
23
+ }
24
+
25
+ // ../api/src/profile.ts
4
26
  import { AsyncLocalStorage } from "async_hooks";
5
27
  var PROFILE_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
6
28
  var DEFAULT_PROFILE = "default";
@@ -24,13 +46,14 @@ function getProfile() {
24
46
  return validateProfile(process.env["FLYSPACE_WORKSPACE"]);
25
47
  }
26
48
 
27
- // src/paths.ts
49
+ // ../api/src/paths.ts
28
50
  import { existsSync, mkdirSync, readdirSync, rmSync, statSync } from "fs";
29
51
  import { homedir } from "os";
30
- import { join, resolve } from "path";
52
+ import { basename, join, resolve } from "path";
31
53
  var home = homedir();
32
54
  var XDG_CONFIG_HOME = process.env["XDG_CONFIG_HOME"] || join(home, ".config");
33
55
  var XDG_DATA_HOME = process.env["XDG_DATA_HOME"] || join(home, ".local", "share");
56
+ var OWN_ROOT = resolve(import.meta.dirname, "..");
34
57
  var paths = {
35
58
  /** Profile-independent config root: `~/.config/flyspace`. */
36
59
  get BASE_CONFIG_DIR() {
@@ -115,7 +138,15 @@ var paths = {
115
138
  get DASHBOARD_SETTINGS_FILE() {
116
139
  return join(this.CONFIG_DIR, "dashboard-settings.json");
117
140
  },
118
- PACKAGE_ROOT: resolve(import.meta.dirname, "..")
141
+ /** Where the CLI's shipped files live (`system.default.md`, `hooks/`,
142
+ * `templates/`, its `node_modules`): packages/host in a checkout, the
143
+ * installed `flyspace-cli` otherwise. This module lives in packages/api, so
144
+ * an unbundled run (tsx, vitest) resolves to the host package next to it;
145
+ * the Fly images ship no host package and keep their own root. */
146
+ PACKAGE_ROOT: basename(OWN_ROOT) === "api" && existsSync(join(OWN_ROOT, "..", "host", "package.json")) ? resolve(OWN_ROOT, "..", "host") : OWN_ROOT,
147
+ /** packages/ui: the SPA source and its `dist/`. Only a checkout (or the
148
+ * share image) has it; the npm-installed CLI ships no UI. */
149
+ WEB_ROOT: resolve(OWN_ROOT, "..", "ui")
119
150
  };
120
151
  function ensureDirs() {
121
152
  for (const dir of [
@@ -147,33 +178,7 @@ function sweepScratchDir(now = Date.now()) {
147
178
  return removed;
148
179
  }
149
180
 
150
- // src/store/supabase-client.ts
151
- import { createClient } from "@supabase/supabase-js";
152
- var REQUEST_TIMEOUT_MS = 15e3;
153
- var client;
154
- function setSupabaseClient(replacement) {
155
- client = replacement;
156
- }
157
- function hasSupabaseCredentials() {
158
- return !!process.env["SUPABASE_URL"] && !!process.env["SUPABASE_SECRET_KEY"];
159
- }
160
- function getSupabaseClient() {
161
- if (client) return client;
162
- const url = process.env["SUPABASE_URL"];
163
- const key = process.env["SUPABASE_SECRET_KEY"];
164
- if (!url || !key) {
165
- throw new Error("SUPABASE_URL / SUPABASE_SECRET_KEY not set \u2014 check .env");
166
- }
167
- client = createClient(url, key, {
168
- auth: { persistSession: false },
169
- global: {
170
- fetch: (input, init) => fetch(input, { ...init, signal: init?.signal ?? AbortSignal.timeout(REQUEST_TIMEOUT_MS) })
171
- }
172
- });
173
- return client;
174
- }
175
-
176
- // src/store/authors.ts
181
+ // ../api/src/store/authors.ts
177
182
  var AGENT_AUTHOR = "agent";
178
183
  var SYNCED_BOT_AUTHOR = "Bot";
179
184
  var LEGACY_BOT_AUTHOR = "Custie";
@@ -184,13 +189,13 @@ function isHumanAuthor(author) {
184
189
  return !NON_HUMAN_AUTHORS.has(author.toLowerCase());
185
190
  }
186
191
 
187
- // src/dashboard/attachment-uploader.ts
192
+ // ../api/src/dashboard/attachment-uploader.ts
188
193
  import { randomUUID } from "crypto";
189
194
  import { readFile, stat } from "fs/promises";
190
- import { basename } from "path";
195
+ import { basename as basename2 } from "path";
191
196
  import { PutObjectCommand } from "@aws-sdk/client-s3";
192
197
 
193
- // src/store/r2-client.ts
198
+ // ../api/src/store/r2-client.ts
194
199
  import { ListObjectsV2Command, S3Client } from "@aws-sdk/client-s3";
195
200
  var client2;
196
201
  function getR2Client() {
@@ -226,7 +231,7 @@ async function sumR2PrefixBytes(prefix) {
226
231
  return total;
227
232
  }
228
233
 
229
- // src/dashboard/attachment-uploader.ts
234
+ // ../api/src/dashboard/attachment-uploader.ts
230
235
  var debug = process.env["DEBUG"] === "true";
231
236
  var LOCAL_IMAGE_LINK = /!\[([^\]]*)\]\((\/[^)\s]+)\)/g;
232
237
  var SCRATCH_VAR_IN_IMAGE_LINK = /(!\[[^\]]*\]\()\$\{?FLYSPACE_SCRATCH_DIR\}?(?=\/)/g;
@@ -274,7 +279,7 @@ async function uploadOne(path) {
274
279
  console.error(`[attachment-uploader] ${path} is ${info.size} bytes, over the ${MAX_FILE_BYTES} limit`);
275
280
  return null;
276
281
  }
277
- const key = `${SCRATCH_PREFIX}/${getProfile()}/${randomUUID()}-${sanitizeFilename(basename(path))}`;
282
+ const key = `${SCRATCH_PREFIX}/${getProfile()}/${randomUUID()}-${sanitizeFilename(basename2(path))}`;
278
283
  await getR2Client().send(
279
284
  new PutObjectCommand({
280
285
  Bucket: getR2Bucket(),
@@ -319,7 +324,7 @@ function deriveThreadTitle(text) {
319
324
  }
320
325
  async function syncPostToDashboard(opts) {
321
326
  const { channelId, ts, threadTs, text } = opts;
322
- if (!process.env["SUPABASE_URL"] || !process.env["SUPABASE_SECRET_KEY"]) {
327
+ if (!databaseReachable()) {
323
328
  console.warn("[dashboard-sync] Supabase not configured \u2014 skipping dashboard sync");
324
329
  return;
325
330
  }
@@ -422,15 +427,17 @@ async function createThread(supabase, channelId, text, title) {
422
427
  }
423
428
 
424
429
  export {
430
+ setSupabaseClient,
431
+ setSupabaseClientFactory,
432
+ hasSupabaseCredentials,
433
+ databaseReachable,
434
+ getSupabaseClient,
425
435
  DEFAULT_PROFILE,
426
436
  runWithProfile,
427
437
  getProfile,
428
438
  paths,
429
439
  ensureDirs,
430
440
  sweepScratchDir,
431
- setSupabaseClient,
432
- hasSupabaseCredentials,
433
- getSupabaseClient,
434
441
  AGENT_AUTHOR,
435
442
  SYNCED_BOT_AUTHOR,
436
443
  isHumanAuthor,