syntaur 0.5.0 → 0.5.2
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/dashboard/dist/assets/{_basePickBy-Bcut0btZ.js → _basePickBy-ij-Ukp6s.js} +1 -1
- package/dashboard/dist/assets/{_baseUniq-AQSP2JEk.js → _baseUniq-CZKk9gZR.js} +1 -1
- package/dashboard/dist/assets/{arc-BLTpY9lc.js → arc-C30UbJZB.js} +1 -1
- package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-CJtwMY_X.js → architectureDiagram-2XIMDMQ5-BDVieGIr.js} +1 -1
- package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-Don-O7X7.js → blockDiagram-WCTKOSBZ-DZYY4t9w.js} +1 -1
- package/dashboard/dist/assets/{c4Diagram-IC4MRINW-C_M3yTTB.js → c4Diagram-IC4MRINW-B019MXol.js} +1 -1
- package/dashboard/dist/assets/channel-DH4gshIt.js +1 -0
- package/dashboard/dist/assets/{chunk-4BX2VUAB-CGss0jXe.js → chunk-4BX2VUAB-DrkTwY15.js} +1 -1
- package/dashboard/dist/assets/{chunk-55IACEB6-BatoPJga.js → chunk-55IACEB6-mFTAE8DD.js} +1 -1
- package/dashboard/dist/assets/{chunk-FMBD7UC4-DxH4wO82.js → chunk-FMBD7UC4-VgDZaNoS.js} +1 -1
- package/dashboard/dist/assets/{chunk-JSJVCQXG-BL3izAFQ.js → chunk-JSJVCQXG-C_KXaq-c.js} +1 -1
- package/dashboard/dist/assets/{chunk-KX2RTZJC-GnqXwnge.js → chunk-KX2RTZJC-DI-P_pPL.js} +1 -1
- package/dashboard/dist/assets/{chunk-NQ4KR5QH-gvCn4QMb.js → chunk-NQ4KR5QH-TgYAsxTk.js} +1 -1
- package/dashboard/dist/assets/{chunk-QZHKN3VN-CYGWogyi.js → chunk-QZHKN3VN-Drfv_VpM.js} +1 -1
- package/dashboard/dist/assets/{chunk-WL4C6EOR-D9mVTQ1F.js → chunk-WL4C6EOR-CpLwvo_U.js} +1 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-emsfh8H4.js +1 -0
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-emsfh8H4.js +1 -0
- package/dashboard/dist/assets/clone-gdeRwgBN.js +1 -0
- package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-CUWQCKt4.js → cose-bilkent-S5V4N54A-CkKtF37m.js} +1 -1
- package/dashboard/dist/assets/{dagre-KLK3FWXG-CH3ijEvV.js → dagre-KLK3FWXG-BBlY_FL3.js} +1 -1
- package/dashboard/dist/assets/{diagram-E7M64L7V-sq83lpV1.js → diagram-E7M64L7V-DLsFDLHm.js} +1 -1
- package/dashboard/dist/assets/{diagram-IFDJBPK2-BzQG_rtq.js → diagram-IFDJBPK2--sb7diMG.js} +1 -1
- package/dashboard/dist/assets/{diagram-P4PSJMXO-Dg0eZn0q.js → diagram-P4PSJMXO-D2LuEWVt.js} +1 -1
- package/dashboard/dist/assets/{erDiagram-INFDFZHY-4b9eQ0uj.js → erDiagram-INFDFZHY-C1BEeili.js} +1 -1
- package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-C9fzKcsZ.js → flowDiagram-PKNHOUZH-BpbapQbU.js} +1 -1
- package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-Bzt6i9SH.js → ganttDiagram-A5KZAMGK-Io60qUuG.js} +1 -1
- package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-D0wFOagh.js → gitGraphDiagram-K3NZZRJ6-oemlGgRh.js} +1 -1
- package/dashboard/dist/assets/{graph-EEIGvqDh.js → graph-BZb-lGfH.js} +1 -1
- package/dashboard/dist/assets/index-BSVCsfvM.css +1 -0
- package/dashboard/dist/assets/index-CXWVuGs-.js +481 -0
- package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-DLYMsj1D.js → infoDiagram-LFFYTUFH-Ca4mwnZF.js} +1 -1
- package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-DVebKkzl.js → ishikawaDiagram-PHBUUO56-9zuQ8y8W.js} +1 -1
- package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-BsmgOWVw.js → journeyDiagram-4ABVD52K-OdeeOdMx.js} +1 -1
- package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-BTnHf0ey.js → kanban-definition-K7BYSVSG-Cie4JtFn.js} +1 -1
- package/dashboard/dist/assets/{layout-BbM7HRvv.js → layout-Bmx2mvFv.js} +1 -1
- package/dashboard/dist/assets/{linear-C37bJKPO.js → linear-CW6K_-MX.js} +1 -1
- package/dashboard/dist/assets/{mermaid.core-MZ_JgnRL.js → mermaid.core-DmfO6BgK.js} +4 -4
- package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-CgHS4hFo.js → mindmap-definition-YRQLILUH-L6b3vG79.js} +1 -1
- package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-CmAgopJe.js → pieDiagram-SKSYHLDU-CkHTCIWg.js} +1 -1
- package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-BvzYUPR6.js → quadrantDiagram-337W2JSQ-B9MqhhIC.js} +1 -1
- package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-Bs52VP7k.js → requirementDiagram-Z7DCOOCP-CyHAfXCK.js} +1 -1
- package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-aXvGPR1o.js → sankeyDiagram-WA2Y5GQK-DHNzGGyE.js} +1 -1
- package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-CzgcfU6K.js → sequenceDiagram-2WXFIKYE-BVvcJkrx.js} +1 -1
- package/dashboard/dist/assets/{stateDiagram-RAJIS63D-BXBJf9Hq.js → stateDiagram-RAJIS63D-CZ2cknh7.js} +1 -1
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-C4CPervD.js +1 -0
- package/dashboard/dist/assets/{timeline-definition-YZTLITO2-BsXp26Ai.js → timeline-definition-YZTLITO2-BXUtlVyd.js} +1 -1
- package/dashboard/dist/assets/{treemap-KZPCXAKY-C3WbDii1.js → treemap-KZPCXAKY-Dgi-hMKM.js} +1 -1
- package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-B28LMHWd.js → vennDiagram-LZ73GAT5-C9zGrrUQ.js} +1 -1
- package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-C3Xwz8mS.js → xychartDiagram-JWTSCODW-Dq71BUtc.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/dashboard/dist/syntaur-logo.svg +14 -0
- package/dist/dashboard/server.js +335 -8
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.js +1256 -131
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dashboard/dist/assets/channel-BfXmPwE5.js +0 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-D7_G1qy0.js +0 -1
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-D7_G1qy0.js +0 -1
- package/dashboard/dist/assets/clone-BKG-N796.js +0 -1
- package/dashboard/dist/assets/index-Bu6ma6my.css +0 -1
- package/dashboard/dist/assets/index-C7f0ySJE.js +0 -481
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-QqOtsuOs.js +0 -1
package/dist/dashboard/server.js
CHANGED
|
@@ -625,6 +625,53 @@ var init_fs_migration = __esm({
|
|
|
625
625
|
// src/utils/config.ts
|
|
626
626
|
import { readFile as readFile3 } from "fs/promises";
|
|
627
627
|
import { resolve as resolve4, isAbsolute } from "path";
|
|
628
|
+
function parseAgentCommand(value, agentId) {
|
|
629
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
630
|
+
throw new AgentConfigError(
|
|
631
|
+
`agent${agentId ? ` "${agentId}"` : ""} has empty command`
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
const expanded = expandHome(value.trim());
|
|
635
|
+
if (isAbsolute(expanded)) {
|
|
636
|
+
return resolve4(expanded);
|
|
637
|
+
}
|
|
638
|
+
if (expanded.includes("/")) {
|
|
639
|
+
throw new AgentConfigError(
|
|
640
|
+
`agent${agentId ? ` "${agentId}"` : ""} command "${value}" is a relative path \u2014 use an absolute path or a bare binary name`
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
return expanded;
|
|
644
|
+
}
|
|
645
|
+
function validateAgentList(agents) {
|
|
646
|
+
const seen = /* @__PURE__ */ new Set();
|
|
647
|
+
let defaults = 0;
|
|
648
|
+
for (const agent of agents) {
|
|
649
|
+
if (!AGENT_ID_PATTERN.test(agent.id)) {
|
|
650
|
+
throw new AgentConfigError(
|
|
651
|
+
`agent id "${agent.id}" is invalid \u2014 must match /^[a-z0-9][a-z0-9_-]*$/`
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
if (seen.has(agent.id)) {
|
|
655
|
+
throw new AgentConfigError(`duplicate agent id "${agent.id}"`);
|
|
656
|
+
}
|
|
657
|
+
seen.add(agent.id);
|
|
658
|
+
if (!agent.label || agent.label.trim() === "") {
|
|
659
|
+
throw new AgentConfigError(`agent "${agent.id}" has empty label`);
|
|
660
|
+
}
|
|
661
|
+
parseAgentCommand(agent.command, agent.id);
|
|
662
|
+
if (agent.promptArgPosition !== void 0 && !PROMPT_ARG_POSITIONS.includes(agent.promptArgPosition)) {
|
|
663
|
+
throw new AgentConfigError(
|
|
664
|
+
`agent "${agent.id}" has invalid promptArgPosition "${agent.promptArgPosition}" \u2014 expected first|last|none`
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
if (agent.default) defaults++;
|
|
668
|
+
}
|
|
669
|
+
if (defaults > 1) {
|
|
670
|
+
throw new AgentConfigError(
|
|
671
|
+
`more than one agent is marked default: true (only one is allowed)`
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
628
675
|
function cloneDefaultConfig() {
|
|
629
676
|
return {
|
|
630
677
|
...DEFAULT_CONFIG,
|
|
@@ -641,9 +688,14 @@ function cloneDefaultConfig() {
|
|
|
641
688
|
definitions: DEFAULT_CONFIG.types.definitions.map((d) => ({ ...d })),
|
|
642
689
|
default: DEFAULT_CONFIG.types.default
|
|
643
690
|
} : null,
|
|
691
|
+
agents: DEFAULT_CONFIG.agents ? DEFAULT_CONFIG.agents.map((a) => ({
|
|
692
|
+
...a,
|
|
693
|
+
...a.args ? { args: [...a.args] } : {}
|
|
694
|
+
})) : null,
|
|
644
695
|
playbooks: {
|
|
645
696
|
disabled: [...DEFAULT_CONFIG.playbooks.disabled]
|
|
646
|
-
}
|
|
697
|
+
},
|
|
698
|
+
theme: DEFAULT_CONFIG.theme ? { ...DEFAULT_CONFIG.theme } : null
|
|
647
699
|
};
|
|
648
700
|
}
|
|
649
701
|
function parseFrontmatter(content) {
|
|
@@ -874,6 +926,71 @@ ${normalizedFm}
|
|
|
874
926
|
---${afterFrontmatter}`;
|
|
875
927
|
await writeFileForce(configPath, newContent);
|
|
876
928
|
}
|
|
929
|
+
function parseThemeConfig(content) {
|
|
930
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
931
|
+
if (!match) return null;
|
|
932
|
+
const fmBlock = match[1];
|
|
933
|
+
const blockStart = fmBlock.match(/^theme:\s*$/m);
|
|
934
|
+
if (!blockStart) return null;
|
|
935
|
+
const startIdx = fmBlock.indexOf(blockStart[0]) + blockStart[0].length;
|
|
936
|
+
const remaining = fmBlock.slice(startIdx).split("\n");
|
|
937
|
+
let preset = null;
|
|
938
|
+
for (const line of remaining) {
|
|
939
|
+
const trimmed = line.trimStart();
|
|
940
|
+
const indent = line.length - trimmed.length;
|
|
941
|
+
if (indent === 0 && trimmed.length > 0) break;
|
|
942
|
+
if (trimmed === "") continue;
|
|
943
|
+
if (indent === 2 && trimmed.startsWith("preset:")) {
|
|
944
|
+
const value = trimmed.slice("preset:".length).trim().replace(/^["']|["']$/g, "");
|
|
945
|
+
if (value.length > 0) preset = value;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
if (!preset) return null;
|
|
949
|
+
return { preset };
|
|
950
|
+
}
|
|
951
|
+
function serializeThemeConfig(theme) {
|
|
952
|
+
return ["theme:", ` preset: ${theme.preset}`].join("\n");
|
|
953
|
+
}
|
|
954
|
+
async function writeThemeConfig(theme) {
|
|
955
|
+
const configPath = resolve4(syntaurRoot(), "config.md");
|
|
956
|
+
const themeBlock = serializeThemeConfig(theme);
|
|
957
|
+
const existing = await fileExists(configPath) ? await readFile3(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
|
|
958
|
+
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
959
|
+
if (!fmMatch) {
|
|
960
|
+
const content = `---
|
|
961
|
+
version: "2.0"
|
|
962
|
+
defaultProjectDir: ${defaultProjectDir()}
|
|
963
|
+
${themeBlock}
|
|
964
|
+
---
|
|
965
|
+
${existing}`;
|
|
966
|
+
await writeFileForce(configPath, content);
|
|
967
|
+
return;
|
|
968
|
+
}
|
|
969
|
+
const fmBlock = fmMatch[2];
|
|
970
|
+
const afterFrontmatter = existing.slice(fmMatch[0].length);
|
|
971
|
+
const cleanedFm = stripTopLevelBlock(fmBlock, "theme");
|
|
972
|
+
const newFm = `${cleanedFm}
|
|
973
|
+
${themeBlock}`.replace(/^\n+/, "");
|
|
974
|
+
const normalizedFm = newFm.replace(/\n+$/, "");
|
|
975
|
+
const newContent = `---
|
|
976
|
+
${normalizedFm}
|
|
977
|
+
---${afterFrontmatter}`;
|
|
978
|
+
await writeFileForce(configPath, newContent);
|
|
979
|
+
}
|
|
980
|
+
async function deleteThemeConfig() {
|
|
981
|
+
const configPath = resolve4(syntaurRoot(), "config.md");
|
|
982
|
+
if (!await fileExists(configPath)) return;
|
|
983
|
+
const existing = await readFile3(configPath, "utf-8");
|
|
984
|
+
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
985
|
+
if (!fmMatch) return;
|
|
986
|
+
const fmBlock = fmMatch[2];
|
|
987
|
+
const afterFrontmatter = existing.slice(fmMatch[0].length);
|
|
988
|
+
const cleanedFm = stripTopLevelBlock(fmBlock, "theme");
|
|
989
|
+
const newContent = `---
|
|
990
|
+
${cleanedFm}
|
|
991
|
+
---${afterFrontmatter}`;
|
|
992
|
+
await writeFileForce(configPath, newContent);
|
|
993
|
+
}
|
|
877
994
|
function stripTopLevelBlock(fmBlock, key) {
|
|
878
995
|
const blockStart = fmBlock.match(new RegExp(`^${key}:\\s*$`, "m"));
|
|
879
996
|
if (!blockStart) {
|
|
@@ -910,6 +1027,164 @@ function parseOptionalAbsolutePath(value, fieldName) {
|
|
|
910
1027
|
}
|
|
911
1028
|
return resolve4(expanded);
|
|
912
1029
|
}
|
|
1030
|
+
function parseAgentsConfig(content) {
|
|
1031
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
1032
|
+
if (!match) return null;
|
|
1033
|
+
const fmBlock = match[1];
|
|
1034
|
+
const agentsStart = fmBlock.match(/^agents:\s*$/m);
|
|
1035
|
+
if (!agentsStart) return null;
|
|
1036
|
+
const startIdx = fmBlock.indexOf(agentsStart[0]) + agentsStart[0].length;
|
|
1037
|
+
const remaining = fmBlock.slice(startIdx);
|
|
1038
|
+
const lines = remaining.split("\n");
|
|
1039
|
+
const agents = [];
|
|
1040
|
+
let current = null;
|
|
1041
|
+
let argsCapture = null;
|
|
1042
|
+
let argsBaseIndent = 0;
|
|
1043
|
+
function flushCurrent() {
|
|
1044
|
+
if (!current) return;
|
|
1045
|
+
if (!current.id || !current.command || !current.label) {
|
|
1046
|
+
current = null;
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
agents.push({
|
|
1050
|
+
id: current.id,
|
|
1051
|
+
label: current.label,
|
|
1052
|
+
command: current.command,
|
|
1053
|
+
...current.args && current.args.length > 0 ? { args: current.args } : {},
|
|
1054
|
+
...current.promptArgPosition ? { promptArgPosition: current.promptArgPosition } : {},
|
|
1055
|
+
...current.default ? { default: true } : {},
|
|
1056
|
+
...current.resolveFromShellAliases ? { resolveFromShellAliases: true } : {}
|
|
1057
|
+
});
|
|
1058
|
+
current = null;
|
|
1059
|
+
argsCapture = null;
|
|
1060
|
+
}
|
|
1061
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1062
|
+
const line = lines[i];
|
|
1063
|
+
const trimmed = line.trimStart();
|
|
1064
|
+
const indent = line.length - trimmed.length;
|
|
1065
|
+
if (indent === 0 && trimmed !== "" && !trimmed.startsWith("#")) {
|
|
1066
|
+
break;
|
|
1067
|
+
}
|
|
1068
|
+
if (argsCapture) {
|
|
1069
|
+
if (indent > argsBaseIndent && trimmed.startsWith("- ")) {
|
|
1070
|
+
argsCapture.push(decodeYamlScalar(trimmed.slice(2).trim()));
|
|
1071
|
+
continue;
|
|
1072
|
+
} else {
|
|
1073
|
+
argsCapture = null;
|
|
1074
|
+
if (current) current.args = current.args ?? [];
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
if (indent === 2 && trimmed.startsWith("- ")) {
|
|
1078
|
+
flushCurrent();
|
|
1079
|
+
current = {};
|
|
1080
|
+
const rest = trimmed.slice(2).trim();
|
|
1081
|
+
const colonIdx = rest.indexOf(":");
|
|
1082
|
+
if (colonIdx > 0) {
|
|
1083
|
+
const k = rest.slice(0, colonIdx).trim();
|
|
1084
|
+
const v = rest.slice(colonIdx + 1).trim();
|
|
1085
|
+
assignAgentField(current, k, v);
|
|
1086
|
+
}
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
if (indent >= 4 && current) {
|
|
1090
|
+
const colonIdx = trimmed.indexOf(":");
|
|
1091
|
+
if (colonIdx <= 0) continue;
|
|
1092
|
+
const k = trimmed.slice(0, colonIdx).trim();
|
|
1093
|
+
const v = trimmed.slice(colonIdx + 1).trim();
|
|
1094
|
+
if (k === "args" && v === "") {
|
|
1095
|
+
argsCapture = [];
|
|
1096
|
+
argsBaseIndent = indent;
|
|
1097
|
+
current.args = argsCapture;
|
|
1098
|
+
continue;
|
|
1099
|
+
}
|
|
1100
|
+
assignAgentField(current, k, v);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
flushCurrent();
|
|
1104
|
+
if (agents.length === 0) return [];
|
|
1105
|
+
return agents;
|
|
1106
|
+
}
|
|
1107
|
+
function normalizeAgentsFromConfig(agents) {
|
|
1108
|
+
if (agents === null) return null;
|
|
1109
|
+
try {
|
|
1110
|
+
const normalized = agents.map((agent) => ({
|
|
1111
|
+
...agent,
|
|
1112
|
+
command: parseAgentCommand(agent.command, agent.id)
|
|
1113
|
+
}));
|
|
1114
|
+
validateAgentList(normalized);
|
|
1115
|
+
return normalized;
|
|
1116
|
+
} catch (err) {
|
|
1117
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1118
|
+
console.warn(
|
|
1119
|
+
`Warning: ~/.syntaur/config.md agents block is invalid (${msg}) \u2014 using built-in defaults`
|
|
1120
|
+
);
|
|
1121
|
+
return null;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
function decodeYamlScalar(value) {
|
|
1125
|
+
const trimmed = value.trim();
|
|
1126
|
+
if (trimmed.length >= 2 && trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
|
1127
|
+
const body = trimmed.slice(1, -1);
|
|
1128
|
+
let out = "";
|
|
1129
|
+
for (let i = 0; i < body.length; i++) {
|
|
1130
|
+
const ch = body[i];
|
|
1131
|
+
if (ch === "\\" && i + 1 < body.length) {
|
|
1132
|
+
const next = body[i + 1];
|
|
1133
|
+
switch (next) {
|
|
1134
|
+
case "\\":
|
|
1135
|
+
out += "\\";
|
|
1136
|
+
break;
|
|
1137
|
+
case '"':
|
|
1138
|
+
out += '"';
|
|
1139
|
+
break;
|
|
1140
|
+
case "n":
|
|
1141
|
+
out += "\n";
|
|
1142
|
+
break;
|
|
1143
|
+
case "t":
|
|
1144
|
+
out += " ";
|
|
1145
|
+
break;
|
|
1146
|
+
case "r":
|
|
1147
|
+
out += "\r";
|
|
1148
|
+
break;
|
|
1149
|
+
default:
|
|
1150
|
+
out += next;
|
|
1151
|
+
break;
|
|
1152
|
+
}
|
|
1153
|
+
i++;
|
|
1154
|
+
continue;
|
|
1155
|
+
}
|
|
1156
|
+
out += ch;
|
|
1157
|
+
}
|
|
1158
|
+
return out;
|
|
1159
|
+
}
|
|
1160
|
+
if (trimmed.length >= 2 && trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
1161
|
+
return trimmed.slice(1, -1).replace(/''/g, "'");
|
|
1162
|
+
}
|
|
1163
|
+
return trimmed;
|
|
1164
|
+
}
|
|
1165
|
+
function assignAgentField(target, key, rawValue) {
|
|
1166
|
+
const value = decodeYamlScalar(rawValue);
|
|
1167
|
+
switch (key) {
|
|
1168
|
+
case "id":
|
|
1169
|
+
target.id = value;
|
|
1170
|
+
break;
|
|
1171
|
+
case "label":
|
|
1172
|
+
target.label = value;
|
|
1173
|
+
break;
|
|
1174
|
+
case "command":
|
|
1175
|
+
target.command = value;
|
|
1176
|
+
break;
|
|
1177
|
+
case "promptArgPosition":
|
|
1178
|
+
target.promptArgPosition = value;
|
|
1179
|
+
break;
|
|
1180
|
+
case "default":
|
|
1181
|
+
target.default = value === "true";
|
|
1182
|
+
break;
|
|
1183
|
+
case "resolveFromShellAliases":
|
|
1184
|
+
target.resolveFromShellAliases = value === "true";
|
|
1185
|
+
break;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
913
1188
|
async function writeStatusConfig(statuses) {
|
|
914
1189
|
const configPath = resolve4(syntaurRoot(), "config.md");
|
|
915
1190
|
const statusBlock = serializeStatusConfig(statuses);
|
|
@@ -1043,7 +1318,10 @@ async function readConfig() {
|
|
|
1043
1318
|
},
|
|
1044
1319
|
agentDefaults: {
|
|
1045
1320
|
trustLevel: fm["agentDefaults.trustLevel"] || DEFAULT_CONFIG.agentDefaults.trustLevel,
|
|
1046
|
-
autoApprove: fm["agentDefaults.autoApprove"] === "true" || DEFAULT_CONFIG.agentDefaults.autoApprove
|
|
1321
|
+
autoApprove: fm["agentDefaults.autoApprove"] === "true" || DEFAULT_CONFIG.agentDefaults.autoApprove,
|
|
1322
|
+
autoCreateWorktree: AUTO_CREATE_WORKTREE_VALUES.includes(
|
|
1323
|
+
fm["agentDefaults.autoCreateWorktree"]
|
|
1324
|
+
) ? fm["agentDefaults.autoCreateWorktree"] : DEFAULT_CONFIG.agentDefaults.autoCreateWorktree
|
|
1047
1325
|
},
|
|
1048
1326
|
integrations: {
|
|
1049
1327
|
claudePluginDir: parseOptionalAbsolutePath(
|
|
@@ -1067,10 +1345,12 @@ async function readConfig() {
|
|
|
1067
1345
|
} : null,
|
|
1068
1346
|
statuses: parseStatusConfig(content),
|
|
1069
1347
|
types: null,
|
|
1070
|
-
|
|
1348
|
+
agents: normalizeAgentsFromConfig(parseAgentsConfig(content)),
|
|
1349
|
+
playbooks: parsePlaybooksConfig(fmBlock),
|
|
1350
|
+
theme: parseThemeConfig(content)
|
|
1071
1351
|
};
|
|
1072
1352
|
}
|
|
1073
|
-
var DEFAULT_CONFIG, migratedConfigPaths;
|
|
1353
|
+
var DEFAULT_CONFIG, AGENT_ID_PATTERN, PROMPT_ARG_POSITIONS, AUTO_CREATE_WORKTREE_VALUES, AgentConfigError, migratedConfigPaths;
|
|
1074
1354
|
var init_config2 = __esm({
|
|
1075
1355
|
"src/utils/config.ts"() {
|
|
1076
1356
|
"use strict";
|
|
@@ -1086,7 +1366,8 @@ var init_config2 = __esm({
|
|
|
1086
1366
|
},
|
|
1087
1367
|
agentDefaults: {
|
|
1088
1368
|
trustLevel: "medium",
|
|
1089
|
-
autoApprove: false
|
|
1369
|
+
autoApprove: false,
|
|
1370
|
+
autoCreateWorktree: "ask"
|
|
1090
1371
|
},
|
|
1091
1372
|
integrations: {
|
|
1092
1373
|
claudePluginDir: null,
|
|
@@ -1096,9 +1377,16 @@ var init_config2 = __esm({
|
|
|
1096
1377
|
backup: null,
|
|
1097
1378
|
statuses: null,
|
|
1098
1379
|
types: null,
|
|
1380
|
+
agents: null,
|
|
1099
1381
|
playbooks: {
|
|
1100
1382
|
disabled: []
|
|
1101
|
-
}
|
|
1383
|
+
},
|
|
1384
|
+
theme: null
|
|
1385
|
+
};
|
|
1386
|
+
AGENT_ID_PATTERN = /^[a-z0-9][a-z0-9_-]*$/;
|
|
1387
|
+
PROMPT_ARG_POSITIONS = ["first", "last", "none"];
|
|
1388
|
+
AUTO_CREATE_WORKTREE_VALUES = ["skip", "ask", "always"];
|
|
1389
|
+
AgentConfigError = class extends Error {
|
|
1102
1390
|
};
|
|
1103
1391
|
migratedConfigPaths = /* @__PURE__ */ new Set();
|
|
1104
1392
|
}
|
|
@@ -8734,6 +9022,43 @@ function createDashboardServer(options) {
|
|
|
8734
9022
|
res.status(500).json({ error: "Failed to reset status config" });
|
|
8735
9023
|
}
|
|
8736
9024
|
});
|
|
9025
|
+
const THEME_PRESET_SLUGS = ["default", "ocean", "forest", "sunset"];
|
|
9026
|
+
const DEFAULT_THEME_PRESET = "default";
|
|
9027
|
+
app.get("/api/config/theme", async (_req, res) => {
|
|
9028
|
+
try {
|
|
9029
|
+
const config = await readConfig();
|
|
9030
|
+
const preset = config.theme?.preset ?? DEFAULT_THEME_PRESET;
|
|
9031
|
+
res.json({ preset, custom: config.theme !== null });
|
|
9032
|
+
} catch (error) {
|
|
9033
|
+
console.error("Error getting theme config:", error);
|
|
9034
|
+
res.status(500).json({ error: "Failed to get theme config" });
|
|
9035
|
+
}
|
|
9036
|
+
});
|
|
9037
|
+
app.post("/api/config/theme", async (req, res) => {
|
|
9038
|
+
try {
|
|
9039
|
+
const { preset } = req.body ?? {};
|
|
9040
|
+
if (typeof preset !== "string" || !THEME_PRESET_SLUGS.includes(preset)) {
|
|
9041
|
+
res.status(400).json({
|
|
9042
|
+
error: `preset must be one of: ${THEME_PRESET_SLUGS.join(", ")}`
|
|
9043
|
+
});
|
|
9044
|
+
return;
|
|
9045
|
+
}
|
|
9046
|
+
await writeThemeConfig({ preset });
|
|
9047
|
+
res.json({ preset, custom: true });
|
|
9048
|
+
} catch (error) {
|
|
9049
|
+
console.error("Error saving theme config:", error);
|
|
9050
|
+
res.status(500).json({ error: "Failed to save theme config" });
|
|
9051
|
+
}
|
|
9052
|
+
});
|
|
9053
|
+
app.delete("/api/config/theme", async (_req, res) => {
|
|
9054
|
+
try {
|
|
9055
|
+
await deleteThemeConfig();
|
|
9056
|
+
res.json({ preset: DEFAULT_THEME_PRESET, custom: false });
|
|
9057
|
+
} catch (error) {
|
|
9058
|
+
console.error("Error resetting theme config:", error);
|
|
9059
|
+
res.status(500).json({ error: "Failed to reset theme config" });
|
|
9060
|
+
}
|
|
9061
|
+
});
|
|
8737
9062
|
app.get("/api/projects", async (req, res) => {
|
|
8738
9063
|
try {
|
|
8739
9064
|
let projects = await listProjects(projectsDir);
|
|
@@ -8873,7 +9198,9 @@ function createDashboardServer(options) {
|
|
|
8873
9198
|
app.use("/api/projects/:projectId/todos", createProjectTodosRouter(projectsDir, broadcast));
|
|
8874
9199
|
app.use("/api/backup", createBackupRouter());
|
|
8875
9200
|
if (serveStaticUi && dashboardDistPath) {
|
|
8876
|
-
|
|
9201
|
+
const sendOpts = { dotfiles: "allow" };
|
|
9202
|
+
app.use("/assets", express.static(resolve18(dashboardDistPath, "assets"), sendOpts));
|
|
9203
|
+
app.use(express.static(dashboardDistPath, { ...sendOpts, index: false, fallthrough: true }));
|
|
8877
9204
|
app.get("{*path}", async (req, res) => {
|
|
8878
9205
|
if (req.path.startsWith("/api") || req.path === "/ws" || req.path.startsWith("/assets")) {
|
|
8879
9206
|
res.status(404).json({ error: "Not Found" });
|
|
@@ -8886,7 +9213,7 @@ function createDashboardServer(options) {
|
|
|
8886
9213
|
);
|
|
8887
9214
|
return;
|
|
8888
9215
|
}
|
|
8889
|
-
res.sendFile(indexPath, (err) => {
|
|
9216
|
+
res.sendFile(indexPath, sendOpts, (err) => {
|
|
8890
9217
|
if (err) {
|
|
8891
9218
|
console.error("Error sending dashboard index.html:", err);
|
|
8892
9219
|
if (!res.headersSent) res.status(500).send("Dashboard load error");
|