flyspace-cli 0.1.0 → 0.1.1

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.
@@ -266,6 +266,12 @@ function stopAutomationRegistryPolling() {
266
266
  import { existsSync as existsSync2, mkdirSync, statSync } from "fs";
267
267
  import { homedir } from "os";
268
268
  import { isAbsolute, resolve as resolve2 } from "path";
269
+ function isLogicalCwd(p) {
270
+ return /^[a-z0-9][a-z0-9-]*\/[a-z0-9][a-z0-9-]*$/.test(p);
271
+ }
272
+ function resolveLogicalCwd(p) {
273
+ return resolve2(process.env["FLYSPACE_ROOT"] || resolve2(homedir(), "Flyspace"), p);
274
+ }
269
275
  function expandPath(p) {
270
276
  let expanded = p;
271
277
  if (expanded === "~") {
@@ -296,7 +302,7 @@ function rowToChannel(row) {
296
302
  id: row.id,
297
303
  name: row.name,
298
304
  categoryId: row.category_id,
299
- cwd: expandPath(row.cwd),
305
+ cwd: isLogicalCwd(row.cwd) ? resolveLogicalCwd(row.cwd) : expandPath(row.cwd),
300
306
  externalChannelId: row.external_channel_id,
301
307
  model: row.model,
302
308
  effort: row.effort && isEffort(row.effort) ? row.effort : null,
@@ -487,7 +493,7 @@ function resolveEffort(explicitEffort, channelId, fallback) {
487
493
  function toRow(input) {
488
494
  const row = {};
489
495
  if (input.name !== void 0) row["name"] = input.name;
490
- if (input.cwd !== void 0) row["cwd"] = expandPath(input.cwd);
496
+ if (input.cwd !== void 0) row["cwd"] = isLogicalCwd(input.cwd) ? input.cwd : expandPath(input.cwd);
491
497
  if (input.categoryId !== void 0) row["category_id"] = input.categoryId;
492
498
  if (input.externalChannelId !== void 0) row["external_channel_id"] = input.externalChannelId;
493
499
  if (input.model !== void 0) row["model"] = input.model;
@@ -513,7 +519,7 @@ async function createChannel(input) {
513
519
  const { data, error } = await getSupabaseClient().from("channels").insert({ ...toRow(input), profile: getProfile() }).select().single();
514
520
  if (error) throw new Error(error.message);
515
521
  const channel = rowToChannel(data);
516
- if (channel.cwd && !isCwdUsable(channel.cwd)) {
522
+ if (channel.cwd && !isLogicalCwd(input.cwd) && !isCwdUsable(channel.cwd)) {
517
523
  try {
518
524
  mkdirSync(channel.cwd, { recursive: true });
519
525
  } catch (err) {
@@ -696,8 +702,8 @@ function loadEffectiveAutomations() {
696
702
 
697
703
  // src/claude/agent.ts
698
704
  import { spawn } from "child_process";
699
- import { existsSync as existsSync7, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
700
- import { resolve as resolve3 } from "path";
705
+ import { existsSync as existsSync8, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
706
+ import { resolve as resolve4 } from "path";
701
707
  import { randomUUID } from "crypto";
702
708
 
703
709
  // src/claude/container.ts
@@ -1012,6 +1018,181 @@ function resolveMiseEnv(cwd) {
1012
1018
  }
1013
1019
  }
1014
1020
 
1021
+ // src/store/output-styles-store.ts
1022
+ import { existsSync as existsSync7, mkdirSync as mkdirSync5, readdirSync, readFileSync as readFileSync2, renameSync, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
1023
+ import { homedir as homedir2 } from "os";
1024
+ import { join as join4, resolve as resolve3, sep } from "path";
1025
+ var BUILT_IN_OUTPUT_STYLES = [
1026
+ { slug: "default", name: "Default", description: "Claude Code\u2019s standard software engineering prompt." },
1027
+ { slug: "proactive", name: "Proactive", description: "Works autonomously and makes reasonable calls instead of asking." },
1028
+ { slug: "concise", name: "Concise", description: "The shortest answer that fully addresses the question." },
1029
+ { slug: "explanatory", name: "Explanatory", description: "Walks through the reasoning and trade-offs, not just the result." },
1030
+ { slug: "learning", name: "Learning", description: "Collaborative mode that asks you to write small pieces of code." }
1031
+ ];
1032
+ var OutputStyleConflictError = class extends Error {
1033
+ };
1034
+ var ID_RE = /^[A-Za-z0-9_-][A-Za-z0-9._-]*$/;
1035
+ function resolveDir(claudeConfigDir) {
1036
+ return claudeConfigDir || join4(homedir2(), ".claude");
1037
+ }
1038
+ function stylesDir(claudeConfigDir) {
1039
+ return join4(resolveDir(claudeConfigDir), "output-styles");
1040
+ }
1041
+ function styleFile(claudeConfigDir, id) {
1042
+ if (!ID_RE.test(id)) return null;
1043
+ const dir = resolve3(stylesDir(claudeConfigDir));
1044
+ const file = resolve3(dir, `${id}.md`);
1045
+ return file.startsWith(dir + sep) ? file : null;
1046
+ }
1047
+ function slugify(name) {
1048
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1049
+ }
1050
+ function unquote(raw) {
1051
+ const v = raw.trim();
1052
+ if (v.startsWith('"')) {
1053
+ try {
1054
+ return JSON.parse(v);
1055
+ } catch {
1056
+ return v.slice(1, v.endsWith('"') ? -1 : void 0);
1057
+ }
1058
+ }
1059
+ if (v.startsWith("'") && v.endsWith("'") && v.length > 1) return v.slice(1, -1).replaceAll("''", "'");
1060
+ return v;
1061
+ }
1062
+ function parseStyle(text, fallbackName) {
1063
+ const m = /^---\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n|$)([\s\S]*)$/.exec(text);
1064
+ if (!m) return { name: fallbackName, description: "", body: text.trim(), extra: [] };
1065
+ let name = "";
1066
+ let description = "";
1067
+ const extra = [];
1068
+ for (const line of m[1].split(/\r?\n/)) {
1069
+ const kv = /^(name|description):(.*)$/.exec(line);
1070
+ if (kv) {
1071
+ if (kv[1] === "name") name = unquote(kv[2]);
1072
+ else description = unquote(kv[2]);
1073
+ } else if (line.trim()) extra.push(line);
1074
+ }
1075
+ return { name: name || fallbackName, description, body: m[2].trim(), extra };
1076
+ }
1077
+ function serialize(p) {
1078
+ const head = [`name: ${JSON.stringify(p.name)}`, `description: ${JSON.stringify(p.description)}`, ...p.extra];
1079
+ return `---
1080
+ ${head.join("\n")}
1081
+ ---
1082
+
1083
+ ${p.body.trim()}
1084
+ `;
1085
+ }
1086
+ function atomicWrite(file, content) {
1087
+ mkdirSync5(resolve3(file, ".."), { recursive: true });
1088
+ const tmp = `${file}.${process.pid}.tmp`;
1089
+ writeFileSync2(tmp, content);
1090
+ renameSync(tmp, file);
1091
+ }
1092
+ function readStyle(claudeConfigDir, id) {
1093
+ const file = styleFile(claudeConfigDir, id);
1094
+ if (!file || !existsSync7(file)) return null;
1095
+ const stat = statSync2(file);
1096
+ const p = parseStyle(readFileSync2(file, "utf8"), id);
1097
+ return {
1098
+ id,
1099
+ name: p.name,
1100
+ description: p.description,
1101
+ body: p.body,
1102
+ createdAt: stat.birthtime.toISOString(),
1103
+ updatedAt: stat.mtime.toISOString()
1104
+ };
1105
+ }
1106
+ function listOutputStyles(claudeConfigDir) {
1107
+ const dir = stylesDir(claudeConfigDir);
1108
+ if (!existsSync7(dir)) return [];
1109
+ 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));
1110
+ }
1111
+ function assertNameFree(claudeConfigDir, name, exceptId) {
1112
+ const lower = name.toLowerCase();
1113
+ const taken = BUILT_IN_OUTPUT_STYLES.some((s) => s.name.toLowerCase() === lower) || listOutputStyles(claudeConfigDir).some((s) => s.id !== exceptId && s.name.toLowerCase() === lower);
1114
+ if (taken) throw new OutputStyleConflictError(`an output style named "${name}" already exists`);
1115
+ }
1116
+ function createOutputStyle(claudeConfigDir, params) {
1117
+ const id = slugify(params.name);
1118
+ if (!id) throw new Error("name must contain letters or digits");
1119
+ assertNameFree(claudeConfigDir, params.name);
1120
+ const file = styleFile(claudeConfigDir, id);
1121
+ if (existsSync7(file) || BUILT_IN_OUTPUT_STYLES.some((s) => s.slug === id)) {
1122
+ throw new OutputStyleConflictError(`an output style named "${params.name}" already exists`);
1123
+ }
1124
+ atomicWrite(file, serialize({ ...params, extra: [] }));
1125
+ return readStyle(claudeConfigDir, id);
1126
+ }
1127
+ function updateOutputStyle(claudeConfigDir, id, patch) {
1128
+ const file = styleFile(claudeConfigDir, id);
1129
+ if (!file || !existsSync7(file)) return null;
1130
+ const current = parseStyle(readFileSync2(file, "utf8"), id);
1131
+ if (patch.name !== void 0 && patch.name !== current.name) assertNameFree(claudeConfigDir, patch.name, id);
1132
+ const next = { ...current, ...patch };
1133
+ atomicWrite(file, serialize(next));
1134
+ if (next.name !== current.name && readSettings(claudeConfigDir)["outputStyle"] === current.name) {
1135
+ writeDefaultName(claudeConfigDir, next.name);
1136
+ }
1137
+ return readStyle(claudeConfigDir, id);
1138
+ }
1139
+ function deleteOutputStyle(claudeConfigDir, id) {
1140
+ const file = styleFile(claudeConfigDir, id);
1141
+ if (!file || !existsSync7(file)) return false;
1142
+ const name = parseStyle(readFileSync2(file, "utf8"), id).name;
1143
+ rmSync(file);
1144
+ if (readSettings(claudeConfigDir)["outputStyle"] === name) writeDefaultName(claudeConfigDir, void 0);
1145
+ return true;
1146
+ }
1147
+ function settingsFile(claudeConfigDir) {
1148
+ return join4(resolveDir(claudeConfigDir), "settings.json");
1149
+ }
1150
+ function readSettings(claudeConfigDir) {
1151
+ const file = settingsFile(claudeConfigDir);
1152
+ if (!existsSync7(file)) return {};
1153
+ const parsed = JSON.parse(readFileSync2(file, "utf8"));
1154
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1155
+ throw new Error(`${file} is not a JSON object`);
1156
+ }
1157
+ return parsed;
1158
+ }
1159
+ function writeDefaultName(claudeConfigDir, name) {
1160
+ const settings = readSettings(claudeConfigDir);
1161
+ if (name === void 0) delete settings["outputStyle"];
1162
+ else settings["outputStyle"] = name;
1163
+ atomicWrite(settingsFile(claudeConfigDir), `${JSON.stringify(settings, null, 2)}
1164
+ `);
1165
+ }
1166
+ function resolveSelectedOutputStyle(claudeConfigDir) {
1167
+ let value;
1168
+ try {
1169
+ value = readSettings(claudeConfigDir)["outputStyle"];
1170
+ } catch {
1171
+ return void 0;
1172
+ }
1173
+ if (typeof value !== "string") return void 0;
1174
+ const builtIn = BUILT_IN_OUTPUT_STYLES.find((s) => s.name.toLowerCase() === value.toLowerCase());
1175
+ if (builtIn) {
1176
+ return builtIn.slug === "default" ? void 0 : { id: builtIn.slug, name: builtIn.name, builtIn: true };
1177
+ }
1178
+ const custom = listOutputStyles(claudeConfigDir).find((s) => s.name === value);
1179
+ return custom ? { id: custom.id, name: custom.name, builtIn: false, body: custom.body } : void 0;
1180
+ }
1181
+ function getOutputStyleDefault(claudeConfigDir) {
1182
+ return resolveSelectedOutputStyle(claudeConfigDir)?.id ?? "default";
1183
+ }
1184
+ function setOutputStyleDefault(claudeConfigDir, id) {
1185
+ const builtIn = BUILT_IN_OUTPUT_STYLES.find((s) => s.slug === id);
1186
+ if (builtIn) {
1187
+ writeDefaultName(claudeConfigDir, builtIn.slug === "default" ? void 0 : builtIn.name);
1188
+ return true;
1189
+ }
1190
+ const style = readStyle(claudeConfigDir, id);
1191
+ if (!style) return false;
1192
+ writeDefaultName(claudeConfigDir, style.name);
1193
+ return true;
1194
+ }
1195
+
1015
1196
  // src/claude/models.ts
1016
1197
  var MODEL_OPTIONS = [
1017
1198
  { value: "opus", label: "Opus", provider: "claude" },
@@ -1408,14 +1589,14 @@ function getMaxDurationMs(streaming) {
1408
1589
  }
1409
1590
  function loadSystemPrompt() {
1410
1591
  const customPath = paths.PROMPT_FILE;
1411
- const defaultPath = resolve3(paths.PACKAGE_ROOT, "system.default.md");
1412
- const filePath = existsSync7(customPath) ? customPath : defaultPath;
1413
- return readFileSync2(filePath, "utf-8").trim();
1592
+ const defaultPath = resolve4(paths.PACKAGE_ROOT, "system.default.md");
1593
+ const filePath = existsSync8(customPath) ? customPath : defaultPath;
1594
+ return readFileSync3(filePath, "utf-8").trim();
1414
1595
  }
1415
1596
  function loadCapabilities() {
1416
- const capabilitiesPath = resolve3(paths.PACKAGE_ROOT, "system.capabilities.md");
1417
- if (!existsSync7(capabilitiesPath)) return "";
1418
- return readFileSync2(capabilitiesPath, "utf-8").trim();
1597
+ const capabilitiesPath = resolve4(paths.PACKAGE_ROOT, "system.capabilities.md");
1598
+ if (!existsSync8(capabilitiesPath)) return "";
1599
+ return readFileSync3(capabilitiesPath, "utf-8").trim();
1419
1600
  }
1420
1601
  function buildSystemPrompt(botName, agentPersona, channelPrompt, outputStyle) {
1421
1602
  const prompt = loadSystemPrompt().replaceAll("{{botName}}", botName);
@@ -1451,12 +1632,12 @@ function owningServiceLabel(env = process.env) {
1451
1632
  if (!label || label === "0") return void 0;
1452
1633
  return /^[A-Za-z0-9._-]+$/.test(label) ? label : void 0;
1453
1634
  }
1454
- function buildHookSettings(runtime, nativeStyleName) {
1455
- const guardScript = runtime === "container" ? `${CONTAINER_PATHS.hooks}/bash-guard.mjs` : resolve3(paths.PACKAGE_ROOT, "hooks/bash-guard.mjs");
1635
+ function buildHookSettings(runtime, builtInStyleName) {
1636
+ const guardScript = runtime === "container" ? `${CONTAINER_PATHS.hooks}/bash-guard.mjs` : resolve4(paths.PACKAGE_ROOT, "hooks/bash-guard.mjs");
1456
1637
  const selfLabel = runtime === "container" ? void 0 : owningServiceLabel();
1457
1638
  const guardEnv = selfLabel ? `FLYSPACE_SELF_SERVICE_LABEL='${selfLabel}' ` : "";
1458
1639
  return JSON.stringify({
1459
- ...nativeStyleName ? { outputStyle: nativeStyleName } : {},
1640
+ ...builtInStyleName ? { outputStyle: builtInStyleName } : {},
1460
1641
  hooks: {
1461
1642
  PreToolUse: [
1462
1643
  {
@@ -1467,7 +1648,7 @@ function buildHookSettings(runtime, nativeStyleName) {
1467
1648
  }
1468
1649
  });
1469
1650
  }
1470
- function buildArgs(prompt, botName, options, resumeSessionId) {
1651
+ function buildArgs(prompt, botName, options, resumeSessionId, isolatedStyle) {
1471
1652
  const args = [
1472
1653
  "--print",
1473
1654
  // stream-json emits NDJSON events as they happen (needed for live
@@ -1481,10 +1662,9 @@ function buildArgs(prompt, botName, options, resumeSessionId) {
1481
1662
  botName,
1482
1663
  options.agentPersona,
1483
1664
  options.channelPrompt,
1484
- // Skip the body when a native style name is set below -- the CLI
1485
- // applies that style's own prompt text itself, so injecting our
1486
- // approximation of the same thing too would just be redundant.
1487
- options.outputStyle?.nativeStyleName ? void 0 : options.outputStyle?.body
1665
+ // Host runs: the CLI applies settings.json's style itself. An isolated run
1666
+ // cannot see that file, so a custom style's body is injected here instead.
1667
+ isolatedStyle?.builtIn ? void 0 : isolatedStyle?.body
1488
1668
  ),
1489
1669
  // A container or sandbox run inherits no user settings: CLAUDE_CONFIG_DIR
1490
1670
  // for both points at an isolated per-channel directory, not the machine's
@@ -1494,7 +1674,7 @@ function buildArgs(prompt, botName, options, resumeSessionId) {
1494
1674
  "--setting-sources",
1495
1675
  options.runtime === "container" || options.runtime === "sandbox" ? "project,local" : "user,project,local",
1496
1676
  "--settings",
1497
- buildHookSettings(options.runtime ?? "host", options.outputStyle?.nativeStyleName)
1677
+ buildHookSettings(options.runtime ?? "host", isolatedStyle?.builtIn ? isolatedStyle.name : void 0)
1498
1678
  ];
1499
1679
  if (mcpStrictConfigEnabled()) {
1500
1680
  args.push("--strict-mcp-config");
@@ -1528,8 +1708,15 @@ function recordUsage2(response, options) {
1528
1708
  });
1529
1709
  }
1530
1710
  function runCli(prompt, cwd, botName, options, claudeConfigDir, resumeSessionId, claudeCodeOauthToken) {
1531
- return new Promise((resolve6, reject) => {
1532
- const args = buildArgs(prompt, botName, options, resumeSessionId);
1711
+ return new Promise((resolve7, reject) => {
1712
+ const isolated = options.runtime === "container" || options.runtime === "sandbox";
1713
+ const args = buildArgs(
1714
+ prompt,
1715
+ botName,
1716
+ options,
1717
+ resumeSessionId,
1718
+ isolated ? resolveSelectedOutputStyle(claudeConfigDir) : void 0
1719
+ );
1533
1720
  const env = resolveMiseEnv(cwd);
1534
1721
  env["FLYSPACE_SCRATCH_DIR"] = paths.SCRATCH_DIR;
1535
1722
  env["CLAUDE_CODE_ARTIFACT"] = "1";
@@ -1668,7 +1855,7 @@ function runCli(prompt, cwd, botName, options, claudeConfigDir, resumeSessionId,
1668
1855
  console.log(`[agent] stderr: ${stderr.trim()}`);
1669
1856
  }
1670
1857
  if (cancelled) {
1671
- resolve6({
1858
+ resolve7({
1672
1859
  sessionId: liveSessionId ?? resumeSessionId ?? "",
1673
1860
  text: "",
1674
1861
  isCancelled: true
@@ -1677,7 +1864,7 @@ function runCli(prompt, cwd, botName, options, claudeConfigDir, resumeSessionId,
1677
1864
  }
1678
1865
  if (timedOut) {
1679
1866
  const text = timeoutKind === "wall-clock" && streaming ? `This task ran for over ${Math.round(maxDurationMs / 6e4)} minutes in total, so I was terminated as a runaway backstop. I was still making progress \u2014 the task is just too big for one turn. Consider splitting it into smaller steps, or continue and I'll pick up where I left off.` : `I got stuck for over ${Math.round((timeoutKind === "idle" ? idleTimeoutMs : maxDurationMs) / 6e4)} minutes with no activity and had to be terminated. Most likely cause: a Bash tool call to a long-running process (dev server, watcher, \`tail -f\`, etc.) that never exits. If you wanted to start a server, ask me to run it in the background (\`nohup ... > /tmp/log 2>&1 & disown\`) and I'll come back with the PID.`;
1680
- resolve6({
1867
+ resolve7({
1681
1868
  sessionId: liveSessionId ?? resumeSessionId ?? "",
1682
1869
  text,
1683
1870
  isError: true,
@@ -1705,16 +1892,16 @@ function runCli(prompt, cwd, botName, options, claudeConfigDir, resumeSessionId,
1705
1892
  options.model
1706
1893
  );
1707
1894
  recordUsage2(response, options);
1708
- resolve6(response);
1895
+ resolve7(response);
1709
1896
  } catch {
1710
1897
  const fallback = onLine ? "" : stdout.trim();
1711
- resolve6({ sessionId: resumeSessionId ?? "", text: fallback || "No response" });
1898
+ resolve7({ sessionId: resumeSessionId ?? "", text: fallback || "No response" });
1712
1899
  }
1713
1900
  });
1714
1901
  });
1715
1902
  }
1716
1903
  async function askClaude(prompt, cwd, botName, options, claudeConfigDir, resumeSessionId, claudeCodeOauthToken) {
1717
- if (!existsSync7(cwd) || !statSync2(cwd).isDirectory()) {
1904
+ if (!existsSync8(cwd) || !statSync3(cwd).isDirectory()) {
1718
1905
  console.error(`[agent] working directory does not exist: ${cwd}`);
1719
1906
  return {
1720
1907
  sessionId: resumeSessionId ?? "",
@@ -2035,97 +2222,9 @@ async function setAgentPaused(workspaceId, paused) {
2035
2222
  if (error) throw new Error(`setAgentPaused(${workspaceId}): ${error.message}`);
2036
2223
  }
2037
2224
 
2038
- // src/store/output-styles-store.ts
2039
- var NATIVE_OUTPUT_STYLE_NAMES = {
2040
- concise: "Concise",
2041
- explanatory: "Explanatory"
2042
- };
2043
- var BUILT_IN_STYLE_BODIES = {
2044
- concise: "Lead with the result. Skip preamble and narration, and keep responses short by default. When asked for an explanation or more detail, answer in full.",
2045
- explanatory: 'Alongside completing the task, share brief "Insights" on the reasoning behind implementation choices and the codebase patterns involved.',
2046
- formal: "Respond in structured, businesslike prose. No casual asides, contractions, or emoji."
2047
- };
2048
- function rowToOutputStyle(row) {
2049
- return {
2050
- id: row["id"],
2051
- workspaceId: row["workspace_id"],
2052
- name: row["name"],
2053
- description: row["description"] ?? "",
2054
- body: row["body"] ?? "",
2055
- createdAt: row["created_at"],
2056
- updatedAt: row["updated_at"]
2057
- };
2058
- }
2059
- async function listOutputStyles(workspaceId) {
2060
- const { data, error } = await getSupabaseClient().from("output_styles").select("*").eq("workspace_id", workspaceId).order("created_at", { ascending: true });
2061
- if (error) throw new Error(`Failed to list output styles: ${error.message}`);
2062
- return (data ?? []).map(rowToOutputStyle);
2063
- }
2064
- async function getOutputStyle(workspaceId, id) {
2065
- const { data, error } = await getSupabaseClient().from("output_styles").select("*").eq("workspace_id", workspaceId).eq("id", id).maybeSingle();
2066
- if (error) throw new Error(`Failed to load output style ${id}: ${error.message}`);
2067
- return data ? rowToOutputStyle(data) : null;
2068
- }
2069
- async function insertOutputStyle(params) {
2070
- const { data, error } = await getSupabaseClient().from("output_styles").insert({
2071
- workspace_id: params.workspaceId,
2072
- name: params.name,
2073
- description: params.description,
2074
- body: params.body
2075
- }).select("*").single();
2076
- if (error) throw new Error(`Failed to create output style: ${error.message}`);
2077
- return rowToOutputStyle(data);
2078
- }
2079
- async function updateOutputStyle(workspaceId, id, patch) {
2080
- const update = { updated_at: (/* @__PURE__ */ new Date()).toISOString() };
2081
- if (patch.name !== void 0) update["name"] = patch.name;
2082
- if (patch.description !== void 0) update["description"] = patch.description;
2083
- if (patch.body !== void 0) update["body"] = patch.body;
2084
- const { data, error } = await getSupabaseClient().from("output_styles").update(update).eq("id", id).eq("workspace_id", workspaceId).select("*").maybeSingle();
2085
- if (error) throw new Error(`Failed to update output style: ${error.message}`);
2086
- return data ? rowToOutputStyle(data) : null;
2087
- }
2088
- async function deleteOutputStyle(workspaceId, id) {
2089
- const { data, error } = await getSupabaseClient().from("output_styles").delete().eq("id", id).eq("workspace_id", workspaceId).select("id").maybeSingle();
2090
- if (error) throw new Error(`Failed to delete output style: ${error.message}`);
2091
- return !!data;
2092
- }
2093
- async function getWorkspaceOutputStyleDefault(workspaceId) {
2094
- const { data, error } = await getSupabaseClient().from("workspaces").select("output_style_default").eq("id", workspaceId).maybeSingle();
2095
- if (error) {
2096
- throw new Error(`Failed to load the workspace's default output style: ${error.message}`);
2097
- }
2098
- return data?.["output_style_default"] ?? "default";
2099
- }
2100
- async function setWorkspaceOutputStyleDefault(workspaceId, id) {
2101
- const { error } = await getSupabaseClient().from("workspaces").update({ output_style_default: id }).eq("id", workspaceId);
2102
- if (error) {
2103
- throw new Error(`Failed to set the workspace's default output style: ${error.message}`);
2104
- }
2105
- }
2106
- async function getEffectiveOutputStyle(workspaceId) {
2107
- const defaultId = await getWorkspaceOutputStyleDefault(workspaceId);
2108
- if (defaultId === "default") return void 0;
2109
- const nativeStyleName = NATIVE_OUTPUT_STYLE_NAMES[defaultId];
2110
- if (nativeStyleName) return { nativeStyleName, body: BUILT_IN_STYLE_BODIES[defaultId] };
2111
- if (defaultId in BUILT_IN_STYLE_BODIES) return { body: BUILT_IN_STYLE_BODIES[defaultId] };
2112
- const style = await getOutputStyle(workspaceId, defaultId);
2113
- return style?.body ? { body: style.body } : void 0;
2114
- }
2115
- async function resolveOutputStyleForProfile(profile) {
2116
- try {
2117
- const workspace = await getWorkspaceBySlug(profile);
2118
- if (!workspace) return void 0;
2119
- return await getEffectiveOutputStyle(workspace.id);
2120
- } catch (err) {
2121
- console.error("[output-styles] resolveOutputStyleForProfile failed:", err.message);
2122
- return void 0;
2123
- }
2124
- }
2125
-
2126
2225
  // src/dashboard/settings.ts
2127
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync5, rmSync } from "fs";
2128
- import { dirname, resolve as resolve4 } from "path";
2226
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync9, mkdirSync as mkdirSync6, rmSync as rmSync2 } from "fs";
2227
+ import { dirname, resolve as resolve5 } from "path";
2129
2228
 
2130
2229
  // src/store/workspace-settings-store.ts
2131
2230
  var BRANDING_DEFAULTS = {
@@ -2277,9 +2376,9 @@ function parseAgentProfiles(raw) {
2277
2376
  return entries.length > 0 ? Object.fromEntries(entries) : void 0;
2278
2377
  }
2279
2378
  function loadDashboardSettings() {
2280
- if (!existsSync8(paths.DASHBOARD_SETTINGS_FILE)) return localDefaults();
2379
+ if (!existsSync9(paths.DASHBOARD_SETTINGS_FILE)) return localDefaults();
2281
2380
  try {
2282
- const raw = JSON.parse(readFileSync3(paths.DASHBOARD_SETTINGS_FILE, "utf-8"));
2381
+ const raw = JSON.parse(readFileSync4(paths.DASHBOARD_SETTINGS_FILE, "utf-8"));
2283
2382
  const providers = parseProviders(raw.providers, {
2284
2383
  agent: normalizeDefaultModel(raw.agent, LOCAL_DEFAULTS.agent),
2285
2384
  fallbackModel: typeof raw.fallbackModel === "string" && isAllowedModel(raw.fallbackModel) ? raw.fallbackModel : void 0
@@ -2306,18 +2405,18 @@ function withFallbackModel(providers, model) {
2306
2405
  return [cleared[0], { runner, model }, ...cleared.slice(1).filter((p) => p.runner !== runner)];
2307
2406
  }
2308
2407
  function readSettingsFile() {
2309
- if (!existsSync8(paths.DASHBOARD_SETTINGS_FILE)) return null;
2408
+ if (!existsSync9(paths.DASHBOARD_SETTINGS_FILE)) return null;
2310
2409
  try {
2311
- const raw = JSON.parse(readFileSync3(paths.DASHBOARD_SETTINGS_FILE, "utf-8"));
2410
+ const raw = JSON.parse(readFileSync4(paths.DASHBOARD_SETTINGS_FILE, "utf-8"));
2312
2411
  return raw && typeof raw === "object" ? raw : null;
2313
2412
  } catch {
2314
2413
  return null;
2315
2414
  }
2316
2415
  }
2317
2416
  function writeSettings(next) {
2318
- mkdirSync5(dirname(paths.DASHBOARD_SETTINGS_FILE), { recursive: true });
2417
+ mkdirSync6(dirname(paths.DASHBOARD_SETTINGS_FILE), { recursive: true });
2319
2418
  const merged = { ...readSettingsFile() ?? {}, ...next };
2320
- writeFileSync2(paths.DASHBOARD_SETTINGS_FILE, JSON.stringify(merged, null, 2), "utf-8");
2419
+ writeFileSync3(paths.DASHBOARD_SETTINGS_FILE, JSON.stringify(merged, null, 2), "utf-8");
2321
2420
  return next;
2322
2421
  }
2323
2422
  function saveDashboardSettings(patch) {
@@ -2381,17 +2480,17 @@ async function loadFullDashboardSettings(profile = getProfile()) {
2381
2480
  return { ...await loadWorkspaceBranding(profile), ...loadDashboardSettings() };
2382
2481
  }
2383
2482
  function defaultPromptPath() {
2384
- return resolve4(paths.PACKAGE_ROOT, "system.default.md");
2483
+ return resolve5(paths.PACKAGE_ROOT, "system.default.md");
2385
2484
  }
2386
2485
  function readDefaultPrompt() {
2387
2486
  const path = defaultPromptPath();
2388
- return existsSync8(path) ? readFileSync3(path, "utf-8").trim() : "";
2487
+ return existsSync9(path) ? readFileSync4(path, "utf-8").trim() : "";
2389
2488
  }
2390
2489
  function loadWorkspacePrompt() {
2391
2490
  const defaultPrompt = readDefaultPrompt();
2392
- const custom = existsSync8(paths.PROMPT_FILE);
2491
+ const custom = existsSync9(paths.PROMPT_FILE);
2393
2492
  return {
2394
- prompt: custom ? readFileSync3(paths.PROMPT_FILE, "utf-8").trim() : defaultPrompt,
2493
+ prompt: custom ? readFileSync4(paths.PROMPT_FILE, "utf-8").trim() : defaultPrompt,
2395
2494
  defaultPrompt,
2396
2495
  custom
2397
2496
  };
@@ -2399,13 +2498,13 @@ function loadWorkspacePrompt() {
2399
2498
  function saveWorkspacePrompt(prompt) {
2400
2499
  const trimmed = prompt.trim();
2401
2500
  if (!trimmed || trimmed === readDefaultPrompt()) return resetWorkspacePrompt();
2402
- mkdirSync5(dirname(paths.PROMPT_FILE), { recursive: true });
2403
- writeFileSync2(paths.PROMPT_FILE, `${trimmed}
2501
+ mkdirSync6(dirname(paths.PROMPT_FILE), { recursive: true });
2502
+ writeFileSync3(paths.PROMPT_FILE, `${trimmed}
2404
2503
  `, "utf-8");
2405
2504
  return loadWorkspacePrompt();
2406
2505
  }
2407
2506
  function resetWorkspacePrompt() {
2408
- rmSync(paths.PROMPT_FILE, { force: true });
2507
+ rmSync2(paths.PROMPT_FILE, { force: true });
2409
2508
  return loadWorkspacePrompt();
2410
2509
  }
2411
2510
  function saveAgentProfile(name, patch) {
@@ -2445,9 +2544,9 @@ async function saveBotIdentity(patch, profile = getProfile()) {
2445
2544
 
2446
2545
  // src/codex/agent.ts
2447
2546
  import { spawn as spawn2 } from "child_process";
2448
- import { existsSync as existsSync9, mkdtempSync, readFileSync as readFileSync4, rmSync as rmSync2, statSync as statSync3 } from "fs";
2547
+ import { existsSync as existsSync10, mkdtempSync, readFileSync as readFileSync5, rmSync as rmSync3, statSync as statSync4 } from "fs";
2449
2548
  import { tmpdir } from "os";
2450
- import { join as join4 } from "path";
2549
+ import { join as join5 } from "path";
2451
2550
  var AUTH_ERROR_PATTERNS = [
2452
2551
  /401 unauthorized/i,
2453
2552
  /missing bearer or basic authentication/i,
@@ -2578,8 +2677,8 @@ function getMaxDurationMs2() {
2578
2677
  }
2579
2678
  function codexAuthAvailable(env = process.env) {
2580
2679
  if (env["OPENAI_API_KEY"]?.trim()) return true;
2581
- const home = env["CODEX_HOME"]?.trim() || join4(env["HOME"] ?? "", ".codex");
2582
- return existsSync9(join4(home, "auth.json"));
2680
+ const home = env["CODEX_HOME"]?.trim() || join5(env["HOME"] ?? "", ".codex");
2681
+ return existsSync10(join5(home, "auth.json"));
2583
2682
  }
2584
2683
  function applySystemPrompt(prompt, options, resumeSessionId) {
2585
2684
  if (resumeSessionId || !options.systemPrompt?.trim()) return prompt;
@@ -2628,13 +2727,13 @@ function recordCodexUsage(response, options) {
2628
2727
  });
2629
2728
  }
2630
2729
  function runCodexCli(prompt, cwd, options, resumeSessionId) {
2631
- return new Promise((resolve6, reject) => {
2730
+ return new Promise((resolve7, reject) => {
2632
2731
  const finish = (response) => {
2633
2732
  recordCodexUsage(response, options);
2634
- resolve6(response);
2733
+ resolve7(response);
2635
2734
  };
2636
- const scratch = mkdtempSync(join4(tmpdir(), "flyspace-codex-"));
2637
- const lastMessageFile = join4(scratch, "last-message.txt");
2735
+ const scratch = mkdtempSync(join5(tmpdir(), "flyspace-codex-"));
2736
+ const lastMessageFile = join5(scratch, "last-message.txt");
2638
2737
  const args = buildArgs2(prompt, options, lastMessageFile, resumeSessionId);
2639
2738
  console.log(`[codex] spawning codex CLI in ${cwd}`);
2640
2739
  console.log(`[codex] args: ${args.slice(0, -1).join(" ")}`);
@@ -2704,7 +2803,7 @@ function runCodexCli(prompt, cwd, options, resumeSessionId) {
2704
2803
  const cleanup = () => {
2705
2804
  clearTimeout(timeoutHandle);
2706
2805
  if (signal) signal.removeEventListener("abort", onAbort);
2707
- rmSync2(scratch, { recursive: true, force: true });
2806
+ rmSync3(scratch, { recursive: true, force: true });
2708
2807
  };
2709
2808
  child.stdout.on("data", (data) => {
2710
2809
  const chunk = data.toString();
@@ -2725,7 +2824,7 @@ function runCodexCli(prompt, cwd, options, resumeSessionId) {
2725
2824
  child.on("close", (code) => {
2726
2825
  let lastMessage = "";
2727
2826
  try {
2728
- lastMessage = readFileSync4(lastMessageFile, "utf8").trim();
2827
+ lastMessage = readFileSync5(lastMessageFile, "utf8").trim();
2729
2828
  } catch {
2730
2829
  lastMessage = "";
2731
2830
  }
@@ -2761,7 +2860,7 @@ function runCodexCli(prompt, cwd, options, resumeSessionId) {
2761
2860
  });
2762
2861
  }
2763
2862
  async function askCodex(prompt, cwd, options = {}, resumeSessionId) {
2764
- if (!existsSync9(cwd) || !statSync3(cwd).isDirectory()) {
2863
+ if (!existsSync10(cwd) || !statSync4(cwd).isDirectory()) {
2765
2864
  console.error(`[codex] working directory does not exist: ${cwd}`);
2766
2865
  return {
2767
2866
  sessionId: resumeSessionId ?? "",
@@ -3209,12 +3308,12 @@ function renderAsciiTable(t) {
3209
3308
  (h, i) => Math.max(h.length, ...rows2.map((r) => (r[i] || "").length))
3210
3309
  );
3211
3310
  const fmt = (cells) => "| " + cells.map((c, i) => c.padEnd(widths[i])).join(" | ") + " |";
3212
- const sep2 = "|" + widths.map((w) => "-".repeat(w + 2)).join("|") + "|";
3213
- return [fmt(headers), sep2, ...rows2.map(fmt)].join("\n");
3311
+ const sep3 = "|" + widths.map((w) => "-".repeat(w + 2)).join("|") + "|";
3312
+ return [fmt(headers), sep3, ...rows2.map(fmt)].join("\n");
3214
3313
  }
3215
3314
 
3216
3315
  // src/store/channel-cache.ts
3217
- import { mkdirSync as mkdirSync6 } from "fs";
3316
+ import { mkdirSync as mkdirSync7 } from "fs";
3218
3317
 
3219
3318
  // src/store/sqlite.ts
3220
3319
  import Database from "better-sqlite3";
@@ -3238,7 +3337,7 @@ function getDb() {
3238
3337
  const file = paths.DB_FILE;
3239
3338
  const existing = dbs.get(file);
3240
3339
  if (existing) return existing;
3241
- mkdirSync6(paths.DATA_DIR, { recursive: true });
3340
+ mkdirSync7(paths.DATA_DIR, { recursive: true });
3242
3341
  const db = openLocalDatabase(file);
3243
3342
  if (!db) return null;
3244
3343
  db.exec(`
@@ -3374,7 +3473,6 @@ async function runAutomation(opts) {
3374
3473
 
3375
3474
  `;
3376
3475
  try {
3377
- const outputStyle = await resolveOutputStyleForProfile(getProfile());
3378
3476
  const useCodex = (explicitModel ? runnerForModel(explicitModel) === "codex" : runnerForModel(loadDashboardSettings().agent) === "codex") && !requiresClaudeAutomationRunner(prompt);
3379
3477
  const response = useCodex ? await askCodex(automationPrefix + prompt, cwd, {
3380
3478
  ...explicitModel && runnerForModel(explicitModel) === "codex" ? { model: explicitModel } : codexModel?.trim() ? { model: codexModel.trim() } : {},
@@ -3384,7 +3482,7 @@ async function runAutomation(opts) {
3384
3482
  botName,
3385
3483
  void 0,
3386
3484
  resolveChannelPrompt(channel),
3387
- outputStyle?.body
3485
+ resolveSelectedOutputStyle(claudeConfigDir)?.body
3388
3486
  ),
3389
3487
  // Same attribution as the Claude branch below — no userId, the
3390
3488
  // schedule's name is the label.
@@ -3399,7 +3497,6 @@ async function runAutomation(opts) {
3399
3497
  model,
3400
3498
  maxBudgetUsd,
3401
3499
  channelPrompt: resolveChannelPrompt(channel),
3402
- outputStyle,
3403
3500
  // No userId: nobody triggered this. The schedule's name is the
3404
3501
  // label, which is what makes "which automation is burning tokens"
3405
3502
  // answerable without joining anything.
@@ -3446,7 +3543,7 @@ var DEFAULT_TIMEOUT_MS = 12e4;
3446
3543
  var KILL_GRACE_MS3 = 5e3;
3447
3544
  function runScriptAutomation(opts) {
3448
3545
  const { name, script, cwd, timeoutMs = DEFAULT_TIMEOUT_MS } = opts;
3449
- return new Promise((resolve6, reject) => {
3546
+ return new Promise((resolve7, reject) => {
3450
3547
  const child = spawn3("/bin/bash", [script], { cwd, env: resolveMiseEnv(cwd), stdio: ["ignore", "pipe", "pipe"] });
3451
3548
  let stdout = "";
3452
3549
  let stderr = "";
@@ -3479,7 +3576,7 @@ function runScriptAutomation(opts) {
3479
3576
  } else if (code !== 0) {
3480
3577
  reject(new Error(`script exited with code ${code}: ${stderr.trim()}`));
3481
3578
  } else {
3482
- resolve6();
3579
+ resolve7();
3483
3580
  }
3484
3581
  });
3485
3582
  });
@@ -3835,17 +3932,17 @@ var TriggerEngine = class {
3835
3932
  };
3836
3933
 
3837
3934
  // src/store/user-cache.ts
3838
- import { existsSync as existsSync10, readFileSync as readFileSync5 } from "fs";
3839
- import { join as join5 } from "path";
3935
+ import { existsSync as existsSync11, readFileSync as readFileSync6 } from "fs";
3936
+ import { join as join6 } from "path";
3840
3937
  function jsonUserCachePath() {
3841
- const file = join5(paths.CONFIG_DIR, "slack_users.json");
3842
- return existsSync10(file) ? file : void 0;
3938
+ const file = join6(paths.CONFIG_DIR, "slack_users.json");
3939
+ return existsSync11(file) ? file : void 0;
3843
3940
  }
3844
3941
  function readJsonUserCache() {
3845
3942
  const file = jsonUserCachePath();
3846
3943
  if (!file) return void 0;
3847
3944
  try {
3848
- const parsed = JSON.parse(readFileSync5(file, "utf8"));
3945
+ const parsed = JSON.parse(readFileSync6(file, "utf8"));
3849
3946
  return parsed.users;
3850
3947
  } catch {
3851
3948
  return void 0;
@@ -4237,8 +4334,8 @@ var MessageQueue = class {
4237
4334
  const chains = Array.from(this.chains.values());
4238
4335
  if (chains.length === 0) return true;
4239
4336
  let timer;
4240
- const timeout = new Promise((resolve6) => {
4241
- timer = setTimeout(() => resolve6(false), timeoutMs);
4337
+ const timeout = new Promise((resolve7) => {
4338
+ timer = setTimeout(() => resolve7(false), timeoutMs);
4242
4339
  });
4243
4340
  const done = Promise.all(chains).then(() => true);
4244
4341
  const result = await Promise.race([done, timeout]);
@@ -4252,7 +4349,7 @@ var MessageQueue = class {
4252
4349
 
4253
4350
  // src/slack/file-downloader.ts
4254
4351
  import { writeFile } from "fs/promises";
4255
- import { join as join6, extname } from "path";
4352
+ import { join as join7, extname } from "path";
4256
4353
  var debug3 = process.env["DEBUG"] === "true";
4257
4354
  var SUPPORTED_IMAGE_MIMETYPES = /* @__PURE__ */ new Set([
4258
4355
  "image/png",
@@ -4352,7 +4449,7 @@ async function downloadOne(file, botToken) {
4352
4449
  const ext = extname(originalName) || `.${file.filetype ?? "bin"}`;
4353
4450
  const safeName = sanitizeFilename(originalName.replace(ext, ""));
4354
4451
  const filename = `${Date.now()}-${file.id ?? "unnamed"}-${safeName}${ext}`;
4355
- const localPath = join6(paths.UPLOADS_DIR, filename);
4452
+ const localPath = join7(paths.UPLOADS_DIR, filename);
4356
4453
  await writeFile(localPath, buffer);
4357
4454
  if (debug3)
4358
4455
  console.log(`[file-downloader] saved ${file.id} -> ${localPath} (${buffer.length} bytes)`);
@@ -4767,44 +4864,44 @@ async function summariseThreadTranscript(transcript, opts, deps = {}) {
4767
4864
  }
4768
4865
 
4769
4866
  // src/claude/skills.ts
4770
- import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
4771
- import { homedir as homedir3 } from "os";
4772
- import { basename as basename2, dirname as dirname2, join as join8 } from "path";
4867
+ import { existsSync as existsSync13, readdirSync as readdirSync3, readFileSync as readFileSync8, statSync as statSync6 } from "fs";
4868
+ import { homedir as homedir4 } from "os";
4869
+ import { basename as basename2, dirname as dirname2, join as join9 } from "path";
4773
4870
  import yaml3 from "js-yaml";
4774
4871
 
4775
4872
  // src/claude/skill-files.ts
4776
4873
  import {
4777
- existsSync as existsSync11,
4778
- mkdirSync as mkdirSync7,
4779
- readFileSync as readFileSync6,
4780
- readdirSync,
4781
- rmSync as rmSync3,
4782
- statSync as statSync4,
4783
- writeFileSync as writeFileSync3
4874
+ existsSync as existsSync12,
4875
+ mkdirSync as mkdirSync8,
4876
+ readFileSync as readFileSync7,
4877
+ readdirSync as readdirSync2,
4878
+ rmSync as rmSync4,
4879
+ statSync as statSync5,
4880
+ writeFileSync as writeFileSync4
4784
4881
  } from "fs";
4785
- import { homedir as homedir2 } from "os";
4786
- import { join as join7, resolve as resolve5, sep } from "path";
4882
+ import { homedir as homedir3 } from "os";
4883
+ import { join as join8, resolve as resolve6, sep as sep2 } from "path";
4787
4884
  import yaml2 from "js-yaml";
4788
4885
  var MAX_SKILL_BYTES = 2 * 1024 * 1024;
4789
4886
  var SKILL_NAME = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
4790
4887
  function expandHome(p) {
4791
- if (p === "~") return homedir2();
4792
- if (p.startsWith("~/")) return join7(homedir2(), p.slice(2));
4888
+ if (p === "~") return homedir3();
4889
+ if (p.startsWith("~/")) return join8(homedir3(), p.slice(2));
4793
4890
  return p;
4794
4891
  }
4795
4892
  function workspaceSkillsDir(configDir) {
4796
- return join7(configDir ? expandHome(configDir) : join7(homedir2(), ".claude"), "skills");
4893
+ return join8(configDir ? expandHome(configDir) : join8(homedir3(), ".claude"), "skills");
4797
4894
  }
4798
4895
  function channelSkillsDir(cwd) {
4799
- return join7(cwd, ".claude", "skills");
4896
+ return join8(cwd, ".claude", "skills");
4800
4897
  }
4801
4898
  function isValidSkillName(name) {
4802
4899
  return SKILL_NAME.test(name);
4803
4900
  }
4804
4901
  function resolveSkillPath(dir, name) {
4805
4902
  if (!isValidSkillName(name)) return null;
4806
- const abs = resolve5(dir, name, "SKILL.md");
4807
- if (!abs.startsWith(resolve5(dir) + sep)) return null;
4903
+ const abs = resolve6(dir, name, "SKILL.md");
4904
+ if (!abs.startsWith(resolve6(dir) + sep2)) return null;
4808
4905
  return abs;
4809
4906
  }
4810
4907
  function splitFrontmatter(raw) {
@@ -4831,7 +4928,7 @@ ${body.replace(/^\n+/, "").trimEnd()}
4831
4928
  }
4832
4929
  function readMeta(abs) {
4833
4930
  try {
4834
- const { fm } = splitFrontmatter(readFileSync6(abs, "utf-8"));
4931
+ const { fm } = splitFrontmatter(readFileSync7(abs, "utf-8"));
4835
4932
  return {
4836
4933
  name: typeof fm["name"] === "string" ? fm["name"] : void 0,
4837
4934
  description: typeof fm["description"] === "string" ? fm["description"] : void 0
@@ -4841,20 +4938,20 @@ function readMeta(abs) {
4841
4938
  }
4842
4939
  }
4843
4940
  function listSkillFiles(dir) {
4844
- if (!existsSync11(dir)) return [];
4941
+ if (!existsSync12(dir)) return [];
4845
4942
  let entries;
4846
4943
  try {
4847
- entries = readdirSync(dir);
4944
+ entries = readdirSync2(dir);
4848
4945
  } catch {
4849
4946
  return [];
4850
4947
  }
4851
4948
  const rows2 = [];
4852
4949
  for (const entry of entries) {
4853
4950
  if (!isValidSkillName(entry)) continue;
4854
- const abs = join7(dir, entry, "SKILL.md");
4951
+ const abs = join8(dir, entry, "SKILL.md");
4855
4952
  let stat;
4856
4953
  try {
4857
- stat = statSync4(abs);
4954
+ stat = statSync5(abs);
4858
4955
  } catch {
4859
4956
  continue;
4860
4957
  }
@@ -4875,12 +4972,12 @@ function readSkillFile(dir, name) {
4875
4972
  if (!abs) return null;
4876
4973
  let stat;
4877
4974
  try {
4878
- stat = statSync4(abs);
4975
+ stat = statSync5(abs);
4879
4976
  } catch {
4880
4977
  return null;
4881
4978
  }
4882
4979
  if (!stat.isFile() || stat.size > MAX_SKILL_BYTES) return null;
4883
- const { fm, body } = splitFrontmatter(readFileSync6(abs, "utf-8"));
4980
+ const { fm, body } = splitFrontmatter(readFileSync7(abs, "utf-8"));
4884
4981
  return {
4885
4982
  name,
4886
4983
  description: typeof fm["description"] === "string" ? fm["description"].trim() : "",
@@ -4894,7 +4991,7 @@ function writeSkillFile(dir, name, patch, baseMtime) {
4894
4991
  if (!abs) return { status: "not-found" };
4895
4992
  let stat;
4896
4993
  try {
4897
- stat = statSync4(abs);
4994
+ stat = statSync5(abs);
4898
4995
  } catch {
4899
4996
  return { status: "not-found" };
4900
4997
  }
@@ -4902,18 +4999,18 @@ function writeSkillFile(dir, name, patch, baseMtime) {
4902
4999
  if (baseMtime && stat.mtime.toISOString() !== baseMtime) {
4903
5000
  return { status: "conflict", mtime: stat.mtime.toISOString() };
4904
5001
  }
4905
- const { fm } = splitFrontmatter(readFileSync6(abs, "utf-8"));
5002
+ const { fm } = splitFrontmatter(readFileSync7(abs, "utf-8"));
4906
5003
  const content = buildSkillFile({ ...fm, name, description: patch.description }, patch.body);
4907
5004
  if (Buffer.byteLength(content, "utf8") > MAX_SKILL_BYTES) return { status: "too-large" };
4908
- writeFileSync3(abs, content, "utf8");
4909
- return { status: "ok", mtime: statSync4(abs).mtime.toISOString() };
5005
+ writeFileSync4(abs, content, "utf8");
5006
+ return { status: "ok", mtime: statSync5(abs).mtime.toISOString() };
4910
5007
  }
4911
5008
  function createSkillFile(dir, name, description) {
4912
5009
  const abs = resolveSkillPath(dir, name);
4913
5010
  if (!abs) return { status: "bad-name" };
4914
- if (existsSync11(abs)) return { status: "exists" };
4915
- mkdirSync7(join7(dir, name), { recursive: true });
4916
- writeFileSync3(
5011
+ if (existsSync12(abs)) return { status: "exists" };
5012
+ mkdirSync8(join8(dir, name), { recursive: true });
5013
+ writeFileSync4(
4917
5014
  abs,
4918
5015
  buildSkillFile(
4919
5016
  { name, description },
@@ -4929,24 +5026,24 @@ Describe what this skill does and when to use it.
4929
5026
  }
4930
5027
  function deleteSkillFile(dir, name) {
4931
5028
  const abs = resolveSkillPath(dir, name);
4932
- if (!abs || !existsSync11(abs)) return { status: "not-found" };
4933
- rmSync3(join7(dir, name), { recursive: true, force: true });
5029
+ if (!abs || !existsSync12(abs)) return { status: "not-found" };
5030
+ rmSync4(join8(dir, name), { recursive: true, force: true });
4934
5031
  return { status: "ok" };
4935
5032
  }
4936
5033
 
4937
5034
  // src/claude/skills.ts
4938
5035
  function defaultConfigDir() {
4939
- return join8(homedir3(), ".claude");
5036
+ return join9(homedir4(), ".claude");
4940
5037
  }
4941
5038
  function expandHome2(p) {
4942
- if (p === "~") return homedir3();
4943
- if (p.startsWith("~/")) return join8(homedir3(), p.slice(2));
5039
+ if (p === "~") return homedir4();
5040
+ if (p.startsWith("~/")) return join9(homedir4(), p.slice(2));
4944
5041
  return p;
4945
5042
  }
4946
5043
  function parseFrontmatter(file) {
4947
5044
  let content;
4948
5045
  try {
4949
- content = readFileSync7(file, "utf-8");
5046
+ content = readFileSync8(file, "utf-8");
4950
5047
  } catch {
4951
5048
  return {};
4952
5049
  }
@@ -4964,25 +5061,25 @@ function parseFrontmatter(file) {
4964
5061
  function isSymlinkedDir(root, entry) {
4965
5062
  if (!entry.isSymbolicLink()) return false;
4966
5063
  try {
4967
- return statSync5(join8(root, entry.name)).isDirectory();
5064
+ return statSync6(join9(root, entry.name)).isDirectory();
4968
5065
  } catch {
4969
5066
  return false;
4970
5067
  }
4971
5068
  }
4972
5069
  function findSkillFiles(root, maxDepth, out) {
4973
- if (maxDepth < 0 || !existsSync12(root)) return;
5070
+ if (maxDepth < 0 || !existsSync13(root)) return;
4974
5071
  let entries;
4975
5072
  try {
4976
- entries = readdirSync2(root, { withFileTypes: true });
5073
+ entries = readdirSync3(root, { withFileTypes: true });
4977
5074
  } catch {
4978
5075
  return;
4979
5076
  }
4980
5077
  for (const entry of entries) {
4981
5078
  if (entry.isFile()) {
4982
- if (entry.name === "SKILL.md") out.push(join8(root, entry.name));
5079
+ if (entry.name === "SKILL.md") out.push(join9(root, entry.name));
4983
5080
  } else if (entry.isDirectory() || isSymlinkedDir(root, entry)) {
4984
5081
  if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
4985
- findSkillFiles(join8(root, entry.name), maxDepth - 1, out);
5082
+ findSkillFiles(join9(root, entry.name), maxDepth - 1, out);
4986
5083
  }
4987
5084
  }
4988
5085
  }
@@ -4991,7 +5088,7 @@ function pluginNameFor(file, root) {
4991
5088
  while (dir.startsWith(root) && dir !== dirname2(dir)) {
4992
5089
  try {
4993
5090
  const manifest = JSON.parse(
4994
- readFileSync7(join8(dir, ".claude-plugin", "plugin.json"), "utf-8")
5091
+ readFileSync8(join9(dir, ".claude-plugin", "plugin.json"), "utf-8")
4995
5092
  );
4996
5093
  if (typeof manifest.name === "string" && manifest.name.trim()) return manifest.name.trim();
4997
5094
  } catch {
@@ -5020,10 +5117,10 @@ function collectFrom(root, source, maxDepth, namePrefix) {
5020
5117
  function collectAll(configDir, cwd) {
5021
5118
  const base = configDir ? expandHome2(configDir) : defaultConfigDir();
5022
5119
  const collected = [
5023
- ...collectFrom(join8(cwd, ".claude", "skills"), "project", 2),
5120
+ ...collectFrom(join9(cwd, ".claude", "skills"), "project", 2),
5024
5121
  ...nestedProjectRoots(cwd).flatMap(({ dir, prefix }) => collectFrom(dir, "project", 2, prefix)),
5025
- ...collectFrom(join8(base, "skills"), "user", 2),
5026
- ...collectFrom(join8(base, "plugins"), "plugin", 8)
5122
+ ...collectFrom(join9(base, "skills"), "user", 2),
5123
+ ...collectFrom(join9(base, "plugins"), "plugin", 8)
5027
5124
  ];
5028
5125
  const byName = /* @__PURE__ */ new Map();
5029
5126
  for (const skill of collected) {
@@ -5034,7 +5131,7 @@ function collectAll(configDir, cwd) {
5034
5131
  function nestedProjectRoots(cwd) {
5035
5132
  let entries;
5036
5133
  try {
5037
- entries = readdirSync2(cwd, { withFileTypes: true });
5134
+ entries = readdirSync3(cwd, { withFileTypes: true });
5038
5135
  } catch {
5039
5136
  return [];
5040
5137
  }
@@ -5042,8 +5139,8 @@ function nestedProjectRoots(cwd) {
5042
5139
  for (const entry of entries) {
5043
5140
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
5044
5141
  if (!entry.isDirectory() && !isSymlinkedDir(cwd, entry)) continue;
5045
- const skillsDir = join8(cwd, entry.name, ".claude", "skills");
5046
- if (existsSync12(skillsDir)) roots.push({ dir: skillsDir, prefix: entry.name });
5142
+ const skillsDir = join9(cwd, entry.name, ".claude", "skills");
5143
+ if (existsSync13(skillsDir)) roots.push({ dir: skillsDir, prefix: entry.name });
5047
5144
  }
5048
5145
  return roots;
5049
5146
  }
@@ -5055,8 +5152,8 @@ function listPluginSkillDetails(configDir, cwd) {
5055
5152
  for (const { file, ...skill } of collectAll(configDir, cwd)) {
5056
5153
  if (skill.source !== "plugin") continue;
5057
5154
  try {
5058
- const { body } = splitFrontmatter(readFileSync7(file, "utf-8"));
5059
- details.push({ ...skill, body, path: file, mtime: statSync5(file).mtime.toISOString() });
5155
+ const { body } = splitFrontmatter(readFileSync8(file, "utf-8"));
5156
+ details.push({ ...skill, body, path: file, mtime: statSync6(file).mtime.toISOString() });
5060
5157
  } catch {
5061
5158
  }
5062
5159
  }
@@ -5065,15 +5162,15 @@ function listPluginSkillDetails(configDir, cwd) {
5065
5162
  function findSkillDetail(configDir, cwd, name, sources) {
5066
5163
  const base = configDir ? expandHome2(configDir) : defaultConfigDir();
5067
5164
  const roots = [
5068
- [join8(cwd, ".claude", "skills"), "project", 2],
5165
+ [join9(cwd, ".claude", "skills"), "project", 2],
5069
5166
  ...nestedProjectRoots(cwd).map(({ dir, prefix }) => [
5070
5167
  dir,
5071
5168
  "project",
5072
5169
  2,
5073
5170
  prefix
5074
5171
  ]),
5075
- [join8(base, "skills"), "user", 2],
5076
- [join8(base, "plugins"), "plugin", 8]
5172
+ [join9(base, "skills"), "user", 2],
5173
+ [join9(base, "plugins"), "plugin", 8]
5077
5174
  ];
5078
5175
  for (const [root, source, maxDepth, namePrefix] of roots) {
5079
5176
  if (!sources.includes(source)) continue;
@@ -5087,8 +5184,8 @@ function findSkillDetail(configDir, cwd, name, sources) {
5087
5184
  let raw;
5088
5185
  let mtime;
5089
5186
  try {
5090
- raw = readFileSync7(file, "utf-8");
5091
- mtime = statSync5(file).mtime.toISOString();
5187
+ raw = readFileSync8(file, "utf-8");
5188
+ mtime = statSync6(file).mtime.toISOString();
5092
5189
  } catch {
5093
5190
  continue;
5094
5191
  }
@@ -5579,7 +5676,6 @@ ${trimmedDetail.slice(0, 1500)}
5579
5676
  const threadModelOverride = store.getModelOverride(channelId, sessionKey);
5580
5677
  const effectiveModel = resolveModel(threadModelOverride, channelId, model);
5581
5678
  const runner = threadModelOverride ? runnerForModel(threadModelOverride) : runnerForModel(loadDashboardSettings().agent);
5582
- const outputStyle = await resolveOutputStyleForProfile(getProfile());
5583
5679
  if (runner === "codex") {
5584
5680
  const stored = store.getSession(channelId, sessionKey);
5585
5681
  const resumeId = stored?.runner === "codex" ? stored.sessionId : void 0;
@@ -5593,7 +5689,7 @@ ${trimmedDetail.slice(0, 1500)}
5593
5689
  botName,
5594
5690
  void 0,
5595
5691
  resolveChannelPrompt(channelId),
5596
- outputStyle?.body
5692
+ resolveSelectedOutputStyle(claudeConfigDir)?.body
5597
5693
  ),
5598
5694
  signal: abortController.signal,
5599
5695
  // Same attribution as the Claude path's `askOptions.usageContext`
@@ -5686,7 +5782,6 @@ ${trimmedDetail.slice(0, 1500)}
5686
5782
  // workspace prompt for this channel only — same source the dashboard
5687
5783
  // chat path reads through resolveChannelConfig().
5688
5784
  channelPrompt: resolveChannelPrompt(channelId),
5689
- outputStyle,
5690
5785
  signal: abortController.signal,
5691
5786
  // Attribution for the usage row each spawn writes. Sharing one options
5692
5787
  // object across every attempt is deliberate: the retries below are
@@ -7848,13 +7943,13 @@ async function recoverStaleReactions(client, reactionStore) {
7848
7943
  var ts2 = () => (/* @__PURE__ */ new Date()).toISOString();
7849
7944
  var POWER_POLL_MS = 3e4;
7850
7945
  function isOnACPower() {
7851
- return new Promise((resolve6) => {
7946
+ return new Promise((resolve7) => {
7852
7947
  execFile("pmset", ["-g", "ps"], { timeout: 2e3 }, (err, stdout) => {
7853
7948
  if (err) {
7854
- resolve6(true);
7949
+ resolve7(true);
7855
7950
  return;
7856
7951
  }
7857
- resolve6(stdout.includes("'AC Power'"));
7952
+ resolve7(stdout.includes("'AC Power'"));
7858
7953
  });
7859
7954
  });
7860
7955
  }
@@ -8019,6 +8114,15 @@ export {
8019
8114
  loadAutomations,
8020
8115
  loadAutomationsFile,
8021
8116
  loadEffectiveAutomations,
8117
+ BUILT_IN_OUTPUT_STYLES,
8118
+ OutputStyleConflictError,
8119
+ listOutputStyles,
8120
+ createOutputStyle,
8121
+ updateOutputStyle,
8122
+ deleteOutputStyle,
8123
+ resolveSelectedOutputStyle,
8124
+ getOutputStyleDefault,
8125
+ setOutputStyleDefault,
8022
8126
  runnerForModel,
8023
8127
  isCodexModel,
8024
8128
  agentLabel,
@@ -8057,14 +8161,6 @@ export {
8057
8161
  setAllowGuestAccess,
8058
8162
  getAgentPaused,
8059
8163
  setAgentPaused,
8060
- listOutputStyles,
8061
- getOutputStyle,
8062
- insertOutputStyle,
8063
- updateOutputStyle,
8064
- deleteOutputStyle,
8065
- getWorkspaceOutputStyleDefault,
8066
- setWorkspaceOutputStyleDefault,
8067
- resolveOutputStyleForProfile,
8068
8164
  BRANDING_DEFAULTS,
8069
8165
  getWorkspaceBranding,
8070
8166
  localDefaults,