flyspace-cli 0.1.30 → 0.1.31
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 +300 -222
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -642,6 +642,26 @@ async function requestHostDb(req) {
|
|
|
642
642
|
send2({ type: "db", id, req });
|
|
643
643
|
});
|
|
644
644
|
}
|
|
645
|
+
var pendingUrls = /* @__PURE__ */ new Map();
|
|
646
|
+
function handleAttachmentUrlResult(id, url) {
|
|
647
|
+
pendingUrls.get(id)?.(url);
|
|
648
|
+
pendingUrls.delete(id);
|
|
649
|
+
}
|
|
650
|
+
async function requestAttachmentUrl(key) {
|
|
651
|
+
const send2 = await whenConnected();
|
|
652
|
+
const id = randomUUID();
|
|
653
|
+
return new Promise((resolve7, reject) => {
|
|
654
|
+
const timer2 = setTimeout(() => {
|
|
655
|
+
pendingUrls.delete(id);
|
|
656
|
+
reject(new Error("Data API did not answer in time"));
|
|
657
|
+
}, REQUEST_TIMEOUT_MS);
|
|
658
|
+
pendingUrls.set(id, (url) => {
|
|
659
|
+
clearTimeout(timer2);
|
|
660
|
+
resolve7(url);
|
|
661
|
+
});
|
|
662
|
+
send2({ type: "attachment-url", id, key });
|
|
663
|
+
});
|
|
664
|
+
}
|
|
645
665
|
var BODYLESS_STATUS = /* @__PURE__ */ new Set([101, 204, 205, 304]);
|
|
646
666
|
function dbFetch(send2) {
|
|
647
667
|
return async (input2, init2) => {
|
|
@@ -861,14 +881,17 @@ function isServiceInstalled(profile) {
|
|
|
861
881
|
return false;
|
|
862
882
|
}
|
|
863
883
|
function serviceBinaryMissing(file) {
|
|
884
|
+
const bin = serviceBinary(file);
|
|
885
|
+
return !!bin && !existsSync3(bin);
|
|
886
|
+
}
|
|
887
|
+
function serviceBinary(file) {
|
|
864
888
|
let text;
|
|
865
889
|
try {
|
|
866
890
|
text = readFileSync5(file, "utf-8");
|
|
867
891
|
} catch {
|
|
868
|
-
return
|
|
892
|
+
return void 0;
|
|
869
893
|
}
|
|
870
|
-
|
|
871
|
-
return !!bin && !existsSync3(bin);
|
|
894
|
+
return text.match(/<key>ProgramArguments<\/key>\s*<array>\s*<string>([^<]+)<\/string>/)?.[1] ?? text.match(/^ExecStart=(\S+)/m)?.[1];
|
|
872
895
|
}
|
|
873
896
|
function profileServiceFile(profile) {
|
|
874
897
|
return platform() === "darwin" ? plistPath(profile) : systemdUnitPath(profile);
|
|
@@ -1835,7 +1858,7 @@ async function runAuthCmd(args) {
|
|
|
1835
1858
|
}
|
|
1836
1859
|
|
|
1837
1860
|
// ../api/src/version.ts
|
|
1838
|
-
var CLI_VERSION = true ? "0.1.
|
|
1861
|
+
var CLI_VERSION = true ? "0.1.31" : null;
|
|
1839
1862
|
function isOlderVersion(a, b) {
|
|
1840
1863
|
const parse = (v) => v.replace(/^v/, "").split("-")[0].split(".").map(Number);
|
|
1841
1864
|
const [pa, pb] = [parse(a), parse(b)];
|
|
@@ -2381,8 +2404,8 @@ async function runProfiles(args = []) {
|
|
|
2381
2404
|
|
|
2382
2405
|
// src/commands/upgrade.ts
|
|
2383
2406
|
import { execSync as execSync6 } from "child_process";
|
|
2384
|
-
import { realpathSync as realpathSync3 } from "fs";
|
|
2385
|
-
import { join as join11 } from "path";
|
|
2407
|
+
import { existsSync as existsSync9, readFileSync as readFileSync10, realpathSync as realpathSync3 } from "fs";
|
|
2408
|
+
import { dirname as dirname5, join as join11 } from "path";
|
|
2386
2409
|
function restartInstalledProfiles() {
|
|
2387
2410
|
if (isHostServiceInstalled()) {
|
|
2388
2411
|
console.log(restartHostService() ? "\nHost restarted." : "\nHost restart failed; run: flyspace setup --start-host --restart");
|
|
@@ -2402,36 +2425,68 @@ Restarting ${installed.length} instance(s)...`);
|
|
|
2402
2425
|
}
|
|
2403
2426
|
}
|
|
2404
2427
|
}
|
|
2405
|
-
function
|
|
2406
|
-
|
|
2428
|
+
function installTarget(entry) {
|
|
2429
|
+
const home2 = flyspaceHome(entry) ?? (entry.endsWith("/bin/flyspace") ? dirname5(dirname5(entry)) : void 0);
|
|
2430
|
+
if (home2 && existsSync9(join11(home2, "cli", "lib", "node_modules", "flyspace-cli"))) {
|
|
2431
|
+
return { prefix: join11(home2, "cli"), nodeBin: join11(home2, "node", "bin") };
|
|
2432
|
+
}
|
|
2433
|
+
try {
|
|
2434
|
+
const real = realpathSync3(entry);
|
|
2435
|
+
const at = real.indexOf(`/lib/node_modules/${"flyspace-cli"}/`);
|
|
2436
|
+
if (at > 0) return { prefix: real.slice(0, at), nodeBin: join11(real.slice(0, at), "bin") };
|
|
2437
|
+
} catch {
|
|
2438
|
+
}
|
|
2439
|
+
return void 0;
|
|
2440
|
+
}
|
|
2441
|
+
function installTargets() {
|
|
2442
|
+
const files = [
|
|
2443
|
+
...isHostServiceInstalled() ? [hostServiceFile()] : [],
|
|
2444
|
+
...listProfiles().filter(isServiceInstalled).map(profileServiceFile)
|
|
2445
|
+
];
|
|
2446
|
+
const entries2 = [process.argv[1] ?? "", ...files.map(serviceBinary).filter((b) => !!b)];
|
|
2447
|
+
const byPrefix = /* @__PURE__ */ new Map();
|
|
2448
|
+
for (const target of entries2.map(installTarget)) {
|
|
2449
|
+
if (target && !byPrefix.has(target.prefix)) byPrefix.set(target.prefix, target);
|
|
2450
|
+
}
|
|
2451
|
+
return [...byPrefix.values()];
|
|
2452
|
+
}
|
|
2453
|
+
function installedVersion(target) {
|
|
2407
2454
|
try {
|
|
2408
|
-
const
|
|
2409
|
-
|
|
2410
|
-
if (at > 0) prefix = entry.slice(0, at);
|
|
2455
|
+
const pkg = join11(target.prefix, "lib", "node_modules", "flyspace-cli", "package.json");
|
|
2456
|
+
return JSON.parse(readFileSync10(pkg, "utf-8")).version;
|
|
2411
2457
|
} catch {
|
|
2458
|
+
return void 0;
|
|
2412
2459
|
}
|
|
2413
|
-
|
|
2460
|
+
}
|
|
2461
|
+
function npmInstallCommand(target) {
|
|
2462
|
+
const global = `-g${target ? ` --prefix "${target.prefix}"` : ""}`;
|
|
2414
2463
|
return `npm install ${global} --ignore-scripts ${"flyspace-cli"}@latest && npm rebuild ${global} better-sqlite3`;
|
|
2415
2464
|
}
|
|
2416
|
-
function npmEnv() {
|
|
2465
|
+
function npmEnv(target) {
|
|
2417
2466
|
const home2 = flyspaceHome();
|
|
2418
|
-
|
|
2467
|
+
const nodeBin = target?.nodeBin ?? (home2 ? join11(home2, "node", "bin") : void 0);
|
|
2468
|
+
return nodeBin ? { ...process.env, PATH: `${nodeBin}:${process.env.PATH ?? ""}` } : process.env;
|
|
2419
2469
|
}
|
|
2420
2470
|
async function runUpgrade() {
|
|
2421
|
-
const current = "0.1.
|
|
2471
|
+
const current = "0.1.31";
|
|
2422
2472
|
console.log(`Current version: ${current}`);
|
|
2423
2473
|
console.log("Checking for updates...\n");
|
|
2424
2474
|
try {
|
|
2425
2475
|
const latest2 = execSync6(`npm view ${"flyspace-cli"} version`, { encoding: "utf-8", env: npmEnv() }).trim();
|
|
2426
|
-
|
|
2476
|
+
const stale = installTargets().filter((t) => installedVersion(t) !== latest2);
|
|
2477
|
+
if (stale.length === 0) {
|
|
2427
2478
|
console.log(`Already on the latest version (${current}).`);
|
|
2428
2479
|
return;
|
|
2429
2480
|
}
|
|
2430
2481
|
console.log(`New version available: ${latest2}`);
|
|
2431
|
-
|
|
2432
|
-
|
|
2482
|
+
for (const target of stale) {
|
|
2483
|
+
console.log(`
|
|
2484
|
+
Upgrading ${target.prefix} (${installedVersion(target) ?? "unknown"})...
|
|
2485
|
+
`);
|
|
2486
|
+
execSync6(npmInstallCommand(target), { stdio: "inherit", env: npmEnv(target) });
|
|
2487
|
+
}
|
|
2433
2488
|
console.log(`
|
|
2434
|
-
Upgraded
|
|
2489
|
+
Upgraded to ${latest2}.`);
|
|
2435
2490
|
restartInstalledProfiles();
|
|
2436
2491
|
console.log("\nReload your shell to use the new version:");
|
|
2437
2492
|
console.log(" source ~/.zshrc # or source ~/.bashrc");
|
|
@@ -2447,13 +2502,13 @@ You can upgrade manually with: ${npmInstallCommand()}`);
|
|
|
2447
2502
|
import { WebClient } from "@slack/web-api";
|
|
2448
2503
|
|
|
2449
2504
|
// src/automations/config-file.ts
|
|
2450
|
-
import { readFileSync as
|
|
2505
|
+
import { readFileSync as readFileSync11, existsSync as existsSync10 } from "fs";
|
|
2451
2506
|
import yaml from "js-yaml";
|
|
2452
2507
|
var EMPTY_CONFIG = { schedules: [], triggers: [], mention_triggers: [] };
|
|
2453
2508
|
function loadAutomationsFile() {
|
|
2454
2509
|
const filePath = paths.AUTOMATIONS_FILE;
|
|
2455
|
-
if (!
|
|
2456
|
-
const raw =
|
|
2510
|
+
if (!existsSync10(filePath)) return { ...EMPTY_CONFIG };
|
|
2511
|
+
const raw = readFileSync11(filePath, "utf-8");
|
|
2457
2512
|
if (!raw.trim()) return { ...EMPTY_CONFIG };
|
|
2458
2513
|
const parsed = yaml.load(raw);
|
|
2459
2514
|
return {
|
|
@@ -2809,7 +2864,7 @@ async function runAutomationCmd(args) {
|
|
|
2809
2864
|
}
|
|
2810
2865
|
|
|
2811
2866
|
// src/commands/usage.ts
|
|
2812
|
-
import { existsSync as
|
|
2867
|
+
import { existsSync as existsSync11 } from "fs";
|
|
2813
2868
|
var HELP4 = `
|
|
2814
2869
|
Usage: flyspace usage [options]
|
|
2815
2870
|
|
|
@@ -2936,7 +2991,7 @@ async function runUsage(args) {
|
|
|
2936
2991
|
return;
|
|
2937
2992
|
}
|
|
2938
2993
|
const { days, by, explain, json } = parsed;
|
|
2939
|
-
if (!
|
|
2994
|
+
if (!existsSync11(paths.DB_FILE)) {
|
|
2940
2995
|
console.log("No usage recorded yet (the database does not exist).");
|
|
2941
2996
|
return;
|
|
2942
2997
|
}
|
|
@@ -3051,13 +3106,13 @@ async function runRestart() {
|
|
|
3051
3106
|
|
|
3052
3107
|
// src/commands/logs.ts
|
|
3053
3108
|
import { spawn as spawn3 } from "child_process";
|
|
3054
|
-
import { existsSync as
|
|
3109
|
+
import { existsSync as existsSync12 } from "fs";
|
|
3055
3110
|
import { join as join12 } from "path";
|
|
3056
3111
|
async function runLogs(args) {
|
|
3057
3112
|
const showErrors = args.includes("--error") || args.includes("-e");
|
|
3058
3113
|
const filename = showErrors ? "custie-error.log" : "custie.log";
|
|
3059
3114
|
const logFile = join12(paths.LOG_DIR, filename);
|
|
3060
|
-
if (!
|
|
3115
|
+
if (!existsSync12(logFile)) {
|
|
3061
3116
|
console.error(`Log file not found: ${logFile}`);
|
|
3062
3117
|
console.error("Is the service installed? Run `flyspace install` first.");
|
|
3063
3118
|
process.exit(1);
|
|
@@ -3078,7 +3133,7 @@ async function runLogs(args) {
|
|
|
3078
3133
|
|
|
3079
3134
|
// src/commands/slack.ts
|
|
3080
3135
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
3081
|
-
import { existsSync as
|
|
3136
|
+
import { existsSync as existsSync13, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
|
|
3082
3137
|
import { resolve as resolve4 } from "path";
|
|
3083
3138
|
import { tmpdir as tmpdir2, homedir as homedir6 } from "os";
|
|
3084
3139
|
import { input, confirm as confirm4, select, checkbox } from "@inquirer/prompts";
|
|
@@ -5164,7 +5219,7 @@ async function threadReplies(client2, nameOrId, ts2) {
|
|
|
5164
5219
|
async function postMessage(client2, args) {
|
|
5165
5220
|
const channelArg = getArg2(args, "--channel");
|
|
5166
5221
|
const textFilePath = getArg2(args, "--text-file");
|
|
5167
|
-
const text = textFilePath ?
|
|
5222
|
+
const text = textFilePath ? readFileSync12(textFilePath, "utf8") : getArg2(args, "--text");
|
|
5168
5223
|
const threadTs = getArg2(args, "--thread");
|
|
5169
5224
|
const markdown = args.includes("--markdown");
|
|
5170
5225
|
const broadcast = args.includes("--broadcast") && Boolean(threadTs);
|
|
@@ -5262,7 +5317,7 @@ function defaultClaudeConfigDir() {
|
|
|
5262
5317
|
return process.env.CLAUDE_CONFIG_DIR || resolve4(homedir6(), ".claude");
|
|
5263
5318
|
}
|
|
5264
5319
|
function hasClaudeCredentials(configDir2) {
|
|
5265
|
-
if (
|
|
5320
|
+
if (existsSync13(resolve4(configDir2, ".credentials.json"))) {
|
|
5266
5321
|
return true;
|
|
5267
5322
|
}
|
|
5268
5323
|
if (process.platform === "darwin") {
|
|
@@ -5319,7 +5374,7 @@ async function ensureClaudeCodeReady() {
|
|
|
5319
5374
|
}
|
|
5320
5375
|
function getManifestYaml(botName) {
|
|
5321
5376
|
const manifestPath = resolve4(paths.PACKAGE_ROOT, "slack-app-manifest.yml");
|
|
5322
|
-
const raw =
|
|
5377
|
+
const raw = readFileSync12(manifestPath, "utf-8");
|
|
5323
5378
|
return raw.replace(/name: Custie/g, `name: ${botName}`);
|
|
5324
5379
|
}
|
|
5325
5380
|
async function stepPersonalise() {
|
|
@@ -5748,10 +5803,10 @@ function printNextSteps() {
|
|
|
5748
5803
|
console.log(" Run \x1B[1mflyspace service install\x1B[0m\n");
|
|
5749
5804
|
}
|
|
5750
5805
|
function copyDefaultPrompt(botName) {
|
|
5751
|
-
if (!
|
|
5806
|
+
if (!existsSync13(paths.PROMPT_FILE)) {
|
|
5752
5807
|
const defaultPrompt = resolve4(paths.PACKAGE_ROOT, "system.default.md");
|
|
5753
|
-
if (
|
|
5754
|
-
const content =
|
|
5808
|
+
if (existsSync13(defaultPrompt)) {
|
|
5809
|
+
const content = readFileSync12(defaultPrompt, "utf-8").replace(/\{\{botName\}\}/g, botName);
|
|
5755
5810
|
writeFileSync7(paths.PROMPT_FILE, content);
|
|
5756
5811
|
success4(`Default prompt copied to ${paths.PROMPT_FILE}`);
|
|
5757
5812
|
}
|
|
@@ -5764,7 +5819,7 @@ async function runSlackSetup(args) {
|
|
|
5764
5819
|
const prereq = await ensureClaudeCodeReady();
|
|
5765
5820
|
if (!prereq) return;
|
|
5766
5821
|
const { claudeConfigDir } = prereq;
|
|
5767
|
-
if (
|
|
5822
|
+
if (existsSync13(paths.CONFIG_FILE)) {
|
|
5768
5823
|
const reconfigure = await confirm4({
|
|
5769
5824
|
message: `Config already exists at ${paths.CONFIG_FILE}. Reconfigure?`,
|
|
5770
5825
|
default: false
|
|
@@ -6075,10 +6130,10 @@ async function runChatCmd(args) {
|
|
|
6075
6130
|
}
|
|
6076
6131
|
|
|
6077
6132
|
// src/commands/memory.ts
|
|
6078
|
-
import { readFileSync as
|
|
6133
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
6079
6134
|
|
|
6080
6135
|
// src/store/claude-memory-import.ts
|
|
6081
|
-
import { existsSync as
|
|
6136
|
+
import { existsSync as existsSync14, readdirSync as readdirSync3, readFileSync as readFileSync13 } from "fs";
|
|
6082
6137
|
import { homedir as homedir7 } from "os";
|
|
6083
6138
|
import { basename as basename5, join as join14 } from "path";
|
|
6084
6139
|
import dotenv from "dotenv";
|
|
@@ -6088,7 +6143,7 @@ function claudeMemoryDir(cwd, configDir2) {
|
|
|
6088
6143
|
function profileClaudeConfigDirFor(profile) {
|
|
6089
6144
|
const dir = profile === "default" ? paths.BASE_CONFIG_DIR : join14(paths.PROFILES_DIR, profile);
|
|
6090
6145
|
const file = join14(dir, "config.env");
|
|
6091
|
-
const env =
|
|
6146
|
+
const env = existsSync14(file) ? dotenv.parse(readFileSync13(file)) : {};
|
|
6092
6147
|
return env["CLAUDE_CONFIG_DIR"]?.trim() || join14(homedir7(), ".claude");
|
|
6093
6148
|
}
|
|
6094
6149
|
var TYPE_MAP = {
|
|
@@ -6134,11 +6189,11 @@ function parseClaudeMemory(fileName, text, channelId) {
|
|
|
6134
6189
|
return input2;
|
|
6135
6190
|
}
|
|
6136
6191
|
async function importClaudeMemories(dir, channelId, opts = {}) {
|
|
6137
|
-
if (!
|
|
6192
|
+
if (!existsSync14(dir)) throw new Error(`No Claude memory directory at ${dir}`);
|
|
6138
6193
|
const files = readdirSync3(dir).filter((f) => f.endsWith(".md") && f !== "MEMORY.md").sort();
|
|
6139
6194
|
const results = [];
|
|
6140
6195
|
for (const file of files) {
|
|
6141
|
-
const parsed = parseClaudeMemory(file,
|
|
6196
|
+
const parsed = parseClaudeMemory(file, readFileSync13(join14(dir, file), "utf-8"), channelId);
|
|
6142
6197
|
if ("skip" in parsed) {
|
|
6143
6198
|
results.push({ file, outcome: "skipped", reason: parsed.skip });
|
|
6144
6199
|
continue;
|
|
@@ -6250,7 +6305,7 @@ ${memory.body}`);
|
|
|
6250
6305
|
);
|
|
6251
6306
|
}
|
|
6252
6307
|
if (!isMemoryType(type)) throw new Error(`--type must be one of ${MEMORY_TYPES.join(", ")}`);
|
|
6253
|
-
const body = bodyArg === "-" ?
|
|
6308
|
+
const body = bodyArg === "-" ? readFileSync14(0, "utf-8") : bodyArg;
|
|
6254
6309
|
const thread = getArg4(rest, "--thread");
|
|
6255
6310
|
const { created, changed } = await saveMemory(
|
|
6256
6311
|
target,
|
|
@@ -6349,12 +6404,12 @@ async function runMcpCmd(args) {
|
|
|
6349
6404
|
|
|
6350
6405
|
// src/commands/dashboard.ts
|
|
6351
6406
|
import { spawn as spawn8, spawnSync } from "child_process";
|
|
6352
|
-
import { existsSync as
|
|
6407
|
+
import { existsSync as existsSync33 } from "fs";
|
|
6353
6408
|
import { platform as platform7 } from "os";
|
|
6354
6409
|
import { join as join29 } from "path";
|
|
6355
6410
|
|
|
6356
6411
|
// src/reconcile.ts
|
|
6357
|
-
import { existsSync as
|
|
6412
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
6358
6413
|
async function boundWorkspaces2() {
|
|
6359
6414
|
return (await boundWorkspaces())?.workspaces ?? null;
|
|
6360
6415
|
}
|
|
@@ -6365,12 +6420,12 @@ async function servedWorkspaces2() {
|
|
|
6365
6420
|
async function reconcileProfile(profile) {
|
|
6366
6421
|
return runWithProfile(profile, async () => {
|
|
6367
6422
|
const log5 = [];
|
|
6368
|
-
const hadConfigDir =
|
|
6369
|
-
const hadDataDir =
|
|
6423
|
+
const hadConfigDir = existsSync15(paths.CONFIG_DIR);
|
|
6424
|
+
const hadDataDir = existsSync15(paths.DATA_DIR);
|
|
6370
6425
|
ensureDirs();
|
|
6371
6426
|
if (!hadConfigDir) log5.push(`config dir created (${paths.CONFIG_DIR})`);
|
|
6372
6427
|
if (!hadDataDir) log5.push(`data dir created (${paths.DATA_DIR})`);
|
|
6373
|
-
if (!
|
|
6428
|
+
if (!existsSync15(paths.CONFIG_FILE)) {
|
|
6374
6429
|
writeFileSync8(paths.CONFIG_FILE, `BOT_NAME=${profile}
|
|
6375
6430
|
`);
|
|
6376
6431
|
log5.push(`config.env written (${paths.CONFIG_FILE})`);
|
|
@@ -6527,7 +6582,7 @@ var requireDocsAccess = async (c, next) => {
|
|
|
6527
6582
|
import { Hono as Hono29 } from "hono";
|
|
6528
6583
|
|
|
6529
6584
|
// ../api/src/dashboard/public-share-routes.ts
|
|
6530
|
-
import { existsSync as
|
|
6585
|
+
import { existsSync as existsSync17, readFileSync as readFileSync16, statSync as statSync3 } from "fs";
|
|
6531
6586
|
import { join as join16 } from "path";
|
|
6532
6587
|
import { Hono as Hono5 } from "hono";
|
|
6533
6588
|
import { GetObjectCommand } from "@aws-sdk/client-s3";
|
|
@@ -6993,11 +7048,11 @@ function injectShareHead(html, head) {
|
|
|
6993
7048
|
|
|
6994
7049
|
// ../api/src/dashboard/app-icon.ts
|
|
6995
7050
|
import { createHash as createHash2 } from "crypto";
|
|
6996
|
-
import { existsSync as
|
|
7051
|
+
import { existsSync as existsSync16, readFileSync as readFileSync15 } from "fs";
|
|
6997
7052
|
import { join as join15 } from "path";
|
|
6998
7053
|
import sharp2 from "sharp";
|
|
6999
7054
|
var PLATE = "#0A0A0F";
|
|
7000
|
-
var BRAND_DIR =
|
|
7055
|
+
var BRAND_DIR = existsSync16(join15(paths.WEB_ROOT, "public")) ? join15(paths.WEB_ROOT, "public") : join15(paths.PACKAGE_ROOT, "dist", "brand");
|
|
7001
7056
|
var MARK_FILE = join15(BRAND_DIR, "icons", "icon-512.png");
|
|
7002
7057
|
var MARK_SVG_FILE = join15(BRAND_DIR, "favicon.svg");
|
|
7003
7058
|
var LAYOUT = {
|
|
@@ -7022,7 +7077,7 @@ function roundedPlate(size, fill = PLATE) {
|
|
|
7022
7077
|
}
|
|
7023
7078
|
async function renderBadge(box) {
|
|
7024
7079
|
const transparent = { r: 0, g: 0, b: 0, alpha: 0 };
|
|
7025
|
-
const raster = await sharp2(
|
|
7080
|
+
const raster = await sharp2(readFileSync15(MARK_SVG_FILE)).resize(512, 512, { fit: "contain", background: transparent }).png().toBuffer();
|
|
7026
7081
|
return sharp2(raster).trim().resize(box, box, { fit: "contain", background: transparent }).png().toBuffer();
|
|
7027
7082
|
}
|
|
7028
7083
|
async function sampleBackground(logo) {
|
|
@@ -7077,7 +7132,7 @@ async function renderAppIcon({
|
|
|
7077
7132
|
if (hit) return hit;
|
|
7078
7133
|
const out = logo && await composeIcon(logo, size, maskable, plain).catch(() => null) || // No workspace logo to lead with — the stock mark is still the best icon,
|
|
7079
7134
|
// either on its usual dark plate or, for a favicon, trimmed and bare.
|
|
7080
|
-
(transparent ? await renderBadge(size) : await sharp2(
|
|
7135
|
+
(transparent ? await renderBadge(size) : await sharp2(readFileSync15(MARK_FILE)).resize(size, size, { fit: "cover" }).png().toBuffer());
|
|
7081
7136
|
cache3.set(key, out);
|
|
7082
7137
|
return out;
|
|
7083
7138
|
}
|
|
@@ -8295,7 +8350,7 @@ var shellCache = null;
|
|
|
8295
8350
|
function readShell(path) {
|
|
8296
8351
|
const { mtimeMs } = statSync3(path);
|
|
8297
8352
|
if (shellCache?.mtimeMs === mtimeMs) return shellCache.html;
|
|
8298
|
-
const html =
|
|
8353
|
+
const html = readFileSync16(path, "utf8").replaceAll('"/assets/', `"${BUILD_PREFIX}/`);
|
|
8299
8354
|
shellCache = { mtimeMs, html };
|
|
8300
8355
|
return html;
|
|
8301
8356
|
}
|
|
@@ -8316,16 +8371,16 @@ function serveBuildFile(c, webDist, dir, name) {
|
|
|
8316
8371
|
return c.text("not found", 404);
|
|
8317
8372
|
}
|
|
8318
8373
|
const path = join16(webDist, dir, name);
|
|
8319
|
-
if (!
|
|
8374
|
+
if (!existsSync17(path)) return c.text("not found", 404);
|
|
8320
8375
|
c.header("Content-Type", type);
|
|
8321
8376
|
c.header("Cache-Control", "public, max-age=31536000, immutable");
|
|
8322
8377
|
if (ext === ".css") {
|
|
8323
|
-
return c.body(
|
|
8378
|
+
return c.body(readFileSync16(path, "utf8").replaceAll("url(/fonts/", `url(${BUILD_PREFIX}/fonts/`));
|
|
8324
8379
|
}
|
|
8325
8380
|
if (ext === ".js") {
|
|
8326
|
-
return c.body(
|
|
8381
|
+
return c.body(readFileSync16(path, "utf8").replaceAll('"/assets/', `"${BUILD_PREFIX}/`));
|
|
8327
8382
|
}
|
|
8328
|
-
return c.body(new Uint8Array(
|
|
8383
|
+
return c.body(new Uint8Array(readFileSync16(path)));
|
|
8329
8384
|
}
|
|
8330
8385
|
var HTML_SHARE_CSP = "sandbox allow-scripts allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox";
|
|
8331
8386
|
function servePublishedHtml(c, share) {
|
|
@@ -8462,7 +8517,7 @@ ${analytics}` : head);
|
|
|
8462
8517
|
const lang = canonicalLanguage(requested);
|
|
8463
8518
|
if (!isTranslatableLanguage(lang)) return next();
|
|
8464
8519
|
const shell = join16(webDist, "index.html");
|
|
8465
|
-
if (!
|
|
8520
|
+
if (!existsSync17(shell)) return next();
|
|
8466
8521
|
const share = await getDocShare(c.req.param("id"));
|
|
8467
8522
|
if (!share) return next();
|
|
8468
8523
|
if (requested !== lang) return c.redirect(`/share/${share.id}/${lang}`, 302);
|
|
@@ -8498,7 +8553,7 @@ ${analytics}` : head);
|
|
|
8498
8553
|
if (!share) return next();
|
|
8499
8554
|
if (share.kind === "html") return servePublishedHtml(c, share);
|
|
8500
8555
|
const shell = join16(webDist, "index.html");
|
|
8501
|
-
if (!
|
|
8556
|
+
if (!existsSync17(shell)) return next();
|
|
8502
8557
|
return readerPage(
|
|
8503
8558
|
c,
|
|
8504
8559
|
share,
|
|
@@ -8564,7 +8619,7 @@ function createGuestRouter() {
|
|
|
8564
8619
|
}
|
|
8565
8620
|
|
|
8566
8621
|
// ../api/src/dashboard/auth-routes.ts
|
|
8567
|
-
import { Hono as
|
|
8622
|
+
import { Hono as Hono9 } from "hono";
|
|
8568
8623
|
|
|
8569
8624
|
// ../api/src/dashboard/supabase-server-client.ts
|
|
8570
8625
|
import { createServerClient, parseCookieHeader, serializeCookieHeader } from "@supabase/ssr";
|
|
@@ -8675,7 +8730,7 @@ function pruneExpired(now) {
|
|
|
8675
8730
|
}
|
|
8676
8731
|
}
|
|
8677
8732
|
var SUPPORT_NAME = "Flyspace Support";
|
|
8678
|
-
var SUPPORT_AVATAR_URL = "/logo/flyspace-
|
|
8733
|
+
var SUPPORT_AVATAR_URL = "/logo/flyspace-support.svg";
|
|
8679
8734
|
async function resolveAuthContext(c, opts = {}) {
|
|
8680
8735
|
const cookie = c.req?.header("Cookie") ?? "";
|
|
8681
8736
|
if (!cookie) return resolveAuthContextUncached(c);
|
|
@@ -8806,7 +8861,7 @@ async function verifyTurnstileToken(token) {
|
|
|
8806
8861
|
}
|
|
8807
8862
|
|
|
8808
8863
|
// ../api/src/dashboard/onboarding-routes.ts
|
|
8809
|
-
import { Hono as
|
|
8864
|
+
import { Hono as Hono8 } from "hono";
|
|
8810
8865
|
|
|
8811
8866
|
// ../api/src/store/device-store.ts
|
|
8812
8867
|
import { createHash as createHash7, createPublicKey as createPublicKey2, randomBytes as randomBytes4, randomInt } from "crypto";
|
|
@@ -9035,23 +9090,83 @@ async function userEmail(userId) {
|
|
|
9035
9090
|
}
|
|
9036
9091
|
|
|
9037
9092
|
// ../api/src/dashboard/agent-bridge-data.ts
|
|
9038
|
-
import { randomBytes as randomBytes5, randomUUID as
|
|
9093
|
+
import { randomBytes as randomBytes5, randomUUID as randomUUID3, verify as verifyRaw } from "crypto";
|
|
9039
9094
|
import { WebSocket, WebSocketServer } from "ws";
|
|
9040
9095
|
|
|
9041
9096
|
// ../api/src/dashboard/host-identity.ts
|
|
9042
9097
|
import { createPrivateKey as createPrivateKey2, createPublicKey as createPublicKey3, generateKeyPairSync as generateKeyPairSync2 } from "crypto";
|
|
9043
|
-
import { existsSync as
|
|
9044
|
-
import { dirname as
|
|
9098
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync17, writeFileSync as writeFileSync9 } from "fs";
|
|
9099
|
+
import { dirname as dirname6, join as join17 } from "path";
|
|
9045
9100
|
function hostPrivateKeyPath() {
|
|
9046
9101
|
return process.env["FLYSPACE_HOST_KEY_PATH"] || join17(paths.BASE_CONFIG_DIR, "host.key");
|
|
9047
9102
|
}
|
|
9048
9103
|
function loadHostPrivateKey(path = hostPrivateKeyPath()) {
|
|
9049
|
-
if (!
|
|
9104
|
+
if (!existsSync18(path)) {
|
|
9050
9105
|
throw new Error(
|
|
9051
9106
|
`No Host identity at ${path}. Run \`pnpm run generate-host-key\` on this machine, then set FLYSPACE_HOST_PUBLIC_KEY on the Data process to the printed public key.`
|
|
9052
9107
|
);
|
|
9053
9108
|
}
|
|
9054
|
-
return createPrivateKey2(
|
|
9109
|
+
return createPrivateKey2(readFileSync17(path, "utf8"));
|
|
9110
|
+
}
|
|
9111
|
+
|
|
9112
|
+
// ../api/src/dashboard/uploads-routes.ts
|
|
9113
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
9114
|
+
import { Hono as Hono7 } from "hono";
|
|
9115
|
+
import { PutObjectCommand as PutObjectCommand2, GetObjectCommand as GetObjectCommand3 } from "@aws-sdk/client-s3";
|
|
9116
|
+
import { getSignedUrl as getSignedUrl3 } from "@aws-sdk/s3-request-presigner";
|
|
9117
|
+
var MAX_FILE_BYTES = 10 * 1024 * 1024;
|
|
9118
|
+
var PRESIGN_TTL_SECONDS2 = 300;
|
|
9119
|
+
var KEY_PREFIX = "chat";
|
|
9120
|
+
var READABLE_PREFIXES = [KEY_PREFIX, SCRATCH_PREFIX];
|
|
9121
|
+
function sanitizeFilename(name) {
|
|
9122
|
+
const cleaned = name.replace(/[/\\]/g, "_").replace(/\s+/g, "-").replace(/[^\w.-]/g, "").trim();
|
|
9123
|
+
return (cleaned || "file").slice(-100);
|
|
9124
|
+
}
|
|
9125
|
+
function encodeKeyForUrl(key) {
|
|
9126
|
+
return key.split("/").map(encodeURIComponent).join("/");
|
|
9127
|
+
}
|
|
9128
|
+
async function presignAttachmentRead(key) {
|
|
9129
|
+
if (!READABLE_PREFIXES.some((prefix) => key.startsWith(`${prefix}/`))) return null;
|
|
9130
|
+
return getSignedUrl3(getR2Client(), new GetObjectCommand3({ Bucket: getR2Bucket(), Key: key }), {
|
|
9131
|
+
expiresIn: PRESIGN_TTL_SECONDS2
|
|
9132
|
+
});
|
|
9133
|
+
}
|
|
9134
|
+
function createUploadsRouter() {
|
|
9135
|
+
const app = new Hono7();
|
|
9136
|
+
app.post("/uploads", async (c) => {
|
|
9137
|
+
const body = await c.req.parseBody().catch(() => null);
|
|
9138
|
+
const file = body?.["file"];
|
|
9139
|
+
if (!(file instanceof File)) return c.json({ error: "missing file" }, 400);
|
|
9140
|
+
if (file.size > MAX_FILE_BYTES) {
|
|
9141
|
+
return c.json({ error: `file must be ${MAX_FILE_BYTES / (1024 * 1024)}MB or smaller` }, 400);
|
|
9142
|
+
}
|
|
9143
|
+
const key = `${KEY_PREFIX}/${getProfile()}/${randomUUID2()}-${sanitizeFilename(file.name)}`;
|
|
9144
|
+
const buffer = Buffer.from(await file.arrayBuffer());
|
|
9145
|
+
await getR2Client().send(
|
|
9146
|
+
new PutObjectCommand2({
|
|
9147
|
+
Bucket: getR2Bucket(),
|
|
9148
|
+
Key: key,
|
|
9149
|
+
Body: buffer,
|
|
9150
|
+
ContentType: file.type || "application/octet-stream"
|
|
9151
|
+
})
|
|
9152
|
+
);
|
|
9153
|
+
return c.json(
|
|
9154
|
+
{
|
|
9155
|
+
url: `/api/attachments/${encodeKeyForUrl(key)}`,
|
|
9156
|
+
name: file.name,
|
|
9157
|
+
type: file.type,
|
|
9158
|
+
size: file.size
|
|
9159
|
+
},
|
|
9160
|
+
201
|
|
9161
|
+
);
|
|
9162
|
+
});
|
|
9163
|
+
app.get("/attachments/:key{.+}", async (c) => {
|
|
9164
|
+
const url = await presignAttachmentRead(c.req.param("key"));
|
|
9165
|
+
if (!url) return c.json({ error: "not found" }, 404);
|
|
9166
|
+
c.header("Cache-Control", `private, max-age=${PRESIGN_TTL_SECONDS2 - 60}`);
|
|
9167
|
+
return c.redirect(url, 302);
|
|
9168
|
+
});
|
|
9169
|
+
return app;
|
|
9055
9170
|
}
|
|
9056
9171
|
|
|
9057
9172
|
// ../core/src/bridge-protocol.ts
|
|
@@ -9216,7 +9331,7 @@ function hostUnavailable(c, agent, method) {
|
|
|
9216
9331
|
return c.json({ error: "host offline", reason: agent.getHostCallFailure?.(method) ?? "offline" }, 503);
|
|
9217
9332
|
}
|
|
9218
9333
|
function createOnboardingRouter(agent) {
|
|
9219
|
-
const app = new
|
|
9334
|
+
const app = new Hono8();
|
|
9220
9335
|
app.get("/scan", async (c) => {
|
|
9221
9336
|
const ctx = await resolveAuthContext(c);
|
|
9222
9337
|
if (ctx?.role !== "admin") return c.json({ error: "admin access required" }, 403);
|
|
@@ -9354,7 +9469,7 @@ async function ensureGreetingThread(workspaceId, channelId, ownerName) {
|
|
|
9354
9469
|
|
|
9355
9470
|
// ../api/src/dashboard/auth-routes.ts
|
|
9356
9471
|
function createAuthRouter() {
|
|
9357
|
-
const auth = new
|
|
9472
|
+
const auth = new Hono9();
|
|
9358
9473
|
const emailedLink = (deliver) => async (c) => {
|
|
9359
9474
|
const body = await c.req.json().catch(() => ({}));
|
|
9360
9475
|
const email = body.email?.trim().toLowerCase();
|
|
@@ -9434,7 +9549,7 @@ var requireWorkspaceMembership = async (c, next) => {
|
|
|
9434
9549
|
};
|
|
9435
9550
|
|
|
9436
9551
|
// ../api/src/dashboard/billing-routes.ts
|
|
9437
|
-
import { Hono as
|
|
9552
|
+
import { Hono as Hono10 } from "hono";
|
|
9438
9553
|
function isPlan(value) {
|
|
9439
9554
|
return value === "local" || value === "cloud";
|
|
9440
9555
|
}
|
|
@@ -9450,7 +9565,7 @@ async function requireActivePlan(c, next) {
|
|
|
9450
9565
|
return next();
|
|
9451
9566
|
}
|
|
9452
9567
|
function createBillingRouter() {
|
|
9453
|
-
const billing = new
|
|
9568
|
+
const billing = new Hono10();
|
|
9454
9569
|
billing.get("/", async (c) => {
|
|
9455
9570
|
const auth = c.get("auth");
|
|
9456
9571
|
const { planStatus, stripeSubscriptionId } = await getWorkspaceBilling(auth.workspaceId);
|
|
@@ -9506,7 +9621,7 @@ function createBillingRouter() {
|
|
|
9506
9621
|
}
|
|
9507
9622
|
|
|
9508
9623
|
// ../api/src/dashboard/admin-routes.ts
|
|
9509
|
-
import { Hono as
|
|
9624
|
+
import { Hono as Hono11 } from "hono";
|
|
9510
9625
|
|
|
9511
9626
|
// ../api/src/dashboard/admin-middleware.ts
|
|
9512
9627
|
function platformAdminEmails() {
|
|
@@ -9532,7 +9647,7 @@ var requirePlatformOperator = async (c, next) => {
|
|
|
9532
9647
|
// ../api/src/dashboard/admin-routes.ts
|
|
9533
9648
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
9534
9649
|
function createAdminRouter() {
|
|
9535
|
-
const admin = new
|
|
9650
|
+
const admin = new Hono11();
|
|
9536
9651
|
admin.use("*", requirePlatformOperator);
|
|
9537
9652
|
admin.get("/workspaces", async (c) => {
|
|
9538
9653
|
const summaries = await listWorkspaceSummaries();
|
|
@@ -9645,11 +9760,11 @@ var BOT_LABEL = "Workspace Agent";
|
|
|
9645
9760
|
var BOT_DM_KEY = "claude";
|
|
9646
9761
|
|
|
9647
9762
|
// ../api/src/dashboard/data-api.ts
|
|
9648
|
-
import { existsSync as
|
|
9763
|
+
import { existsSync as existsSync20 } from "fs";
|
|
9649
9764
|
import sharp5 from "sharp";
|
|
9650
9765
|
|
|
9651
9766
|
// ../api/src/dashboard/automations-routes.ts
|
|
9652
|
-
import { Hono as
|
|
9767
|
+
import { Hono as Hono12 } from "hono";
|
|
9653
9768
|
var TYPES2 = ["schedule", "trigger", "mention-trigger"];
|
|
9654
9769
|
function isType(t) {
|
|
9655
9770
|
return TYPES2.includes(t);
|
|
@@ -9666,7 +9781,7 @@ function statusFor(message) {
|
|
|
9666
9781
|
return 400;
|
|
9667
9782
|
}
|
|
9668
9783
|
function createAutomationWriteRouter() {
|
|
9669
|
-
const app = new
|
|
9784
|
+
const app = new Hono12();
|
|
9670
9785
|
const manager = () => new AutomationManager();
|
|
9671
9786
|
app.get("/:type/:name", (c) => {
|
|
9672
9787
|
const item = manager().get(c.req.param("name"));
|
|
@@ -9722,9 +9837,9 @@ function createAutomationWriteRouter() {
|
|
|
9722
9837
|
}
|
|
9723
9838
|
|
|
9724
9839
|
// ../api/src/dashboard/categories-routes.ts
|
|
9725
|
-
import { Hono as
|
|
9840
|
+
import { Hono as Hono13 } from "hono";
|
|
9726
9841
|
function createCategoryWriteRouter() {
|
|
9727
|
-
const app = new
|
|
9842
|
+
const app = new Hono13();
|
|
9728
9843
|
app.get("/", async (c) => {
|
|
9729
9844
|
const { data, error: error2 } = await getSupabaseClient().from("categories").select("*").eq("profile", getProfile()).order("position", { ascending: true });
|
|
9730
9845
|
if (error2) return c.json({ error: error2.message }, 500);
|
|
@@ -9778,7 +9893,7 @@ function createCategoryWriteRouter() {
|
|
|
9778
9893
|
}
|
|
9779
9894
|
|
|
9780
9895
|
// ../api/src/dashboard/chat-routes.ts
|
|
9781
|
-
import { Hono as
|
|
9896
|
+
import { Hono as Hono14 } from "hono";
|
|
9782
9897
|
|
|
9783
9898
|
// ../api/src/dashboard/fork-summary.ts
|
|
9784
9899
|
var GROQ_API_URL4 = "https://api.groq.com/openai/v1/chat/completions";
|
|
@@ -10265,7 +10380,7 @@ async function generateAutoTitle(threadId, channelId, body) {
|
|
|
10265
10380
|
await supabase.from("threads").update({ auto_title: autoTitle }).eq("id", threadId).is("title", null);
|
|
10266
10381
|
}
|
|
10267
10382
|
function createChatRouter(agent = {}) {
|
|
10268
|
-
const app = new
|
|
10383
|
+
const app = new Hono14();
|
|
10269
10384
|
const {
|
|
10270
10385
|
onChatMessage: onMessage,
|
|
10271
10386
|
isAgentThinking,
|
|
@@ -10779,7 +10894,7 @@ function createChatRouter(agent = {}) {
|
|
|
10779
10894
|
}
|
|
10780
10895
|
|
|
10781
10896
|
// ../api/src/dashboard/doc-shares-routes.ts
|
|
10782
|
-
import { Hono as
|
|
10897
|
+
import { Hono as Hono15 } from "hono";
|
|
10783
10898
|
|
|
10784
10899
|
// ../api/src/dashboard/doc-share-features.ts
|
|
10785
10900
|
import { DeleteObjectCommand as DeleteObjectCommand2 } from "@aws-sdk/client-s3";
|
|
@@ -10839,7 +10954,7 @@ async function updateShareFeatures(share, requested) {
|
|
|
10839
10954
|
|
|
10840
10955
|
// ../api/src/dashboard/doc-share-publish.ts
|
|
10841
10956
|
import { randomBytes as randomBytes6 } from "crypto";
|
|
10842
|
-
import { CopyObjectCommand, PutObjectCommand as
|
|
10957
|
+
import { CopyObjectCommand, PutObjectCommand as PutObjectCommand3 } from "@aws-sdk/client-s3";
|
|
10843
10958
|
|
|
10844
10959
|
// ../api/src/dashboard/bridge-types.ts
|
|
10845
10960
|
var SHARE_ASSET_PLACEHOLDER = "/share/{{flyspace-share-id}}/assets/";
|
|
@@ -10935,7 +11050,7 @@ async function publishDocShare(input2, readBundle) {
|
|
|
10935
11050
|
);
|
|
10936
11051
|
} else {
|
|
10937
11052
|
await client2.send(
|
|
10938
|
-
new
|
|
11053
|
+
new PutObjectCommand3({
|
|
10939
11054
|
Bucket: bucket,
|
|
10940
11055
|
Key: key,
|
|
10941
11056
|
Body: Buffer.from(asset.data, "base64"),
|
|
@@ -11114,7 +11229,7 @@ function resolveChannel2(c) {
|
|
|
11114
11229
|
}
|
|
11115
11230
|
var LIST_LIMIT = 500;
|
|
11116
11231
|
function createDocShareListRouter() {
|
|
11117
|
-
const app = new
|
|
11232
|
+
const app = new Hono15();
|
|
11118
11233
|
app.get("/shares", async (c) => {
|
|
11119
11234
|
const viewer = c.get("auth");
|
|
11120
11235
|
const readable = await filterReadableDocsChannels(
|
|
@@ -11158,7 +11273,7 @@ function createDocShareListRouter() {
|
|
|
11158
11273
|
return app;
|
|
11159
11274
|
}
|
|
11160
11275
|
function createDocShareWriteRouter(agent = {}) {
|
|
11161
|
-
const app = new
|
|
11276
|
+
const app = new Hono15();
|
|
11162
11277
|
app.use("/:id/docs/share", requireDocsAccess);
|
|
11163
11278
|
app.use("/:id/docs/share/*", requireDocsAccess);
|
|
11164
11279
|
app.use("/:id/docs/shares", requireDocsAccess);
|
|
@@ -11331,7 +11446,7 @@ function createDocShareWriteRouter(agent = {}) {
|
|
|
11331
11446
|
}
|
|
11332
11447
|
|
|
11333
11448
|
// ../api/src/dashboard/search-routes.ts
|
|
11334
|
-
import { Hono as
|
|
11449
|
+
import { Hono as Hono16 } from "hono";
|
|
11335
11450
|
function matchScore(q, fields) {
|
|
11336
11451
|
const terms = q.toLowerCase().split(/\s+/).filter(Boolean);
|
|
11337
11452
|
if (terms.length === 0) return 0;
|
|
@@ -11479,7 +11594,7 @@ function searchAutomations(q) {
|
|
|
11479
11594
|
}
|
|
11480
11595
|
var RESULT_LIMIT = 30;
|
|
11481
11596
|
function createSearchRouter() {
|
|
11482
|
-
const app = new
|
|
11597
|
+
const app = new Hono16();
|
|
11483
11598
|
app.get("/", async (c) => {
|
|
11484
11599
|
const q = c.req.query("q")?.trim();
|
|
11485
11600
|
if (!q) return c.json({ results: [] });
|
|
@@ -11495,14 +11610,14 @@ function createSearchRouter() {
|
|
|
11495
11610
|
}
|
|
11496
11611
|
|
|
11497
11612
|
// ../api/src/dashboard/feature-flags-routes.ts
|
|
11498
|
-
import { Hono as
|
|
11613
|
+
import { Hono as Hono17 } from "hono";
|
|
11499
11614
|
async function isFeatureEnabled(c, flagId) {
|
|
11500
11615
|
const auth = c.get("auth");
|
|
11501
11616
|
const enabled = await listEnabledFeatureFlags(auth.workspaceId);
|
|
11502
11617
|
return resolveFeatureFlags(enabled, isDevHost(c))[flagId];
|
|
11503
11618
|
}
|
|
11504
11619
|
function createFeatureFlagsRouter() {
|
|
11505
|
-
const app = new
|
|
11620
|
+
const app = new Hono17();
|
|
11506
11621
|
app.get("/", async (c) => {
|
|
11507
11622
|
const auth = c.get("auth");
|
|
11508
11623
|
const devHost = isDevHost(c);
|
|
@@ -11527,67 +11642,6 @@ function createFeatureFlagsRouter() {
|
|
|
11527
11642
|
return app;
|
|
11528
11643
|
}
|
|
11529
11644
|
|
|
11530
|
-
// ../api/src/dashboard/uploads-routes.ts
|
|
11531
|
-
import { randomUUID as randomUUID3 } from "crypto";
|
|
11532
|
-
import { Hono as Hono17 } from "hono";
|
|
11533
|
-
import { PutObjectCommand as PutObjectCommand3, GetObjectCommand as GetObjectCommand3 } from "@aws-sdk/client-s3";
|
|
11534
|
-
import { getSignedUrl as getSignedUrl3 } from "@aws-sdk/s3-request-presigner";
|
|
11535
|
-
var MAX_FILE_BYTES = 10 * 1024 * 1024;
|
|
11536
|
-
var PRESIGN_TTL_SECONDS2 = 300;
|
|
11537
|
-
var KEY_PREFIX = "chat";
|
|
11538
|
-
var READABLE_PREFIXES = [KEY_PREFIX, SCRATCH_PREFIX];
|
|
11539
|
-
function sanitizeFilename(name) {
|
|
11540
|
-
const cleaned = name.replace(/[/\\]/g, "_").replace(/\s+/g, "-").replace(/[^\w.-]/g, "").trim();
|
|
11541
|
-
return (cleaned || "file").slice(-100);
|
|
11542
|
-
}
|
|
11543
|
-
function encodeKeyForUrl(key) {
|
|
11544
|
-
return key.split("/").map(encodeURIComponent).join("/");
|
|
11545
|
-
}
|
|
11546
|
-
function createUploadsRouter() {
|
|
11547
|
-
const app = new Hono17();
|
|
11548
|
-
app.post("/uploads", async (c) => {
|
|
11549
|
-
const body = await c.req.parseBody().catch(() => null);
|
|
11550
|
-
const file = body?.["file"];
|
|
11551
|
-
if (!(file instanceof File)) return c.json({ error: "missing file" }, 400);
|
|
11552
|
-
if (file.size > MAX_FILE_BYTES) {
|
|
11553
|
-
return c.json({ error: `file must be ${MAX_FILE_BYTES / (1024 * 1024)}MB or smaller` }, 400);
|
|
11554
|
-
}
|
|
11555
|
-
const key = `${KEY_PREFIX}/${getProfile()}/${randomUUID3()}-${sanitizeFilename(file.name)}`;
|
|
11556
|
-
const buffer = Buffer.from(await file.arrayBuffer());
|
|
11557
|
-
await getR2Client().send(
|
|
11558
|
-
new PutObjectCommand3({
|
|
11559
|
-
Bucket: getR2Bucket(),
|
|
11560
|
-
Key: key,
|
|
11561
|
-
Body: buffer,
|
|
11562
|
-
ContentType: file.type || "application/octet-stream"
|
|
11563
|
-
})
|
|
11564
|
-
);
|
|
11565
|
-
return c.json(
|
|
11566
|
-
{
|
|
11567
|
-
url: `/api/attachments/${encodeKeyForUrl(key)}`,
|
|
11568
|
-
name: file.name,
|
|
11569
|
-
type: file.type,
|
|
11570
|
-
size: file.size
|
|
11571
|
-
},
|
|
11572
|
-
201
|
|
11573
|
-
);
|
|
11574
|
-
});
|
|
11575
|
-
app.get("/attachments/:key{.+}", async (c) => {
|
|
11576
|
-
const key = c.req.param("key");
|
|
11577
|
-
if (!READABLE_PREFIXES.some((prefix) => key.startsWith(`${prefix}/`))) {
|
|
11578
|
-
return c.json({ error: "not found" }, 404);
|
|
11579
|
-
}
|
|
11580
|
-
const url = await getSignedUrl3(
|
|
11581
|
-
getR2Client(),
|
|
11582
|
-
new GetObjectCommand3({ Bucket: getR2Bucket(), Key: key }),
|
|
11583
|
-
{ expiresIn: PRESIGN_TTL_SECONDS2 }
|
|
11584
|
-
);
|
|
11585
|
-
c.header("Cache-Control", `private, max-age=${PRESIGN_TTL_SECONDS2 - 60}`);
|
|
11586
|
-
return c.redirect(url, 302);
|
|
11587
|
-
});
|
|
11588
|
-
return app;
|
|
11589
|
-
}
|
|
11590
|
-
|
|
11591
11645
|
// ../api/src/dashboard/transcribe-routes.ts
|
|
11592
11646
|
import { Hono as Hono18 } from "hono";
|
|
11593
11647
|
var GROQ_TRANSCRIBE_URL = "https://api.groq.com/openai/v1/audio/transcriptions";
|
|
@@ -13245,7 +13299,7 @@ async function sessionUsageForThreads(workspace, threadTsList) {
|
|
|
13245
13299
|
}
|
|
13246
13300
|
|
|
13247
13301
|
// ../api/src/dashboard/usage-report.ts
|
|
13248
|
-
import { existsSync as
|
|
13302
|
+
import { existsSync as existsSync19 } from "fs";
|
|
13249
13303
|
function mergeByLabel(buckets) {
|
|
13250
13304
|
const merged = /* @__PURE__ */ new Map();
|
|
13251
13305
|
for (const bucket of buckets) {
|
|
@@ -13291,7 +13345,7 @@ function toReport(days, rows, labelChannel) {
|
|
|
13291
13345
|
};
|
|
13292
13346
|
}
|
|
13293
13347
|
function fromLocalStore(days, labelChannel) {
|
|
13294
|
-
const store =
|
|
13348
|
+
const store = existsSync19(paths.DB_FILE) ? getLocalCache().openUsageStore(paths.DB_FILE) : null;
|
|
13295
13349
|
if (!store) return { ...EMPTY, days };
|
|
13296
13350
|
const window = days === 0 ? void 0 : days;
|
|
13297
13351
|
try {
|
|
@@ -13333,7 +13387,7 @@ async function buildChannelUsageReport(channelId, days, labelChannel) {
|
|
|
13333
13387
|
const { totals, byDay } = await channelUsageForWorkspace(workspace, aliasIds, window);
|
|
13334
13388
|
return { days, totals: totals.runs > 0 ? totals : null, byDay };
|
|
13335
13389
|
} catch {
|
|
13336
|
-
const store =
|
|
13390
|
+
const store = existsSync19(paths.DB_FILE) ? getLocalCache().openUsageStore(paths.DB_FILE) : null;
|
|
13337
13391
|
if (!store) return { days, totals: null, byDay: [] };
|
|
13338
13392
|
try {
|
|
13339
13393
|
const targetLabel = labelChannel(channelId);
|
|
@@ -13355,7 +13409,7 @@ async function buildThreadUsage(threadTs) {
|
|
|
13355
13409
|
if (totals.runs === 0) return { threadTs, totals: null, byModel: [] };
|
|
13356
13410
|
return { threadTs, totals, byModel };
|
|
13357
13411
|
} catch {
|
|
13358
|
-
const store =
|
|
13412
|
+
const store = existsSync19(paths.DB_FILE) ? getLocalCache().openUsageStore(paths.DB_FILE) : null;
|
|
13359
13413
|
if (!store) return { threadTs, totals: null, byModel: [] };
|
|
13360
13414
|
try {
|
|
13361
13415
|
const totals = store.threadTotals(threadTs);
|
|
@@ -13793,7 +13847,7 @@ function registerDataRoutes(api, agent = {}) {
|
|
|
13793
13847
|
runs.set(name, { lastRun: run4.lastRunAt.toISOString(), lastStatus: run4.lastStatus });
|
|
13794
13848
|
}
|
|
13795
13849
|
} catch {
|
|
13796
|
-
const runStore =
|
|
13850
|
+
const runStore = existsSync20(paths.DB_FILE) ? getLocalCache().openAutomationRunStore(paths.DB_FILE) : null;
|
|
13797
13851
|
if (runStore) {
|
|
13798
13852
|
try {
|
|
13799
13853
|
for (const run4 of runStore.listLastRuns()) {
|
|
@@ -13855,7 +13909,7 @@ function registerDataRoutes(api, agent = {}) {
|
|
|
13855
13909
|
const runs = (await recentRunsForWorkspace(getProfile(), 200)).map(toResponse5);
|
|
13856
13910
|
return c.json({ runs });
|
|
13857
13911
|
} catch {
|
|
13858
|
-
const runStore =
|
|
13912
|
+
const runStore = existsSync20(paths.DB_FILE) ? getLocalCache().openAutomationRunStore(paths.DB_FILE) : null;
|
|
13859
13913
|
if (!runStore) return c.json({ runs: [] });
|
|
13860
13914
|
try {
|
|
13861
13915
|
const runs = runStore.listRuns(200).map(toResponse5);
|
|
@@ -13977,7 +14031,7 @@ function registerDataRoutes(api, agent = {}) {
|
|
|
13977
14031
|
} catch {
|
|
13978
14032
|
latest2 = /* @__PURE__ */ new Map();
|
|
13979
14033
|
totals = /* @__PURE__ */ new Map();
|
|
13980
|
-
const usageStore =
|
|
14034
|
+
const usageStore = existsSync20(paths.DB_FILE) ? getLocalCache().openUsageStore(paths.DB_FILE) : null;
|
|
13981
14035
|
if (usageStore) {
|
|
13982
14036
|
try {
|
|
13983
14037
|
latest2 = usageStore.latestByThread(threadTsList);
|
|
@@ -14243,11 +14297,11 @@ function createDeviceAuthRouter() {
|
|
|
14243
14297
|
}
|
|
14244
14298
|
|
|
14245
14299
|
// ../api/src/dashboard/skills-routes.ts
|
|
14246
|
-
import { dirname as
|
|
14300
|
+
import { dirname as dirname7 } from "path";
|
|
14247
14301
|
|
|
14248
14302
|
// ../api/src/dashboard/skill-mirror.ts
|
|
14249
14303
|
import { createHash as createHash11 } from "crypto";
|
|
14250
|
-
import { existsSync as
|
|
14304
|
+
import { existsSync as existsSync21, statSync as statSync4 } from "fs";
|
|
14251
14305
|
var SYNC_INTERVAL_MS = 6e4;
|
|
14252
14306
|
var UPSERT_BATCH = 50;
|
|
14253
14307
|
function mirrorScopeOf(ref) {
|
|
@@ -14255,7 +14309,7 @@ function mirrorScopeOf(ref) {
|
|
|
14255
14309
|
}
|
|
14256
14310
|
function isDir(path) {
|
|
14257
14311
|
try {
|
|
14258
|
-
return
|
|
14312
|
+
return existsSync21(path) && statSync4(path).isDirectory();
|
|
14259
14313
|
} catch {
|
|
14260
14314
|
return false;
|
|
14261
14315
|
}
|
|
@@ -14580,12 +14634,12 @@ function createGatedRouter(agent, register) {
|
|
|
14580
14634
|
}
|
|
14581
14635
|
|
|
14582
14636
|
// src/dashboard/host-api.ts
|
|
14583
|
-
import { existsSync as
|
|
14637
|
+
import { existsSync as existsSync30, readFileSync as readFileSync24, statSync as statSync8 } from "fs";
|
|
14584
14638
|
import { join as join26 } from "path";
|
|
14585
14639
|
import sharp6 from "sharp";
|
|
14586
14640
|
|
|
14587
14641
|
// src/dashboard/channels-routes.ts
|
|
14588
|
-
import { existsSync as
|
|
14642
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync10 } from "fs";
|
|
14589
14643
|
import { Hono as Hono30 } from "hono";
|
|
14590
14644
|
function coerceAccess(raw) {
|
|
14591
14645
|
if (raw === "open" || raw === "*" || raw === "all") return raw;
|
|
@@ -14624,7 +14678,7 @@ function coerceMemberEmails(raw) {
|
|
|
14624
14678
|
function ensureCwdDir(cwd) {
|
|
14625
14679
|
const expanded = expandPath(cwd);
|
|
14626
14680
|
if (isLogicalCwd(cwd) || isUnderLogicalRoot(expanded)) return;
|
|
14627
|
-
if (!
|
|
14681
|
+
if (!existsSync22(expanded)) mkdirSync10(expanded, { recursive: true });
|
|
14628
14682
|
}
|
|
14629
14683
|
function toResponse3(channel) {
|
|
14630
14684
|
return {
|
|
@@ -14774,13 +14828,13 @@ function createChannelWriteRouter() {
|
|
|
14774
14828
|
import {
|
|
14775
14829
|
closeSync as closeSync2,
|
|
14776
14830
|
createReadStream,
|
|
14777
|
-
existsSync as
|
|
14831
|
+
existsSync as existsSync26,
|
|
14778
14832
|
lstatSync as lstatSync2,
|
|
14779
14833
|
mkdirSync as mkdirSync11,
|
|
14780
14834
|
openSync as openSync2,
|
|
14781
14835
|
readSync as readSync2,
|
|
14782
14836
|
readdirSync as readdirSync5,
|
|
14783
|
-
readFileSync as
|
|
14837
|
+
readFileSync as readFileSync21,
|
|
14784
14838
|
realpathSync as realpathSync4,
|
|
14785
14839
|
renameSync,
|
|
14786
14840
|
rmSync as rmSync8,
|
|
@@ -14788,12 +14842,12 @@ import {
|
|
|
14788
14842
|
writeFileSync as writeFileSync11
|
|
14789
14843
|
} from "fs";
|
|
14790
14844
|
import { Readable } from "stream";
|
|
14791
|
-
import { basename as basename8, dirname as
|
|
14845
|
+
import { basename as basename8, dirname as dirname8, extname, join as join23, relative, resolve as resolve5, sep } from "path";
|
|
14792
14846
|
import { Hono as Hono31 } from "hono";
|
|
14793
14847
|
import { streamSSE as streamSSE2 } from "hono/streaming";
|
|
14794
14848
|
|
|
14795
14849
|
// src/dashboard/docs-watcher.ts
|
|
14796
|
-
import { existsSync as
|
|
14850
|
+
import { existsSync as existsSync23, watch } from "fs";
|
|
14797
14851
|
import { basename as basename6, join as join18 } from "path";
|
|
14798
14852
|
var DEBOUNCE_MS = 200;
|
|
14799
14853
|
var MAX_PENDING = 200;
|
|
@@ -14835,7 +14889,7 @@ function watchDocs(cwd, listener) {
|
|
|
14835
14889
|
const current = entries.get(cwd);
|
|
14836
14890
|
if (!current || filename === null) return;
|
|
14837
14891
|
const rel = filename.split("\\").join("/");
|
|
14838
|
-
if (rel === root && !
|
|
14892
|
+
if (rel === root && !existsSync23(join18(cwd, rel))) return;
|
|
14839
14893
|
if (isIgnoredDocPath(rel)) return;
|
|
14840
14894
|
if (current.pending.size < MAX_PENDING) current.pending.add(rel);
|
|
14841
14895
|
if (current.timer === null) current.timer = setTimeout(() => flush(cwd), DEBOUNCE_MS);
|
|
@@ -15072,7 +15126,7 @@ async function readOrQueueDocAudio(input2) {
|
|
|
15072
15126
|
}
|
|
15073
15127
|
|
|
15074
15128
|
// src/dashboard/artifact-export.ts
|
|
15075
|
-
import { readFileSync as
|
|
15129
|
+
import { readFileSync as readFileSync20 } from "fs";
|
|
15076
15130
|
|
|
15077
15131
|
// src/dashboard/chat-agent.ts
|
|
15078
15132
|
import { homedir as homedir9 } from "os";
|
|
@@ -15290,7 +15344,7 @@ async function withMcpConfig(profile, connectionIds, fn) {
|
|
|
15290
15344
|
}
|
|
15291
15345
|
|
|
15292
15346
|
// src/claude/agents.ts
|
|
15293
|
-
import { existsSync as
|
|
15347
|
+
import { existsSync as existsSync24, readdirSync as readdirSync4, readFileSync as readFileSync18 } from "fs";
|
|
15294
15348
|
import { homedir as homedir8 } from "os";
|
|
15295
15349
|
import { basename as basename7, join as join20 } from "path";
|
|
15296
15350
|
import yaml2 from "js-yaml";
|
|
@@ -15305,7 +15359,7 @@ function expandHome(p) {
|
|
|
15305
15359
|
function parseFrontmatter(file) {
|
|
15306
15360
|
let content;
|
|
15307
15361
|
try {
|
|
15308
|
-
content =
|
|
15362
|
+
content = readFileSync18(file, "utf-8");
|
|
15309
15363
|
} catch {
|
|
15310
15364
|
return {};
|
|
15311
15365
|
}
|
|
@@ -15321,7 +15375,7 @@ function parseFrontmatter(file) {
|
|
|
15321
15375
|
}
|
|
15322
15376
|
}
|
|
15323
15377
|
function collectFrom(root, source) {
|
|
15324
|
-
if (!
|
|
15378
|
+
if (!existsSync24(root)) return [];
|
|
15325
15379
|
let entries2;
|
|
15326
15380
|
try {
|
|
15327
15381
|
entries2 = readdirSync4(root).filter((f) => f.endsWith(".md"));
|
|
@@ -15351,7 +15405,7 @@ function readAgentPersona(configDir2, cwd, name) {
|
|
|
15351
15405
|
const agent = listAgents(configDir2, cwd).find((a) => a.name === name);
|
|
15352
15406
|
if (!agent) return void 0;
|
|
15353
15407
|
try {
|
|
15354
|
-
const content =
|
|
15408
|
+
const content = readFileSync18(agent.path, "utf-8");
|
|
15355
15409
|
return content.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "").trim();
|
|
15356
15410
|
} catch {
|
|
15357
15411
|
return void 0;
|
|
@@ -15360,7 +15414,7 @@ function readAgentPersona(configDir2, cwd, name) {
|
|
|
15360
15414
|
|
|
15361
15415
|
// src/dashboard/memory-extraction-runner.ts
|
|
15362
15416
|
import { spawn as spawn4 } from "child_process";
|
|
15363
|
-
import { mkdtempSync as mkdtempSync2, readFileSync as
|
|
15417
|
+
import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync19, rmSync as rmSync7 } from "fs";
|
|
15364
15418
|
import { tmpdir as tmpdir4 } from "os";
|
|
15365
15419
|
import { join as join21 } from "path";
|
|
15366
15420
|
var CLAUDE_MODEL = "sonnet";
|
|
@@ -15452,7 +15506,7 @@ function run3(inv, cwd) {
|
|
|
15452
15506
|
let raw = stdout;
|
|
15453
15507
|
if (inv.outputFile) {
|
|
15454
15508
|
try {
|
|
15455
|
-
raw =
|
|
15509
|
+
raw = readFileSync19(inv.outputFile, "utf-8");
|
|
15456
15510
|
} catch {
|
|
15457
15511
|
raw = "";
|
|
15458
15512
|
}
|
|
@@ -15769,23 +15823,43 @@ function extractAttachmentKeys(body) {
|
|
|
15769
15823
|
}
|
|
15770
15824
|
return keys;
|
|
15771
15825
|
}
|
|
15826
|
+
async function fetchObject(key) {
|
|
15827
|
+
if (process.env["CLOUDFLARE_R2_ACCESS_KEY_ID"]) {
|
|
15828
|
+
const response2 = await getR2Client().send(
|
|
15829
|
+
new GetObjectCommand5({ Bucket: getR2Bucket(), Key: key })
|
|
15830
|
+
);
|
|
15831
|
+
return {
|
|
15832
|
+
mimetype: response2.ContentType ?? "application/octet-stream",
|
|
15833
|
+
contentLength: response2.ContentLength,
|
|
15834
|
+
read: async () => response2.Body?.transformToByteArray()
|
|
15835
|
+
};
|
|
15836
|
+
}
|
|
15837
|
+
const url = await requestAttachmentUrl(key);
|
|
15838
|
+
if (!url) throw new Error("Data API refused the attachment");
|
|
15839
|
+
const response = await fetch(url);
|
|
15840
|
+
if (!response.ok) throw new Error(`presigned GET answered ${response.status}`);
|
|
15841
|
+
const length = response.headers.get("content-length");
|
|
15842
|
+
return {
|
|
15843
|
+
mimetype: response.headers.get("content-type") ?? "application/octet-stream",
|
|
15844
|
+
contentLength: length === null ? void 0 : Number(length),
|
|
15845
|
+
read: async () => new Uint8Array(await response.arrayBuffer())
|
|
15846
|
+
};
|
|
15847
|
+
}
|
|
15772
15848
|
async function downloadOne(key) {
|
|
15773
15849
|
const lastSegment = key.slice(key.lastIndexOf("/") + 1);
|
|
15774
15850
|
const name = displayName(lastSegment);
|
|
15775
15851
|
try {
|
|
15776
|
-
const response = await
|
|
15777
|
-
|
|
15778
|
-
);
|
|
15779
|
-
const mimetype = response.ContentType ?? "application/octet-stream";
|
|
15852
|
+
const response = await fetchObject(key);
|
|
15853
|
+
const mimetype = response.mimetype;
|
|
15780
15854
|
const sizeLimit = mimetypeSizeLimit(mimetype);
|
|
15781
15855
|
if (sizeLimit === null) {
|
|
15782
15856
|
if (debug) console.log(`[attachment-downloader] unsupported mimetype: ${mimetype} (${key})`);
|
|
15783
15857
|
return { kind: "skip", skipped: { name, mimetype, reason: "unsupported" } };
|
|
15784
15858
|
}
|
|
15785
|
-
if (response.
|
|
15859
|
+
if (response.contentLength !== void 0 && response.contentLength > sizeLimit) {
|
|
15786
15860
|
return { kind: "skip", skipped: { name, mimetype, reason: "too_large" } };
|
|
15787
15861
|
}
|
|
15788
|
-
const bytes = await response.
|
|
15862
|
+
const bytes = await response.read();
|
|
15789
15863
|
if (!bytes) {
|
|
15790
15864
|
return { kind: "skip", skipped: { name, mimetype, reason: "download_failed" } };
|
|
15791
15865
|
}
|
|
@@ -15817,11 +15891,11 @@ async function downloadChatAttachments(body) {
|
|
|
15817
15891
|
}
|
|
15818
15892
|
|
|
15819
15893
|
// src/dashboard/doc-mention-guard.ts
|
|
15820
|
-
import { existsSync as
|
|
15894
|
+
import { existsSync as existsSync25, statSync as statSync5 } from "fs";
|
|
15821
15895
|
var DOC_MENTION_RE = /(?<![\w@/`])@((?:[\w.-]+\/)+[\w.-]+\.[A-Za-z0-9]{1,6})(?::(\d+))?(?![\w-])/g;
|
|
15822
15896
|
function isRealDoc(root, rel) {
|
|
15823
15897
|
const abs = resolveDocPath(root, rel);
|
|
15824
|
-
if (!abs || !
|
|
15898
|
+
if (!abs || !existsSync25(abs)) return false;
|
|
15825
15899
|
try {
|
|
15826
15900
|
return statSync5(abs).isFile();
|
|
15827
15901
|
} catch {
|
|
@@ -17091,7 +17165,7 @@ async function exportDocAsArtifact(channelId, docPath) {
|
|
|
17091
17165
|
);
|
|
17092
17166
|
const abs = resolveDocPath(channelConfig.cwd, docPath);
|
|
17093
17167
|
if (!abs) throw new Error(`doc not found: ${docPath}`);
|
|
17094
|
-
const content =
|
|
17168
|
+
const content = readFileSync20(abs, "utf8");
|
|
17095
17169
|
const title = extractTitle(abs, "md");
|
|
17096
17170
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
17097
17171
|
const prompt = `Publish the document at \`${docPath}\` (already read below) as a Claude Artifact, then record the result as a stub file under this channel's \`docs/artifacts/\` folder (create the folder if it doesn't exist).
|
|
@@ -17372,12 +17446,12 @@ function readGitBranch(dir) {
|
|
|
17372
17446
|
try {
|
|
17373
17447
|
let gitDir = join23(dir, ".git");
|
|
17374
17448
|
if (statSync6(gitDir).isFile()) {
|
|
17375
|
-
const pointer =
|
|
17449
|
+
const pointer = readFileSync21(gitDir, "utf8").trim();
|
|
17376
17450
|
const match = pointer.match(/^gitdir:\s*(.+)$/);
|
|
17377
17451
|
if (!match) return void 0;
|
|
17378
17452
|
gitDir = resolve5(dir, match[1]);
|
|
17379
17453
|
}
|
|
17380
|
-
const head =
|
|
17454
|
+
const head = readFileSync21(join23(gitDir, "HEAD"), "utf8").trim();
|
|
17381
17455
|
const branchMatch = head.match(/^ref:\s*refs\/heads\/(.+)$/);
|
|
17382
17456
|
if (branchMatch) return branchMatch[1];
|
|
17383
17457
|
return /^[0-9a-f]{7,40}$/i.test(head) ? head.slice(0, 7) : void 0;
|
|
@@ -17406,7 +17480,7 @@ function listDocLevel(root, relDir = "", sort = "newest", showHidden = false) {
|
|
|
17406
17480
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
17407
17481
|
const probe3 = probeDir(abs, showHidden);
|
|
17408
17482
|
if (!probe3.hasDocs && probe3.hasOther) continue;
|
|
17409
|
-
const isRepo =
|
|
17483
|
+
const isRepo = existsSync26(join23(abs, ".git"));
|
|
17410
17484
|
dirs.push({
|
|
17411
17485
|
path,
|
|
17412
17486
|
name: entry.name,
|
|
@@ -17612,7 +17686,7 @@ function moveDocEntry(root, from, to) {
|
|
|
17612
17686
|
return { status: "bad-target" };
|
|
17613
17687
|
}
|
|
17614
17688
|
}
|
|
17615
|
-
const absToDir =
|
|
17689
|
+
const absToDir = dirname8(absTo);
|
|
17616
17690
|
if (resolveDirPath(root, relative(root, absToDir)) === null) return { status: "bad-target" };
|
|
17617
17691
|
try {
|
|
17618
17692
|
if (!statSync6(absToDir).isDirectory()) return { status: "bad-target" };
|
|
@@ -17703,7 +17777,7 @@ function createDocsRouter({ gate = requireDocsAccess } = {}) {
|
|
|
17703
17777
|
}
|
|
17704
17778
|
if (!stat.isFile()) return c.json({ error: "not found" }, 404);
|
|
17705
17779
|
if (stat.size > MAX_RAW_BYTES) return c.json({ error: "file too large" }, 413);
|
|
17706
|
-
return c.body(withDocLinkBridge(
|
|
17780
|
+
return c.body(withDocLinkBridge(readFileSync21(abs, "utf8")), 200, {
|
|
17707
17781
|
"Content-Type": "text/html; charset=utf-8",
|
|
17708
17782
|
"Content-Security-Policy": HTML_SHARE_CSP,
|
|
17709
17783
|
"X-Content-Type-Options": "nosniff",
|
|
@@ -17888,7 +17962,7 @@ function createDocsRouter({ gate = requireDocsAccess } = {}) {
|
|
|
17888
17962
|
title: kind ? extractTitle(abs, kind) : basename8(abs),
|
|
17889
17963
|
mtime: stat.mtime.toISOString(),
|
|
17890
17964
|
tooLarge: tooLarge || void 0,
|
|
17891
|
-
content: tooLarge ? "" :
|
|
17965
|
+
content: tooLarge ? "" : readFileSync21(abs, "utf8")
|
|
17892
17966
|
});
|
|
17893
17967
|
});
|
|
17894
17968
|
app.put("/:id/docs/content", async (c) => {
|
|
@@ -17931,7 +18005,7 @@ function createDocsRouter({ gate = requireDocsAccess } = {}) {
|
|
|
17931
18005
|
channel,
|
|
17932
18006
|
rel,
|
|
17933
18007
|
title: extractTitle(abs, "md"),
|
|
17934
|
-
content:
|
|
18008
|
+
content: readFileSync21(abs, "utf8")
|
|
17935
18009
|
};
|
|
17936
18010
|
};
|
|
17937
18011
|
app.get("/:id/docs/translation/:lang", async (c) => {
|
|
@@ -17986,8 +18060,8 @@ function withDocLinkBridge(html) {
|
|
|
17986
18060
|
}
|
|
17987
18061
|
|
|
17988
18062
|
// src/dashboard/skills-routes-host.ts
|
|
17989
|
-
import { existsSync as
|
|
17990
|
-
import { dirname as
|
|
18063
|
+
import { existsSync as existsSync27, statSync as statSync7 } from "fs";
|
|
18064
|
+
import { dirname as dirname9 } from "path";
|
|
17991
18065
|
import { Hono as Hono32 } from "hono";
|
|
17992
18066
|
function workspaceScope() {
|
|
17993
18067
|
const claudeConfigDir = profileClaudeConfigDir();
|
|
@@ -17995,7 +18069,7 @@ function workspaceScope() {
|
|
|
17995
18069
|
return {
|
|
17996
18070
|
dir: workspaceSkillsDir(claudeConfigDir),
|
|
17997
18071
|
// `~/.claude` itself, which exists wherever the CLI has ever run.
|
|
17998
|
-
root:
|
|
18072
|
+
root: dirname9(workspaceSkillsDir(claudeConfigDir)),
|
|
17999
18073
|
cwd,
|
|
18000
18074
|
claudeConfigDir,
|
|
18001
18075
|
// Only plugin skills. Project skills belong to a specific channel's cwd, so
|
|
@@ -18021,7 +18095,7 @@ function inheritedSkills(scope, own) {
|
|
|
18021
18095
|
}
|
|
18022
18096
|
function rootExists(dir) {
|
|
18023
18097
|
try {
|
|
18024
|
-
return
|
|
18098
|
+
return existsSync27(dir) && statSync7(dir).isDirectory();
|
|
18025
18099
|
} catch {
|
|
18026
18100
|
return false;
|
|
18027
18101
|
}
|
|
@@ -18131,7 +18205,7 @@ async function resolveAgentIdentities() {
|
|
|
18131
18205
|
|
|
18132
18206
|
// ../api/src/dashboard/providers.ts
|
|
18133
18207
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
18134
|
-
import { existsSync as
|
|
18208
|
+
import { existsSync as existsSync28, readFileSync as readFileSync22 } from "fs";
|
|
18135
18209
|
import { homedir as homedir10 } from "os";
|
|
18136
18210
|
import { join as join24, resolve as resolve6 } from "path";
|
|
18137
18211
|
var PROVIDER_LABELS = {
|
|
@@ -18154,7 +18228,7 @@ function binaryOnPath(bin) {
|
|
|
18154
18228
|
function claudeAuthAvailable() {
|
|
18155
18229
|
if (profileEnv("CLAUDE_CODE_OAUTH_TOKEN")?.trim()) return true;
|
|
18156
18230
|
const configDir2 = profileClaudeConfigDir() || resolve6(homedir10(), ".claude");
|
|
18157
|
-
if (
|
|
18231
|
+
if (existsSync28(join24(configDir2, ".credentials.json"))) return true;
|
|
18158
18232
|
if (process.platform !== "darwin") return false;
|
|
18159
18233
|
try {
|
|
18160
18234
|
execFileSync4("security", ["find-generic-password", "-s", "Claude Code-credentials"], {
|
|
@@ -18200,7 +18274,7 @@ function claudeAccount() {
|
|
|
18200
18274
|
function codexAccount() {
|
|
18201
18275
|
const home2 = process.env["CODEX_HOME"]?.trim() || join24(homedir10(), ".codex");
|
|
18202
18276
|
try {
|
|
18203
|
-
const auth = JSON.parse(
|
|
18277
|
+
const auth = JSON.parse(readFileSync22(join24(home2, "auth.json"), "utf8"));
|
|
18204
18278
|
const payload = auth.tokens?.id_token?.split(".")[1];
|
|
18205
18279
|
if (!payload) return void 0;
|
|
18206
18280
|
const claims = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
@@ -18231,9 +18305,9 @@ function providerStatuses() {
|
|
|
18231
18305
|
// src/dashboard/provider-login-host.ts
|
|
18232
18306
|
import { spawn as spawn6 } from "child_process";
|
|
18233
18307
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
18234
|
-
import { chmodSync, existsSync as
|
|
18308
|
+
import { chmodSync, existsSync as existsSync29, mkdirSync as mkdirSync12, readFileSync as readFileSync23, writeFileSync as writeFileSync12 } from "fs";
|
|
18235
18309
|
import { createRequire } from "module";
|
|
18236
|
-
import { dirname as
|
|
18310
|
+
import { dirname as dirname10, join as join25 } from "path";
|
|
18237
18311
|
import { Hono as Hono33 } from "hono";
|
|
18238
18312
|
var SESSION_TTL_MS = 10 * 6e4;
|
|
18239
18313
|
var URL_WAIT_MS = 3e4;
|
|
@@ -18296,10 +18370,10 @@ function waitFor(s, parse, ms) {
|
|
|
18296
18370
|
}
|
|
18297
18371
|
function loadPty() {
|
|
18298
18372
|
const require2 = createRequire(import.meta.url);
|
|
18299
|
-
const root =
|
|
18373
|
+
const root = dirname10(require2.resolve("node-pty/package.json"));
|
|
18300
18374
|
const helper = join25(root, "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper");
|
|
18301
18375
|
try {
|
|
18302
|
-
if (
|
|
18376
|
+
if (existsSync29(helper)) chmodSync(helper, 493);
|
|
18303
18377
|
} catch {
|
|
18304
18378
|
}
|
|
18305
18379
|
return require2("node-pty");
|
|
@@ -18339,8 +18413,8 @@ async function startClaude() {
|
|
|
18339
18413
|
return { id, url };
|
|
18340
18414
|
}
|
|
18341
18415
|
function saveClaudeToken(configFile, token) {
|
|
18342
|
-
mkdirSync12(
|
|
18343
|
-
const current =
|
|
18416
|
+
mkdirSync12(dirname10(configFile), { recursive: true });
|
|
18417
|
+
const current = existsSync29(configFile) ? readFileSync23(configFile, "utf-8") : "";
|
|
18344
18418
|
writeFileSync12(configFile, upsertEnvLine(current, "CLAUDE_CODE_OAUTH_TOKEN", token), { mode: 384 });
|
|
18345
18419
|
const cached = cachedProfileConfig();
|
|
18346
18420
|
if (cached) cached.env["CLAUDE_CODE_OAUTH_TOKEN"] = token;
|
|
@@ -18559,7 +18633,7 @@ function registerHostRoutes(api) {
|
|
|
18559
18633
|
const limit = Math.min(Number(c.req.query("limit")) || 200, 2e3);
|
|
18560
18634
|
const filename = errors ? "custie-error.log" : "custie.log";
|
|
18561
18635
|
const file = join26(paths.LOG_DIR, filename);
|
|
18562
|
-
const exists =
|
|
18636
|
+
const exists = existsSync30(file);
|
|
18563
18637
|
return c.json({
|
|
18564
18638
|
file,
|
|
18565
18639
|
exists,
|
|
@@ -18569,8 +18643,8 @@ function registerHostRoutes(api) {
|
|
|
18569
18643
|
});
|
|
18570
18644
|
}
|
|
18571
18645
|
function tailFile(file, limit) {
|
|
18572
|
-
if (!
|
|
18573
|
-
const lines =
|
|
18646
|
+
if (!existsSync30(file)) return [];
|
|
18647
|
+
const lines = readFileSync24(file, "utf-8").split("\n");
|
|
18574
18648
|
if (lines.at(-1) === "") lines.pop();
|
|
18575
18649
|
return lines.slice(-limit);
|
|
18576
18650
|
}
|
|
@@ -18588,7 +18662,7 @@ function createHostApiRouter(agent = {}) {
|
|
|
18588
18662
|
|
|
18589
18663
|
// src/dashboard/agent-bridge-host.ts
|
|
18590
18664
|
import { sign as signRaw, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
18591
|
-
import { existsSync as
|
|
18665
|
+
import { existsSync as existsSync31, readFileSync as readFileSync26 } from "fs";
|
|
18592
18666
|
import dotenv2 from "dotenv";
|
|
18593
18667
|
import { WebSocket as WebSocket2 } from "ws";
|
|
18594
18668
|
|
|
@@ -18622,7 +18696,7 @@ async function handleHostRequest(req) {
|
|
|
18622
18696
|
}
|
|
18623
18697
|
|
|
18624
18698
|
// src/dashboard/doc-share-publisher.ts
|
|
18625
|
-
import { readFileSync as
|
|
18699
|
+
import { readFileSync as readFileSync25, statSync as statSync9 } from "fs";
|
|
18626
18700
|
import { extname as extname2, posix } from "path";
|
|
18627
18701
|
var MAX_ASSET_BYTES = 20 * 1024 * 1024;
|
|
18628
18702
|
var MAX_CONTENT_BYTES2 = 2 * 1024 * 1024;
|
|
@@ -18737,7 +18811,7 @@ function readDocShareBundle({ cwd, sourcePath }) {
|
|
|
18737
18811
|
}
|
|
18738
18812
|
if (!stat.isFile()) return { status: "not-found" };
|
|
18739
18813
|
if (stat.size > MAX_CONTENT_BYTES2) return { status: "too-large" };
|
|
18740
|
-
const source =
|
|
18814
|
+
const source = readFileSync25(abs, "utf8");
|
|
18741
18815
|
const title = extractTitle(abs, kind === "markdown" ? "md" : kind);
|
|
18742
18816
|
if (kind === "excalidraw") {
|
|
18743
18817
|
try {
|
|
@@ -18808,7 +18882,7 @@ function readDocShareBundle({ cwd, sourcePath }) {
|
|
|
18808
18882
|
let text = null;
|
|
18809
18883
|
try {
|
|
18810
18884
|
const size = statSync9(docAbs).size;
|
|
18811
|
-
if (size <= budget) text =
|
|
18885
|
+
if (size <= budget) text = readFileSync25(docAbs, "utf8");
|
|
18812
18886
|
} catch {
|
|
18813
18887
|
continue;
|
|
18814
18888
|
}
|
|
@@ -18825,7 +18899,7 @@ function readDocShareBundle({ cwd, sourcePath }) {
|
|
|
18825
18899
|
let body;
|
|
18826
18900
|
try {
|
|
18827
18901
|
if (statSync9(resolved2.abs).size > MAX_ASSET_BYTES) continue;
|
|
18828
|
-
body =
|
|
18902
|
+
body = readFileSync25(resolved2.abs);
|
|
18829
18903
|
} catch {
|
|
18830
18904
|
continue;
|
|
18831
18905
|
}
|
|
@@ -18880,7 +18954,7 @@ function dataSocketUrl() {
|
|
|
18880
18954
|
return `ws://127.0.0.1:${process.env["FLYSPACE_DATA_API_PORT"] ?? DEFAULT_DATA_API_PORT}${HOST_SOCKET_PATH}`;
|
|
18881
18955
|
}
|
|
18882
18956
|
function listLocalSessions() {
|
|
18883
|
-
if (!
|
|
18957
|
+
if (!existsSync31(paths.DB_FILE)) return [];
|
|
18884
18958
|
const store = new SessionStore(paths.DB_FILE);
|
|
18885
18959
|
try {
|
|
18886
18960
|
return store.listSessions();
|
|
@@ -18922,7 +18996,7 @@ function buildHostConfigSnapshot() {
|
|
|
18922
18996
|
const snapshot2 = {};
|
|
18923
18997
|
for (const profile of listProfiles()) {
|
|
18924
18998
|
snapshot2[profile] = runWithProfile(profile, () => ({
|
|
18925
|
-
env:
|
|
18999
|
+
env: existsSync31(paths.CONFIG_FILE) ? dotenv2.parse(readFileSync26(paths.CONFIG_FILE, "utf-8")) : {},
|
|
18926
19000
|
agentModel: loadDashboardSettings().agent
|
|
18927
19001
|
}));
|
|
18928
19002
|
}
|
|
@@ -19002,6 +19076,10 @@ function connectHostSocket(url, callbacks, onAuthenticated, onWorkspaces) {
|
|
|
19002
19076
|
handleHostDbResult(msg.id, msg.res);
|
|
19003
19077
|
return;
|
|
19004
19078
|
}
|
|
19079
|
+
if (msg.type === "attachment-url-result") {
|
|
19080
|
+
handleAttachmentUrlResult(msg.id, msg.url);
|
|
19081
|
+
return;
|
|
19082
|
+
}
|
|
19005
19083
|
if (msg.type === "call") {
|
|
19006
19084
|
void handleCall(msg, callbacks, ws);
|
|
19007
19085
|
}
|
|
@@ -19168,7 +19246,7 @@ function startPushWatcher() {
|
|
|
19168
19246
|
}
|
|
19169
19247
|
|
|
19170
19248
|
// src/dashboard/machine-server.ts
|
|
19171
|
-
import { existsSync as
|
|
19249
|
+
import { existsSync as existsSync32 } from "fs";
|
|
19172
19250
|
import { join as join28 } from "path";
|
|
19173
19251
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
19174
19252
|
|
|
@@ -19271,14 +19349,14 @@ async function bootMachine() {
|
|
|
19271
19349
|
function mountSpa(app) {
|
|
19272
19350
|
app.route("/share", createPublicShareAssetRouter(WEB_DIST));
|
|
19273
19351
|
app.route("/", createAppIconRouter());
|
|
19274
|
-
if (
|
|
19352
|
+
if (existsSync32(WEB_DIST) || existsSync32(join28(paths.WEB_ROOT, "package.json"))) {
|
|
19275
19353
|
app.use("/*", serveStatic({ root: WEB_DIST }));
|
|
19276
19354
|
}
|
|
19277
19355
|
app.get("/assets/*", (c) => c.text("stale asset \u2014 reload for the current build", 404));
|
|
19278
19356
|
const spaFallback = serveStatic({ path: join28(WEB_DIST, "index.html") });
|
|
19279
19357
|
app.get("*", async (c, next) => {
|
|
19280
|
-
if (!
|
|
19281
|
-
const isCheckout =
|
|
19358
|
+
if (!existsSync32(join28(WEB_DIST, "index.html"))) {
|
|
19359
|
+
const isCheckout = existsSync32(join28(paths.WEB_ROOT, "package.json"));
|
|
19282
19360
|
return c.text(
|
|
19283
19361
|
isCheckout ? `Workspace UI build missing (${WEB_DIST}).
|
|
19284
19362
|
Run \`pnpm build:web\` from the repo root.
|
|
@@ -19412,8 +19490,8 @@ function openBrowser2(url) {
|
|
|
19412
19490
|
}
|
|
19413
19491
|
}
|
|
19414
19492
|
function ensureWebBuild() {
|
|
19415
|
-
if (
|
|
19416
|
-
if (!
|
|
19493
|
+
if (existsSync33(join29(paths.WEB_ROOT, "dist", "index.html"))) return;
|
|
19494
|
+
if (!existsSync33(join29(paths.WEB_ROOT, "package.json"))) return;
|
|
19417
19495
|
console.log(" packages/ui/dist missing, building the dashboard UI...");
|
|
19418
19496
|
const result = spawnSync("pnpm", ["build"], {
|
|
19419
19497
|
cwd: paths.WEB_ROOT,
|
|
@@ -19463,7 +19541,7 @@ async function runDashboard(args) {
|
|
|
19463
19541
|
}
|
|
19464
19542
|
|
|
19465
19543
|
// src/commands/workspace.ts
|
|
19466
|
-
import { existsSync as
|
|
19544
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync14, writeFileSync as writeFileSync13 } from "fs";
|
|
19467
19545
|
var USAGE7 = `
|
|
19468
19546
|
Usage: flyspace workspace <subcommand> [options]
|
|
19469
19547
|
|
|
@@ -19549,7 +19627,7 @@ function provisionLocal(botName) {
|
|
|
19549
19627
|
ensureDirs();
|
|
19550
19628
|
console.log(` config dir ready (${paths.CONFIG_DIR})`);
|
|
19551
19629
|
console.log(` data dir ready (${paths.DATA_DIR})`);
|
|
19552
|
-
if (
|
|
19630
|
+
if (existsSync34(paths.CONFIG_FILE)) {
|
|
19553
19631
|
console.log(" config.env exists");
|
|
19554
19632
|
} else {
|
|
19555
19633
|
writeFileSync13(paths.CONFIG_FILE, `BOT_NAME=${botName}
|
|
@@ -19566,7 +19644,7 @@ async function provisionChannels(specs) {
|
|
|
19566
19644
|
continue;
|
|
19567
19645
|
}
|
|
19568
19646
|
const cwd = expandPath(spec.cwd);
|
|
19569
|
-
if (!
|
|
19647
|
+
if (!existsSync34(cwd)) {
|
|
19570
19648
|
mkdirSync14(cwd, { recursive: true });
|
|
19571
19649
|
console.log(` created cwd ${cwd}`);
|
|
19572
19650
|
}
|
|
@@ -19785,7 +19863,7 @@ async function main() {
|
|
|
19785
19863
|
break;
|
|
19786
19864
|
case "-v":
|
|
19787
19865
|
case "--version":
|
|
19788
|
-
printRaw("0.1.
|
|
19866
|
+
printRaw("0.1.31");
|
|
19789
19867
|
break;
|
|
19790
19868
|
case "-h":
|
|
19791
19869
|
case "--help":
|