flyspace-cli 0.1.18 → 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.
@@ -11,19 +11,20 @@ import {
11
11
  paths,
12
12
  postToDashboardChannel,
13
13
  runWithProfile,
14
+ setSupabaseClientFactory,
14
15
  sweepScratchDir,
15
16
  syncPostToDashboard
16
- } from "./chunk-L3I3BPLP.js";
17
+ } from "./chunk-GYHCSGMJ.js";
17
18
 
18
19
  // src/index.ts
19
20
  import { execFile, spawn as spawn4 } from "child_process";
20
21
 
21
- // src/config.ts
22
+ // ../api/src/config.ts
22
23
  import dotenv from "dotenv";
23
24
  import { existsSync } from "fs";
24
25
  import { resolve } from "path";
25
26
 
26
- // src/effort.ts
27
+ // ../api/src/effort.ts
27
28
  var EFFORT_LEVELS = ["low", "medium", "high", "max"];
28
29
  function isEffort(value) {
29
30
  return EFFORT_LEVELS.includes(value);
@@ -47,7 +48,7 @@ function resolveCodexEffort(effort) {
47
48
  return CODEX_EFFORT[effort];
48
49
  }
49
50
 
50
- // src/config.ts
51
+ // ../api/src/config.ts
51
52
  var DEFAULT_CODEX_MODEL = "";
52
53
  function mcpStrictConfigEnabled() {
53
54
  return process.env["MCP_STRICT_CONFIG"]?.trim() === "true";
@@ -121,7 +122,7 @@ function loadConfig() {
121
122
  };
122
123
  }
123
124
 
124
- // src/automations/store.ts
125
+ // ../api/src/automations/store.ts
125
126
  function toAutomationType(kind) {
126
127
  return kind === "mention-trigger" ? "mention_trigger" : kind;
127
128
  }
@@ -263,7 +264,7 @@ function stopAutomationRegistryPolling() {
263
264
  }
264
265
  }
265
266
 
266
- // src/channels.ts
267
+ // ../api/src/channels.ts
267
268
  import { existsSync as existsSync2, mkdirSync, realpathSync, statSync } from "fs";
268
269
  import { homedir } from "os";
269
270
  import { isAbsolute, resolve as resolve2, sep } from "path";
@@ -710,27 +711,12 @@ async function ensureMemberDmChannel(a, b) {
710
711
  }
711
712
  }
712
713
 
713
- // src/automations/config.ts
714
- import { readFileSync, existsSync as existsSync3 } from "fs";
715
- import yaml from "js-yaml";
714
+ // ../api/src/automations/config.ts
716
715
  import cron from "node-cron";
717
716
  var DEFAULT_TIMEZONE = "Australia/Sydney";
718
- var EMPTY_CONFIG = { schedules: [], triggers: [], mention_triggers: [] };
719
717
  function loadAutomations() {
720
718
  return getStoredAutomations();
721
719
  }
722
- function loadAutomationsFile() {
723
- const filePath = paths.AUTOMATIONS_FILE;
724
- if (!existsSync3(filePath)) return { ...EMPTY_CONFIG };
725
- const raw = readFileSync(filePath, "utf-8");
726
- if (!raw.trim()) return { ...EMPTY_CONFIG };
727
- const parsed = yaml.load(raw);
728
- return {
729
- schedules: parsed?.schedules ?? [],
730
- triggers: parsed?.triggers ?? [],
731
- mention_triggers: parsed?.mention_triggers ?? []
732
- };
733
- }
734
720
  function validateSchedule(s, opts = {}) {
735
721
  const errors = [];
736
722
  if (!s.name) errors.push("name is required");
@@ -812,7 +798,7 @@ function loadEffectiveAutomations() {
812
798
 
813
799
  // src/claude/agent.ts
814
800
  import { spawn } from "child_process";
815
- import { existsSync as existsSync8, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
801
+ import { existsSync as existsSync7, readFileSync as readFileSync2, statSync as statSync3 } from "fs";
816
802
  import { resolve as resolve4, resolve as resolvePath } from "path";
817
803
  import { homedir as homedir3 } from "os";
818
804
  import { randomUUID } from "crypto";
@@ -820,11 +806,11 @@ import { randomUUID } from "crypto";
820
806
  // src/claude/container.ts
821
807
  import { execFileSync } from "child_process";
822
808
  import { createHash } from "crypto";
823
- import { existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
809
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
824
810
  import { join as join2 } from "path";
825
811
 
826
812
  // src/claude/mounts.ts
827
- import { existsSync as existsSync4, lstatSync, mkdirSync as mkdirSync2, readlinkSync, symlinkSync, unlinkSync } from "fs";
813
+ import { existsSync as existsSync3, lstatSync, mkdirSync as mkdirSync2, readlinkSync, symlinkSync, unlinkSync } from "fs";
828
814
  import { basename, join } from "path";
829
815
  var MOUNTS_DIR = "mounts";
830
816
  function resolveMounts(paths2) {
@@ -853,7 +839,7 @@ function materialiseMountLinks(cwd, mounts) {
853
839
  for (const repo of mounts) {
854
840
  const link = join(root, repo.name);
855
841
  try {
856
- if (existsSync4(link) || isBrokenSymlink(link)) {
842
+ if (existsSync3(link) || isBrokenSymlink(link)) {
857
843
  if (!lstatSync(link).isSymbolicLink()) {
858
844
  problems.push(`${link} exists and is not a symlink \u2014 leaving it alone`);
859
845
  continue;
@@ -943,7 +929,7 @@ function rewriteArgsForContainer(args) {
943
929
  function buildContainerSpawn(input) {
944
930
  const home = containerHomeFor(input.cwd);
945
931
  for (const dir of [home, paths.SCRATCH_DIR]) {
946
- if (!existsSync5(dir)) mkdirSync3(dir, { recursive: true });
932
+ if (!existsSync4(dir)) mkdirSync3(dir, { recursive: true });
947
933
  }
948
934
  const containerName = `flyspace-agent-${input.runId}`;
949
935
  const env = buildContainerEnv(input.hostEnv);
@@ -1040,7 +1026,7 @@ function userFlags() {
1040
1026
  // src/claude/sandbox.ts
1041
1027
  import { execFileSync as execFileSync2 } from "child_process";
1042
1028
  import { createHash as createHash2 } from "crypto";
1043
- import { existsSync as existsSync6, mkdirSync as mkdirSync4, writeFileSync } from "fs";
1029
+ import { existsSync as existsSync5, mkdirSync as mkdirSync4, writeFileSync } from "fs";
1044
1030
  import { join as join3 } from "path";
1045
1031
  function sandboxRuntimeEntrypoint() {
1046
1032
  return join3(paths.PACKAGE_ROOT, "node_modules/@anthropic-ai/sandbox-runtime/dist/cli.js");
@@ -1053,7 +1039,7 @@ function sandboxHomeFor(cwd) {
1053
1039
  function buildSandboxSpawn(input) {
1054
1040
  const home = sandboxHomeFor(input.cwd);
1055
1041
  for (const dir of [home, paths.SCRATCH_DIR]) {
1056
- if (!existsSync6(dir)) mkdirSync4(dir, { recursive: true });
1042
+ if (!existsSync5(dir)) mkdirSync4(dir, { recursive: true });
1057
1043
  }
1058
1044
  const claudeBin = process.env["FLYSPACE_CLAUDE_BIN"]?.trim() || execFileSync2("which", ["claude"]).toString().trim();
1059
1045
  const allowRead = [input.cwd, home, paths.SCRATCH_DIR, join3(paths.PACKAGE_ROOT, "node_modules")];
@@ -1098,7 +1084,7 @@ function buildSandboxSpawn(input) {
1098
1084
  };
1099
1085
  }
1100
1086
  function sandboxRuntimeStatus() {
1101
- if (existsSync6(sandboxRuntimeEntrypoint())) return { ok: true };
1087
+ if (existsSync5(sandboxRuntimeEntrypoint())) return { ok: true };
1102
1088
  return {
1103
1089
  ok: false,
1104
1090
  message: `This channel runs its agent in a sandbox, but \`@anthropic-ai/sandbox-runtime\` is not installed.
@@ -1114,7 +1100,7 @@ function resolveModelAlias(model) {
1114
1100
  return MODEL_ALIASES[model.toLowerCase()] ?? model;
1115
1101
  }
1116
1102
 
1117
- // src/utils/mise-env.ts
1103
+ // ../api/src/utils/mise-env.ts
1118
1104
  import { execFileSync as execFileSync3 } from "child_process";
1119
1105
  function resolveMiseEnv(cwd) {
1120
1106
  try {
@@ -1131,8 +1117,8 @@ function resolveMiseEnv(cwd) {
1131
1117
  }
1132
1118
  }
1133
1119
 
1134
- // src/store/output-styles-store.ts
1135
- import { existsSync as existsSync7, mkdirSync as mkdirSync5, readdirSync, readFileSync as readFileSync2, renameSync, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
1120
+ // ../api/src/store/output-styles-store.ts
1121
+ import { existsSync as existsSync6, mkdirSync as mkdirSync5, readdirSync, readFileSync, renameSync, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
1136
1122
  import { homedir as homedir2 } from "os";
1137
1123
  import { join as join4, resolve as resolve3, sep as sep2 } from "path";
1138
1124
  var BUILT_IN_OUTPUT_STYLES = [
@@ -1204,9 +1190,9 @@ function atomicWrite(file, content) {
1204
1190
  }
1205
1191
  function readStyle(claudeConfigDir, id) {
1206
1192
  const file = styleFile(claudeConfigDir, id);
1207
- if (!file || !existsSync7(file)) return null;
1193
+ if (!file || !existsSync6(file)) return null;
1208
1194
  const stat = statSync2(file);
1209
- const p = parseStyle(readFileSync2(file, "utf8"), id);
1195
+ const p = parseStyle(readFileSync(file, "utf8"), id);
1210
1196
  return {
1211
1197
  id,
1212
1198
  name: p.name,
@@ -1218,7 +1204,7 @@ function readStyle(claudeConfigDir, id) {
1218
1204
  }
1219
1205
  function listOutputStyles(claudeConfigDir) {
1220
1206
  const dir = stylesDir(claudeConfigDir);
1221
- if (!existsSync7(dir)) return [];
1207
+ if (!existsSync6(dir)) return [];
1222
1208
  return readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => readStyle(claudeConfigDir, f.slice(0, -3))).filter((s) => !!s).sort((a, b) => a.name.localeCompare(b.name));
1223
1209
  }
1224
1210
  function assertNameFree(claudeConfigDir, name, exceptId) {
@@ -1231,7 +1217,7 @@ function createOutputStyle(claudeConfigDir, params) {
1231
1217
  if (!id) throw new Error("name must contain letters or digits");
1232
1218
  assertNameFree(claudeConfigDir, params.name);
1233
1219
  const file = styleFile(claudeConfigDir, id);
1234
- if (existsSync7(file) || BUILT_IN_OUTPUT_STYLES.some((s) => s.slug === id)) {
1220
+ if (existsSync6(file) || BUILT_IN_OUTPUT_STYLES.some((s) => s.slug === id)) {
1235
1221
  throw new OutputStyleConflictError(`an output style named "${params.name}" already exists`);
1236
1222
  }
1237
1223
  atomicWrite(file, serialize({ ...params, extra: [] }));
@@ -1239,8 +1225,8 @@ function createOutputStyle(claudeConfigDir, params) {
1239
1225
  }
1240
1226
  function updateOutputStyle(claudeConfigDir, id, patch) {
1241
1227
  const file = styleFile(claudeConfigDir, id);
1242
- if (!file || !existsSync7(file)) return null;
1243
- const current = parseStyle(readFileSync2(file, "utf8"), id);
1228
+ if (!file || !existsSync6(file)) return null;
1229
+ const current = parseStyle(readFileSync(file, "utf8"), id);
1244
1230
  if (patch.name !== void 0 && patch.name !== current.name) assertNameFree(claudeConfigDir, patch.name, id);
1245
1231
  const next = { ...current, ...patch };
1246
1232
  atomicWrite(file, serialize(next));
@@ -1251,8 +1237,8 @@ function updateOutputStyle(claudeConfigDir, id, patch) {
1251
1237
  }
1252
1238
  function deleteOutputStyle(claudeConfigDir, id) {
1253
1239
  const file = styleFile(claudeConfigDir, id);
1254
- if (!file || !existsSync7(file)) return false;
1255
- const name = parseStyle(readFileSync2(file, "utf8"), id).name;
1240
+ if (!file || !existsSync6(file)) return false;
1241
+ const name = parseStyle(readFileSync(file, "utf8"), id).name;
1256
1242
  rmSync(file);
1257
1243
  if (readSettings(claudeConfigDir)["outputStyle"] === name) writeDefaultName(claudeConfigDir, void 0);
1258
1244
  return true;
@@ -1262,8 +1248,8 @@ function settingsFile(claudeConfigDir) {
1262
1248
  }
1263
1249
  function readSettings(claudeConfigDir) {
1264
1250
  const file = settingsFile(claudeConfigDir);
1265
- if (!existsSync7(file)) return {};
1266
- const parsed = JSON.parse(readFileSync2(file, "utf8"));
1251
+ if (!existsSync6(file)) return {};
1252
+ const parsed = JSON.parse(readFileSync(file, "utf8"));
1267
1253
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1268
1254
  throw new Error(`${file} is not a JSON object`);
1269
1255
  }
@@ -1306,7 +1292,7 @@ function setOutputStyleDefault(claudeConfigDir, id) {
1306
1292
  return true;
1307
1293
  }
1308
1294
 
1309
- // src/claude/models.ts
1295
+ // ../api/src/claude/models.ts
1310
1296
  var MODEL_OPTIONS = [
1311
1297
  { value: "opus", label: "Opus", provider: "claude" },
1312
1298
  { value: "sonnet", label: "Sonnet", provider: "claude" },
@@ -1378,7 +1364,7 @@ function modelLabel(value) {
1378
1364
  return longContext ? `${label} \xB7 1M context` : label;
1379
1365
  }
1380
1366
 
1381
- // src/agents/usage-limit.ts
1367
+ // ../api/src/agents/usage-limit.ts
1382
1368
  var USAGE_LIMIT_PATTERNS = [
1383
1369
  /usage limit reached/i,
1384
1370
  /\d+\s*-?\s*hour limit reached/i,
@@ -1430,7 +1416,7 @@ function usageLimitMessage(rawText, agent, model, now = Date.now()) {
1430
1416
  ].filter(Boolean).join("\n");
1431
1417
  }
1432
1418
 
1433
- // src/agents/usage-limit-state.ts
1419
+ // ../api/src/agents/usage-limit-state.ts
1434
1420
  var ALL_MODELS = "*";
1435
1421
  var limitedUntilByKey = /* @__PURE__ */ new Map();
1436
1422
  function stateKey(profile, agent, model) {
@@ -1478,7 +1464,7 @@ function usageLimitedModels(agent) {
1478
1464
  return limited;
1479
1465
  }
1480
1466
 
1481
- // src/agents/auth-failure-state.ts
1467
+ // ../api/src/agents/auth-failure-state.ts
1482
1468
  var failedProfiles = /* @__PURE__ */ new Set();
1483
1469
  function markClaudeAuthFailed() {
1484
1470
  failedProfiles.add(getProfile());
@@ -1490,7 +1476,7 @@ function claudeAuthFailed() {
1490
1476
  return failedProfiles.has(getProfile());
1491
1477
  }
1492
1478
 
1493
- // src/agents/usage-recorder.ts
1479
+ // ../api/src/agents/usage-recorder.ts
1494
1480
  var recorder;
1495
1481
  function setUsageRecorder(next) {
1496
1482
  recorder = next;
@@ -1592,12 +1578,24 @@ var CONTEXT_TOO_LONG_PATTERNS = [
1592
1578
  function isContextTooLongError(text) {
1593
1579
  return CONTEXT_TOO_LONG_PATTERNS.some((p) => p.test(text));
1594
1580
  }
1595
- var AUTH_ERROR_PATTERNS = [/failed to authenticate/i, /oauth session expired/i, /invalid api key/i];
1581
+ var AUTH_ERROR_PATTERNS = [
1582
+ /failed to authenticate/i,
1583
+ /oauth session expired/i,
1584
+ /invalid api key/i,
1585
+ /not logged in/i
1586
+ ];
1596
1587
  function isAuthError(text) {
1597
1588
  return AUTH_ERROR_PATTERNS.some((p) => p.test(text));
1598
1589
  }
1599
- function authErrorMessage(raw) {
1600
- return `The agent can't sign in to Claude right now (the Host's login expired and could not be refreshed).
1590
+ function authErrorMessage(raw, usingSetupToken = false) {
1591
+ const tokenHint = usingSetupToken ? `This profile's config.env sets CLAUDE_CODE_OAUTH_TOKEN, which overrides \`claude auth login\`. Use Sign in or Paste a token in Settings \u2192 Agent \u2192 Providers, or run \`claude setup-token\` and replace it in ~/.config/flyspace/profiles/<name>/config.env (not a launchd plist: the dashboard only reads config.env).
1592
+ ` : "";
1593
+ if (usingSetupToken)
1594
+ console.warn(
1595
+ "[agent] auth failed while CLAUDE_CODE_OAUTH_TOKEN is set: the token overrides the CLI login"
1596
+ );
1597
+ return `The agent can't sign in to Claude right now (the Host's Claude login is missing or expired).
1598
+ ` + tokenHint + `A long-lived token must live in the profile's config.env (~/.config/flyspace/profiles/<name>/config.env), not in a launchd plist or shell: the dashboard only reads config.env. Restart the dashboard service after editing. Run \`flyspace doctor\` to see which profile is broken.
1601
1599
  To fix it, a workspace admin can open Settings \u2192 Agent \u2192 Providers and click Sign in next to Claude Code.
1602
1600
 
1603
1601
  > Original error: ${raw}`;
@@ -1641,23 +1639,29 @@ function extractUsage(result) {
1641
1639
  };
1642
1640
  }
1643
1641
  function budgetExceededMessage(maxBudgetUsd, resumable = false) {
1644
- const cap = maxBudgetUsd ? `$${maxBudgetUsd}` : "\u82B1\u8CBB\u4E0A\u9650";
1642
+ const cap = maxBudgetUsd ? `$${maxBudgetUsd}` : "spend limit";
1645
1643
  if (resumable) {
1646
- return `\u9019\u6B21\u4EFB\u52D9\u82B1\u5230\u4E86 ${cap} \u7684\u55AE\u6B21\u4E0A\u9650\uFF0C\u6211\u5148\u628A\u5B83\u66AB\u505C\u4E86 \u23F8\uFE0F
1647
- \u9019\u4E0D\u662F\u5931\u6557 \u2014 \u9032\u5EA6\u548C\u4E0A\u4E0B\u6587\u90FD\u9084\u7559\u8457\u3002\u6309\u300C\u7E7C\u7E8C\u300D\u6703\u5F9E\u4E2D\u65B7\u7684\u5730\u65B9\u63A5\u8457\u505A\u5B8C\uFF08\u91CD\u65B0\u8A08\u4E00\u4EFD\u984D\u5EA6\uFF09\u3002
1648
- \u5982\u679C\u89BA\u5F97\u9019\u984C\u672C\u4F86\u5C31\u592A\u91CD\uFF0C\u4E5F\u53EF\u4EE5\u6539\u7528\u6458\u8981 fork \u5230\u65B0 thread\uFF0Ccontext \u8B8A\u8F15\u3001\u6210\u672C\u66F4\u4F4E\u3002`;
1644
+ return `This task hit the ${cap} per-run limit, so I paused it \u23F8\uFE0F
1645
+ This isn't a failure. Progress and context are kept. Press Continue to pick up where it stopped (with a fresh budget).
1646
+ If the task is just too heavy, you can also fork a summary into a new thread for a lighter context and lower cost.`;
1649
1647
  }
1650
- return `\u9019\u6B21\u4EFB\u52D9\u8D85\u904E\u4E86 ${cap} \u7684\u55AE\u6B21\u82B1\u8CBB\u4E0A\u9650\u88AB\u4E2D\u6B62\uFF0C\u6C92\u6709\u7522\u51FA\u7D50\u679C\uFF0C\u4E5F\u6C92\u6709\u53EF\u4EE5\u63A5\u7E8C\u7684\u9032\u5EA6\u3002
1651
- \u901A\u5E38\u662F\u55AE\u4E00\u8ACB\u6C42\u505A\u592A\u591A\u4E8B\uFF08\u4F8B\u5982\u4E00\u6B21 spawn \u591A\u500B\u8F03\u8CB4\u7684\u5B50 agent\uFF09\u3002
1652
- \u53EF\u4EE5\u7528\u4E0B\u9762\u7684\u6309\u9215\u628A\u76EE\u524D\u8A0E\u8AD6\u6458\u8981\u5F8C fork \u5230\u65B0 thread \u7E7C\u7E8C\uFF08context \u8B8A\u8F15\u3001\u6210\u672C\u964D\u4F4E\uFF09\uFF0C\u6216\u628A\u4EFB\u52D9\u62C6\u5C0F\u518D\u8A66\u3002`;
1648
+ return `This task went over the ${cap} per-run spend limit and was stopped. There is no result and no progress to resume.
1649
+ This usually means one request did too much (for example, spawning several expensive sub-agents at once).
1650
+ Use the button below to fork a summary of this discussion into a new thread (lighter context, lower cost), or split the task into smaller pieces and try again.`;
1653
1651
  }
1654
- function interpretCliResult(result, resumeSessionId, maxBudgetUsd, requestedModel) {
1652
+ function interpretCliResult(result, resumeSessionId, maxBudgetUsd, requestedModel, usingSetupToken = false) {
1655
1653
  const model = requestedModel ?? primaryModel(result.modelUsage);
1656
- const response = interpretCliOutcome(result, resumeSessionId, maxBudgetUsd, model);
1654
+ const response = interpretCliOutcome(
1655
+ result,
1656
+ resumeSessionId,
1657
+ maxBudgetUsd,
1658
+ model,
1659
+ usingSetupToken
1660
+ );
1657
1661
  const usage = extractUsage(result);
1658
1662
  return usage ? { ...response, usage } : response;
1659
1663
  }
1660
- function interpretCliOutcome(result, resumeSessionId, maxBudgetUsd, model) {
1664
+ function interpretCliOutcome(result, resumeSessionId, maxBudgetUsd, model, usingSetupToken = false) {
1661
1665
  const sessionId = result.session_id ?? resumeSessionId ?? "";
1662
1666
  if (result.is_error) {
1663
1667
  if (result.subtype === "error_max_budget_usd") {
@@ -1680,7 +1684,7 @@ function interpretCliOutcome(result, resumeSessionId, maxBudgetUsd, model) {
1680
1684
  }
1681
1685
  if (isAuthError(text)) {
1682
1686
  markClaudeAuthFailed();
1683
- return { sessionId, text: authErrorMessage(text), isError: true };
1687
+ return { sessionId, text: authErrorMessage(text, usingSetupToken), isError: true };
1684
1688
  }
1685
1689
  const contextTooLong = isContextTooLongError(text);
1686
1690
  const crashedMidExecution = result.subtype === "error_during_execution";
@@ -1730,13 +1734,13 @@ function getMaxDurationMs(streaming) {
1730
1734
  function loadSystemPrompt() {
1731
1735
  const customPath = paths.PROMPT_FILE;
1732
1736
  const defaultPath = resolve4(paths.PACKAGE_ROOT, "system.default.md");
1733
- const filePath = existsSync8(customPath) ? customPath : defaultPath;
1734
- return readFileSync3(filePath, "utf-8").trim();
1737
+ const filePath = existsSync7(customPath) ? customPath : defaultPath;
1738
+ return readFileSync2(filePath, "utf-8").trim();
1735
1739
  }
1736
1740
  function loadCapabilities() {
1737
1741
  const capabilitiesPath = resolve4(paths.PACKAGE_ROOT, "system.capabilities.md");
1738
- if (!existsSync8(capabilitiesPath)) return "";
1739
- return readFileSync3(capabilitiesPath, "utf-8").trim();
1742
+ if (!existsSync7(capabilitiesPath)) return "";
1743
+ return readFileSync2(capabilitiesPath, "utf-8").trim();
1740
1744
  }
1741
1745
  function buildSystemPrompt(botName, agentPersona, channelPrompt, outputStyle) {
1742
1746
  const prompt = loadSystemPrompt().replaceAll("{{botName}}", botName);
@@ -1838,7 +1842,10 @@ function buildArgs(prompt, botName, options, resumeSessionId, isolatedStyle) {
1838
1842
  "--setting-sources",
1839
1843
  options.runtime === "container" || options.runtime === "sandbox" ? "project,local" : "user,project,local",
1840
1844
  "--settings",
1841
- buildHookSettings(options.runtime ?? "host", isolatedStyle?.builtIn ? isolatedStyle.name : void 0)
1845
+ buildHookSettings(
1846
+ options.runtime ?? "host",
1847
+ isolatedStyle?.builtIn ? isolatedStyle.name : void 0
1848
+ )
1842
1849
  ];
1843
1850
  if (mcpStrictConfigEnabled()) {
1844
1851
  args.push("--strict-mcp-config");
@@ -2059,7 +2066,8 @@ function runCli(prompt, cwd, botName, options, claudeConfigDir, resumeSessionId,
2059
2066
  result,
2060
2067
  resumeSessionId,
2061
2068
  options.maxBudgetUsd,
2062
- options.model
2069
+ options.model,
2070
+ !!claudeCodeOauthToken
2063
2071
  );
2064
2072
  recordUsage2(response, options);
2065
2073
  resolve7(response);
@@ -2071,7 +2079,7 @@ function runCli(prompt, cwd, botName, options, claudeConfigDir, resumeSessionId,
2071
2079
  });
2072
2080
  }
2073
2081
  async function askClaude(prompt, cwd, botName, options, claudeConfigDir, resumeSessionId, claudeCodeOauthToken) {
2074
- if (!existsSync8(cwd) || !statSync3(cwd).isDirectory()) {
2082
+ if (!existsSync7(cwd) || !statSync3(cwd).isDirectory()) {
2075
2083
  console.error(`[agent] working directory does not exist: ${cwd}`);
2076
2084
  return {
2077
2085
  sessionId: resumeSessionId ?? "",
@@ -2141,7 +2149,7 @@ Fix the channel's working directory in its settings (or recreate the directory),
2141
2149
  }
2142
2150
  }
2143
2151
 
2144
- // src/feature-flags.ts
2152
+ // ../api/src/feature-flags.ts
2145
2153
  var featureFlags = {
2146
2154
  "ai-cost": {
2147
2155
  title: "AI cost",
@@ -2191,7 +2199,7 @@ function resolveFeatureFlags(enabledIds, devHost) {
2191
2199
  return out;
2192
2200
  }
2193
2201
 
2194
- // src/store/feature-flag-store.ts
2202
+ // ../api/src/store/feature-flag-store.ts
2195
2203
  async function listEnabledFeatureFlags(workspaceId) {
2196
2204
  const { data, error } = await getSupabaseClient().from("feature_flags").select("flag_id").eq("workspace_id", workspaceId);
2197
2205
  if (error) throw new Error(`listEnabledFeatureFlags(${workspaceId}): ${error.message}`);
@@ -2214,7 +2222,7 @@ async function disableFeatureFlag(workspaceId, flagId) {
2214
2222
  if (error) throw new Error(`disableFeatureFlag(${workspaceId}, ${flagId}): ${error.message}`);
2215
2223
  }
2216
2224
 
2217
- // src/store/memory-store.ts
2225
+ // ../api/src/store/memory-store.ts
2218
2226
  var MEMORY_TYPES = ["preference", "decision", "fact", "reference"];
2219
2227
  var channelTarget = (channelId) => ({ scope: "channel", channelId });
2220
2228
  var NAME_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
@@ -2535,7 +2543,7 @@ function formatMemoryPrompt(channelId, memories, extras = {}) {
2535
2543
  ].join("\n");
2536
2544
  }
2537
2545
 
2538
- // src/store/workspace-store.ts
2546
+ // ../api/src/store/workspace-store.ts
2539
2547
  function rowToMembership(row) {
2540
2548
  return {
2541
2549
  id: row["id"],
@@ -2858,11 +2866,11 @@ async function buildPrompt(profile, channelId, opts) {
2858
2866
  return formatMemoryPrompt(channelId, channel, extras);
2859
2867
  }
2860
2868
 
2861
- // src/dashboard/settings.ts
2862
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync9, mkdirSync as mkdirSync6, rmSync as rmSync2 } from "fs";
2863
- import { dirname, resolve as resolve5 } from "path";
2869
+ // src/dashboard/settings-host.ts
2870
+ import { writeFileSync as writeFileSync3, existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync4, rmSync as rmSync2 } from "fs";
2871
+ import { dirname } from "path";
2864
2872
 
2865
- // src/dashboard/auto-title.ts
2873
+ // ../api/src/dashboard/auto-title.ts
2866
2874
  var GROQ_API_URL = "https://api.groq.com/openai/v1/chat/completions";
2867
2875
  var TITLE_MODEL = "openai/gpt-oss-20b";
2868
2876
  var TIMEOUT_MS = 4e3;
@@ -2949,7 +2957,11 @@ ${input.body.slice(0, MAX_BODY_CHARS)}`
2949
2957
  }
2950
2958
  }
2951
2959
 
2952
- // src/store/workspace-settings-store.ts
2960
+ // ../api/src/dashboard/settings.ts
2961
+ import { readFileSync as readFileSync3, existsSync as existsSync8 } from "fs";
2962
+ import { resolve as resolve5 } from "path";
2963
+
2964
+ // ../api/src/store/workspace-settings-store.ts
2953
2965
  var BRANDING_DEFAULTS = {
2954
2966
  theme: "default",
2955
2967
  font: "default",
@@ -3021,7 +3033,7 @@ async function upsertWorkspaceBranding(profile, patch) {
3021
3033
  return next;
3022
3034
  }
3023
3035
 
3024
- // src/dashboard/settings.ts
3036
+ // ../api/src/dashboard/settings.ts
3025
3037
  var VALID_THEMES = [
3026
3038
  "default",
3027
3039
  "classic",
@@ -3041,20 +3053,12 @@ var VALID_FONTS = [
3041
3053
  "playfair",
3042
3054
  "inter"
3043
3055
  ];
3044
- var LEGACY_AGENT_TO_MODEL = {
3045
- claude: "sonnet",
3046
- codex: "gpt-5.6-sol"
3047
- };
3048
3056
  var GA_MEASUREMENT_ID = /^G-[A-Z0-9]{4,24}$/;
3049
3057
  function parseGaMeasurementId(raw) {
3050
3058
  if (typeof raw !== "string") return void 0;
3051
3059
  const id = raw.trim().toUpperCase();
3052
3060
  return GA_MEASUREMENT_ID.test(id) ? id : void 0;
3053
3061
  }
3054
- var KNOWN_RUNNERS = ["claude", "codex"];
3055
- function firstModelFor(runner) {
3056
- return modelOptionsFor(runner)[0].value;
3057
- }
3058
3062
  var LOCAL_DEFAULTS = { agent: "sonnet" };
3059
3063
  function localDefaults() {
3060
3064
  return {
@@ -3062,6 +3066,97 @@ function localDefaults() {
3062
3066
  providers: [{ runner: "claude", model: LOCAL_DEFAULTS.agent }, { runner: "codex" }]
3063
3067
  };
3064
3068
  }
3069
+ var AUTO_TITLE_PROMPT_MAX = 2e3;
3070
+ function readSettingsFile() {
3071
+ if (!existsSync8(paths.DASHBOARD_SETTINGS_FILE)) return null;
3072
+ try {
3073
+ const raw = JSON.parse(readFileSync3(paths.DASHBOARD_SETTINGS_FILE, "utf-8"));
3074
+ return raw && typeof raw === "object" ? raw : null;
3075
+ } catch {
3076
+ return null;
3077
+ }
3078
+ }
3079
+ function brandingToSettings(branding) {
3080
+ return {
3081
+ theme: branding.theme,
3082
+ font: branding.font,
3083
+ logo: branding.logo ?? void 0,
3084
+ displayName: branding.displayName ?? void 0,
3085
+ gaMeasurementId: branding.gaMeasurementId ?? void 0,
3086
+ autoTitleEnabled: branding.autoTitleEnabled,
3087
+ autoTitlePrompt: branding.autoTitlePrompt ?? void 0
3088
+ };
3089
+ }
3090
+ function legacyBranding(raw) {
3091
+ return {
3092
+ theme: typeof raw["theme"] === "string" && VALID_THEMES.includes(raw["theme"]) ? raw["theme"] : BRANDING_DEFAULTS.theme,
3093
+ font: typeof raw["font"] === "string" && VALID_FONTS.includes(raw["font"]) ? raw["font"] : BRANDING_DEFAULTS.font,
3094
+ logo: typeof raw["logo"] === "string" ? raw["logo"] : null,
3095
+ displayName: typeof raw["displayName"] === "string" ? raw["displayName"].trim() || null : null,
3096
+ gaMeasurementId: parseGaMeasurementId(raw["gaMeasurementId"]) ?? null
3097
+ };
3098
+ }
3099
+ async function loadWorkspaceBranding(profile = getProfile()) {
3100
+ const stored = await getWorkspaceBranding(profile);
3101
+ if (stored) return brandingToSettings(stored);
3102
+ const legacy = runWithProfile(profile, () => readSettingsFile());
3103
+ if (!legacy) return brandingToSettings(BRANDING_DEFAULTS);
3104
+ return brandingToSettings(await upsertWorkspaceBranding(profile, legacyBranding(legacy)));
3105
+ }
3106
+ async function saveWorkspaceBranding(patch, profile = getProfile()) {
3107
+ const current = await loadWorkspaceBranding(profile);
3108
+ const next = {
3109
+ theme: patch.theme && VALID_THEMES.includes(patch.theme) ? patch.theme : current.theme,
3110
+ font: patch.font && VALID_FONTS.includes(patch.font) ? patch.font : current.font,
3111
+ logo: patch.logo === null ? null : typeof patch.logo === "string" ? patch.logo : void 0,
3112
+ displayName: patch.displayName === null || patch.displayName === "" ? null : typeof patch.displayName === "string" ? patch.displayName.trim() : void 0,
3113
+ gaMeasurementId: patch.gaMeasurementId === null || patch.gaMeasurementId === "" ? null : typeof patch.gaMeasurementId === "string" ? parseGaMeasurementId(patch.gaMeasurementId) : void 0,
3114
+ autoTitleEnabled: typeof patch.autoTitleEnabled === "boolean" ? patch.autoTitleEnabled : void 0,
3115
+ autoTitlePrompt: patch.autoTitlePrompt === null || patch.autoTitlePrompt === "" ? null : typeof patch.autoTitlePrompt === "string" ? patch.autoTitlePrompt.trim().slice(0, AUTO_TITLE_PROMPT_MAX) || null : void 0
3116
+ };
3117
+ return brandingToSettings(await upsertWorkspaceBranding(profile, next));
3118
+ }
3119
+ function defaultPromptPath() {
3120
+ return resolve5(paths.PACKAGE_ROOT, "system.default.md");
3121
+ }
3122
+ function readDefaultPrompt() {
3123
+ const path = defaultPromptPath();
3124
+ return existsSync8(path) ? readFileSync3(path, "utf-8").trim() : "";
3125
+ }
3126
+ function loadWorkspacePrompt() {
3127
+ const defaultPrompt = readDefaultPrompt();
3128
+ const custom = existsSync8(paths.PROMPT_FILE);
3129
+ return {
3130
+ prompt: custom ? readFileSync3(paths.PROMPT_FILE, "utf-8").trim() : defaultPrompt,
3131
+ defaultPrompt,
3132
+ custom
3133
+ };
3134
+ }
3135
+ var BOT_PROFILE_KEY = "bot";
3136
+ async function loadBotIdentity(profile = getProfile()) {
3137
+ const branding = await getWorkspaceBranding(profile);
3138
+ return {
3139
+ displayName: branding?.botName ?? void 0,
3140
+ avatar: branding?.botAvatar ?? void 0
3141
+ };
3142
+ }
3143
+ async function saveBotIdentity(patch, profile = getProfile()) {
3144
+ const next = await upsertWorkspaceBranding(profile, {
3145
+ botName: patch.displayName === void 0 ? void 0 : patch.displayName?.trim() || null,
3146
+ botAvatar: patch.avatar
3147
+ });
3148
+ return { displayName: next.botName ?? void 0, avatar: next.botAvatar ?? void 0 };
3149
+ }
3150
+
3151
+ // src/dashboard/settings-host.ts
3152
+ var LEGACY_AGENT_TO_MODEL = {
3153
+ claude: "sonnet",
3154
+ codex: "gpt-5.6-sol"
3155
+ };
3156
+ var KNOWN_RUNNERS = ["claude", "codex"];
3157
+ function firstModelFor(runner) {
3158
+ return modelOptionsFor(runner)[0].value;
3159
+ }
3065
3160
  function normalizeDefaultModel(raw, fallback) {
3066
3161
  if (typeof raw !== "string") return fallback;
3067
3162
  if (raw in LEGACY_AGENT_TO_MODEL) return LEGACY_AGENT_TO_MODEL[raw];
@@ -3121,7 +3216,7 @@ function loadDashboardSettings() {
3121
3216
  try {
3122
3217
  const raw = JSON.parse(readFileSync4(paths.DASHBOARD_SETTINGS_FILE, "utf-8"));
3123
3218
  const providers = parseProviders(raw.providers, {
3124
- agent: normalizeDefaultModel(raw.agent, LOCAL_DEFAULTS.agent),
3219
+ agent: normalizeDefaultModel(raw.agent, localDefaults().agent),
3125
3220
  fallbackModel: typeof raw.fallbackModel === "string" && isAllowedModel(raw.fallbackModel) ? raw.fallbackModel : void 0
3126
3221
  });
3127
3222
  return {
@@ -3133,7 +3228,6 @@ function loadDashboardSettings() {
3133
3228
  return localDefaults();
3134
3229
  }
3135
3230
  }
3136
- var AUTO_TITLE_PROMPT_MAX = 2e3;
3137
3231
  function withDefaultModel(providers, model) {
3138
3232
  const runner = runnerForModel(model);
3139
3233
  const rest = providers.filter((p) => p.runner !== runner);
@@ -3146,15 +3240,6 @@ function withFallbackModel(providers, model) {
3146
3240
  if (runner === cleared[0].runner) return cleared;
3147
3241
  return [cleared[0], { runner, model }, ...cleared.slice(1).filter((p) => p.runner !== runner)];
3148
3242
  }
3149
- function readSettingsFile() {
3150
- if (!existsSync9(paths.DASHBOARD_SETTINGS_FILE)) return null;
3151
- try {
3152
- const raw = JSON.parse(readFileSync4(paths.DASHBOARD_SETTINGS_FILE, "utf-8"));
3153
- return raw && typeof raw === "object" ? raw : null;
3154
- } catch {
3155
- return null;
3156
- }
3157
- }
3158
3243
  function writeSettings(next) {
3159
3244
  mkdirSync6(dirname(paths.DASHBOARD_SETTINGS_FILE), { recursive: true });
3160
3245
  const merged = { ...readSettingsFile() ?? {}, ...next };
@@ -3182,46 +3267,6 @@ function saveDashboardSettings(patch) {
3182
3267
  agentProfiles: current.agentProfiles
3183
3268
  });
3184
3269
  }
3185
- function brandingToSettings(branding) {
3186
- return {
3187
- theme: branding.theme,
3188
- font: branding.font,
3189
- logo: branding.logo ?? void 0,
3190
- displayName: branding.displayName ?? void 0,
3191
- gaMeasurementId: branding.gaMeasurementId ?? void 0,
3192
- autoTitleEnabled: branding.autoTitleEnabled,
3193
- autoTitlePrompt: branding.autoTitlePrompt ?? void 0
3194
- };
3195
- }
3196
- function legacyBranding(raw) {
3197
- return {
3198
- theme: typeof raw["theme"] === "string" && VALID_THEMES.includes(raw["theme"]) ? raw["theme"] : BRANDING_DEFAULTS.theme,
3199
- font: typeof raw["font"] === "string" && VALID_FONTS.includes(raw["font"]) ? raw["font"] : BRANDING_DEFAULTS.font,
3200
- logo: typeof raw["logo"] === "string" ? raw["logo"] : null,
3201
- displayName: typeof raw["displayName"] === "string" ? raw["displayName"].trim() || null : null,
3202
- gaMeasurementId: parseGaMeasurementId(raw["gaMeasurementId"]) ?? null
3203
- };
3204
- }
3205
- async function loadWorkspaceBranding(profile = getProfile()) {
3206
- const stored = await getWorkspaceBranding(profile);
3207
- if (stored) return brandingToSettings(stored);
3208
- const legacy = runWithProfile(profile, () => readSettingsFile());
3209
- if (!legacy) return brandingToSettings(BRANDING_DEFAULTS);
3210
- return brandingToSettings(await upsertWorkspaceBranding(profile, legacyBranding(legacy)));
3211
- }
3212
- async function saveWorkspaceBranding(patch, profile = getProfile()) {
3213
- const current = await loadWorkspaceBranding(profile);
3214
- const next = {
3215
- theme: patch.theme && VALID_THEMES.includes(patch.theme) ? patch.theme : current.theme,
3216
- font: patch.font && VALID_FONTS.includes(patch.font) ? patch.font : current.font,
3217
- logo: patch.logo === null ? null : typeof patch.logo === "string" ? patch.logo : void 0,
3218
- displayName: patch.displayName === null || patch.displayName === "" ? null : typeof patch.displayName === "string" ? patch.displayName.trim() : void 0,
3219
- gaMeasurementId: patch.gaMeasurementId === null || patch.gaMeasurementId === "" ? null : typeof patch.gaMeasurementId === "string" ? parseGaMeasurementId(patch.gaMeasurementId) : void 0,
3220
- autoTitleEnabled: typeof patch.autoTitleEnabled === "boolean" ? patch.autoTitleEnabled : void 0,
3221
- autoTitlePrompt: patch.autoTitlePrompt === null || patch.autoTitlePrompt === "" ? null : typeof patch.autoTitlePrompt === "string" ? patch.autoTitlePrompt.trim().slice(0, AUTO_TITLE_PROMPT_MAX) || null : void 0
3222
- };
3223
- return brandingToSettings(await upsertWorkspaceBranding(profile, next));
3224
- }
3225
3270
  async function loadFullDashboardSettings(profile = getProfile()) {
3226
3271
  return {
3227
3272
  ...await loadWorkspaceBranding(profile),
@@ -3229,25 +3274,9 @@ async function loadFullDashboardSettings(profile = getProfile()) {
3229
3274
  autoTitleDefaultPrompt: DEFAULT_TITLE_RULES
3230
3275
  };
3231
3276
  }
3232
- function defaultPromptPath() {
3233
- return resolve5(paths.PACKAGE_ROOT, "system.default.md");
3234
- }
3235
- function readDefaultPrompt() {
3236
- const path = defaultPromptPath();
3237
- return existsSync9(path) ? readFileSync4(path, "utf-8").trim() : "";
3238
- }
3239
- function loadWorkspacePrompt() {
3240
- const defaultPrompt = readDefaultPrompt();
3241
- const custom = existsSync9(paths.PROMPT_FILE);
3242
- return {
3243
- prompt: custom ? readFileSync4(paths.PROMPT_FILE, "utf-8").trim() : defaultPrompt,
3244
- defaultPrompt,
3245
- custom
3246
- };
3247
- }
3248
3277
  function saveWorkspacePrompt(prompt) {
3249
3278
  const trimmed = prompt.trim();
3250
- if (!trimmed || trimmed === readDefaultPrompt()) return resetWorkspacePrompt();
3279
+ if (!trimmed || trimmed === loadWorkspacePrompt().defaultPrompt) return resetWorkspacePrompt();
3251
3280
  mkdirSync6(dirname(paths.PROMPT_FILE), { recursive: true });
3252
3281
  writeFileSync3(paths.PROMPT_FILE, `${trimmed}
3253
3282
  `, "utf-8");
@@ -3276,23 +3305,8 @@ function saveAgentProfile(name, patch) {
3276
3305
  agentProfiles: Object.keys(agentProfiles).length > 0 ? agentProfiles : void 0
3277
3306
  });
3278
3307
  }
3279
- var BOT_PROFILE_KEY = "bot";
3280
- async function loadBotIdentity(profile = getProfile()) {
3281
- const branding = await getWorkspaceBranding(profile);
3282
- return {
3283
- displayName: branding?.botName ?? void 0,
3284
- avatar: branding?.botAvatar ?? void 0
3285
- };
3286
- }
3287
- async function saveBotIdentity(patch, profile = getProfile()) {
3288
- const next = await upsertWorkspaceBranding(profile, {
3289
- botName: patch.displayName === void 0 ? void 0 : patch.displayName?.trim() || null,
3290
- botAvatar: patch.avatar
3291
- });
3292
- return { displayName: next.botName ?? void 0, avatar: next.botAvatar ?? void 0 };
3293
- }
3294
3308
 
3295
- // src/codex/agent.ts
3309
+ // ../api/src/codex/agent.ts
3296
3310
  import { spawn as spawn2 } from "child_process";
3297
3311
  import { existsSync as existsSync10, mkdtempSync, readFileSync as readFileSync5, rmSync as rmSync3, statSync as statSync4 } from "fs";
3298
3312
  import { tmpdir } from "os";
@@ -4338,7 +4352,7 @@ function runScriptAutomation(opts) {
4338
4352
  });
4339
4353
  }
4340
4354
 
4341
- // src/automations/manager.ts
4355
+ // ../api/src/automations/manager.ts
4342
4356
  function findInChannels(name) {
4343
4357
  for (const channel of getProfileChannelRegistry()) {
4344
4358
  const a = channel.automations;
@@ -5631,13 +5645,13 @@ async function summariseThreadTranscript(transcript, opts, deps = {}) {
5631
5645
  return res.text;
5632
5646
  }
5633
5647
 
5634
- // src/claude/skills.ts
5648
+ // ../api/src/claude/skills.ts
5635
5649
  import { existsSync as existsSync13, readdirSync as readdirSync3, readFileSync as readFileSync8, statSync as statSync6 } from "fs";
5636
5650
  import { homedir as homedir5 } from "os";
5637
5651
  import { basename as basename2, dirname as dirname2, join as join9 } from "path";
5638
- import yaml3 from "js-yaml";
5652
+ import yaml2 from "js-yaml";
5639
5653
 
5640
- // src/claude/skill-files.ts
5654
+ // ../api/src/claude/skill-files.ts
5641
5655
  import {
5642
5656
  existsSync as existsSync12,
5643
5657
  mkdirSync as mkdirSync8,
@@ -5649,7 +5663,7 @@ import {
5649
5663
  } from "fs";
5650
5664
  import { homedir as homedir4 } from "os";
5651
5665
  import { join as join8, resolve as resolve6, sep as sep3 } from "path";
5652
- import yaml2 from "js-yaml";
5666
+ import yaml from "js-yaml";
5653
5667
  var MAX_SKILL_BYTES = 2 * 1024 * 1024;
5654
5668
  var SKILL_NAME = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
5655
5669
  function expandHome(p) {
@@ -5677,7 +5691,7 @@ function splitFrontmatter(raw) {
5677
5691
  if (!match) return { fm: {}, body: raw };
5678
5692
  let fm = {};
5679
5693
  try {
5680
- fm = yaml2.load(match[1]) ?? {};
5694
+ fm = yaml.load(match[1]) ?? {};
5681
5695
  } catch {
5682
5696
  fm = {};
5683
5697
  }
@@ -5686,7 +5700,7 @@ function splitFrontmatter(raw) {
5686
5700
  function buildSkillFile(fm, body) {
5687
5701
  const { name, description, ...rest } = fm;
5688
5702
  const ordered = { name, description, ...rest };
5689
- const front = yaml2.dump(ordered, { lineWidth: -1 }).trimEnd();
5703
+ const front = yaml.dump(ordered, { lineWidth: -1 }).trimEnd();
5690
5704
  return `---
5691
5705
  ${front}
5692
5706
  ---
@@ -5799,7 +5813,7 @@ function deleteSkillFile(dir, name) {
5799
5813
  return { status: "ok" };
5800
5814
  }
5801
5815
 
5802
- // src/claude/skills.ts
5816
+ // ../api/src/claude/skills.ts
5803
5817
  function defaultConfigDir() {
5804
5818
  return join9(homedir5(), ".claude");
5805
5819
  }
@@ -5818,7 +5832,7 @@ function parseFrontmatter(file) {
5818
5832
  const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
5819
5833
  if (!match) return {};
5820
5834
  try {
5821
- const fm = yaml3.load(match[1]);
5835
+ const fm = yaml2.load(match[1]);
5822
5836
  const name = typeof fm?.["name"] === "string" ? fm["name"] : void 0;
5823
5837
  const description = typeof fm?.["description"] === "string" ? fm["description"] : void 0;
5824
5838
  return { name, description };
@@ -6377,12 +6391,12 @@ ${trimmedDetail.slice(0, 1500)}
6377
6391
  threadTs,
6378
6392
  reactTs
6379
6393
  });
6380
- const text = "\u9019\u500B\u4EFB\u52D9\u8DD1\u5F97\u6709\u9EDE\u4E45\uFF0C\u6211\u5148\u628A\u5B83\u66AB\u505C\u4E86 \u23F8\uFE0F\n\u9019\u4E0D\u662F\u5931\u6557 \u2014 \u9032\u5EA6\u548C\u4E0A\u4E0B\u6587\u90FD\u9084\u7559\u8457\u3002\u8981\u6211\u63A5\u8457\u505A\u5B8C\u55CE\uFF1F";
6394
+ const text = "This task is taking a while, so I paused it \u23F8\uFE0F\nThis isn't a failure. Progress and context are kept. Want me to finish it?";
6381
6395
  await say({
6382
6396
  text,
6383
6397
  blocks: [
6384
6398
  { type: "section", text: { type: "mrkdwn", text } },
6385
- buildRetryBlock(retryId, "\u25B6\uFE0F \u7E7C\u7E8C")
6399
+ buildRetryBlock(retryId, "\u25B6\uFE0F Continue")
6386
6400
  ],
6387
6401
  ...threadTs ? { thread_ts: threadTs } : {}
6388
6402
  });
@@ -6402,7 +6416,7 @@ ${trimmedDetail.slice(0, 1500)}
6402
6416
  });
6403
6417
  const blocks = [
6404
6418
  { type: "section", text: { type: "mrkdwn", text: message } },
6405
- buildRetryBlock(retryId, "\u25B6\uFE0F \u7E7C\u7E8C")
6419
+ buildRetryBlock(retryId, "\u25B6\uFE0F Continue")
6406
6420
  ];
6407
6421
  if (threadTs) {
6408
6422
  blocks.push(
@@ -6699,7 +6713,7 @@ retry: ${retryDetail}`);
6699
6713
  }
6700
6714
  await clearReaction();
6701
6715
  await say({
6702
- text: "\u9019\u500B\u4EFB\u52D9\u8DD1\u5F97\u6709\u9EDE\u4E45\uFF0C\u88AB\u6211\u66AB\u505C\u4E86 \u23F8\uFE0F \u9019\u6B21\u6C92\u6709\u53EF\u4EE5\u63A5\u7E8C\u7684\u9032\u5EA6\uFF0C\u9EBB\u7169\u4F60\u518D\u50B3\u4E00\u6B21\uFF0C\u6216\u628A\u8981\u505A\u7684\u4E8B\u62C6\u5C0F\u4E00\u9EDE\u3002",
6716
+ text: "This task took too long and I paused it \u23F8\uFE0F There is no progress to resume, so please send it again, or split the work into smaller pieces.",
6703
6717
  ...threadTs ? { thread_ts: threadTs } : {}
6704
6718
  });
6705
6719
  return;
@@ -7081,12 +7095,12 @@ ${matched.prompt}`,
7081
7095
  await client.chat.update({
7082
7096
  channel: channelId,
7083
7097
  ts: message.ts,
7084
- text: message.text ?? "\u91CD\u8A66\u5DF2\u903E\u6642",
7098
+ text: message.text ?? "Retry expired",
7085
7099
  blocks: [
7086
7100
  ...remainingBlocks,
7087
7101
  {
7088
7102
  type: "context",
7089
- elements: [{ type: "mrkdwn", text: "\u231B \u9019\u500B\u91CD\u8A66\u5DF2\u903E\u6642\uFF0C\u8ACB\u76F4\u63A5\u91CD\u65B0\u50B3\u4E00\u6B21\u8A0A\u606F\u3002" }]
7103
+ elements: [{ type: "mrkdwn", text: "\u231B This retry has expired. Please send your message again." }]
7090
7104
  }
7091
7105
  ]
7092
7106
  });
@@ -7153,12 +7167,12 @@ ${matched.prompt}`,
7153
7167
  await client.chat.update({
7154
7168
  channel: channelId,
7155
7169
  ts: message.ts,
7156
- text: message.text ?? "fork \u5DF2\u903E\u6642",
7170
+ text: message.text ?? "Fork expired",
7157
7171
  blocks: [
7158
7172
  ...remainingBlocks,
7159
7173
  {
7160
7174
  type: "context",
7161
- elements: [{ type: "mrkdwn", text: "\u231B \u9019\u500B fork \u5DF2\u903E\u6642\uFF0C\u8ACB\u91CD\u65B0\u89F8\u767C\u4E00\u6B21\u3002" }]
7175
+ elements: [{ type: "mrkdwn", text: "\u231B This fork has expired. Please trigger it again." }]
7162
7176
  }
7163
7177
  ]
7164
7178
  });
@@ -7568,7 +7582,7 @@ var AutomationRunStore = class {
7568
7582
  }
7569
7583
  };
7570
7584
 
7571
- // src/store/automation-run-sync.ts
7585
+ // ../api/src/store/automation-run-sync.ts
7572
7586
  var BATCH_SIZE = 500;
7573
7587
  var SYNC_INTERVAL_MS = 6e4;
7574
7588
  function toRecord(row, workspace) {
@@ -7815,7 +7829,7 @@ var SessionStore = class {
7815
7829
  import { randomUUID as randomUUID3 } from "crypto";
7816
7830
  import Database4 from "better-sqlite3";
7817
7831
 
7818
- // src/store/rate-cards.ts
7832
+ // ../api/src/store/rate-cards.ts
7819
7833
  var EPOCH = "1970-01-01";
7820
7834
  var RATE_CARDS = [
7821
7835
  {
@@ -8611,6 +8625,55 @@ var ReactionStore = class {
8611
8625
  }
8612
8626
  };
8613
8627
 
8628
+ // ../api/src/store/supabase-direct.ts
8629
+ import { createClient } from "@supabase/supabase-js";
8630
+ var REQUEST_TIMEOUT_MS = 15e3;
8631
+ function createDirectSupabaseClient() {
8632
+ const url = process.env["SUPABASE_URL"];
8633
+ const key = process.env["SUPABASE_SECRET_KEY"];
8634
+ if (!url || !key) {
8635
+ throw new Error("SUPABASE_URL / SUPABASE_SECRET_KEY not set \u2014 check .env");
8636
+ }
8637
+ return createClient(url, key, {
8638
+ auth: { persistSession: false },
8639
+ global: {
8640
+ fetch: (input, init) => fetch(input, { ...init, signal: init?.signal ?? AbortSignal.timeout(REQUEST_TIMEOUT_MS) })
8641
+ }
8642
+ });
8643
+ }
8644
+ function useDirectSupabase() {
8645
+ setSupabaseClientFactory(createDirectSupabaseClient);
8646
+ }
8647
+
8648
+ // ../api/src/store/local-cache.ts
8649
+ var EMPTY = {
8650
+ listActiveUsers: () => [],
8651
+ listUsersWithAvatars: () => [],
8652
+ displayNameFor: (id) => id,
8653
+ lookupChannelById: () => void 0,
8654
+ openUsageStore: () => null,
8655
+ openAutomationRunStore: () => null
8656
+ };
8657
+ var cache2 = EMPTY;
8658
+ function registerLocalCache(implementation) {
8659
+ cache2 = implementation;
8660
+ }
8661
+ function getLocalCache() {
8662
+ return cache2;
8663
+ }
8664
+
8665
+ // src/store/local-cache.ts
8666
+ function useLocalCache() {
8667
+ registerLocalCache({
8668
+ listActiveUsers,
8669
+ listUsersWithAvatars,
8670
+ displayNameFor,
8671
+ lookupChannelById: lookupById,
8672
+ openUsageStore: (file) => new UsageStore(file),
8673
+ openAutomationRunStore: (file) => new AutomationRunStore(file)
8674
+ });
8675
+ }
8676
+
8614
8677
  // src/health/watchdog.ts
8615
8678
  import { lookup } from "dns/promises";
8616
8679
  var ts = () => (/* @__PURE__ */ new Date()).toISOString();
@@ -8794,6 +8857,8 @@ async function startSlack(app, store, reactionStore, config, automations) {
8794
8857
  return { listeners, watchdog };
8795
8858
  }
8796
8859
  async function startServer() {
8860
+ useDirectSupabase();
8861
+ useLocalCache();
8797
8862
  ensureDirs();
8798
8863
  const sweptScratch = sweepScratchDir();
8799
8864
  if (sweptScratch > 0) console.log(`[flyspace] swept ${sweptScratch} stale scratch file(s)`);
@@ -8848,6 +8913,18 @@ async function startServer() {
8848
8913
  }
8849
8914
 
8850
8915
  export {
8916
+ useDirectSupabase,
8917
+ getLocalCache,
8918
+ listMemberChannels,
8919
+ refreshCache,
8920
+ resolveChannelId,
8921
+ UsageStore,
8922
+ listActiveUsers,
8923
+ displayNameFor,
8924
+ refreshUserCache,
8925
+ resolveUserId,
8926
+ ensureUsersCached,
8927
+ useLocalCache,
8851
8928
  isEffort,
8852
8929
  DEFAULT_CODEX_MODEL,
8853
8930
  mcpStrictConfigEnabled,
@@ -8884,7 +8961,6 @@ export {
8884
8961
  ensureMemberDmChannel,
8885
8962
  DEFAULT_TIMEZONE,
8886
8963
  loadAutomations,
8887
- loadAutomationsFile,
8888
8964
  loadEffectiveAutomations,
8889
8965
  BUILT_IN_OUTPUT_STYLES,
8890
8966
  OutputStyleConflictError,
@@ -8976,35 +9052,26 @@ export {
8976
9052
  buildAutoTitle,
8977
9053
  BRANDING_DEFAULTS,
8978
9054
  getWorkspaceBranding,
8979
- loadDashboardSettings,
8980
- saveDashboardSettings,
9055
+ upsertWorkspaceBranding,
8981
9056
  loadWorkspaceBranding,
8982
9057
  saveWorkspaceBranding,
8983
- loadFullDashboardSettings,
8984
9058
  loadWorkspacePrompt,
8985
- saveWorkspacePrompt,
8986
- resetWorkspacePrompt,
8987
- saveAgentProfile,
8988
9059
  BOT_PROFILE_KEY,
8989
9060
  loadBotIdentity,
8990
9061
  saveBotIdentity,
9062
+ loadDashboardSettings,
9063
+ saveDashboardSettings,
9064
+ loadFullDashboardSettings,
9065
+ saveWorkspacePrompt,
9066
+ resetWorkspacePrompt,
9067
+ saveAgentProfile,
8991
9068
  codexAuthAvailable,
8992
9069
  askCodex,
8993
9070
  markdownToBlocks,
8994
9071
  blockToFallbackText,
8995
- lookupById,
8996
- listMemberChannels,
8997
- refreshCache,
8998
- resolveChannelId,
8999
9072
  runAutomation,
9000
9073
  runScriptAutomation,
9001
9074
  AutomationManager,
9002
- listActiveUsers,
9003
- listUsersWithAvatars,
9004
- displayNameFor,
9005
- refreshUserCache,
9006
- resolveUserId,
9007
- ensureUsersCached,
9008
9075
  MessageQueue,
9009
9076
  mimetypeSizeLimit,
9010
9077
  buildFilesPromptSection,
@@ -9024,11 +9091,9 @@ export {
9024
9091
  listSkills,
9025
9092
  listPluginSkillDetails,
9026
9093
  findSkillDetail,
9027
- AutomationRunStore,
9028
9094
  recentRunsForWorkspace,
9029
9095
  lastRunsForWorkspace,
9030
9096
  SessionStore,
9031
- UsageStore,
9032
9097
  installUsageRecording,
9033
9098
  startServer
9034
9099
  };