flyspace-cli 0.1.18 → 0.1.21
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/{chunk-B3KW3N5Y.js → chunk-EINS55BS.js} +1 -1
- package/dist/{chunk-SWLIZNEI.js → chunk-GHGQCED7.js} +283 -210
- package/dist/{chunk-L3I3BPLP.js → chunk-GYHCSGMJ.js} +46 -43
- package/dist/cli.js +9454 -9249
- package/dist/index.js +2 -2
- package/dist/{threads-EWR6YAZY.js → threads-5KRBNPM7.js} +2 -2
- package/package.json +9 -31
- package/templates/general/02-working-with-the-agent.html +38 -0
- package/templates/general/03-channels-and-folders.html +38 -0
- package/templates/general/04-docs.html +38 -0
- package/templates/general/05-sharing-docs.html +38 -0
- package/templates/general/06-inviting-your-team.html +38 -0
- package/templates/general/07-automations.html +38 -0
- package/templates/general/README.html +61 -0
- package/README.md +0 -68
- package/templates/general/01-welcome.md +0 -20
- package/templates/general/02-working-with-the-agent.md +0 -21
- package/templates/general/03-channels-and-folders.md +0 -19
- package/templates/general/04-docs.md +0 -14
- package/templates/general/05-inviting-your-team.md +0 -17
- package/templates/general/06-automations.md +0 -21
|
@@ -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-
|
|
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";
|
|
@@ -651,7 +652,7 @@ async function ensureChannelProvisioned(externalChannelId, opts = {}) {
|
|
|
651
652
|
async function upsertChannelByAgentName(input) {
|
|
652
653
|
const { data, error } = await getSupabaseClient().from("channels").upsert(
|
|
653
654
|
{ ...toRow(input), profile: getProfile(), updated_at: (/* @__PURE__ */ new Date()).toISOString() },
|
|
654
|
-
{ onConflict: "agent_name" }
|
|
655
|
+
{ onConflict: "profile,agent_name" }
|
|
655
656
|
).select().single();
|
|
656
657
|
if (error) throw new Error(error.message);
|
|
657
658
|
await refreshChannelRegistry();
|
|
@@ -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
|
|
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
|
|
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
|
|
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 (
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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 (
|
|
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
|
|
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 || !
|
|
1193
|
+
if (!file || !existsSync6(file)) return null;
|
|
1208
1194
|
const stat = statSync2(file);
|
|
1209
|
-
const p = parseStyle(
|
|
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 (!
|
|
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 (
|
|
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 || !
|
|
1243
|
-
const current = parseStyle(
|
|
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 || !
|
|
1255
|
-
const name = parseStyle(
|
|
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 (!
|
|
1266
|
-
const parsed = JSON.parse(
|
|
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 = [
|
|
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
|
-
|
|
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}` : "
|
|
1642
|
+
const cap = maxBudgetUsd ? `$${maxBudgetUsd}` : "spend limit";
|
|
1645
1643
|
if (resumable) {
|
|
1646
|
-
return
|
|
1647
|
-
|
|
1648
|
-
|
|
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
|
|
1651
|
-
|
|
1652
|
-
|
|
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(
|
|
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 =
|
|
1734
|
-
return
|
|
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 (!
|
|
1739
|
-
return
|
|
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(
|
|
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 (!
|
|
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"],
|
|
@@ -2626,6 +2634,13 @@ async function markWorkspaceProjectsSetup(workspaceId) {
|
|
|
2626
2634
|
async function markWorkspaceGreeted(workspaceId) {
|
|
2627
2635
|
await stampOnce(workspaceId, "greeted_at");
|
|
2628
2636
|
}
|
|
2637
|
+
async function resetWorkspaceOnboarding(workspaceId) {
|
|
2638
|
+
const { error } = await getSupabaseClient().from("workspaces").update({ projects_setup_at: null, greeted_at: null }).eq("id", workspaceId);
|
|
2639
|
+
if (error) throw new Error(`resetWorkspaceOnboarding(${workspaceId}): ${error.message}`);
|
|
2640
|
+
for (const [slug, entry] of workspaceCache) {
|
|
2641
|
+
if (entry.workspace?.id === workspaceId) workspaceCache.delete(slug);
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2629
2644
|
async function getWorkspaceGreetedAt(workspaceId) {
|
|
2630
2645
|
const { data, error } = await getSupabaseClient().from("workspaces").select("greeted_at").eq("id", workspaceId).maybeSingle();
|
|
2631
2646
|
if (error) throw new Error(`getWorkspaceGreetedAt(${workspaceId}): ${error.message}`);
|
|
@@ -2858,11 +2873,11 @@ async function buildPrompt(profile, channelId, opts) {
|
|
|
2858
2873
|
return formatMemoryPrompt(channelId, channel, extras);
|
|
2859
2874
|
}
|
|
2860
2875
|
|
|
2861
|
-
// src/dashboard/settings.ts
|
|
2862
|
-
import {
|
|
2863
|
-
import { dirname
|
|
2876
|
+
// src/dashboard/settings-host.ts
|
|
2877
|
+
import { writeFileSync as writeFileSync3, existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync4, rmSync as rmSync2 } from "fs";
|
|
2878
|
+
import { dirname } from "path";
|
|
2864
2879
|
|
|
2865
|
-
// src/dashboard/auto-title.ts
|
|
2880
|
+
// ../api/src/dashboard/auto-title.ts
|
|
2866
2881
|
var GROQ_API_URL = "https://api.groq.com/openai/v1/chat/completions";
|
|
2867
2882
|
var TITLE_MODEL = "openai/gpt-oss-20b";
|
|
2868
2883
|
var TIMEOUT_MS = 4e3;
|
|
@@ -2949,7 +2964,11 @@ ${input.body.slice(0, MAX_BODY_CHARS)}`
|
|
|
2949
2964
|
}
|
|
2950
2965
|
}
|
|
2951
2966
|
|
|
2952
|
-
// src/
|
|
2967
|
+
// ../api/src/dashboard/settings.ts
|
|
2968
|
+
import { readFileSync as readFileSync3, existsSync as existsSync8 } from "fs";
|
|
2969
|
+
import { resolve as resolve5 } from "path";
|
|
2970
|
+
|
|
2971
|
+
// ../api/src/store/workspace-settings-store.ts
|
|
2953
2972
|
var BRANDING_DEFAULTS = {
|
|
2954
2973
|
theme: "default",
|
|
2955
2974
|
font: "default",
|
|
@@ -3021,7 +3040,7 @@ async function upsertWorkspaceBranding(profile, patch) {
|
|
|
3021
3040
|
return next;
|
|
3022
3041
|
}
|
|
3023
3042
|
|
|
3024
|
-
// src/dashboard/settings.ts
|
|
3043
|
+
// ../api/src/dashboard/settings.ts
|
|
3025
3044
|
var VALID_THEMES = [
|
|
3026
3045
|
"default",
|
|
3027
3046
|
"classic",
|
|
@@ -3041,20 +3060,12 @@ var VALID_FONTS = [
|
|
|
3041
3060
|
"playfair",
|
|
3042
3061
|
"inter"
|
|
3043
3062
|
];
|
|
3044
|
-
var LEGACY_AGENT_TO_MODEL = {
|
|
3045
|
-
claude: "sonnet",
|
|
3046
|
-
codex: "gpt-5.6-sol"
|
|
3047
|
-
};
|
|
3048
3063
|
var GA_MEASUREMENT_ID = /^G-[A-Z0-9]{4,24}$/;
|
|
3049
3064
|
function parseGaMeasurementId(raw) {
|
|
3050
3065
|
if (typeof raw !== "string") return void 0;
|
|
3051
3066
|
const id = raw.trim().toUpperCase();
|
|
3052
3067
|
return GA_MEASUREMENT_ID.test(id) ? id : void 0;
|
|
3053
3068
|
}
|
|
3054
|
-
var KNOWN_RUNNERS = ["claude", "codex"];
|
|
3055
|
-
function firstModelFor(runner) {
|
|
3056
|
-
return modelOptionsFor(runner)[0].value;
|
|
3057
|
-
}
|
|
3058
3069
|
var LOCAL_DEFAULTS = { agent: "sonnet" };
|
|
3059
3070
|
function localDefaults() {
|
|
3060
3071
|
return {
|
|
@@ -3062,6 +3073,97 @@ function localDefaults() {
|
|
|
3062
3073
|
providers: [{ runner: "claude", model: LOCAL_DEFAULTS.agent }, { runner: "codex" }]
|
|
3063
3074
|
};
|
|
3064
3075
|
}
|
|
3076
|
+
var AUTO_TITLE_PROMPT_MAX = 2e3;
|
|
3077
|
+
function readSettingsFile() {
|
|
3078
|
+
if (!existsSync8(paths.DASHBOARD_SETTINGS_FILE)) return null;
|
|
3079
|
+
try {
|
|
3080
|
+
const raw = JSON.parse(readFileSync3(paths.DASHBOARD_SETTINGS_FILE, "utf-8"));
|
|
3081
|
+
return raw && typeof raw === "object" ? raw : null;
|
|
3082
|
+
} catch {
|
|
3083
|
+
return null;
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
function brandingToSettings(branding) {
|
|
3087
|
+
return {
|
|
3088
|
+
theme: branding.theme,
|
|
3089
|
+
font: branding.font,
|
|
3090
|
+
logo: branding.logo ?? void 0,
|
|
3091
|
+
displayName: branding.displayName ?? void 0,
|
|
3092
|
+
gaMeasurementId: branding.gaMeasurementId ?? void 0,
|
|
3093
|
+
autoTitleEnabled: branding.autoTitleEnabled,
|
|
3094
|
+
autoTitlePrompt: branding.autoTitlePrompt ?? void 0
|
|
3095
|
+
};
|
|
3096
|
+
}
|
|
3097
|
+
function legacyBranding(raw) {
|
|
3098
|
+
return {
|
|
3099
|
+
theme: typeof raw["theme"] === "string" && VALID_THEMES.includes(raw["theme"]) ? raw["theme"] : BRANDING_DEFAULTS.theme,
|
|
3100
|
+
font: typeof raw["font"] === "string" && VALID_FONTS.includes(raw["font"]) ? raw["font"] : BRANDING_DEFAULTS.font,
|
|
3101
|
+
logo: typeof raw["logo"] === "string" ? raw["logo"] : null,
|
|
3102
|
+
displayName: typeof raw["displayName"] === "string" ? raw["displayName"].trim() || null : null,
|
|
3103
|
+
gaMeasurementId: parseGaMeasurementId(raw["gaMeasurementId"]) ?? null
|
|
3104
|
+
};
|
|
3105
|
+
}
|
|
3106
|
+
async function loadWorkspaceBranding(profile = getProfile()) {
|
|
3107
|
+
const stored = await getWorkspaceBranding(profile);
|
|
3108
|
+
if (stored) return brandingToSettings(stored);
|
|
3109
|
+
const legacy = runWithProfile(profile, () => readSettingsFile());
|
|
3110
|
+
if (!legacy) return brandingToSettings(BRANDING_DEFAULTS);
|
|
3111
|
+
return brandingToSettings(await upsertWorkspaceBranding(profile, legacyBranding(legacy)));
|
|
3112
|
+
}
|
|
3113
|
+
async function saveWorkspaceBranding(patch, profile = getProfile()) {
|
|
3114
|
+
const current = await loadWorkspaceBranding(profile);
|
|
3115
|
+
const next = {
|
|
3116
|
+
theme: patch.theme && VALID_THEMES.includes(patch.theme) ? patch.theme : current.theme,
|
|
3117
|
+
font: patch.font && VALID_FONTS.includes(patch.font) ? patch.font : current.font,
|
|
3118
|
+
logo: patch.logo === null ? null : typeof patch.logo === "string" ? patch.logo : void 0,
|
|
3119
|
+
displayName: patch.displayName === null || patch.displayName === "" ? null : typeof patch.displayName === "string" ? patch.displayName.trim() : void 0,
|
|
3120
|
+
gaMeasurementId: patch.gaMeasurementId === null || patch.gaMeasurementId === "" ? null : typeof patch.gaMeasurementId === "string" ? parseGaMeasurementId(patch.gaMeasurementId) : void 0,
|
|
3121
|
+
autoTitleEnabled: typeof patch.autoTitleEnabled === "boolean" ? patch.autoTitleEnabled : void 0,
|
|
3122
|
+
autoTitlePrompt: patch.autoTitlePrompt === null || patch.autoTitlePrompt === "" ? null : typeof patch.autoTitlePrompt === "string" ? patch.autoTitlePrompt.trim().slice(0, AUTO_TITLE_PROMPT_MAX) || null : void 0
|
|
3123
|
+
};
|
|
3124
|
+
return brandingToSettings(await upsertWorkspaceBranding(profile, next));
|
|
3125
|
+
}
|
|
3126
|
+
function defaultPromptPath() {
|
|
3127
|
+
return resolve5(paths.PACKAGE_ROOT, "system.default.md");
|
|
3128
|
+
}
|
|
3129
|
+
function readDefaultPrompt() {
|
|
3130
|
+
const path = defaultPromptPath();
|
|
3131
|
+
return existsSync8(path) ? readFileSync3(path, "utf-8").trim() : "";
|
|
3132
|
+
}
|
|
3133
|
+
function loadWorkspacePrompt() {
|
|
3134
|
+
const defaultPrompt = readDefaultPrompt();
|
|
3135
|
+
const custom = existsSync8(paths.PROMPT_FILE);
|
|
3136
|
+
return {
|
|
3137
|
+
prompt: custom ? readFileSync3(paths.PROMPT_FILE, "utf-8").trim() : defaultPrompt,
|
|
3138
|
+
defaultPrompt,
|
|
3139
|
+
custom
|
|
3140
|
+
};
|
|
3141
|
+
}
|
|
3142
|
+
var BOT_PROFILE_KEY = "bot";
|
|
3143
|
+
async function loadBotIdentity(profile = getProfile()) {
|
|
3144
|
+
const branding = await getWorkspaceBranding(profile);
|
|
3145
|
+
return {
|
|
3146
|
+
displayName: branding?.botName ?? void 0,
|
|
3147
|
+
avatar: branding?.botAvatar ?? void 0
|
|
3148
|
+
};
|
|
3149
|
+
}
|
|
3150
|
+
async function saveBotIdentity(patch, profile = getProfile()) {
|
|
3151
|
+
const next = await upsertWorkspaceBranding(profile, {
|
|
3152
|
+
botName: patch.displayName === void 0 ? void 0 : patch.displayName?.trim() || null,
|
|
3153
|
+
botAvatar: patch.avatar
|
|
3154
|
+
});
|
|
3155
|
+
return { displayName: next.botName ?? void 0, avatar: next.botAvatar ?? void 0 };
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
// src/dashboard/settings-host.ts
|
|
3159
|
+
var LEGACY_AGENT_TO_MODEL = {
|
|
3160
|
+
claude: "sonnet",
|
|
3161
|
+
codex: "gpt-5.6-sol"
|
|
3162
|
+
};
|
|
3163
|
+
var KNOWN_RUNNERS = ["claude", "codex"];
|
|
3164
|
+
function firstModelFor(runner) {
|
|
3165
|
+
return modelOptionsFor(runner)[0].value;
|
|
3166
|
+
}
|
|
3065
3167
|
function normalizeDefaultModel(raw, fallback) {
|
|
3066
3168
|
if (typeof raw !== "string") return fallback;
|
|
3067
3169
|
if (raw in LEGACY_AGENT_TO_MODEL) return LEGACY_AGENT_TO_MODEL[raw];
|
|
@@ -3121,7 +3223,7 @@ function loadDashboardSettings() {
|
|
|
3121
3223
|
try {
|
|
3122
3224
|
const raw = JSON.parse(readFileSync4(paths.DASHBOARD_SETTINGS_FILE, "utf-8"));
|
|
3123
3225
|
const providers = parseProviders(raw.providers, {
|
|
3124
|
-
agent: normalizeDefaultModel(raw.agent,
|
|
3226
|
+
agent: normalizeDefaultModel(raw.agent, localDefaults().agent),
|
|
3125
3227
|
fallbackModel: typeof raw.fallbackModel === "string" && isAllowedModel(raw.fallbackModel) ? raw.fallbackModel : void 0
|
|
3126
3228
|
});
|
|
3127
3229
|
return {
|
|
@@ -3133,7 +3235,6 @@ function loadDashboardSettings() {
|
|
|
3133
3235
|
return localDefaults();
|
|
3134
3236
|
}
|
|
3135
3237
|
}
|
|
3136
|
-
var AUTO_TITLE_PROMPT_MAX = 2e3;
|
|
3137
3238
|
function withDefaultModel(providers, model) {
|
|
3138
3239
|
const runner = runnerForModel(model);
|
|
3139
3240
|
const rest = providers.filter((p) => p.runner !== runner);
|
|
@@ -3146,15 +3247,6 @@ function withFallbackModel(providers, model) {
|
|
|
3146
3247
|
if (runner === cleared[0].runner) return cleared;
|
|
3147
3248
|
return [cleared[0], { runner, model }, ...cleared.slice(1).filter((p) => p.runner !== runner)];
|
|
3148
3249
|
}
|
|
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
3250
|
function writeSettings(next) {
|
|
3159
3251
|
mkdirSync6(dirname(paths.DASHBOARD_SETTINGS_FILE), { recursive: true });
|
|
3160
3252
|
const merged = { ...readSettingsFile() ?? {}, ...next };
|
|
@@ -3182,46 +3274,6 @@ function saveDashboardSettings(patch) {
|
|
|
3182
3274
|
agentProfiles: current.agentProfiles
|
|
3183
3275
|
});
|
|
3184
3276
|
}
|
|
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
3277
|
async function loadFullDashboardSettings(profile = getProfile()) {
|
|
3226
3278
|
return {
|
|
3227
3279
|
...await loadWorkspaceBranding(profile),
|
|
@@ -3229,25 +3281,9 @@ async function loadFullDashboardSettings(profile = getProfile()) {
|
|
|
3229
3281
|
autoTitleDefaultPrompt: DEFAULT_TITLE_RULES
|
|
3230
3282
|
};
|
|
3231
3283
|
}
|
|
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
3284
|
function saveWorkspacePrompt(prompt) {
|
|
3249
3285
|
const trimmed = prompt.trim();
|
|
3250
|
-
if (!trimmed || trimmed ===
|
|
3286
|
+
if (!trimmed || trimmed === loadWorkspacePrompt().defaultPrompt) return resetWorkspacePrompt();
|
|
3251
3287
|
mkdirSync6(dirname(paths.PROMPT_FILE), { recursive: true });
|
|
3252
3288
|
writeFileSync3(paths.PROMPT_FILE, `${trimmed}
|
|
3253
3289
|
`, "utf-8");
|
|
@@ -3276,23 +3312,8 @@ function saveAgentProfile(name, patch) {
|
|
|
3276
3312
|
agentProfiles: Object.keys(agentProfiles).length > 0 ? agentProfiles : void 0
|
|
3277
3313
|
});
|
|
3278
3314
|
}
|
|
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
3315
|
|
|
3295
|
-
// src/codex/agent.ts
|
|
3316
|
+
// ../api/src/codex/agent.ts
|
|
3296
3317
|
import { spawn as spawn2 } from "child_process";
|
|
3297
3318
|
import { existsSync as existsSync10, mkdtempSync, readFileSync as readFileSync5, rmSync as rmSync3, statSync as statSync4 } from "fs";
|
|
3298
3319
|
import { tmpdir } from "os";
|
|
@@ -4338,7 +4359,7 @@ function runScriptAutomation(opts) {
|
|
|
4338
4359
|
});
|
|
4339
4360
|
}
|
|
4340
4361
|
|
|
4341
|
-
// src/automations/manager.ts
|
|
4362
|
+
// ../api/src/automations/manager.ts
|
|
4342
4363
|
function findInChannels(name) {
|
|
4343
4364
|
for (const channel of getProfileChannelRegistry()) {
|
|
4344
4365
|
const a = channel.automations;
|
|
@@ -5631,13 +5652,13 @@ async function summariseThreadTranscript(transcript, opts, deps = {}) {
|
|
|
5631
5652
|
return res.text;
|
|
5632
5653
|
}
|
|
5633
5654
|
|
|
5634
|
-
// src/claude/skills.ts
|
|
5655
|
+
// ../api/src/claude/skills.ts
|
|
5635
5656
|
import { existsSync as existsSync13, readdirSync as readdirSync3, readFileSync as readFileSync8, statSync as statSync6 } from "fs";
|
|
5636
5657
|
import { homedir as homedir5 } from "os";
|
|
5637
5658
|
import { basename as basename2, dirname as dirname2, join as join9 } from "path";
|
|
5638
|
-
import
|
|
5659
|
+
import yaml2 from "js-yaml";
|
|
5639
5660
|
|
|
5640
|
-
// src/claude/skill-files.ts
|
|
5661
|
+
// ../api/src/claude/skill-files.ts
|
|
5641
5662
|
import {
|
|
5642
5663
|
existsSync as existsSync12,
|
|
5643
5664
|
mkdirSync as mkdirSync8,
|
|
@@ -5649,7 +5670,7 @@ import {
|
|
|
5649
5670
|
} from "fs";
|
|
5650
5671
|
import { homedir as homedir4 } from "os";
|
|
5651
5672
|
import { join as join8, resolve as resolve6, sep as sep3 } from "path";
|
|
5652
|
-
import
|
|
5673
|
+
import yaml from "js-yaml";
|
|
5653
5674
|
var MAX_SKILL_BYTES = 2 * 1024 * 1024;
|
|
5654
5675
|
var SKILL_NAME = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
|
|
5655
5676
|
function expandHome(p) {
|
|
@@ -5677,7 +5698,7 @@ function splitFrontmatter(raw) {
|
|
|
5677
5698
|
if (!match) return { fm: {}, body: raw };
|
|
5678
5699
|
let fm = {};
|
|
5679
5700
|
try {
|
|
5680
|
-
fm =
|
|
5701
|
+
fm = yaml.load(match[1]) ?? {};
|
|
5681
5702
|
} catch {
|
|
5682
5703
|
fm = {};
|
|
5683
5704
|
}
|
|
@@ -5686,7 +5707,7 @@ function splitFrontmatter(raw) {
|
|
|
5686
5707
|
function buildSkillFile(fm, body) {
|
|
5687
5708
|
const { name, description, ...rest } = fm;
|
|
5688
5709
|
const ordered = { name, description, ...rest };
|
|
5689
|
-
const front =
|
|
5710
|
+
const front = yaml.dump(ordered, { lineWidth: -1 }).trimEnd();
|
|
5690
5711
|
return `---
|
|
5691
5712
|
${front}
|
|
5692
5713
|
---
|
|
@@ -5799,7 +5820,7 @@ function deleteSkillFile(dir, name) {
|
|
|
5799
5820
|
return { status: "ok" };
|
|
5800
5821
|
}
|
|
5801
5822
|
|
|
5802
|
-
// src/claude/skills.ts
|
|
5823
|
+
// ../api/src/claude/skills.ts
|
|
5803
5824
|
function defaultConfigDir() {
|
|
5804
5825
|
return join9(homedir5(), ".claude");
|
|
5805
5826
|
}
|
|
@@ -5818,7 +5839,7 @@ function parseFrontmatter(file) {
|
|
|
5818
5839
|
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
5819
5840
|
if (!match) return {};
|
|
5820
5841
|
try {
|
|
5821
|
-
const fm =
|
|
5842
|
+
const fm = yaml2.load(match[1]);
|
|
5822
5843
|
const name = typeof fm?.["name"] === "string" ? fm["name"] : void 0;
|
|
5823
5844
|
const description = typeof fm?.["description"] === "string" ? fm["description"] : void 0;
|
|
5824
5845
|
return { name, description };
|
|
@@ -6377,12 +6398,12 @@ ${trimmedDetail.slice(0, 1500)}
|
|
|
6377
6398
|
threadTs,
|
|
6378
6399
|
reactTs
|
|
6379
6400
|
});
|
|
6380
|
-
const text = "
|
|
6401
|
+
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
6402
|
await say({
|
|
6382
6403
|
text,
|
|
6383
6404
|
blocks: [
|
|
6384
6405
|
{ type: "section", text: { type: "mrkdwn", text } },
|
|
6385
|
-
buildRetryBlock(retryId, "\u25B6\uFE0F
|
|
6406
|
+
buildRetryBlock(retryId, "\u25B6\uFE0F Continue")
|
|
6386
6407
|
],
|
|
6387
6408
|
...threadTs ? { thread_ts: threadTs } : {}
|
|
6388
6409
|
});
|
|
@@ -6402,7 +6423,7 @@ ${trimmedDetail.slice(0, 1500)}
|
|
|
6402
6423
|
});
|
|
6403
6424
|
const blocks = [
|
|
6404
6425
|
{ type: "section", text: { type: "mrkdwn", text: message } },
|
|
6405
|
-
buildRetryBlock(retryId, "\u25B6\uFE0F
|
|
6426
|
+
buildRetryBlock(retryId, "\u25B6\uFE0F Continue")
|
|
6406
6427
|
];
|
|
6407
6428
|
if (threadTs) {
|
|
6408
6429
|
blocks.push(
|
|
@@ -6699,7 +6720,7 @@ retry: ${retryDetail}`);
|
|
|
6699
6720
|
}
|
|
6700
6721
|
await clearReaction();
|
|
6701
6722
|
await say({
|
|
6702
|
-
text: "
|
|
6723
|
+
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
6724
|
...threadTs ? { thread_ts: threadTs } : {}
|
|
6704
6725
|
});
|
|
6705
6726
|
return;
|
|
@@ -7081,12 +7102,12 @@ ${matched.prompt}`,
|
|
|
7081
7102
|
await client.chat.update({
|
|
7082
7103
|
channel: channelId,
|
|
7083
7104
|
ts: message.ts,
|
|
7084
|
-
text: message.text ?? "
|
|
7105
|
+
text: message.text ?? "Retry expired",
|
|
7085
7106
|
blocks: [
|
|
7086
7107
|
...remainingBlocks,
|
|
7087
7108
|
{
|
|
7088
7109
|
type: "context",
|
|
7089
|
-
elements: [{ type: "mrkdwn", text: "\u231B
|
|
7110
|
+
elements: [{ type: "mrkdwn", text: "\u231B This retry has expired. Please send your message again." }]
|
|
7090
7111
|
}
|
|
7091
7112
|
]
|
|
7092
7113
|
});
|
|
@@ -7153,12 +7174,12 @@ ${matched.prompt}`,
|
|
|
7153
7174
|
await client.chat.update({
|
|
7154
7175
|
channel: channelId,
|
|
7155
7176
|
ts: message.ts,
|
|
7156
|
-
text: message.text ?? "
|
|
7177
|
+
text: message.text ?? "Fork expired",
|
|
7157
7178
|
blocks: [
|
|
7158
7179
|
...remainingBlocks,
|
|
7159
7180
|
{
|
|
7160
7181
|
type: "context",
|
|
7161
|
-
elements: [{ type: "mrkdwn", text: "\u231B
|
|
7182
|
+
elements: [{ type: "mrkdwn", text: "\u231B This fork has expired. Please trigger it again." }]
|
|
7162
7183
|
}
|
|
7163
7184
|
]
|
|
7164
7185
|
});
|
|
@@ -7568,7 +7589,7 @@ var AutomationRunStore = class {
|
|
|
7568
7589
|
}
|
|
7569
7590
|
};
|
|
7570
7591
|
|
|
7571
|
-
// src/store/automation-run-sync.ts
|
|
7592
|
+
// ../api/src/store/automation-run-sync.ts
|
|
7572
7593
|
var BATCH_SIZE = 500;
|
|
7573
7594
|
var SYNC_INTERVAL_MS = 6e4;
|
|
7574
7595
|
function toRecord(row, workspace) {
|
|
@@ -7815,7 +7836,7 @@ var SessionStore = class {
|
|
|
7815
7836
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
7816
7837
|
import Database4 from "better-sqlite3";
|
|
7817
7838
|
|
|
7818
|
-
// src/store/rate-cards.ts
|
|
7839
|
+
// ../api/src/store/rate-cards.ts
|
|
7819
7840
|
var EPOCH = "1970-01-01";
|
|
7820
7841
|
var RATE_CARDS = [
|
|
7821
7842
|
{
|
|
@@ -8611,6 +8632,55 @@ var ReactionStore = class {
|
|
|
8611
8632
|
}
|
|
8612
8633
|
};
|
|
8613
8634
|
|
|
8635
|
+
// ../api/src/store/supabase-direct.ts
|
|
8636
|
+
import { createClient } from "@supabase/supabase-js";
|
|
8637
|
+
var REQUEST_TIMEOUT_MS = 15e3;
|
|
8638
|
+
function createDirectSupabaseClient() {
|
|
8639
|
+
const url = process.env["SUPABASE_URL"];
|
|
8640
|
+
const key = process.env["SUPABASE_SECRET_KEY"];
|
|
8641
|
+
if (!url || !key) {
|
|
8642
|
+
throw new Error("SUPABASE_URL / SUPABASE_SECRET_KEY not set \u2014 check .env");
|
|
8643
|
+
}
|
|
8644
|
+
return createClient(url, key, {
|
|
8645
|
+
auth: { persistSession: false },
|
|
8646
|
+
global: {
|
|
8647
|
+
fetch: (input, init) => fetch(input, { ...init, signal: init?.signal ?? AbortSignal.timeout(REQUEST_TIMEOUT_MS) })
|
|
8648
|
+
}
|
|
8649
|
+
});
|
|
8650
|
+
}
|
|
8651
|
+
function useDirectSupabase() {
|
|
8652
|
+
setSupabaseClientFactory(createDirectSupabaseClient);
|
|
8653
|
+
}
|
|
8654
|
+
|
|
8655
|
+
// ../api/src/store/local-cache.ts
|
|
8656
|
+
var EMPTY = {
|
|
8657
|
+
listActiveUsers: () => [],
|
|
8658
|
+
listUsersWithAvatars: () => [],
|
|
8659
|
+
displayNameFor: (id) => id,
|
|
8660
|
+
lookupChannelById: () => void 0,
|
|
8661
|
+
openUsageStore: () => null,
|
|
8662
|
+
openAutomationRunStore: () => null
|
|
8663
|
+
};
|
|
8664
|
+
var cache2 = EMPTY;
|
|
8665
|
+
function registerLocalCache(implementation) {
|
|
8666
|
+
cache2 = implementation;
|
|
8667
|
+
}
|
|
8668
|
+
function getLocalCache() {
|
|
8669
|
+
return cache2;
|
|
8670
|
+
}
|
|
8671
|
+
|
|
8672
|
+
// src/store/local-cache.ts
|
|
8673
|
+
function useLocalCache() {
|
|
8674
|
+
registerLocalCache({
|
|
8675
|
+
listActiveUsers,
|
|
8676
|
+
listUsersWithAvatars,
|
|
8677
|
+
displayNameFor,
|
|
8678
|
+
lookupChannelById: lookupById,
|
|
8679
|
+
openUsageStore: (file) => new UsageStore(file),
|
|
8680
|
+
openAutomationRunStore: (file) => new AutomationRunStore(file)
|
|
8681
|
+
});
|
|
8682
|
+
}
|
|
8683
|
+
|
|
8614
8684
|
// src/health/watchdog.ts
|
|
8615
8685
|
import { lookup } from "dns/promises";
|
|
8616
8686
|
var ts = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -8794,6 +8864,8 @@ async function startSlack(app, store, reactionStore, config, automations) {
|
|
|
8794
8864
|
return { listeners, watchdog };
|
|
8795
8865
|
}
|
|
8796
8866
|
async function startServer() {
|
|
8867
|
+
useDirectSupabase();
|
|
8868
|
+
useLocalCache();
|
|
8797
8869
|
ensureDirs();
|
|
8798
8870
|
const sweptScratch = sweepScratchDir();
|
|
8799
8871
|
if (sweptScratch > 0) console.log(`[flyspace] swept ${sweptScratch} stale scratch file(s)`);
|
|
@@ -8848,6 +8920,18 @@ async function startServer() {
|
|
|
8848
8920
|
}
|
|
8849
8921
|
|
|
8850
8922
|
export {
|
|
8923
|
+
useDirectSupabase,
|
|
8924
|
+
getLocalCache,
|
|
8925
|
+
listMemberChannels,
|
|
8926
|
+
refreshCache,
|
|
8927
|
+
resolveChannelId,
|
|
8928
|
+
UsageStore,
|
|
8929
|
+
listActiveUsers,
|
|
8930
|
+
displayNameFor,
|
|
8931
|
+
refreshUserCache,
|
|
8932
|
+
resolveUserId,
|
|
8933
|
+
ensureUsersCached,
|
|
8934
|
+
useLocalCache,
|
|
8851
8935
|
isEffort,
|
|
8852
8936
|
DEFAULT_CODEX_MODEL,
|
|
8853
8937
|
mcpStrictConfigEnabled,
|
|
@@ -8884,7 +8968,6 @@ export {
|
|
|
8884
8968
|
ensureMemberDmChannel,
|
|
8885
8969
|
DEFAULT_TIMEZONE,
|
|
8886
8970
|
loadAutomations,
|
|
8887
|
-
loadAutomationsFile,
|
|
8888
8971
|
loadEffectiveAutomations,
|
|
8889
8972
|
BUILT_IN_OUTPUT_STYLES,
|
|
8890
8973
|
OutputStyleConflictError,
|
|
@@ -8945,6 +9028,7 @@ export {
|
|
|
8945
9028
|
setWorkspaceStripeSubscription,
|
|
8946
9029
|
markWorkspaceProjectsSetup,
|
|
8947
9030
|
markWorkspaceGreeted,
|
|
9031
|
+
resetWorkspaceOnboarding,
|
|
8948
9032
|
getWorkspaceGreetedAt,
|
|
8949
9033
|
getWorkspaceByStripeCustomerId,
|
|
8950
9034
|
getWorkspaceBilling,
|
|
@@ -8976,35 +9060,26 @@ export {
|
|
|
8976
9060
|
buildAutoTitle,
|
|
8977
9061
|
BRANDING_DEFAULTS,
|
|
8978
9062
|
getWorkspaceBranding,
|
|
8979
|
-
|
|
8980
|
-
saveDashboardSettings,
|
|
9063
|
+
upsertWorkspaceBranding,
|
|
8981
9064
|
loadWorkspaceBranding,
|
|
8982
9065
|
saveWorkspaceBranding,
|
|
8983
|
-
loadFullDashboardSettings,
|
|
8984
9066
|
loadWorkspacePrompt,
|
|
8985
|
-
saveWorkspacePrompt,
|
|
8986
|
-
resetWorkspacePrompt,
|
|
8987
|
-
saveAgentProfile,
|
|
8988
9067
|
BOT_PROFILE_KEY,
|
|
8989
9068
|
loadBotIdentity,
|
|
8990
9069
|
saveBotIdentity,
|
|
9070
|
+
loadDashboardSettings,
|
|
9071
|
+
saveDashboardSettings,
|
|
9072
|
+
loadFullDashboardSettings,
|
|
9073
|
+
saveWorkspacePrompt,
|
|
9074
|
+
resetWorkspacePrompt,
|
|
9075
|
+
saveAgentProfile,
|
|
8991
9076
|
codexAuthAvailable,
|
|
8992
9077
|
askCodex,
|
|
8993
9078
|
markdownToBlocks,
|
|
8994
9079
|
blockToFallbackText,
|
|
8995
|
-
lookupById,
|
|
8996
|
-
listMemberChannels,
|
|
8997
|
-
refreshCache,
|
|
8998
|
-
resolveChannelId,
|
|
8999
9080
|
runAutomation,
|
|
9000
9081
|
runScriptAutomation,
|
|
9001
9082
|
AutomationManager,
|
|
9002
|
-
listActiveUsers,
|
|
9003
|
-
listUsersWithAvatars,
|
|
9004
|
-
displayNameFor,
|
|
9005
|
-
refreshUserCache,
|
|
9006
|
-
resolveUserId,
|
|
9007
|
-
ensureUsersCached,
|
|
9008
9083
|
MessageQueue,
|
|
9009
9084
|
mimetypeSizeLimit,
|
|
9010
9085
|
buildFilesPromptSection,
|
|
@@ -9024,11 +9099,9 @@ export {
|
|
|
9024
9099
|
listSkills,
|
|
9025
9100
|
listPluginSkillDetails,
|
|
9026
9101
|
findSkillDetail,
|
|
9027
|
-
AutomationRunStore,
|
|
9028
9102
|
recentRunsForWorkspace,
|
|
9029
9103
|
lastRunsForWorkspace,
|
|
9030
9104
|
SessionStore,
|
|
9031
|
-
UsageStore,
|
|
9032
9105
|
installUsageRecording,
|
|
9033
9106
|
startServer
|
|
9034
9107
|
};
|