syntaur 0.75.0 → 0.77.0
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/.claude-plugin/plugin.json +1 -1
- package/dashboard/dist/assets/{_basePickBy-Cj5wouIO.js → _basePickBy-CmtR3VlC.js} +1 -1
- package/dashboard/dist/assets/{_baseUniq-uoD3r5Lh.js → _baseUniq-d5yVqkuO.js} +1 -1
- package/dashboard/dist/assets/{arc-Bsl9iLIF.js → arc-BTfvlUzk.js} +1 -1
- package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-ChAY3fon.js → architectureDiagram-2XIMDMQ5-ComKmfQn.js} +1 -1
- package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-CiALbCXV.js → blockDiagram-WCTKOSBZ-69xtTOqC.js} +1 -1
- package/dashboard/dist/assets/{c4Diagram-IC4MRINW-B9ykJE5a.js → c4Diagram-IC4MRINW-B5MsrIyR.js} +1 -1
- package/dashboard/dist/assets/channel-B55sx3Pw.js +1 -0
- package/dashboard/dist/assets/{chunk-4BX2VUAB-DPNMTYz8.js → chunk-4BX2VUAB-BV-rQx2S.js} +1 -1
- package/dashboard/dist/assets/{chunk-55IACEB6-UFkoEp3B.js → chunk-55IACEB6-BHoZ0_2C.js} +1 -1
- package/dashboard/dist/assets/{chunk-FMBD7UC4-BN4UsRVp.js → chunk-FMBD7UC4-BZppz6s9.js} +1 -1
- package/dashboard/dist/assets/{chunk-JSJVCQXG-H_f-EJCZ.js → chunk-JSJVCQXG-BKJIycjQ.js} +1 -1
- package/dashboard/dist/assets/{chunk-KX2RTZJC-BPjizgwa.js → chunk-KX2RTZJC-Drv6rL3f.js} +1 -1
- package/dashboard/dist/assets/{chunk-NQ4KR5QH-DgeG5isU.js → chunk-NQ4KR5QH-u1ws00gN.js} +1 -1
- package/dashboard/dist/assets/{chunk-QZHKN3VN-CJXZCDFY.js → chunk-QZHKN3VN-zCyNaZcO.js} +1 -1
- package/dashboard/dist/assets/{chunk-WL4C6EOR-DXPbG5r8.js → chunk-WL4C6EOR-Dz0hDBUx.js} +1 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-Kgg-J05j.js +1 -0
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-Kgg-J05j.js +1 -0
- package/dashboard/dist/assets/clone-DXxPBQmb.js +1 -0
- package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-B0S22TLu.js → cose-bilkent-S5V4N54A-CO0Ms-ys.js} +1 -1
- package/dashboard/dist/assets/{dagre-KLK3FWXG-iW797T4v.js → dagre-KLK3FWXG-BDBGlQ5i.js} +1 -1
- package/dashboard/dist/assets/{diagram-E7M64L7V-zXYLlqYa.js → diagram-E7M64L7V-C1jhhA3a.js} +1 -1
- package/dashboard/dist/assets/{diagram-IFDJBPK2-BDdMdE2u.js → diagram-IFDJBPK2-DYA2G930.js} +1 -1
- package/dashboard/dist/assets/{diagram-P4PSJMXO-CwqwK1lQ.js → diagram-P4PSJMXO-iox20fhC.js} +1 -1
- package/dashboard/dist/assets/{erDiagram-INFDFZHY-CmlGISPx.js → erDiagram-INFDFZHY-CdrG4ZUW.js} +1 -1
- package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-BAxunYoQ.js → flowDiagram-PKNHOUZH-CMuagI-6.js} +1 -1
- package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-Cn4q3HyV.js → ganttDiagram-A5KZAMGK-C8jgdfRO.js} +1 -1
- package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-Dazu58q1.js → gitGraphDiagram-K3NZZRJ6-Chu0FgBt.js} +1 -1
- package/dashboard/dist/assets/{graph-BBx_Y0Dm.js → graph-RWP7g4cL.js} +1 -1
- package/dashboard/dist/assets/index-BFpKR1Z0.js +690 -0
- package/dashboard/dist/assets/{index-BetqH_3H.css → index-C6KBRx3q.css} +1 -1
- package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-C27nHoRd.js → infoDiagram-LFFYTUFH-bIlmxe7x.js} +1 -1
- package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-DYxpNPld.js → ishikawaDiagram-PHBUUO56-CvvXAmzr.js} +1 -1
- package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-Dm0g2SlP.js → journeyDiagram-4ABVD52K-BlSVnlQk.js} +1 -1
- package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-DFMR1cb5.js → kanban-definition-K7BYSVSG-D6kAus7L.js} +1 -1
- package/dashboard/dist/assets/{layout-lF_n-m9p.js → layout-BIoVL4m2.js} +1 -1
- package/dashboard/dist/assets/{linear-D3fOfDjk.js → linear-B4ySyXON.js} +1 -1
- package/dashboard/dist/assets/{mermaid.core-BQxxvCJY.js → mermaid.core-B_8IjgQO.js} +4 -4
- package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-BD31M5_l.js → mindmap-definition-YRQLILUH-B6RTS8xi.js} +1 -1
- package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-C2RHC4j8.js → pieDiagram-SKSYHLDU-EntB8Xmg.js} +1 -1
- package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-BuzGUAFP.js → quadrantDiagram-337W2JSQ-UTEbe4g6.js} +1 -1
- package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-BfbKujmv.js → requirementDiagram-Z7DCOOCP-qG2oV68i.js} +1 -1
- package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-BeHTatTO.js → sankeyDiagram-WA2Y5GQK-C-EzJpn8.js} +1 -1
- package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-D0iiDmN4.js → sequenceDiagram-2WXFIKYE-rCjfcAr5.js} +1 -1
- package/dashboard/dist/assets/{stateDiagram-RAJIS63D-DT9Q9hP4.js → stateDiagram-RAJIS63D-C3hoQmLC.js} +1 -1
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-rHFeeHzp.js +1 -0
- package/dashboard/dist/assets/{timeline-definition-YZTLITO2-DJiIMZoa.js → timeline-definition-YZTLITO2-2gGWKHHW.js} +1 -1
- package/dashboard/dist/assets/{treemap-KZPCXAKY-DmEMf93k.js → treemap-KZPCXAKY-BV6TTFvC.js} +1 -1
- package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-Curdpkhp.js → vennDiagram-LZ73GAT5-C1aeXQ29.js} +1 -1
- package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-BXin4AvW.js → xychartDiagram-JWTSCODW-BDbba6Mg.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/dist/dashboard/server.js +845 -147
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.js +1290 -547
- package/dist/index.js.map +1 -1
- package/dist/launch/index.d.ts +41 -0
- package/dist/launch/index.js +200 -21
- package/dist/launch/index.js.map +1 -1
- package/package.json +1 -1
- package/platforms/claude-code/.claude-plugin/plugin.json +1 -1
- package/platforms/codex/.codex-plugin/plugin.json +1 -1
- package/platforms/hermes/plugins/syntaur/__pycache__/__init__.cpython-312.pyc +0 -0
- package/platforms/hermes/plugins/syntaur/__pycache__/boundary.cpython-312.pyc +0 -0
- package/dashboard/dist/assets/channel-DGGrKtvR.js +0 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-O5pXkiFS.js +0 -1
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-O5pXkiFS.js +0 -1
- package/dashboard/dist/assets/clone-DjMP6PdW.js +0 -1
- package/dashboard/dist/assets/index-D9z0k09w.js +0 -675
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-dTCQtscr.js +0 -1
package/dist/index.js
CHANGED
|
@@ -2647,6 +2647,14 @@ function agentNameArgs(agent) {
|
|
|
2647
2647
|
const n = agent.agentName?.trim();
|
|
2648
2648
|
return n ? ["--agent", n] : [];
|
|
2649
2649
|
}
|
|
2650
|
+
function resolveRunner(agent) {
|
|
2651
|
+
if (agent.runner) return agent.runner;
|
|
2652
|
+
if (agent.agentName && agent.agentName.trim() !== "") return "claude";
|
|
2653
|
+
const cmd = agent.command ?? "";
|
|
2654
|
+
if (/claude/i.test(cmd) || agent.id === "claude") return "claude";
|
|
2655
|
+
if (/codex/i.test(cmd) || agent.id === "codex") return "codex";
|
|
2656
|
+
return "pi";
|
|
2657
|
+
}
|
|
2650
2658
|
function stripModelFlags(args) {
|
|
2651
2659
|
const out = [];
|
|
2652
2660
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -3917,6 +3925,7 @@ __export(config_exports, {
|
|
|
3917
3925
|
parseStatusConfig: () => parseStatusConfig,
|
|
3918
3926
|
parseTerminalConfig: () => parseTerminalConfig,
|
|
3919
3927
|
readConfig: () => readConfig,
|
|
3928
|
+
serializeAgentDiscoveryConfig: () => serializeAgentDiscoveryConfig,
|
|
3920
3929
|
serializeSearchConfig: () => serializeSearchConfig,
|
|
3921
3930
|
serializeStatusConfig: () => serializeStatusConfig,
|
|
3922
3931
|
toTitleCase: () => toTitleCase,
|
|
@@ -3930,6 +3939,7 @@ __export(config_exports, {
|
|
|
3930
3939
|
validateDeriveShape: () => validateDeriveShape,
|
|
3931
3940
|
validateFactDeclarations: () => validateFactDeclarations,
|
|
3932
3941
|
validateStalenessConfig: () => validateStalenessConfig,
|
|
3942
|
+
writeAgentDiscoveryConfig: () => writeAgentDiscoveryConfig,
|
|
3933
3943
|
writeAgentsConfig: () => writeAgentsConfig,
|
|
3934
3944
|
writeHotkeyBindingsConfig: () => writeHotkeyBindingsConfig,
|
|
3935
3945
|
writeSearchConfig: () => writeSearchConfig,
|
|
@@ -4022,6 +4032,50 @@ function validateAgentList(agents) {
|
|
|
4022
4032
|
`agent "${agent.id}" sets both agentName and model \u2014 the agent definition's own model is authoritative; remove the profile model`
|
|
4023
4033
|
);
|
|
4024
4034
|
}
|
|
4035
|
+
if (agent.runner !== void 0 && !RUNNER_KINDS.includes(agent.runner)) {
|
|
4036
|
+
throw new AgentConfigError(
|
|
4037
|
+
`agent "${agent.id}" has invalid runner "${agent.runner}" \u2014 must be one of ${RUNNER_KINDS.join(", ")}`
|
|
4038
|
+
);
|
|
4039
|
+
}
|
|
4040
|
+
if (agent.sourceKind !== void 0 && !AGENT_SOURCE_KINDS.includes(agent.sourceKind)) {
|
|
4041
|
+
throw new AgentConfigError(
|
|
4042
|
+
`agent "${agent.id}" has invalid sourceKind "${agent.sourceKind}" \u2014 must be one of ${AGENT_SOURCE_KINDS.join(", ")}`
|
|
4043
|
+
);
|
|
4044
|
+
}
|
|
4045
|
+
if (agent.sourcePath !== void 0 && /[\r\n]/.test(agent.sourcePath)) {
|
|
4046
|
+
throw new AgentConfigError(
|
|
4047
|
+
`agent "${agent.id}" has invalid sourcePath \u2014 must be a single line (no newlines)`
|
|
4048
|
+
);
|
|
4049
|
+
}
|
|
4050
|
+
if (agent.sourceRepo !== void 0 && /[\r\n]/.test(agent.sourceRepo)) {
|
|
4051
|
+
throw new AgentConfigError(
|
|
4052
|
+
`agent "${agent.id}" has invalid sourceRepo \u2014 must be a single line (no newlines)`
|
|
4053
|
+
);
|
|
4054
|
+
}
|
|
4055
|
+
if (agent.runner === "claude" && agent.workdir !== void 0 && agent.workdir.trim() !== "") {
|
|
4056
|
+
throw new AgentConfigError(
|
|
4057
|
+
`agent "${agent.id}" has runner "claude" but sets workdir \u2014 a claude agent uses agentName, not workdir`
|
|
4058
|
+
);
|
|
4059
|
+
}
|
|
4060
|
+
if ((agent.runner === "pi" || agent.runner === "codex") && agent.agentName !== void 0 && agent.agentName.trim() !== "") {
|
|
4061
|
+
throw new AgentConfigError(
|
|
4062
|
+
`agent "${agent.id}" has runner "${agent.runner}" but sets agentName \u2014 a directory agent uses workdir, not agentName`
|
|
4063
|
+
);
|
|
4064
|
+
}
|
|
4065
|
+
if (agent.runner !== void 0 && agent.sourceKind !== void 0) {
|
|
4066
|
+
const directorySource = agent.sourceKind === "directory";
|
|
4067
|
+
const claudeRunner = agent.runner === "claude";
|
|
4068
|
+
if (directorySource && claudeRunner) {
|
|
4069
|
+
throw new AgentConfigError(
|
|
4070
|
+
`agent "${agent.id}" has sourceKind "directory" but runner "claude" \u2014 a directory source is a pi/codex agent`
|
|
4071
|
+
);
|
|
4072
|
+
}
|
|
4073
|
+
if (!directorySource && !claudeRunner) {
|
|
4074
|
+
throw new AgentConfigError(
|
|
4075
|
+
`agent "${agent.id}" has sourceKind "${agent.sourceKind}" but runner "${agent.runner}" \u2014 a ${agent.sourceKind} source is a claude agent`
|
|
4076
|
+
);
|
|
4077
|
+
}
|
|
4078
|
+
}
|
|
4025
4079
|
validateSessionInvocation(agent, "resume", agent.resume);
|
|
4026
4080
|
validateSessionInvocation(agent, "fork", agent.fork);
|
|
4027
4081
|
if (agent.default) defaults++;
|
|
@@ -4124,6 +4178,21 @@ function parseInstalledAgents(fm) {
|
|
|
4124
4178
|
}
|
|
4125
4179
|
return Object.keys(installedAgents).length > 0 ? { installedAgents } : {};
|
|
4126
4180
|
}
|
|
4181
|
+
function parseAgentDiscoveryFromFm(fm) {
|
|
4182
|
+
const flag = (key, def) => {
|
|
4183
|
+
const v = fm[key];
|
|
4184
|
+
if (v === void 0) return def;
|
|
4185
|
+
return String(v).toLowerCase() === "true";
|
|
4186
|
+
};
|
|
4187
|
+
const rootsRaw = fm["agentDiscovery.roots"];
|
|
4188
|
+
const roots = rootsRaw !== void 0 && String(rootsRaw).trim() !== "" ? String(rootsRaw).split(":").map((r) => r.trim()).filter((r) => r.length > 0) : [];
|
|
4189
|
+
return {
|
|
4190
|
+
claudeGlobal: flag("agentDiscovery.claudeGlobal", true),
|
|
4191
|
+
claudeProject: flag("agentDiscovery.claudeProject", true),
|
|
4192
|
+
directory: flag("agentDiscovery.directory", true),
|
|
4193
|
+
roots: roots.length > 0 ? roots : DEFAULT_CONFIG.agentDiscovery.roots.slice()
|
|
4194
|
+
};
|
|
4195
|
+
}
|
|
4127
4196
|
function parseStatusConfig(content) {
|
|
4128
4197
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
4129
4198
|
if (!match) return null;
|
|
@@ -4632,6 +4701,43 @@ ${cleanedFm}
|
|
|
4632
4701
|
---${afterFrontmatter}`;
|
|
4633
4702
|
await writeFileForce(configPath2, newContent);
|
|
4634
4703
|
}
|
|
4704
|
+
function serializeAgentDiscoveryConfig(cfg) {
|
|
4705
|
+
return [
|
|
4706
|
+
"agentDiscovery:",
|
|
4707
|
+
` claudeGlobal: ${cfg.claudeGlobal}`,
|
|
4708
|
+
` claudeProject: ${cfg.claudeProject}`,
|
|
4709
|
+
` directory: ${cfg.directory}`,
|
|
4710
|
+
` roots: ${cfg.roots.join(":")}`
|
|
4711
|
+
].join("\n");
|
|
4712
|
+
}
|
|
4713
|
+
async function writeAgentDiscoveryConfig(cfg, standaloneDefaultCwd) {
|
|
4714
|
+
const configPath2 = resolve7(syntaurRoot(), "config.md");
|
|
4715
|
+
const block = serializeAgentDiscoveryConfig(cfg);
|
|
4716
|
+
const scalarLine = standaloneDefaultCwd ? `standaloneDefaultCwd: ${standaloneDefaultCwd}` : "";
|
|
4717
|
+
const additions = [block, scalarLine].filter(Boolean).join("\n");
|
|
4718
|
+
const existing = await fileExists(configPath2) ? await readFile5(configPath2, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
|
|
4719
|
+
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
4720
|
+
if (!fmMatch) {
|
|
4721
|
+
const content = `---
|
|
4722
|
+
version: "2.0"
|
|
4723
|
+
defaultProjectDir: ${defaultProjectDir()}
|
|
4724
|
+
${additions}
|
|
4725
|
+
---
|
|
4726
|
+
${existing}`;
|
|
4727
|
+
await writeFileForce(configPath2, content);
|
|
4728
|
+
return;
|
|
4729
|
+
}
|
|
4730
|
+
const fmBlock = fmMatch[2];
|
|
4731
|
+
const afterFrontmatter = existing.slice(fmMatch[0].length);
|
|
4732
|
+
let cleanedFm = stripTopLevelBlock(fmBlock, "agentDiscovery");
|
|
4733
|
+
cleanedFm = stripTopLevelScalar(cleanedFm, "standaloneDefaultCwd");
|
|
4734
|
+
const newFm = `${cleanedFm}
|
|
4735
|
+
${additions}`.replace(/^\n+/, "").replace(/\n+$/, "");
|
|
4736
|
+
const newContent = `---
|
|
4737
|
+
${newFm}
|
|
4738
|
+
---${afterFrontmatter}`;
|
|
4739
|
+
await writeFileForce(configPath2, newContent);
|
|
4740
|
+
}
|
|
4635
4741
|
function stripTopLevelScalar(fmBlock, key) {
|
|
4636
4742
|
const lines = fmBlock.split("\n");
|
|
4637
4743
|
const keyRegex = new RegExp(`^${key}:\\s*\\S`);
|
|
@@ -4844,6 +4950,10 @@ function parseAgentsConfig(content) {
|
|
|
4844
4950
|
...current.launchPrompt ? { launchPrompt: current.launchPrompt } : {},
|
|
4845
4951
|
...current.agentName ? { agentName: current.agentName } : {},
|
|
4846
4952
|
...current.workdir ? { workdir: current.workdir } : {},
|
|
4953
|
+
...current.runner ? { runner: current.runner } : {},
|
|
4954
|
+
...current.sourceKind ? { sourceKind: current.sourceKind } : {},
|
|
4955
|
+
...current.sourcePath ? { sourcePath: current.sourcePath } : {},
|
|
4956
|
+
...current.sourceRepo ? { sourceRepo: current.sourceRepo } : {},
|
|
4847
4957
|
...current.resume ? { resume: current.resume } : {},
|
|
4848
4958
|
...current.fork ? { fork: current.fork } : {}
|
|
4849
4959
|
});
|
|
@@ -5041,6 +5151,18 @@ function assignAgentField(target, key, rawValue) {
|
|
|
5041
5151
|
case "workdir":
|
|
5042
5152
|
target.workdir = value;
|
|
5043
5153
|
break;
|
|
5154
|
+
case "runner":
|
|
5155
|
+
target.runner = value;
|
|
5156
|
+
break;
|
|
5157
|
+
case "sourceKind":
|
|
5158
|
+
target.sourceKind = value;
|
|
5159
|
+
break;
|
|
5160
|
+
case "sourcePath":
|
|
5161
|
+
target.sourcePath = value;
|
|
5162
|
+
break;
|
|
5163
|
+
case "sourceRepo":
|
|
5164
|
+
target.sourceRepo = value;
|
|
5165
|
+
break;
|
|
5044
5166
|
}
|
|
5045
5167
|
}
|
|
5046
5168
|
function yamlQuoteScalar(value) {
|
|
@@ -5076,6 +5198,18 @@ function serializeAgentsConfig(agents) {
|
|
|
5076
5198
|
if (a.workdir) {
|
|
5077
5199
|
lines.push(` workdir: ${yamlQuoteScalar(a.workdir)}`);
|
|
5078
5200
|
}
|
|
5201
|
+
if (a.runner) {
|
|
5202
|
+
lines.push(` runner: ${yamlQuoteScalar(a.runner)}`);
|
|
5203
|
+
}
|
|
5204
|
+
if (a.sourceKind) {
|
|
5205
|
+
lines.push(` sourceKind: ${yamlQuoteScalar(a.sourceKind)}`);
|
|
5206
|
+
}
|
|
5207
|
+
if (a.sourcePath) {
|
|
5208
|
+
lines.push(` sourcePath: ${yamlQuoteScalar(a.sourcePath)}`);
|
|
5209
|
+
}
|
|
5210
|
+
if (a.sourceRepo) {
|
|
5211
|
+
lines.push(` sourceRepo: ${yamlQuoteScalar(a.sourceRepo)}`);
|
|
5212
|
+
}
|
|
5079
5213
|
if (a.args && a.args.length > 0) {
|
|
5080
5214
|
lines.push(` args:`);
|
|
5081
5215
|
for (const arg of a.args) {
|
|
@@ -5561,7 +5695,12 @@ async function readConfig() {
|
|
|
5561
5695
|
searchConfig: parseSearchConfig(content),
|
|
5562
5696
|
workspaceVisibility: parseWorkspaceVisibilityConfig(fmBlock),
|
|
5563
5697
|
staleness: parseStalenessConfig(content),
|
|
5564
|
-
stalenessWatchdog: String(fm["stalenessWatchdog"]).toLowerCase() === "true"
|
|
5698
|
+
stalenessWatchdog: String(fm["stalenessWatchdog"]).toLowerCase() === "true",
|
|
5699
|
+
standaloneDefaultCwd: parseOptionalAbsolutePath(
|
|
5700
|
+
fm["standaloneDefaultCwd"],
|
|
5701
|
+
"standaloneDefaultCwd"
|
|
5702
|
+
),
|
|
5703
|
+
agentDiscovery: parseAgentDiscoveryFromFm(fm)
|
|
5565
5704
|
};
|
|
5566
5705
|
}
|
|
5567
5706
|
function getAssignmentTypes(config) {
|
|
@@ -5624,7 +5763,7 @@ async function updateAgentsConfig(mutation, options = {}) {
|
|
|
5624
5763
|
await writeAgentsConfig(next);
|
|
5625
5764
|
return { previous, next, written: true };
|
|
5626
5765
|
}
|
|
5627
|
-
var STALENESS_KEY_TO_FIELD, DURATION_RE, DURATION_UNIT_MS, DEFAULT_ASSIGNMENT_TYPES, DEFAULT_CONFIG, AUTO_CREATE_WORKTREE_VALUES, SESSION_AUTO_TRACK_VALUES, AgentConfigError, DEFAULT_STATUS_COLORS, KNOWN_AGENT_SCALAR_FIELDS, migratedConfigPaths, TerminalConfigError;
|
|
5766
|
+
var STALENESS_KEY_TO_FIELD, DURATION_RE, DURATION_UNIT_MS, DEFAULT_ASSIGNMENT_TYPES, DEFAULT_CONFIG, AUTO_CREATE_WORKTREE_VALUES, SESSION_AUTO_TRACK_VALUES, RUNNER_KINDS, AGENT_SOURCE_KINDS, AgentConfigError, DEFAULT_STATUS_COLORS, KNOWN_AGENT_SCALAR_FIELDS, migratedConfigPaths, TerminalConfigError;
|
|
5628
5767
|
var init_config2 = __esm({
|
|
5629
5768
|
"src/utils/config.ts"() {
|
|
5630
5769
|
"use strict";
|
|
@@ -5700,10 +5839,23 @@ var init_config2 = __esm({
|
|
|
5700
5839
|
hidden: []
|
|
5701
5840
|
},
|
|
5702
5841
|
staleness: null,
|
|
5703
|
-
stalenessWatchdog: false
|
|
5842
|
+
stalenessWatchdog: false,
|
|
5843
|
+
standaloneDefaultCwd: null,
|
|
5844
|
+
agentDiscovery: {
|
|
5845
|
+
claudeGlobal: true,
|
|
5846
|
+
claudeProject: true,
|
|
5847
|
+
directory: true,
|
|
5848
|
+
roots: ["~"]
|
|
5849
|
+
}
|
|
5704
5850
|
};
|
|
5705
5851
|
AUTO_CREATE_WORKTREE_VALUES = ["skip", "ask", "always"];
|
|
5706
5852
|
SESSION_AUTO_TRACK_VALUES = ["all", "workspaces-only", "off"];
|
|
5853
|
+
RUNNER_KINDS = ["claude", "pi", "codex"];
|
|
5854
|
+
AGENT_SOURCE_KINDS = [
|
|
5855
|
+
"claude-global",
|
|
5856
|
+
"claude-project",
|
|
5857
|
+
"directory"
|
|
5858
|
+
];
|
|
5707
5859
|
AgentConfigError = class extends Error {
|
|
5708
5860
|
};
|
|
5709
5861
|
DEFAULT_STATUS_COLORS = {
|
|
@@ -5725,7 +5877,11 @@ var init_config2 = __esm({
|
|
|
5725
5877
|
"playbook",
|
|
5726
5878
|
"launchPrompt",
|
|
5727
5879
|
"agentName",
|
|
5728
|
-
"workdir"
|
|
5880
|
+
"workdir",
|
|
5881
|
+
"runner",
|
|
5882
|
+
"sourceKind",
|
|
5883
|
+
"sourcePath",
|
|
5884
|
+
"sourceRepo"
|
|
5729
5885
|
]);
|
|
5730
5886
|
migratedConfigPaths = /* @__PURE__ */ new Set();
|
|
5731
5887
|
TerminalConfigError = class extends Error {
|
|
@@ -7279,6 +7435,7 @@ var init_assignment_resolver = __esm({
|
|
|
7279
7435
|
|
|
7280
7436
|
// src/launch/cwd.ts
|
|
7281
7437
|
import { existsSync, statSync } from "fs";
|
|
7438
|
+
import { homedir as homedir2 } from "os";
|
|
7282
7439
|
import { isAbsolute as isAbsolute2 } from "path";
|
|
7283
7440
|
function isExistingDir(p) {
|
|
7284
7441
|
if (!p || !isAbsolute2(p)) return false;
|
|
@@ -7324,6 +7481,31 @@ function resolveLaunchCwd(agent, worktreeCwd) {
|
|
|
7324
7481
|
}
|
|
7325
7482
|
return { spawnCwd: worktreeCwd, worktreePath: worktreeCwd, invalidReason: null };
|
|
7326
7483
|
}
|
|
7484
|
+
function resolveStandaloneCwd(agent, standaloneDefaultCwd) {
|
|
7485
|
+
const wd = agent.workdir?.trim();
|
|
7486
|
+
if (wd) {
|
|
7487
|
+
const expanded = expandHome(wd);
|
|
7488
|
+
if (!isExistingDir(expanded)) {
|
|
7489
|
+
return {
|
|
7490
|
+
cwd: null,
|
|
7491
|
+
invalidReason: `agent "${agent.id}" workdir ${agent.workdir} (resolved ${expanded}) is not an existing directory \u2014 a standalone launch requires a valid workdir.`
|
|
7492
|
+
};
|
|
7493
|
+
}
|
|
7494
|
+
return { cwd: expanded, invalidReason: null };
|
|
7495
|
+
}
|
|
7496
|
+
if (resolveRunner(agent) === "claude") {
|
|
7497
|
+
const configured = standaloneDefaultCwd?.trim();
|
|
7498
|
+
if (configured) {
|
|
7499
|
+
const expanded = expandHome(configured);
|
|
7500
|
+
if (isExistingDir(expanded)) return { cwd: expanded, invalidReason: null };
|
|
7501
|
+
}
|
|
7502
|
+
return { cwd: homedir2(), invalidReason: null };
|
|
7503
|
+
}
|
|
7504
|
+
return {
|
|
7505
|
+
cwd: null,
|
|
7506
|
+
invalidReason: `agent "${agent.id}" has no workdir \u2014 a standalone launch of a ${resolveRunner(agent)} agent requires a valid workdir.`
|
|
7507
|
+
};
|
|
7508
|
+
}
|
|
7327
7509
|
function formatFallbackCwdWarning(opts) {
|
|
7328
7510
|
const missing = [];
|
|
7329
7511
|
if (!opts.worktreePath) missing.push("worktreePath");
|
|
@@ -7335,6 +7517,7 @@ function formatFallbackCwdWarning(opts) {
|
|
|
7335
7517
|
var init_cwd = __esm({
|
|
7336
7518
|
"src/launch/cwd.ts"() {
|
|
7337
7519
|
"use strict";
|
|
7520
|
+
init_agents_schema();
|
|
7338
7521
|
init_paths();
|
|
7339
7522
|
}
|
|
7340
7523
|
});
|
|
@@ -9276,8 +9459,8 @@ async function migrateFromMarkdown(projectsDir2) {
|
|
|
9276
9459
|
return allSessions.length;
|
|
9277
9460
|
}
|
|
9278
9461
|
async function parseMarkdownSessionsIndex(filePath, projectSlug) {
|
|
9279
|
-
const { readFile:
|
|
9280
|
-
const raw2 = await
|
|
9462
|
+
const { readFile: readFile85 } = await import("fs/promises");
|
|
9463
|
+
const raw2 = await readFile85(filePath, "utf-8");
|
|
9281
9464
|
const sessions = [];
|
|
9282
9465
|
const lines = raw2.split("\n");
|
|
9283
9466
|
let inTable = false;
|
|
@@ -10123,7 +10306,7 @@ function emptyScan() {
|
|
|
10123
10306
|
return { sessions: [], tmuxAvailable: false };
|
|
10124
10307
|
}
|
|
10125
10308
|
function scanKey(serversDir2, projectsDir2, assignmentsDir2) {
|
|
10126
|
-
return
|
|
10309
|
+
return JSON.stringify([serversDir2, projectsDir2, assignmentsDir2 ?? ""]);
|
|
10127
10310
|
}
|
|
10128
10311
|
function delay(ms) {
|
|
10129
10312
|
return new Promise((resolve112) => {
|
|
@@ -13121,12 +13304,12 @@ var init_transcript = __esm({
|
|
|
13121
13304
|
// src/usage/cwd-extractor.ts
|
|
13122
13305
|
import { open as open3, readdir as readdir14, stat as stat4 } from "fs/promises";
|
|
13123
13306
|
import { join as join3 } from "path";
|
|
13124
|
-
import { homedir as
|
|
13307
|
+
import { homedir as homedir3 } from "os";
|
|
13125
13308
|
async function extractClaudeSessionMeta(jsonlPath) {
|
|
13126
13309
|
const cwd = await derivePathFromTranscript(jsonlPath);
|
|
13127
13310
|
if (!cwd) return null;
|
|
13128
|
-
const
|
|
13129
|
-
const sessionId =
|
|
13311
|
+
const basename11 = jsonlPath.split("/").pop() ?? "";
|
|
13312
|
+
const sessionId = basename11.replace(/\.jsonl$/, "");
|
|
13130
13313
|
if (!sessionId) return null;
|
|
13131
13314
|
const startTs = await readFirstTimestamp(jsonlPath);
|
|
13132
13315
|
const endTs = await readLastTimestamp(jsonlPath);
|
|
@@ -13221,8 +13404,8 @@ async function* walkClaudeProjects(opts = {}) {
|
|
|
13221
13404
|
async function* walkCodexSessions(opts = {}) {
|
|
13222
13405
|
const root = resolveCodexSessionsRoot(opts.root);
|
|
13223
13406
|
for await (const filePath of walkJsonlRecursive(root)) {
|
|
13224
|
-
const
|
|
13225
|
-
if (!
|
|
13407
|
+
const basename11 = filePath.split("/").pop() ?? "";
|
|
13408
|
+
if (!basename11.endsWith(".jsonl")) continue;
|
|
13226
13409
|
if (opts.sinceMtimeMs !== void 0) {
|
|
13227
13410
|
const mtime = await mtimeMs(filePath);
|
|
13228
13411
|
if (mtime !== null && mtime < opts.sinceMtimeMs) continue;
|
|
@@ -13237,13 +13420,13 @@ function resolveCodexSessionsRoot(override3) {
|
|
|
13237
13420
|
if (fromSessionsEnv && fromSessionsEnv.length > 0) return expandHome(fromSessionsEnv);
|
|
13238
13421
|
const fromHomeEnv = process.env.CODEX_HOME;
|
|
13239
13422
|
if (fromHomeEnv && fromHomeEnv.length > 0) return join3(expandHome(fromHomeEnv), "sessions");
|
|
13240
|
-
return join3(
|
|
13423
|
+
return join3(homedir3(), ".codex", "sessions");
|
|
13241
13424
|
}
|
|
13242
13425
|
async function extractPiSessionMeta(jsonlPath) {
|
|
13243
|
-
const
|
|
13244
|
-
const underscoreIdx =
|
|
13426
|
+
const basename11 = jsonlPath.split("/").pop() ?? "";
|
|
13427
|
+
const underscoreIdx = basename11.lastIndexOf("_");
|
|
13245
13428
|
if (underscoreIdx === -1) return null;
|
|
13246
|
-
const sessionId =
|
|
13429
|
+
const sessionId = basename11.slice(underscoreIdx + 1).replace(/\.jsonl$/, "");
|
|
13247
13430
|
if (!sessionId) return null;
|
|
13248
13431
|
let handle;
|
|
13249
13432
|
try {
|
|
@@ -13295,7 +13478,7 @@ function resolvePiSessionsRoot(override3) {
|
|
|
13295
13478
|
if (override3) return expandHome(override3);
|
|
13296
13479
|
const fromHomeEnv = process.env.PI_AGENT_DIR;
|
|
13297
13480
|
if (fromHomeEnv && fromHomeEnv.length > 0) return join3(expandHome(fromHomeEnv), "sessions");
|
|
13298
|
-
return join3(
|
|
13481
|
+
return join3(homedir3(), ".pi", "agent", "sessions");
|
|
13299
13482
|
}
|
|
13300
13483
|
async function* walkPiSessions(opts = {}) {
|
|
13301
13484
|
const root = resolvePiSessionsRoot(opts.root);
|
|
@@ -13459,7 +13642,7 @@ var init_cwd_extractor = __esm({
|
|
|
13459
13642
|
// src/utils/session-id.ts
|
|
13460
13643
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
13461
13644
|
import { mkdirSync, readFileSync as readFileSync2, statSync as statSync4, writeFileSync } from "fs";
|
|
13462
|
-
import { homedir as
|
|
13645
|
+
import { homedir as homedir4 } from "os";
|
|
13463
13646
|
import { dirname as dirname6, join as join4 } from "path";
|
|
13464
13647
|
function isSafeSessionId(value) {
|
|
13465
13648
|
return typeof value === "string" && value.length > 0 && value.length <= 256 && SAFE_SESSION_ID.test(value);
|
|
@@ -13549,7 +13732,7 @@ async function resolveOwnSessionId(opts = {}, deps = {}) {
|
|
|
13549
13732
|
}
|
|
13550
13733
|
const sideChannel = await resolveSideChannelSessionId(opts, deps);
|
|
13551
13734
|
if (sideChannel) return { id: sideChannel, provenance: "EXPLICIT" };
|
|
13552
|
-
const home2 = deps.homeDir ??
|
|
13735
|
+
const home2 = deps.homeDir ?? homedir4();
|
|
13553
13736
|
const claudeSessionsDir = deps.claudeSessionsDir ?? join4(home2, ".claude", "sessions");
|
|
13554
13737
|
const runtimeSessionsDir2 = deps.runtimeSessionsDir ?? join4(home2, ".syntaur", "runtime", "sessions");
|
|
13555
13738
|
const startPid = deps.startPid ?? process.ppid;
|
|
@@ -13832,10 +14015,10 @@ var init_user_descriptors = __esm({
|
|
|
13832
14015
|
});
|
|
13833
14016
|
|
|
13834
14017
|
// src/targets/registry.ts
|
|
13835
|
-
import { homedir as
|
|
14018
|
+
import { homedir as homedir5 } from "os";
|
|
13836
14019
|
import { join as join5, resolve as resolve30 } from "path";
|
|
13837
14020
|
function home(...segments) {
|
|
13838
|
-
return resolve30(
|
|
14021
|
+
return resolve30(homedir5(), ...segments);
|
|
13839
14022
|
}
|
|
13840
14023
|
function hermesHome() {
|
|
13841
14024
|
const env = process.env.HERMES_HOME;
|
|
@@ -14130,8 +14313,8 @@ __export(launch_exports, {
|
|
|
14130
14313
|
shellQuote: () => shellQuote
|
|
14131
14314
|
});
|
|
14132
14315
|
import { spawn as spawn2 } from "child_process";
|
|
14133
|
-
import { mkdir as
|
|
14134
|
-
import { isAbsolute as
|
|
14316
|
+
import { mkdir as mkdir3, writeFile as writeFile5 } from "fs/promises";
|
|
14317
|
+
import { isAbsolute as isAbsolute6, resolve as resolve31 } from "path";
|
|
14135
14318
|
function shellQuote(arg) {
|
|
14136
14319
|
if (arg === "") return "''";
|
|
14137
14320
|
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
@@ -14146,7 +14329,7 @@ function buildAgentArgv(agent, prompt, env = process.env) {
|
|
|
14146
14329
|
const requested = env.SHELL;
|
|
14147
14330
|
let shell = requested;
|
|
14148
14331
|
let warning = null;
|
|
14149
|
-
if (!shell || !
|
|
14332
|
+
if (!shell || !isAbsolute6(shell)) {
|
|
14150
14333
|
warning = `syntaur: $SHELL ${requested ? `("${requested}") is not absolute` : "is unset"} \u2014 falling back to /bin/sh for shell-alias resolution`;
|
|
14151
14334
|
shell = "/bin/sh";
|
|
14152
14335
|
}
|
|
@@ -14211,7 +14394,7 @@ async function launchAgent(options) {
|
|
|
14211
14394
|
const spawnCwd = launchCwd.spawnCwd;
|
|
14212
14395
|
const worktreePath = launchCwd.worktreePath;
|
|
14213
14396
|
const contextDir = resolve31(worktreePath, ".syntaur");
|
|
14214
|
-
await
|
|
14397
|
+
await mkdir3(contextDir, { recursive: true });
|
|
14215
14398
|
const context = {
|
|
14216
14399
|
repository: detail.workspace.repository ?? null,
|
|
14217
14400
|
branch: detail.workspace.branch ?? null,
|
|
@@ -14219,7 +14402,7 @@ async function launchAgent(options) {
|
|
|
14219
14402
|
workspaceRoot: worktreePath,
|
|
14220
14403
|
grabbedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
14221
14404
|
};
|
|
14222
|
-
await
|
|
14405
|
+
await writeFile5(
|
|
14223
14406
|
resolve31(contextDir, "context.json"),
|
|
14224
14407
|
JSON.stringify(context, null, 2) + "\n"
|
|
14225
14408
|
);
|
|
@@ -14852,15 +15035,15 @@ import {
|
|
|
14852
15035
|
unlinkSync
|
|
14853
15036
|
} from "fs";
|
|
14854
15037
|
import { fileURLToPath as fileURLToPath9, pathToFileURL } from "url";
|
|
14855
|
-
import { dirname as
|
|
14856
|
-
import { homedir as
|
|
15038
|
+
import { dirname as dirname22, resolve as resolve74, join as join19 } from "path";
|
|
15039
|
+
import { homedir as homedir15, tmpdir as tmpdir2 } from "os";
|
|
14857
15040
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
14858
15041
|
function syntaurRootMjs() {
|
|
14859
15042
|
const override3 = process.env.SYNTAUR_HOME;
|
|
14860
15043
|
if (override3 && override3.length > 0) {
|
|
14861
15044
|
return override3;
|
|
14862
15045
|
}
|
|
14863
|
-
return
|
|
15046
|
+
return join19(homedir15(), ".syntaur");
|
|
14864
15047
|
}
|
|
14865
15048
|
async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
14866
15049
|
const { throwOnFailure } = options;
|
|
@@ -14890,22 +15073,22 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
|
14890
15073
|
throw err2;
|
|
14891
15074
|
}
|
|
14892
15075
|
try {
|
|
14893
|
-
const pkgRoot = resolve74(
|
|
15076
|
+
const pkgRoot = resolve74(dirname22(fileURLToPath9(import.meta.url)), "..");
|
|
14894
15077
|
const cliBin = realpathSync4(resolve74(pkgRoot, "bin/syntaur.js"));
|
|
14895
15078
|
const nodeBin = process.execPath;
|
|
14896
|
-
const bundleParent =
|
|
14897
|
-
|
|
15079
|
+
const bundleParent = join19(
|
|
15080
|
+
homedir15(),
|
|
14898
15081
|
"Library",
|
|
14899
15082
|
"Application Support",
|
|
14900
15083
|
"Syntaur"
|
|
14901
15084
|
);
|
|
14902
|
-
const bundlePath =
|
|
15085
|
+
const bundlePath = join19(bundleParent, "syntaur-url.app");
|
|
14903
15086
|
mkdirSync3(bundleParent, { recursive: true });
|
|
14904
15087
|
if (existsSync6(bundlePath)) {
|
|
14905
15088
|
rmSync(bundlePath, { recursive: true, force: true });
|
|
14906
15089
|
}
|
|
14907
15090
|
const installedTerminals = detectInstalledTerminals();
|
|
14908
|
-
const scriptPath =
|
|
15091
|
+
const scriptPath = join19(
|
|
14909
15092
|
tmpdir2(),
|
|
14910
15093
|
`syntaur-url-handler-${process.pid}.applescript`
|
|
14911
15094
|
);
|
|
@@ -14924,7 +15107,7 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
|
14924
15107
|
`osacompile exited with code ${compile.status}: ${compile.stderr || compile.stdout}`
|
|
14925
15108
|
);
|
|
14926
15109
|
}
|
|
14927
|
-
const infoPlistPath =
|
|
15110
|
+
const infoPlistPath = join19(bundlePath, "Contents", "Info.plist");
|
|
14928
15111
|
if (!existsSync6(infoPlistPath)) {
|
|
14929
15112
|
throw new Error(`osacompile did not produce ${infoPlistPath}`);
|
|
14930
15113
|
}
|
|
@@ -15019,7 +15202,7 @@ function detectInstalledTerminals() {
|
|
|
15019
15202
|
ghostty: "Ghostty.app",
|
|
15020
15203
|
warp: "Warp.app"
|
|
15021
15204
|
};
|
|
15022
|
-
const appDirs = ["/Applications",
|
|
15205
|
+
const appDirs = ["/Applications", join19(homedir15(), "Applications")];
|
|
15023
15206
|
for (const [id, bundleId] of Object.entries(bundleIds)) {
|
|
15024
15207
|
const r = spawnSync7(
|
|
15025
15208
|
"mdfind",
|
|
@@ -15031,7 +15214,7 @@ function detectInstalledTerminals() {
|
|
|
15031
15214
|
continue;
|
|
15032
15215
|
}
|
|
15033
15216
|
const name = bundleNames[id];
|
|
15034
|
-
if (name && appDirs.some((dir) => existsSync6(
|
|
15217
|
+
if (name && appDirs.some((dir) => existsSync6(join19(dir, name)))) {
|
|
15035
15218
|
installed.add(id);
|
|
15036
15219
|
}
|
|
15037
15220
|
}
|
|
@@ -15754,8 +15937,8 @@ __export(launchd_exports, {
|
|
|
15754
15937
|
});
|
|
15755
15938
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
15756
15939
|
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync3, rmSync as rmSync2, realpathSync as realpathSync5, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
15757
|
-
import { homedir as
|
|
15758
|
-
import { dirname as
|
|
15940
|
+
import { homedir as homedir18, userInfo } from "os";
|
|
15941
|
+
import { dirname as dirname29, join as join29, resolve as resolve99 } from "path";
|
|
15759
15942
|
function buildPlist(spec) {
|
|
15760
15943
|
const args = [spec.nodePath, spec.syntaurBin, ...spec.command ?? ["schedule", "tick"]];
|
|
15761
15944
|
const argXml = args.map((a) => ` <string>${escapeXml(a)}</string>`).join("\n");
|
|
@@ -15787,8 +15970,8 @@ function escapeXml(value) {
|
|
|
15787
15970
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
15788
15971
|
}
|
|
15789
15972
|
function defaultAcquireInstallLock(home2) {
|
|
15790
|
-
const lockPath =
|
|
15791
|
-
mkdirSync4(
|
|
15973
|
+
const lockPath = join29(home2, ".syntaur", "install-launch-agent.lock");
|
|
15974
|
+
mkdirSync4(dirname29(lockPath), { recursive: true });
|
|
15792
15975
|
const fd = openSync2(lockPath, "wx");
|
|
15793
15976
|
return () => {
|
|
15794
15977
|
try {
|
|
@@ -15815,7 +15998,7 @@ function defaultRun(command, args) {
|
|
|
15815
15998
|
}
|
|
15816
15999
|
}
|
|
15817
16000
|
function resolveSpec(config, deps) {
|
|
15818
|
-
const home2 = deps.homeDir ??
|
|
16001
|
+
const home2 = deps.homeDir ?? homedir18();
|
|
15819
16002
|
const uid = deps.uid ?? userInfo().uid;
|
|
15820
16003
|
const spec = {
|
|
15821
16004
|
label: config.label,
|
|
@@ -15823,22 +16006,22 @@ function resolveSpec(config, deps) {
|
|
|
15823
16006
|
nodePath: deps.nodePath ?? process.execPath,
|
|
15824
16007
|
syntaurBin: absolutize(deps.syntaurBin ?? process.argv[1] ?? "syntaur"),
|
|
15825
16008
|
intervalSeconds: deps.intervalSeconds ?? config.defaultIntervalSeconds,
|
|
15826
|
-
outLog:
|
|
15827
|
-
errLog:
|
|
16009
|
+
outLog: join29(home2, ".syntaur", "logs", config.outLogName),
|
|
16010
|
+
errLog: join29(home2, ".syntaur", "logs", config.errLogName)
|
|
15828
16011
|
};
|
|
15829
|
-
const plistPath =
|
|
16012
|
+
const plistPath = join29(home2, "Library", "LaunchAgents", `${spec.label}.plist`);
|
|
15830
16013
|
return { spec, plistPath, home: home2, uid };
|
|
15831
16014
|
}
|
|
15832
16015
|
function installAgent(config, deps) {
|
|
15833
16016
|
const { spec, plistPath, home: home2, uid } = resolveSpec(config, deps);
|
|
15834
16017
|
const mkdirp = deps.mkdirp ?? ((p) => mkdirSync4(p, { recursive: true }));
|
|
15835
|
-
const
|
|
16018
|
+
const writeFile18 = deps.writeFile ?? ((p, c2) => writeFileSync3(p, c2));
|
|
15836
16019
|
const run3 = deps.run ?? defaultRun;
|
|
15837
16020
|
const releaseLock2 = (deps.acquireInstallLock ?? (() => defaultAcquireInstallLock(home2)))();
|
|
15838
16021
|
try {
|
|
15839
|
-
mkdirp(
|
|
15840
|
-
mkdirp(
|
|
15841
|
-
|
|
16022
|
+
mkdirp(join29(home2, ".syntaur", "logs"));
|
|
16023
|
+
mkdirp(join29(home2, "Library", "LaunchAgents"));
|
|
16024
|
+
writeFile18(plistPath, buildPlist(spec));
|
|
15842
16025
|
const domain = `gui/${uid}`;
|
|
15843
16026
|
run3("launchctl", ["bootout", `${domain}/${spec.label}`]);
|
|
15844
16027
|
const boot = run3("launchctl", ["bootstrap", domain, plistPath]);
|
|
@@ -16063,7 +16246,7 @@ init_create_assignment();
|
|
|
16063
16246
|
init_config2();
|
|
16064
16247
|
import { spawn as spawn5 } from "child_process";
|
|
16065
16248
|
import { createServer as createNetServer } from "net";
|
|
16066
|
-
import { resolve as resolve51, dirname as
|
|
16249
|
+
import { resolve as resolve51, dirname as dirname14 } from "path";
|
|
16067
16250
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
16068
16251
|
|
|
16069
16252
|
// src/dashboard/server.ts
|
|
@@ -16074,7 +16257,7 @@ init_agent_sessions();
|
|
|
16074
16257
|
import express from "express";
|
|
16075
16258
|
import { createServer } from "http";
|
|
16076
16259
|
import { resolve as resolve50 } from "path";
|
|
16077
|
-
import { writeFile as
|
|
16260
|
+
import { writeFile as writeFile9, unlink as unlink9 } from "fs/promises";
|
|
16078
16261
|
import { WebSocketServer, WebSocket } from "ws";
|
|
16079
16262
|
|
|
16080
16263
|
// src/dashboard/session-liveness.ts
|
|
@@ -20714,6 +20897,7 @@ function createAgentSessionsRouter(projectsDir2, broadcast, assignmentsDir2) {
|
|
|
20714
20897
|
init_config2();
|
|
20715
20898
|
init_agents_schema();
|
|
20716
20899
|
import { Router as Router5 } from "express";
|
|
20900
|
+
import { access as access4 } from "fs/promises";
|
|
20717
20901
|
|
|
20718
20902
|
// src/targets/agent-definitions.ts
|
|
20719
20903
|
init_parser();
|
|
@@ -20762,7 +20946,293 @@ async function discoverClaudeAgents(root) {
|
|
|
20762
20946
|
return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
20763
20947
|
}
|
|
20764
20948
|
|
|
20949
|
+
// src/targets/agent-discovery.ts
|
|
20950
|
+
init_paths();
|
|
20951
|
+
init_parser();
|
|
20952
|
+
import { access as access2, readdir as readdir17, readFile as readFile22 } from "fs/promises";
|
|
20953
|
+
import { join as join7 } from "path";
|
|
20954
|
+
async function pathExists(p) {
|
|
20955
|
+
try {
|
|
20956
|
+
await access2(p);
|
|
20957
|
+
return true;
|
|
20958
|
+
} catch {
|
|
20959
|
+
return false;
|
|
20960
|
+
}
|
|
20961
|
+
}
|
|
20962
|
+
function coerceRunner(raw2) {
|
|
20963
|
+
return raw2 === "claude" || raw2 === "pi" || raw2 === "codex" ? raw2 : void 0;
|
|
20964
|
+
}
|
|
20965
|
+
async function readSyntaurMeta(file) {
|
|
20966
|
+
let content;
|
|
20967
|
+
try {
|
|
20968
|
+
content = await readFile22(file, "utf-8");
|
|
20969
|
+
} catch {
|
|
20970
|
+
return null;
|
|
20971
|
+
}
|
|
20972
|
+
const [fm] = extractFrontmatter(content);
|
|
20973
|
+
if (!fm) return null;
|
|
20974
|
+
if (!/^syntaur:[ \t]*$/m.test(fm)) return null;
|
|
20975
|
+
return {
|
|
20976
|
+
name: getNestedField(fm, "syntaur", "name")?.trim() || void 0,
|
|
20977
|
+
runner: coerceRunner(getNestedField(fm, "syntaur", "runner")?.trim() || void 0),
|
|
20978
|
+
description: getNestedField(fm, "syntaur", "description")?.trim() || void 0
|
|
20979
|
+
};
|
|
20980
|
+
}
|
|
20981
|
+
async function fileHasSyntaurBlock(file) {
|
|
20982
|
+
return await readSyntaurMeta(file) !== null;
|
|
20983
|
+
}
|
|
20984
|
+
function claudeAlreadyRegistered(agents, path, name) {
|
|
20985
|
+
return agents.some((a) => a.sourcePath === path || !!a.agentName && a.agentName === name);
|
|
20986
|
+
}
|
|
20987
|
+
function directoryAlreadyRegistered(agents, dir) {
|
|
20988
|
+
return agents.some((a) => a.sourcePath === dir || a.workdir === dir);
|
|
20989
|
+
}
|
|
20990
|
+
async function toClaudeCandidate(d, source, agents, sourceRepo) {
|
|
20991
|
+
return {
|
|
20992
|
+
name: d.name,
|
|
20993
|
+
runner: "claude",
|
|
20994
|
+
description: d.description,
|
|
20995
|
+
path: d.path,
|
|
20996
|
+
source,
|
|
20997
|
+
...sourceRepo ? { sourceRepo } : {},
|
|
20998
|
+
recommended: await fileHasSyntaurBlock(d.path),
|
|
20999
|
+
alreadyRegistered: claudeAlreadyRegistered(agents, d.path, d.name)
|
|
21000
|
+
};
|
|
21001
|
+
}
|
|
21002
|
+
async function inspectDirCandidate(dir, basename11, agents) {
|
|
21003
|
+
const hasPi = await pathExists(join7(dir, ".pi"));
|
|
21004
|
+
const hasMcp = await pathExists(join7(dir, ".mcp.json"));
|
|
21005
|
+
const hasSyntaurMd = await pathExists(join7(dir, "SYNTAUR.md"));
|
|
21006
|
+
const hasAgentsMd = await pathExists(join7(dir, "AGENTS.md"));
|
|
21007
|
+
let syntaur = null;
|
|
21008
|
+
if (hasSyntaurMd) syntaur = await readSyntaurMeta(join7(dir, "SYNTAUR.md"));
|
|
21009
|
+
if (!syntaur && hasAgentsMd) syntaur = await readSyntaurMeta(join7(dir, "AGENTS.md"));
|
|
21010
|
+
const strong = hasPi || hasMcp || syntaur !== null;
|
|
21011
|
+
if (!strong) return null;
|
|
21012
|
+
return {
|
|
21013
|
+
name: syntaur?.name ?? basename11,
|
|
21014
|
+
// A directory agent is pi/codex by definition; a contradictory
|
|
21015
|
+
// `syntaur.runner: claude` opt-in is clamped to pi so the candidate never
|
|
21016
|
+
// carries an impossible directory+claude combo.
|
|
21017
|
+
runner: syntaur?.runner === "codex" ? "codex" : "pi",
|
|
21018
|
+
description: syntaur?.description,
|
|
21019
|
+
path: dir,
|
|
21020
|
+
source: "directory",
|
|
21021
|
+
recommended: syntaur !== null,
|
|
21022
|
+
alreadyRegistered: directoryAlreadyRegistered(agents, dir)
|
|
21023
|
+
};
|
|
21024
|
+
}
|
|
21025
|
+
async function discoverAgents(input4) {
|
|
21026
|
+
const out = [];
|
|
21027
|
+
if (input4.claudeGlobal) {
|
|
21028
|
+
for (const d of await discoverClaudeAgents()) {
|
|
21029
|
+
out.push(await toClaudeCandidate(d, "claude-global", input4.agents));
|
|
21030
|
+
}
|
|
21031
|
+
}
|
|
21032
|
+
if (input4.claudeProject && input4.repo) {
|
|
21033
|
+
const projRoot = join7(input4.repo, ".claude", "agents");
|
|
21034
|
+
for (const d of await discoverClaudeAgents(projRoot)) {
|
|
21035
|
+
out.push(await toClaudeCandidate(d, "claude-project", input4.agents, input4.repo));
|
|
21036
|
+
}
|
|
21037
|
+
}
|
|
21038
|
+
if (input4.directory || input4.claudeProject) {
|
|
21039
|
+
for (const rawRoot of input4.roots) {
|
|
21040
|
+
const root = expandHome(rawRoot);
|
|
21041
|
+
let entries;
|
|
21042
|
+
try {
|
|
21043
|
+
entries = await readdir17(root, { withFileTypes: true });
|
|
21044
|
+
} catch {
|
|
21045
|
+
continue;
|
|
21046
|
+
}
|
|
21047
|
+
for (const e of entries) {
|
|
21048
|
+
if (!e.isDirectory()) continue;
|
|
21049
|
+
const dir = join7(root, e.name);
|
|
21050
|
+
if (input4.directory) {
|
|
21051
|
+
const dirCand = await inspectDirCandidate(dir, e.name, input4.agents);
|
|
21052
|
+
if (dirCand) out.push(dirCand);
|
|
21053
|
+
}
|
|
21054
|
+
if (input4.claudeProject && await pathExists(join7(dir, ".claude", "agents"))) {
|
|
21055
|
+
const projRoot = join7(dir, ".claude", "agents");
|
|
21056
|
+
for (const d of await discoverClaudeAgents(projRoot)) {
|
|
21057
|
+
out.push(await toClaudeCandidate(d, "claude-project", input4.agents, dir));
|
|
21058
|
+
}
|
|
21059
|
+
}
|
|
21060
|
+
}
|
|
21061
|
+
}
|
|
21062
|
+
}
|
|
21063
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21064
|
+
const deduped = [];
|
|
21065
|
+
for (const c2 of out) {
|
|
21066
|
+
const key = JSON.stringify([c2.source, c2.path, c2.name]);
|
|
21067
|
+
if (seen.has(key)) continue;
|
|
21068
|
+
seen.add(key);
|
|
21069
|
+
deduped.push(c2);
|
|
21070
|
+
}
|
|
21071
|
+
deduped.sort(
|
|
21072
|
+
(a, b) => a.recommended === b.recommended ? a.name.localeCompare(b.name) : a.recommended ? -1 : 1
|
|
21073
|
+
);
|
|
21074
|
+
return deduped;
|
|
21075
|
+
}
|
|
21076
|
+
|
|
21077
|
+
// src/targets/agent-authoring.ts
|
|
21078
|
+
init_paths();
|
|
21079
|
+
init_parser();
|
|
21080
|
+
init_agents_schema();
|
|
21081
|
+
import { mkdir as mkdir2, writeFile as writeFile4, access as access3, readFile as readFile23, stat as stat5 } from "fs/promises";
|
|
21082
|
+
import { homedir as homedir6 } from "os";
|
|
21083
|
+
import { basename as basename5, dirname as dirname7, isAbsolute as isAbsolute5, join as join8 } from "path";
|
|
21084
|
+
var RUNNER_COMMAND = {
|
|
21085
|
+
claude: "claude",
|
|
21086
|
+
pi: "pi",
|
|
21087
|
+
codex: "codex"
|
|
21088
|
+
};
|
|
21089
|
+
function requireAbsolutePath(raw2, what = "path") {
|
|
21090
|
+
const p = expandHome(raw2.trim());
|
|
21091
|
+
if (!isAbsolute5(p)) {
|
|
21092
|
+
throw new Error(`${what} must be an absolute path (got ${JSON.stringify(raw2)})`);
|
|
21093
|
+
}
|
|
21094
|
+
return p;
|
|
21095
|
+
}
|
|
21096
|
+
function slugifyAgentId(name) {
|
|
21097
|
+
const slug = name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
21098
|
+
const safe = /^[a-z0-9]/.test(slug) ? slug : `agent-${slug}`;
|
|
21099
|
+
return AGENT_ID_PATTERN.test(safe) ? safe : "agent";
|
|
21100
|
+
}
|
|
21101
|
+
function uniqueAgentId(base, existingIds) {
|
|
21102
|
+
const taken = new Set(existingIds);
|
|
21103
|
+
if (!taken.has(base)) return base;
|
|
21104
|
+
for (let n = 2; ; n++) {
|
|
21105
|
+
const candidate = `${base}-${n}`;
|
|
21106
|
+
if (!taken.has(candidate)) return candidate;
|
|
21107
|
+
}
|
|
21108
|
+
}
|
|
21109
|
+
function buildRegisteredAgent(input4) {
|
|
21110
|
+
const id = uniqueAgentId(slugifyAgentId(input4.name), input4.existingIds);
|
|
21111
|
+
const agent = {
|
|
21112
|
+
id,
|
|
21113
|
+
label: input4.name,
|
|
21114
|
+
command: RUNNER_COMMAND[input4.runner],
|
|
21115
|
+
runner: input4.runner,
|
|
21116
|
+
sourceKind: input4.sourceKind,
|
|
21117
|
+
sourcePath: input4.sourcePath
|
|
21118
|
+
};
|
|
21119
|
+
if (input4.sourceRepo) agent.sourceRepo = input4.sourceRepo;
|
|
21120
|
+
if (input4.runner === "claude") {
|
|
21121
|
+
agent.agentName = input4.name;
|
|
21122
|
+
} else {
|
|
21123
|
+
agent.workdir = input4.sourcePath;
|
|
21124
|
+
}
|
|
21125
|
+
return agent;
|
|
21126
|
+
}
|
|
21127
|
+
async function pathExists2(p) {
|
|
21128
|
+
try {
|
|
21129
|
+
await access3(p);
|
|
21130
|
+
return true;
|
|
21131
|
+
} catch {
|
|
21132
|
+
return false;
|
|
21133
|
+
}
|
|
21134
|
+
}
|
|
21135
|
+
function frontmatterLines(fields) {
|
|
21136
|
+
const lines = [];
|
|
21137
|
+
for (const [k, v] of Object.entries(fields)) {
|
|
21138
|
+
if (v !== void 0 && v !== "") lines.push(`${k}: ${JSON.stringify(v)}`);
|
|
21139
|
+
}
|
|
21140
|
+
return lines;
|
|
21141
|
+
}
|
|
21142
|
+
function syntaurBlock(name, runner, description) {
|
|
21143
|
+
const lines = ["syntaur:", ` name: ${JSON.stringify(name)}`, ` runner: ${runner}`];
|
|
21144
|
+
if (description) lines.push(` description: ${JSON.stringify(description)}`);
|
|
21145
|
+
return lines;
|
|
21146
|
+
}
|
|
21147
|
+
async function authorAgentDef(input4) {
|
|
21148
|
+
const slug = slugifyAgentId(input4.name);
|
|
21149
|
+
if (input4.runner === "claude") {
|
|
21150
|
+
const dir2 = input4.location ? requireAbsolutePath(input4.location, "location") : join8(homedir6(), ".claude", "agents");
|
|
21151
|
+
const path = join8(dir2, `${slug}.md`);
|
|
21152
|
+
if (await pathExists2(path)) {
|
|
21153
|
+
throw new Error(`refusing to overwrite existing def at ${path}`);
|
|
21154
|
+
}
|
|
21155
|
+
const fm2 = [
|
|
21156
|
+
"---",
|
|
21157
|
+
...frontmatterLines({
|
|
21158
|
+
name: input4.name,
|
|
21159
|
+
description: input4.description,
|
|
21160
|
+
model: input4.model
|
|
21161
|
+
}),
|
|
21162
|
+
...syntaurBlock(input4.name, "claude", input4.description),
|
|
21163
|
+
"---"
|
|
21164
|
+
];
|
|
21165
|
+
await mkdir2(dir2, { recursive: true });
|
|
21166
|
+
await writeFile4(path, `${fm2.join("\n")}
|
|
21167
|
+
|
|
21168
|
+
${input4.instructions.trim()}
|
|
21169
|
+
`);
|
|
21170
|
+
if (!input4.location) {
|
|
21171
|
+
return { path, sourceKind: "claude-global" };
|
|
21172
|
+
}
|
|
21173
|
+
const sourceRepo = basename5(dir2) === "agents" && basename5(dirname7(dir2)) === ".claude" ? dirname7(dirname7(dir2)) : void 0;
|
|
21174
|
+
return { path, sourceKind: "claude-project", ...sourceRepo ? { sourceRepo } : {} };
|
|
21175
|
+
}
|
|
21176
|
+
const parent = input4.location ? requireAbsolutePath(input4.location, "location") : homedir6();
|
|
21177
|
+
const dir = join8(parent, slug);
|
|
21178
|
+
const agentsMd = join8(dir, "AGENTS.md");
|
|
21179
|
+
if (await pathExists2(agentsMd)) {
|
|
21180
|
+
throw new Error(`refusing to overwrite existing def at ${agentsMd}`);
|
|
21181
|
+
}
|
|
21182
|
+
const fm = ["---", ...syntaurBlock(input4.name, input4.runner, input4.description), "---"];
|
|
21183
|
+
await mkdir2(dir, { recursive: true });
|
|
21184
|
+
await writeFile4(agentsMd, `${fm.join("\n")}
|
|
21185
|
+
|
|
21186
|
+
${input4.instructions.trim()}
|
|
21187
|
+
`);
|
|
21188
|
+
return { path: dir, sourceKind: "directory" };
|
|
21189
|
+
}
|
|
21190
|
+
async function inferManualAdd(rawPath) {
|
|
21191
|
+
const path = requireAbsolutePath(rawPath);
|
|
21192
|
+
const info = await stat5(path);
|
|
21193
|
+
if (info.isFile()) {
|
|
21194
|
+
const content = await readFile23(path, "utf-8");
|
|
21195
|
+
const [fm] = extractFrontmatter(content);
|
|
21196
|
+
const name = getNestedField(fm, "syntaur", "name")?.trim() || getField(fm, "name")?.trim() || basename5(path).replace(/\.md$/, "");
|
|
21197
|
+
const description = getNestedField(fm, "syntaur", "description")?.trim() || getField(fm, "description")?.trim() || void 0;
|
|
21198
|
+
return { name, runner: "claude", sourceKind: "claude-global", sourcePath: path, description };
|
|
21199
|
+
}
|
|
21200
|
+
let syntaurName;
|
|
21201
|
+
let syntaurRunner;
|
|
21202
|
+
let syntaurDesc;
|
|
21203
|
+
for (const f of ["SYNTAUR.md", "AGENTS.md"]) {
|
|
21204
|
+
const p = join8(path, f);
|
|
21205
|
+
if (await pathExists2(p)) {
|
|
21206
|
+
const [fm] = extractFrontmatter(await readFile23(p, "utf-8"));
|
|
21207
|
+
syntaurName = getNestedField(fm, "syntaur", "name")?.trim() || syntaurName;
|
|
21208
|
+
const r = getNestedField(fm, "syntaur", "runner")?.trim();
|
|
21209
|
+
if (r === "claude" || r === "pi" || r === "codex") syntaurRunner = r;
|
|
21210
|
+
syntaurDesc = getNestedField(fm, "syntaur", "description")?.trim() || syntaurDesc;
|
|
21211
|
+
if (syntaurName || syntaurRunner) break;
|
|
21212
|
+
}
|
|
21213
|
+
}
|
|
21214
|
+
return {
|
|
21215
|
+
name: syntaurName ?? basename5(path),
|
|
21216
|
+
// A directory (pi/codex) agent is never claude — clamp a contradictory
|
|
21217
|
+
// `syntaur.runner: claude` opt-in to pi (parity with inspectDirCandidate).
|
|
21218
|
+
runner: syntaurRunner === "codex" ? "codex" : "pi",
|
|
21219
|
+
sourceKind: "directory",
|
|
21220
|
+
sourcePath: path,
|
|
21221
|
+
description: syntaurDesc
|
|
21222
|
+
};
|
|
21223
|
+
}
|
|
21224
|
+
|
|
20765
21225
|
// src/dashboard/api-agents.ts
|
|
21226
|
+
async function pathExists3(p) {
|
|
21227
|
+
try {
|
|
21228
|
+
await access4(p);
|
|
21229
|
+
return true;
|
|
21230
|
+
} catch {
|
|
21231
|
+
return false;
|
|
21232
|
+
}
|
|
21233
|
+
}
|
|
21234
|
+
var RUNNER_KINDS_SET = /* @__PURE__ */ new Set(["claude", "pi", "codex"]);
|
|
21235
|
+
var SOURCE_KINDS_SET = /* @__PURE__ */ new Set(["claude-global", "claude-project", "directory"]);
|
|
20766
21236
|
function mapAgentErrorToFieldErrors(err2) {
|
|
20767
21237
|
const message = err2.message;
|
|
20768
21238
|
let match = message.match(/^agent id "([^"]*)" is invalid/);
|
|
@@ -21057,6 +21527,22 @@ function coerceAgentRow(raw2, index) {
|
|
|
21057
21527
|
const workdir = entry.workdir.trim();
|
|
21058
21528
|
if (workdir) cleaned.workdir = workdir;
|
|
21059
21529
|
}
|
|
21530
|
+
for (const field of ["runner", "sourceKind", "sourcePath", "sourceRepo"]) {
|
|
21531
|
+
const raw3 = entry[field];
|
|
21532
|
+
if (raw3 === void 0) continue;
|
|
21533
|
+
if (typeof raw3 !== "string") {
|
|
21534
|
+
return {
|
|
21535
|
+
ok: false,
|
|
21536
|
+
status: 400,
|
|
21537
|
+
body: {
|
|
21538
|
+
error: `agents[${index}].${field} must be a string`,
|
|
21539
|
+
fieldErrors: [{ id, field, message: `${field} must be a string` }]
|
|
21540
|
+
}
|
|
21541
|
+
};
|
|
21542
|
+
}
|
|
21543
|
+
const v = raw3.trim();
|
|
21544
|
+
if (v) cleaned[field] = v;
|
|
21545
|
+
}
|
|
21060
21546
|
return { ok: true, value: cleaned };
|
|
21061
21547
|
}
|
|
21062
21548
|
function createAgentsRouter() {
|
|
@@ -21070,6 +21556,164 @@ function createAgentsRouter() {
|
|
|
21070
21556
|
res.status(500).json({ error: "Failed to discover Claude agents" });
|
|
21071
21557
|
}
|
|
21072
21558
|
});
|
|
21559
|
+
router.get("/discovered", async (req2, res) => {
|
|
21560
|
+
try {
|
|
21561
|
+
const config = await readConfig();
|
|
21562
|
+
const agents = config.agents ?? BUILTIN_AGENTS;
|
|
21563
|
+
const repo = typeof req2.query.repo === "string" && req2.query.repo ? req2.query.repo : null;
|
|
21564
|
+
const d = config.agentDiscovery;
|
|
21565
|
+
const candidates = await discoverAgents({
|
|
21566
|
+
claudeGlobal: d.claudeGlobal,
|
|
21567
|
+
claudeProject: d.claudeProject,
|
|
21568
|
+
directory: d.directory,
|
|
21569
|
+
roots: d.roots,
|
|
21570
|
+
repo,
|
|
21571
|
+
agents
|
|
21572
|
+
});
|
|
21573
|
+
res.json({ candidates });
|
|
21574
|
+
} catch (err2) {
|
|
21575
|
+
console.error("Error discovering agents:", err2);
|
|
21576
|
+
res.status(500).json({ error: "Failed to discover agents" });
|
|
21577
|
+
}
|
|
21578
|
+
});
|
|
21579
|
+
async function appendAndPersist(agent, res) {
|
|
21580
|
+
const config = await readConfig();
|
|
21581
|
+
const base = config.agents ?? BUILTIN_AGENTS;
|
|
21582
|
+
if (agent.sourcePath && base.some((a) => a.sourcePath === agent.sourcePath)) {
|
|
21583
|
+
res.status(409).json({ error: `already registered: ${agent.sourcePath}` });
|
|
21584
|
+
return null;
|
|
21585
|
+
}
|
|
21586
|
+
const next = [...base, agent];
|
|
21587
|
+
try {
|
|
21588
|
+
await writeAgentsConfig(next);
|
|
21589
|
+
} catch (err2) {
|
|
21590
|
+
if (err2 instanceof AgentConfigError) {
|
|
21591
|
+
res.status(400).json(mapAgentErrorToFieldErrors(err2));
|
|
21592
|
+
return null;
|
|
21593
|
+
}
|
|
21594
|
+
throw err2;
|
|
21595
|
+
}
|
|
21596
|
+
return next;
|
|
21597
|
+
}
|
|
21598
|
+
router.post("/register", async (req2, res) => {
|
|
21599
|
+
try {
|
|
21600
|
+
const b = req2.body ?? {};
|
|
21601
|
+
if (!b.path || !b.name || !b.runner || !b.sourceKind) {
|
|
21602
|
+
res.status(400).json({ error: "register requires path, name, runner, sourceKind" });
|
|
21603
|
+
return;
|
|
21604
|
+
}
|
|
21605
|
+
if (!RUNNER_KINDS_SET.has(b.runner) || !SOURCE_KINDS_SET.has(b.sourceKind)) {
|
|
21606
|
+
res.status(400).json({ error: "invalid runner or sourceKind" });
|
|
21607
|
+
return;
|
|
21608
|
+
}
|
|
21609
|
+
let regPath;
|
|
21610
|
+
let sourceRepo;
|
|
21611
|
+
try {
|
|
21612
|
+
regPath = requireAbsolutePath(b.path);
|
|
21613
|
+
sourceRepo = b.sourceRepo ? requireAbsolutePath(b.sourceRepo, "sourceRepo") : void 0;
|
|
21614
|
+
} catch (err2) {
|
|
21615
|
+
res.status(400).json({ error: err2 instanceof Error ? err2.message : "invalid path" });
|
|
21616
|
+
return;
|
|
21617
|
+
}
|
|
21618
|
+
if (!await pathExists3(regPath)) {
|
|
21619
|
+
res.status(400).json({ error: `path not found: ${regPath}` });
|
|
21620
|
+
return;
|
|
21621
|
+
}
|
|
21622
|
+
const config = await readConfig();
|
|
21623
|
+
const base = config.agents ?? BUILTIN_AGENTS;
|
|
21624
|
+
const agent = buildRegisteredAgent({
|
|
21625
|
+
name: b.name,
|
|
21626
|
+
runner: b.runner,
|
|
21627
|
+
sourceKind: b.sourceKind,
|
|
21628
|
+
sourcePath: regPath,
|
|
21629
|
+
sourceRepo,
|
|
21630
|
+
description: b.description,
|
|
21631
|
+
existingIds: base.map((a) => a.id)
|
|
21632
|
+
});
|
|
21633
|
+
const next = await appendAndPersist(agent, res);
|
|
21634
|
+
if (!next) return;
|
|
21635
|
+
res.json({ agent, agents: next, custom: true });
|
|
21636
|
+
} catch (err2) {
|
|
21637
|
+
console.error("Error registering agent:", err2);
|
|
21638
|
+
res.status(500).json({ error: "Failed to register agent" });
|
|
21639
|
+
}
|
|
21640
|
+
});
|
|
21641
|
+
router.post("/manual-add", async (req2, res) => {
|
|
21642
|
+
try {
|
|
21643
|
+
const p = (req2.body ?? {}).path;
|
|
21644
|
+
if (typeof p !== "string" || !p) {
|
|
21645
|
+
res.status(400).json({ error: "manual-add requires a path" });
|
|
21646
|
+
return;
|
|
21647
|
+
}
|
|
21648
|
+
let inferred;
|
|
21649
|
+
try {
|
|
21650
|
+
inferred = await inferManualAdd(p);
|
|
21651
|
+
} catch {
|
|
21652
|
+
res.status(400).json({ error: `path not found or unreadable: ${p}` });
|
|
21653
|
+
return;
|
|
21654
|
+
}
|
|
21655
|
+
const config = await readConfig();
|
|
21656
|
+
const base = config.agents ?? BUILTIN_AGENTS;
|
|
21657
|
+
const agent = buildRegisteredAgent({
|
|
21658
|
+
name: inferred.name,
|
|
21659
|
+
runner: inferred.runner,
|
|
21660
|
+
sourceKind: inferred.sourceKind,
|
|
21661
|
+
sourcePath: inferred.sourcePath,
|
|
21662
|
+
description: inferred.description,
|
|
21663
|
+
existingIds: base.map((a) => a.id)
|
|
21664
|
+
});
|
|
21665
|
+
const next = await appendAndPersist(agent, res);
|
|
21666
|
+
if (!next) return;
|
|
21667
|
+
res.json({ agent, agents: next, custom: true });
|
|
21668
|
+
} catch (err2) {
|
|
21669
|
+
console.error("Error manual-adding agent:", err2);
|
|
21670
|
+
res.status(500).json({ error: "Failed to manual-add agent" });
|
|
21671
|
+
}
|
|
21672
|
+
});
|
|
21673
|
+
router.post("/create", async (req2, res) => {
|
|
21674
|
+
try {
|
|
21675
|
+
const b = req2.body ?? {};
|
|
21676
|
+
if (!b.name || !b.runner || typeof b.instructions !== "string") {
|
|
21677
|
+
res.status(400).json({ error: "create requires name, runner, instructions" });
|
|
21678
|
+
return;
|
|
21679
|
+
}
|
|
21680
|
+
if (!RUNNER_KINDS_SET.has(b.runner)) {
|
|
21681
|
+
res.status(400).json({ error: "invalid runner" });
|
|
21682
|
+
return;
|
|
21683
|
+
}
|
|
21684
|
+
let authored;
|
|
21685
|
+
try {
|
|
21686
|
+
authored = await authorAgentDef({
|
|
21687
|
+
name: b.name,
|
|
21688
|
+
runner: b.runner,
|
|
21689
|
+
model: b.model,
|
|
21690
|
+
description: b.description,
|
|
21691
|
+
instructions: b.instructions,
|
|
21692
|
+
location: b.location
|
|
21693
|
+
});
|
|
21694
|
+
} catch (err2) {
|
|
21695
|
+
res.status(400).json({ error: err2 instanceof Error ? err2.message : "failed to author def" });
|
|
21696
|
+
return;
|
|
21697
|
+
}
|
|
21698
|
+
const config = await readConfig();
|
|
21699
|
+
const base = config.agents ?? BUILTIN_AGENTS;
|
|
21700
|
+
const agent = buildRegisteredAgent({
|
|
21701
|
+
name: b.name,
|
|
21702
|
+
runner: b.runner,
|
|
21703
|
+
sourceKind: authored.sourceKind,
|
|
21704
|
+
sourcePath: authored.path,
|
|
21705
|
+
sourceRepo: authored.sourceRepo,
|
|
21706
|
+
description: b.description,
|
|
21707
|
+
existingIds: base.map((a) => a.id)
|
|
21708
|
+
});
|
|
21709
|
+
const next = await appendAndPersist(agent, res);
|
|
21710
|
+
if (!next) return;
|
|
21711
|
+
res.json({ agent, path: authored.path, agents: next, custom: true });
|
|
21712
|
+
} catch (err2) {
|
|
21713
|
+
console.error("Error creating agent:", err2);
|
|
21714
|
+
res.status(500).json({ error: "Failed to create agent" });
|
|
21715
|
+
}
|
|
21716
|
+
});
|
|
21073
21717
|
router.get("/", async (_req, res) => {
|
|
21074
21718
|
try {
|
|
21075
21719
|
const config = await readConfig();
|
|
@@ -21132,8 +21776,8 @@ import { Router as Router6 } from "express";
|
|
|
21132
21776
|
// src/utils/terminal-probe.ts
|
|
21133
21777
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
21134
21778
|
import { existsSync as existsSync2 } from "fs";
|
|
21135
|
-
import { homedir as
|
|
21136
|
-
import { join as
|
|
21779
|
+
import { homedir as homedir7 } from "os";
|
|
21780
|
+
import { join as join9 } from "path";
|
|
21137
21781
|
var APP_BUNDLE_IDS = {
|
|
21138
21782
|
"terminal-app": "com.apple.Terminal",
|
|
21139
21783
|
iterm: "com.googlecode.iterm2",
|
|
@@ -21150,7 +21794,7 @@ var APP_FIXED_PATHS = {
|
|
|
21150
21794
|
"terminal-app": "/System/Applications/Utilities/Terminal.app"
|
|
21151
21795
|
};
|
|
21152
21796
|
function defaultApplicationsDirs() {
|
|
21153
|
-
return ["/Applications",
|
|
21797
|
+
return ["/Applications", join9(homedir7(), "Applications")];
|
|
21154
21798
|
}
|
|
21155
21799
|
function findAppBundle(terminal, dirs = defaultApplicationsDirs()) {
|
|
21156
21800
|
const fixed = APP_FIXED_PATHS[terminal];
|
|
@@ -21158,7 +21802,7 @@ function findAppBundle(terminal, dirs = defaultApplicationsDirs()) {
|
|
|
21158
21802
|
const bundleName = APP_BUNDLE_NAMES[terminal];
|
|
21159
21803
|
if (bundleName) {
|
|
21160
21804
|
for (const dir of dirs) {
|
|
21161
|
-
const candidate =
|
|
21805
|
+
const candidate = join9(dir, bundleName);
|
|
21162
21806
|
if (existsSync2(candidate)) return candidate;
|
|
21163
21807
|
}
|
|
21164
21808
|
}
|
|
@@ -21188,11 +21832,11 @@ var defaultCmuxLsappinfoRunner = () => {
|
|
|
21188
21832
|
function resolveCmuxCli(applicationsDirsOverride, cliDirsOverride, lsappinfoRunnerOverride) {
|
|
21189
21833
|
const bundle = findAppBundle("cmux", applicationsDirsOverride);
|
|
21190
21834
|
if (bundle) {
|
|
21191
|
-
const cli =
|
|
21835
|
+
const cli = join9(bundle, "Contents/Resources/bin/cmux");
|
|
21192
21836
|
if (existsSync2(cli)) return cli;
|
|
21193
21837
|
}
|
|
21194
21838
|
for (const dir of cliDirsOverride ?? CMUX_CLI_DIRS) {
|
|
21195
|
-
const cli =
|
|
21839
|
+
const cli = join9(dir, "cmux");
|
|
21196
21840
|
if (existsSync2(cli)) return cli;
|
|
21197
21841
|
}
|
|
21198
21842
|
if (process.platform === "darwin") {
|
|
@@ -21201,7 +21845,7 @@ function resolveCmuxCli(applicationsDirsOverride, cliDirsOverride, lsappinfoRunn
|
|
|
21201
21845
|
if (stdout) {
|
|
21202
21846
|
const match = stdout.match(/"LSBundlePath"="([^"]+)"/);
|
|
21203
21847
|
if (match) {
|
|
21204
|
-
const cli =
|
|
21848
|
+
const cli = join9(match[1], "Contents/Resources/bin/cmux");
|
|
21205
21849
|
if (existsSync2(cli)) return cli;
|
|
21206
21850
|
}
|
|
21207
21851
|
}
|
|
@@ -21460,7 +22104,7 @@ init_agent_sessions();
|
|
|
21460
22104
|
// src/launch/argv.ts
|
|
21461
22105
|
init_agents_schema();
|
|
21462
22106
|
init_launch();
|
|
21463
|
-
import { isAbsolute as
|
|
22107
|
+
import { isAbsolute as isAbsolute7 } from "path";
|
|
21464
22108
|
var buildFreshArgv = buildAgentArgv;
|
|
21465
22109
|
function buildSessionArgv(agent, sessionId, mode, env = process.env) {
|
|
21466
22110
|
const invocation = agent[mode];
|
|
@@ -21479,7 +22123,7 @@ function buildSessionArgv(agent, sessionId, mode, env = process.env) {
|
|
|
21479
22123
|
const requested = env.SHELL;
|
|
21480
22124
|
let shell = requested;
|
|
21481
22125
|
let warning = null;
|
|
21482
|
-
if (!shell || !
|
|
22126
|
+
if (!shell || !isAbsolute7(shell)) {
|
|
21483
22127
|
warning = `syntaur: $SHELL ${requested ? `("${requested}") is not absolute` : "is unset"} \u2014 falling back to /bin/sh for shell-alias resolution`;
|
|
21484
22128
|
shell = "/bin/sh";
|
|
21485
22129
|
}
|
|
@@ -21539,18 +22183,14 @@ async function resolveStandalonePlan(input4, terminal) {
|
|
|
21539
22183
|
`Agent "${agentId}" requested for a standalone launch is not in your agents list.`
|
|
21540
22184
|
);
|
|
21541
22185
|
}
|
|
21542
|
-
const
|
|
21543
|
-
|
|
21544
|
-
|
|
21545
|
-
|
|
21546
|
-
|
|
21547
|
-
);
|
|
21548
|
-
}
|
|
21549
|
-
const expanded = expandHome(wd);
|
|
21550
|
-
if (!isExistingDir(expanded)) {
|
|
22186
|
+
const { cwd: spawnCwd, invalidReason } = resolveStandaloneCwd(
|
|
22187
|
+
agent,
|
|
22188
|
+
input4.config.standaloneDefaultCwd
|
|
22189
|
+
);
|
|
22190
|
+
if (spawnCwd === null) {
|
|
21551
22191
|
throw new LaunchError(
|
|
21552
22192
|
"workspace-path-invalid",
|
|
21553
|
-
`Agent "${agent.id}"
|
|
22193
|
+
invalidReason ?? `Agent "${agent.id}" has no valid standalone launch directory.`
|
|
21554
22194
|
);
|
|
21555
22195
|
}
|
|
21556
22196
|
const knownPlaybookSlugs = await listPlaybookSlugs(playbooksDir());
|
|
@@ -21564,7 +22204,7 @@ async function resolveStandalonePlan(input4, terminal) {
|
|
|
21564
22204
|
const { argv, shellFallbackWarning } = buildFreshArgv(agent, prompt);
|
|
21565
22205
|
return {
|
|
21566
22206
|
terminal,
|
|
21567
|
-
cwd:
|
|
22207
|
+
cwd: spawnCwd,
|
|
21568
22208
|
argv,
|
|
21569
22209
|
env: process.env,
|
|
21570
22210
|
agentId: agent.id,
|
|
@@ -21732,8 +22372,8 @@ async function resolveSessionPlan(input4, terminal) {
|
|
|
21732
22372
|
// src/launch/execute.ts
|
|
21733
22373
|
init_launch();
|
|
21734
22374
|
import { spawn as spawn3 } from "child_process";
|
|
21735
|
-
import { homedir as
|
|
21736
|
-
import { basename as
|
|
22375
|
+
import { homedir as homedir8 } from "os";
|
|
22376
|
+
import { basename as basename6, join as join10, resolve as resolve32 } from "path";
|
|
21737
22377
|
init_fs();
|
|
21738
22378
|
init_config2();
|
|
21739
22379
|
init_session_id();
|
|
@@ -21753,7 +22393,7 @@ var TerminalNotFoundError = class extends Error {
|
|
|
21753
22393
|
var realSpawn = (command, args, options) => spawn3(command, args, options);
|
|
21754
22394
|
var WRAPPER_COMMANDS = /* @__PURE__ */ new Set(["osascript", "open", "sh"]);
|
|
21755
22395
|
function isWrapperCommand(command) {
|
|
21756
|
-
return WRAPPER_COMMANDS.has(
|
|
22396
|
+
return WRAPPER_COMMANDS.has(basename6(command));
|
|
21757
22397
|
}
|
|
21758
22398
|
var WRAPPER_EXIT_TIMEOUT_MS = 1500;
|
|
21759
22399
|
async function executeLaunchPlan(plan, spawnFn = realSpawn) {
|
|
@@ -21839,7 +22479,7 @@ async function registerLaunchAtBirth(plan, child) {
|
|
|
21839
22479
|
const sessionId = plan.session?.sessionId ?? null;
|
|
21840
22480
|
const procStart = captureProcessStartedAt(pid);
|
|
21841
22481
|
const envDir = process.env.SYNTAUR_RUNTIME_SESSIONS_DIR;
|
|
21842
|
-
const markerDir = envDir && envDir.length > 0 ? envDir :
|
|
22482
|
+
const markerDir = envDir && envDir.length > 0 ? envDir : join10(homedir8(), ".syntaur", "runtime", "sessions");
|
|
21843
22483
|
writeRuntimeMarker(
|
|
21844
22484
|
pid,
|
|
21845
22485
|
{
|
|
@@ -22031,7 +22671,7 @@ init_launch_prompt();
|
|
|
22031
22671
|
init_paths();
|
|
22032
22672
|
init_fs();
|
|
22033
22673
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
22034
|
-
import { dirname as
|
|
22674
|
+
import { dirname as dirname8, resolve as resolve33, join as join11 } from "path";
|
|
22035
22675
|
import { realpathSync, readFileSync as readFileSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
22036
22676
|
var NPX_PATTERNS = [
|
|
22037
22677
|
{ kind: "npm", re: /\/_npx\/([^/]+)\/node_modules(?:\/|$)/ },
|
|
@@ -22057,7 +22697,7 @@ function normalizeSlashes(p) {
|
|
|
22057
22697
|
}
|
|
22058
22698
|
function detectInstallKind(scriptUrl, opts = {}) {
|
|
22059
22699
|
const realpath3 = opts.realpath ?? realpathSync.native;
|
|
22060
|
-
const
|
|
22700
|
+
const readFile85 = opts.readFile ?? ((p) => readFileSync3(p, "utf-8"));
|
|
22061
22701
|
const ua = opts.envUserAgent !== void 0 ? opts.envUserAgent : process.env.npm_config_user_agent ?? "";
|
|
22062
22702
|
const resolved = resolveScriptPath(scriptUrl, realpath3);
|
|
22063
22703
|
if (resolved === null) {
|
|
@@ -22073,14 +22713,14 @@ function detectInstallKind(scriptUrl, opts = {}) {
|
|
|
22073
22713
|
if (GLOBAL_PATTERN.test(norm)) {
|
|
22074
22714
|
return "global";
|
|
22075
22715
|
}
|
|
22076
|
-
let dir =
|
|
22716
|
+
let dir = dirname8(resolved);
|
|
22077
22717
|
for (let depth = 0; depth < 8; depth++) {
|
|
22078
|
-
const pkgJsonPath =
|
|
22718
|
+
const pkgJsonPath = join11(dir, "package.json");
|
|
22079
22719
|
let raw2;
|
|
22080
22720
|
try {
|
|
22081
|
-
raw2 =
|
|
22721
|
+
raw2 = readFile85(pkgJsonPath);
|
|
22082
22722
|
} catch {
|
|
22083
|
-
const parent2 =
|
|
22723
|
+
const parent2 = dirname8(dir);
|
|
22084
22724
|
if (parent2 === dir) break;
|
|
22085
22725
|
dir = parent2;
|
|
22086
22726
|
continue;
|
|
@@ -22092,7 +22732,7 @@ function detectInstallKind(scriptUrl, opts = {}) {
|
|
|
22092
22732
|
}
|
|
22093
22733
|
} catch {
|
|
22094
22734
|
}
|
|
22095
|
-
const parent =
|
|
22735
|
+
const parent = dirname8(dir);
|
|
22096
22736
|
if (parent === dir) break;
|
|
22097
22737
|
dir = parent;
|
|
22098
22738
|
}
|
|
@@ -22116,7 +22756,7 @@ function sanitizeHash(hash) {
|
|
|
22116
22756
|
return hash.replace(/[^A-Za-z0-9_-]/g, "_") || "_";
|
|
22117
22757
|
}
|
|
22118
22758
|
function nudgeStampPath(hash) {
|
|
22119
|
-
return
|
|
22759
|
+
return join11(nudgeStampDir(), sanitizeHash(hash));
|
|
22120
22760
|
}
|
|
22121
22761
|
async function hasNudgedHash(hash) {
|
|
22122
22762
|
return fileExists(nudgeStampPath(hash));
|
|
@@ -22549,21 +23189,78 @@ function createWorkspaceVisibilityConfigRouter() {
|
|
|
22549
23189
|
return router;
|
|
22550
23190
|
}
|
|
22551
23191
|
|
|
23192
|
+
// src/dashboard/api-agent-discovery-config.ts
|
|
23193
|
+
init_config2();
|
|
23194
|
+
import { Router as Router11 } from "express";
|
|
23195
|
+
function createAgentDiscoveryConfigRouter() {
|
|
23196
|
+
const router = Router11();
|
|
23197
|
+
router.get("/", async (_req, res) => {
|
|
23198
|
+
try {
|
|
23199
|
+
const config = await readConfig();
|
|
23200
|
+
res.json({
|
|
23201
|
+
agentDiscovery: config.agentDiscovery,
|
|
23202
|
+
standaloneDefaultCwd: config.standaloneDefaultCwd
|
|
23203
|
+
});
|
|
23204
|
+
} catch (error) {
|
|
23205
|
+
console.error("Error getting agent-discovery config:", error);
|
|
23206
|
+
res.status(500).json({ error: "Failed to get agent-discovery config" });
|
|
23207
|
+
}
|
|
23208
|
+
});
|
|
23209
|
+
router.post("/", async (req2, res) => {
|
|
23210
|
+
try {
|
|
23211
|
+
const b = req2.body ?? {};
|
|
23212
|
+
const d = b.agentDiscovery ?? {};
|
|
23213
|
+
let roots;
|
|
23214
|
+
try {
|
|
23215
|
+
roots = (Array.isArray(d.roots) ? d.roots : []).filter((r) => typeof r === "string" && r.trim() !== "").map((r) => {
|
|
23216
|
+
requireAbsolutePath(r, "root");
|
|
23217
|
+
return r.trim();
|
|
23218
|
+
});
|
|
23219
|
+
} catch (err2) {
|
|
23220
|
+
res.status(400).json({ error: err2 instanceof Error ? err2.message : "invalid root" });
|
|
23221
|
+
return;
|
|
23222
|
+
}
|
|
23223
|
+
const cfg = {
|
|
23224
|
+
// Default-true semantics: only an explicit `false` turns a source off.
|
|
23225
|
+
claudeGlobal: d.claudeGlobal !== false,
|
|
23226
|
+
claudeProject: d.claudeProject !== false,
|
|
23227
|
+
directory: d.directory !== false,
|
|
23228
|
+
roots: roots.length > 0 ? roots : ["~"]
|
|
23229
|
+
};
|
|
23230
|
+
let cwd = null;
|
|
23231
|
+
if (typeof b.standaloneDefaultCwd === "string" && b.standaloneDefaultCwd.trim()) {
|
|
23232
|
+
try {
|
|
23233
|
+
cwd = requireAbsolutePath(b.standaloneDefaultCwd, "standaloneDefaultCwd");
|
|
23234
|
+
} catch (err2) {
|
|
23235
|
+
res.status(400).json({ error: err2 instanceof Error ? err2.message : "invalid cwd" });
|
|
23236
|
+
return;
|
|
23237
|
+
}
|
|
23238
|
+
}
|
|
23239
|
+
await writeAgentDiscoveryConfig(cfg, cwd);
|
|
23240
|
+
res.json({ agentDiscovery: cfg, standaloneDefaultCwd: cwd });
|
|
23241
|
+
} catch (error) {
|
|
23242
|
+
console.error("Error saving agent-discovery config:", error);
|
|
23243
|
+
res.status(500).json({ error: "Failed to save agent-discovery config" });
|
|
23244
|
+
}
|
|
23245
|
+
});
|
|
23246
|
+
return router;
|
|
23247
|
+
}
|
|
23248
|
+
|
|
22552
23249
|
// src/dashboard/api-status-config.ts
|
|
22553
23250
|
init_config2();
|
|
22554
23251
|
init_fact_registry();
|
|
22555
23252
|
init_state_machine();
|
|
22556
23253
|
init_api();
|
|
22557
23254
|
init_derive();
|
|
22558
|
-
import { Router as
|
|
23255
|
+
import { Router as Router12 } from "express";
|
|
22559
23256
|
|
|
22560
23257
|
// src/utils/status-config-resolution.ts
|
|
22561
23258
|
init_frontmatter();
|
|
22562
23259
|
init_event_emit();
|
|
22563
23260
|
init_assignment_walk();
|
|
22564
23261
|
init_timestamp();
|
|
22565
|
-
import { readFile as
|
|
22566
|
-
import { dirname as
|
|
23262
|
+
import { readFile as readFile24, writeFile as writeFile6, rm as rm2 } from "fs/promises";
|
|
23263
|
+
import { dirname as dirname9 } from "path";
|
|
22567
23264
|
var StatusResolutionError = class extends Error {
|
|
22568
23265
|
constructor(message, code) {
|
|
22569
23266
|
super(message);
|
|
@@ -22581,7 +23278,7 @@ async function scanAssignmentsByStatus(projectsDir2, standaloneDir, ids) {
|
|
|
22581
23278
|
const assignmentPath = `${entry.assignmentDir}/assignment.md`;
|
|
22582
23279
|
let content;
|
|
22583
23280
|
try {
|
|
22584
|
-
content = await
|
|
23281
|
+
content = await readFile24(assignmentPath, "utf-8");
|
|
22585
23282
|
} catch (err2) {
|
|
22586
23283
|
const code = err2?.code;
|
|
22587
23284
|
if (code === "ENOENT") {
|
|
@@ -22644,7 +23341,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
|
|
|
22644
23341
|
const list = affected.get(r.id) ?? [];
|
|
22645
23342
|
for (const a of list) {
|
|
22646
23343
|
try {
|
|
22647
|
-
const content = await
|
|
23344
|
+
const content = await readFile24(a.path, "utf-8");
|
|
22648
23345
|
buffer.set(a.path, content);
|
|
22649
23346
|
} catch (err2) {
|
|
22650
23347
|
const code = err2?.code;
|
|
@@ -22673,7 +23370,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
|
|
|
22673
23370
|
for (const a of list) {
|
|
22674
23371
|
let current;
|
|
22675
23372
|
try {
|
|
22676
|
-
current = await
|
|
23373
|
+
current = await readFile24(a.path, "utf-8");
|
|
22677
23374
|
} catch (err2) {
|
|
22678
23375
|
const code = err2?.code;
|
|
22679
23376
|
if (code === "ENOENT") {
|
|
@@ -22696,7 +23393,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
|
|
|
22696
23393
|
}),
|
|
22697
23394
|
{ at: now, from: r.id, to: r.target, command: "remap", by: null }
|
|
22698
23395
|
);
|
|
22699
|
-
await
|
|
23396
|
+
await writeFile6(a.path, next, "utf-8");
|
|
22700
23397
|
pendingRemapEvents.push({
|
|
22701
23398
|
assignmentId: fm.id,
|
|
22702
23399
|
projectSlug: a.projectSlug,
|
|
@@ -22714,7 +23411,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
|
|
|
22714
23411
|
for (const p of writtenPaths) {
|
|
22715
23412
|
const original = buffer.get(p);
|
|
22716
23413
|
if (original !== void 0) {
|
|
22717
|
-
await
|
|
23414
|
+
await writeFile6(p, original, "utf-8").catch((rollbackErr) => {
|
|
22718
23415
|
console.error(
|
|
22719
23416
|
`status-config-resolution: rollback write failed for ${p}:`,
|
|
22720
23417
|
rollbackErr
|
|
@@ -22744,7 +23441,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
|
|
|
22744
23441
|
const list = affected.get(r.id) ?? [];
|
|
22745
23442
|
for (const a of list) {
|
|
22746
23443
|
try {
|
|
22747
|
-
const current = await
|
|
23444
|
+
const current = await readFile24(a.path, "utf-8");
|
|
22748
23445
|
const fm = parseAssignmentFrontmatter(current);
|
|
22749
23446
|
if (fm.status !== r.id) {
|
|
22750
23447
|
console.warn(
|
|
@@ -22755,7 +23452,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
|
|
|
22755
23452
|
} catch {
|
|
22756
23453
|
continue;
|
|
22757
23454
|
}
|
|
22758
|
-
const assignmentDir =
|
|
23455
|
+
const assignmentDir = dirname9(a.path);
|
|
22759
23456
|
try {
|
|
22760
23457
|
await rm2(assignmentDir, { recursive: true, force: true });
|
|
22761
23458
|
deleted++;
|
|
@@ -22795,7 +23492,7 @@ async function scanAssignmentsReferencingStatus(projectsDir2, standaloneDir, id)
|
|
|
22795
23492
|
const assignmentPath = `${entry.assignmentDir}/assignment.md`;
|
|
22796
23493
|
let content;
|
|
22797
23494
|
try {
|
|
22798
|
-
content = await
|
|
23495
|
+
content = await readFile24(assignmentPath, "utf-8");
|
|
22799
23496
|
} catch (err2) {
|
|
22800
23497
|
const code = err2?.code;
|
|
22801
23498
|
if (code === "ENOENT") continue;
|
|
@@ -22929,7 +23626,7 @@ function mapResolutionErrorToHttp(err2, applied) {
|
|
|
22929
23626
|
}
|
|
22930
23627
|
}
|
|
22931
23628
|
function createStatusConfigRouter(projectsDir2, assignmentsDir2) {
|
|
22932
|
-
const router =
|
|
23629
|
+
const router = Router12();
|
|
22933
23630
|
installRecordsInvalidation(router);
|
|
22934
23631
|
router.get("/", async (_req, res) => {
|
|
22935
23632
|
try {
|
|
@@ -23249,7 +23946,7 @@ function createStatusConfigRouter(projectsDir2, assignmentsDir2) {
|
|
|
23249
23946
|
}
|
|
23250
23947
|
|
|
23251
23948
|
// src/dashboard/api-leases.ts
|
|
23252
|
-
import { Router as
|
|
23949
|
+
import { Router as Router13 } from "express";
|
|
23253
23950
|
|
|
23254
23951
|
// src/db/leases-db.ts
|
|
23255
23952
|
init_paths();
|
|
@@ -23882,7 +24579,7 @@ function releaseLeasesByRequestedFor(tag) {
|
|
|
23882
24579
|
|
|
23883
24580
|
// src/dashboard/api-leases.ts
|
|
23884
24581
|
function createLeasesRouter(broadcast) {
|
|
23885
|
-
const router =
|
|
24582
|
+
const router = Router13();
|
|
23886
24583
|
router.get("/", (_req, res) => {
|
|
23887
24584
|
try {
|
|
23888
24585
|
initLeasesDb();
|
|
@@ -23938,14 +24635,14 @@ function createLeasesRouter(broadcast) {
|
|
|
23938
24635
|
|
|
23939
24636
|
// src/dashboard/api-schedules.ts
|
|
23940
24637
|
init_timestamp();
|
|
23941
|
-
import { Router as
|
|
24638
|
+
import { Router as Router14 } from "express";
|
|
23942
24639
|
|
|
23943
24640
|
// src/schedules/store.ts
|
|
23944
24641
|
init_fs();
|
|
23945
24642
|
init_paths();
|
|
23946
24643
|
init_timestamp();
|
|
23947
24644
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
23948
|
-
import { readFile as
|
|
24645
|
+
import { readFile as readFile25, readdir as readdir18, rm as rm3 } from "fs/promises";
|
|
23949
24646
|
import { resolve as resolve35 } from "path";
|
|
23950
24647
|
function schedulesDir() {
|
|
23951
24648
|
const override3 = process.env.SYNTAUR_SCHEDULES_DIR;
|
|
@@ -24078,7 +24775,7 @@ function validateJob(raw2) {
|
|
|
24078
24775
|
async function readJob(id) {
|
|
24079
24776
|
const path = jobPath(id);
|
|
24080
24777
|
if (!await fileExists(path)) return null;
|
|
24081
|
-
return parseJobFile(await
|
|
24778
|
+
return parseJobFile(await readFile25(path, "utf-8"));
|
|
24082
24779
|
}
|
|
24083
24780
|
async function writeJob(job) {
|
|
24084
24781
|
const next = { ...job, updatedAt: nowTimestamp() };
|
|
@@ -24088,7 +24785,7 @@ async function writeJob(job) {
|
|
|
24088
24785
|
async function listJobs() {
|
|
24089
24786
|
let names;
|
|
24090
24787
|
try {
|
|
24091
|
-
names = await
|
|
24788
|
+
names = await readdir18(schedulesDir());
|
|
24092
24789
|
} catch {
|
|
24093
24790
|
return [];
|
|
24094
24791
|
}
|
|
@@ -24096,7 +24793,7 @@ async function listJobs() {
|
|
|
24096
24793
|
for (const name of names) {
|
|
24097
24794
|
if (!name.endsWith(".md")) continue;
|
|
24098
24795
|
try {
|
|
24099
|
-
jobs.push(parseJobFile(await
|
|
24796
|
+
jobs.push(parseJobFile(await readFile25(resolve35(schedulesDir(), name), "utf-8")));
|
|
24100
24797
|
} catch {
|
|
24101
24798
|
}
|
|
24102
24799
|
}
|
|
@@ -24106,8 +24803,8 @@ async function listJobs() {
|
|
|
24106
24803
|
|
|
24107
24804
|
// src/schedules/event-log.ts
|
|
24108
24805
|
init_timestamp();
|
|
24109
|
-
import { appendFile, readFile as
|
|
24110
|
-
import { dirname as
|
|
24806
|
+
import { appendFile, readFile as readFile26, mkdir as mkdir4 } from "fs/promises";
|
|
24807
|
+
import { dirname as dirname10, resolve as resolve36 } from "path";
|
|
24111
24808
|
function eventLogPath(jobId) {
|
|
24112
24809
|
if (!/^[A-Za-z0-9_-]+$/.test(jobId)) {
|
|
24113
24810
|
throw new Error(`Unsafe schedule id: ${JSON.stringify(jobId)}`);
|
|
@@ -24117,7 +24814,7 @@ function eventLogPath(jobId) {
|
|
|
24117
24814
|
async function appendEvent(jobId, type, data) {
|
|
24118
24815
|
const event = { type, at: nowTimestamp(), ...data ? { data } : {} };
|
|
24119
24816
|
const path = eventLogPath(jobId);
|
|
24120
|
-
await
|
|
24817
|
+
await mkdir4(dirname10(path), { recursive: true });
|
|
24121
24818
|
await appendFile(path, `${JSON.stringify(event)}
|
|
24122
24819
|
`, "utf-8");
|
|
24123
24820
|
return event;
|
|
@@ -24125,7 +24822,7 @@ async function appendEvent(jobId, type, data) {
|
|
|
24125
24822
|
async function readEvents(jobId) {
|
|
24126
24823
|
let content;
|
|
24127
24824
|
try {
|
|
24128
|
-
content = await
|
|
24825
|
+
content = await readFile26(eventLogPath(jobId), "utf-8");
|
|
24129
24826
|
} catch {
|
|
24130
24827
|
return [];
|
|
24131
24828
|
}
|
|
@@ -24144,7 +24841,7 @@ async function readEvents(jobId) {
|
|
|
24144
24841
|
|
|
24145
24842
|
// src/schedules/attempt.ts
|
|
24146
24843
|
import { createHash as createHash3 } from "crypto";
|
|
24147
|
-
import { open as open4, readFile as
|
|
24844
|
+
import { open as open4, readFile as readFile27, stat as stat6, unlink as unlink6 } from "fs/promises";
|
|
24148
24845
|
import { resolve as resolve37 } from "path";
|
|
24149
24846
|
|
|
24150
24847
|
// src/schedules/triggers.ts
|
|
@@ -24333,7 +25030,7 @@ async function acquireJobLock(id) {
|
|
|
24333
25030
|
await handle.close();
|
|
24334
25031
|
return async () => {
|
|
24335
25032
|
try {
|
|
24336
|
-
const current = await
|
|
25033
|
+
const current = await readFile27(lockPath, "utf-8");
|
|
24337
25034
|
if (current === token) await unlink6(lockPath);
|
|
24338
25035
|
} catch {
|
|
24339
25036
|
}
|
|
@@ -24342,7 +25039,7 @@ async function acquireJobLock(id) {
|
|
|
24342
25039
|
const code = err2.code;
|
|
24343
25040
|
if (code !== "EEXIST") throw err2;
|
|
24344
25041
|
try {
|
|
24345
|
-
const info = await
|
|
25042
|
+
const info = await stat6(lockPath);
|
|
24346
25043
|
if (Date.now() - info.mtimeMs > LOCK_STALE_MS2) {
|
|
24347
25044
|
await unlink6(lockPath).catch(() => {
|
|
24348
25045
|
});
|
|
@@ -24681,7 +25378,7 @@ function canFire(job, deps) {
|
|
|
24681
25378
|
init_agent_sessions();
|
|
24682
25379
|
init_session_db();
|
|
24683
25380
|
function createSchedulesRouter(broadcast) {
|
|
24684
|
-
const router =
|
|
25381
|
+
const router = Router14();
|
|
24685
25382
|
const notify = () => broadcast?.({ type: "schedules-updated", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
24686
25383
|
router.get("/", async (_req, res) => {
|
|
24687
25384
|
try {
|
|
@@ -24806,20 +25503,20 @@ init_config2();
|
|
|
24806
25503
|
init_paths();
|
|
24807
25504
|
init_assignment_resolver();
|
|
24808
25505
|
init_frontmatter();
|
|
24809
|
-
import { readFile as
|
|
25506
|
+
import { readFile as readFile28 } from "fs/promises";
|
|
24810
25507
|
import { resolve as resolve39 } from "path";
|
|
24811
25508
|
|
|
24812
25509
|
// src/schedules/launch-ack.ts
|
|
24813
25510
|
init_session_id();
|
|
24814
25511
|
import { readdirSync as readdirSync2 } from "fs";
|
|
24815
|
-
import { homedir as
|
|
24816
|
-
import { join as
|
|
25512
|
+
import { homedir as homedir9 } from "os";
|
|
25513
|
+
import { join as join12 } from "path";
|
|
24817
25514
|
function defaultSleep(ms) {
|
|
24818
25515
|
return new Promise((r) => setTimeout(r, ms));
|
|
24819
25516
|
}
|
|
24820
25517
|
function runtimeSessionsDir() {
|
|
24821
25518
|
const override3 = process.env.SYNTAUR_RUNTIME_SESSIONS_DIR;
|
|
24822
|
-
return override3 && override3.length > 0 ? override3 :
|
|
25519
|
+
return override3 && override3.length > 0 ? override3 : join12(homedir9(), ".syntaur", "runtime", "sessions");
|
|
24823
25520
|
}
|
|
24824
25521
|
function defaultAckProbe(handle) {
|
|
24825
25522
|
const dir = runtimeSessionsDir();
|
|
@@ -24867,7 +25564,7 @@ async function defaultReadAssignment(assignmentId) {
|
|
|
24867
25564
|
const resolved = await resolveAssignmentById(projectsDir2, assignmentsDir(), assignmentId);
|
|
24868
25565
|
if (!resolved) return null;
|
|
24869
25566
|
try {
|
|
24870
|
-
const content = await
|
|
25567
|
+
const content = await readFile28(resolve39(resolved.assignmentDir, "assignment.md"), "utf-8");
|
|
24871
25568
|
return parseAssignmentFrontmatter(content);
|
|
24872
25569
|
} catch {
|
|
24873
25570
|
return null;
|
|
@@ -24954,7 +25651,7 @@ async function runTick(deps = {}) {
|
|
|
24954
25651
|
}
|
|
24955
25652
|
|
|
24956
25653
|
// src/dashboard/api-usage.ts
|
|
24957
|
-
import { Router as
|
|
25654
|
+
import { Router as Router15 } from "express";
|
|
24958
25655
|
|
|
24959
25656
|
// src/db/usage-db.ts
|
|
24960
25657
|
init_paths();
|
|
@@ -25404,7 +26101,7 @@ function projectWindowCosts(opts) {
|
|
|
25404
26101
|
|
|
25405
26102
|
// src/dashboard/api-usage.ts
|
|
25406
26103
|
function createUsageRouter(projectsDir2, assignmentsDir2) {
|
|
25407
|
-
const router =
|
|
26104
|
+
const router = Router15();
|
|
25408
26105
|
router.get("/facets", (_req, res) => {
|
|
25409
26106
|
try {
|
|
25410
26107
|
initUsageDb();
|
|
@@ -25645,11 +26342,11 @@ function projectAssignmentRollup(projectSlug, rows, common) {
|
|
|
25645
26342
|
init_fs();
|
|
25646
26343
|
init_parser();
|
|
25647
26344
|
init_events_db();
|
|
25648
|
-
import { Router as
|
|
26345
|
+
import { Router as Router16 } from "express";
|
|
25649
26346
|
import { resolve as resolve41 } from "path";
|
|
25650
|
-
import { readFile as
|
|
26347
|
+
import { readFile as readFile29 } from "fs/promises";
|
|
25651
26348
|
function createEventsRouter(projectsDir2, assignmentsDir2) {
|
|
25652
|
-
const router =
|
|
26349
|
+
const router = Router16();
|
|
25653
26350
|
router.get("/projects/:slug/assignments/:aslug/events", async (req2, res) => {
|
|
25654
26351
|
try {
|
|
25655
26352
|
const { slug, aslug } = req2.params;
|
|
@@ -25686,7 +26383,7 @@ function createEventsRouter(projectsDir2, assignmentsDir2) {
|
|
|
25686
26383
|
}
|
|
25687
26384
|
async function readAssignmentId2(assignmentMdPath2) {
|
|
25688
26385
|
if (!await fileExists(assignmentMdPath2)) return null;
|
|
25689
|
-
const content = await
|
|
26386
|
+
const content = await readFile29(assignmentMdPath2, "utf-8");
|
|
25690
26387
|
const [fm] = extractFrontmatter(content);
|
|
25691
26388
|
const id = getField(fm, "id");
|
|
25692
26389
|
return id && id.length > 0 ? id : null;
|
|
@@ -25723,7 +26420,7 @@ function parseFilters(query) {
|
|
|
25723
26420
|
}
|
|
25724
26421
|
|
|
25725
26422
|
// src/dashboard/api-inbox.ts
|
|
25726
|
-
import { Router as
|
|
26423
|
+
import { Router as Router17 } from "express";
|
|
25727
26424
|
|
|
25728
26425
|
// src/inbox/index.ts
|
|
25729
26426
|
init_fs();
|
|
@@ -25732,7 +26429,7 @@ init_parser();
|
|
|
25732
26429
|
init_facts();
|
|
25733
26430
|
init_state_machine();
|
|
25734
26431
|
import { resolve as resolve42 } from "path";
|
|
25735
|
-
import { readFile as
|
|
26432
|
+
import { readFile as readFile30 } from "fs/promises";
|
|
25736
26433
|
|
|
25737
26434
|
// src/inbox/types.ts
|
|
25738
26435
|
var INBOX_CATEGORIES = [
|
|
@@ -25912,7 +26609,7 @@ async function computeInbox(opts) {
|
|
|
25912
26609
|
if (opts.project !== void 0 && entry.projectSlug !== opts.project) continue;
|
|
25913
26610
|
let parsed;
|
|
25914
26611
|
try {
|
|
25915
|
-
const content = await
|
|
26612
|
+
const content = await readFile30(resolve42(entry.assignmentDir, "assignment.md"), "utf-8");
|
|
25916
26613
|
parsed = parseAssignmentFull(content);
|
|
25917
26614
|
} catch {
|
|
25918
26615
|
continue;
|
|
@@ -25958,7 +26655,7 @@ async function computeInbox(opts) {
|
|
|
25958
26655
|
const commentsPath = resolve42(entry.assignmentDir, "comments.md");
|
|
25959
26656
|
if (await fileExists(commentsPath)) {
|
|
25960
26657
|
try {
|
|
25961
|
-
const content = await
|
|
26658
|
+
const content = await readFile30(commentsPath, "utf-8");
|
|
25962
26659
|
const parsedComments = parseComments(content);
|
|
25963
26660
|
for (const c2 of unresolvedQuestions(parsedComments.entries)) {
|
|
25964
26661
|
const since = resolveSince("question", parsed, now, c2);
|
|
@@ -26014,7 +26711,7 @@ async function computeInbox(opts) {
|
|
|
26014
26711
|
init_api();
|
|
26015
26712
|
init_config2();
|
|
26016
26713
|
function createInboxRouter(projectsDir2, assignmentsDir2) {
|
|
26017
|
-
const router =
|
|
26714
|
+
const router = Router17();
|
|
26018
26715
|
router.get("/inbox", async (req2, res) => {
|
|
26019
26716
|
try {
|
|
26020
26717
|
const project = typeof req2.query.project === "string" && req2.query.project.length > 0 ? req2.query.project : void 0;
|
|
@@ -26070,9 +26767,9 @@ init_timestamp();
|
|
|
26070
26767
|
init_fs();
|
|
26071
26768
|
init_playbook();
|
|
26072
26769
|
init_playbooks();
|
|
26073
|
-
import { Router as
|
|
26770
|
+
import { Router as Router18 } from "express";
|
|
26074
26771
|
import { resolve as resolve43 } from "path";
|
|
26075
|
-
import { readFile as
|
|
26772
|
+
import { readFile as readFile31 } from "fs/promises";
|
|
26076
26773
|
function statusForPlaybookError(code) {
|
|
26077
26774
|
switch (code) {
|
|
26078
26775
|
case "manifest":
|
|
@@ -26086,7 +26783,7 @@ function statusForPlaybookError(code) {
|
|
|
26086
26783
|
}
|
|
26087
26784
|
}
|
|
26088
26785
|
function createPlaybooksRouter(playbooksDir3) {
|
|
26089
|
-
const router =
|
|
26786
|
+
const router = Router18();
|
|
26090
26787
|
router.get("/", async (_req, res) => {
|
|
26091
26788
|
try {
|
|
26092
26789
|
const playbooks = await listPlaybooks(playbooksDir3);
|
|
@@ -26154,7 +26851,7 @@ function createPlaybooksRouter(playbooksDir3) {
|
|
|
26154
26851
|
return;
|
|
26155
26852
|
}
|
|
26156
26853
|
const filePath = resolve43(playbooksDir3, resolved.filename);
|
|
26157
|
-
const content = await
|
|
26854
|
+
const content = await readFile31(filePath, "utf-8");
|
|
26158
26855
|
res.json({
|
|
26159
26856
|
documentType: "playbook",
|
|
26160
26857
|
title: `Edit Playbook: ${resolved.slug}`,
|
|
@@ -26250,10 +26947,10 @@ init_fs_migration();
|
|
|
26250
26947
|
init_parser2();
|
|
26251
26948
|
init_fs();
|
|
26252
26949
|
init_paths();
|
|
26253
|
-
import { Router as
|
|
26254
|
-
import { readdir as
|
|
26255
|
-
import { resolve as resolvePath, dirname as
|
|
26256
|
-
import { rename as rename6, mkdir as
|
|
26950
|
+
import { Router as Router20 } from "express";
|
|
26951
|
+
import { readdir as readdir20 } from "fs/promises";
|
|
26952
|
+
import { resolve as resolvePath, dirname as dirname12 } from "path";
|
|
26953
|
+
import { rename as rename6, mkdir as mkdir6 } from "fs/promises";
|
|
26257
26954
|
init_slug();
|
|
26258
26955
|
init_promote_todos();
|
|
26259
26956
|
init_api();
|
|
@@ -26262,8 +26959,8 @@ init_api();
|
|
|
26262
26959
|
import { raw } from "express";
|
|
26263
26960
|
|
|
26264
26961
|
// src/todos/attachments.ts
|
|
26265
|
-
import { mkdir as
|
|
26266
|
-
import { resolve as resolve44, basename as
|
|
26962
|
+
import { mkdir as mkdir5, readdir as readdir19, stat as stat7, rename as rename5, rm as rm4, unlink as unlink7, writeFile as writeFile7, cp } from "fs/promises";
|
|
26963
|
+
import { resolve as resolve44, basename as basename7, dirname as dirname11, extname } from "path";
|
|
26267
26964
|
|
|
26268
26965
|
// src/utils/proof-artifact-id.ts
|
|
26269
26966
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
@@ -26360,7 +27057,7 @@ function isSafeInlineMime(mime) {
|
|
|
26360
27057
|
return SAFE_INLINE_MIME.has(mime);
|
|
26361
27058
|
}
|
|
26362
27059
|
function sanitizeAttachmentName(name) {
|
|
26363
|
-
let n =
|
|
27060
|
+
let n = basename7(name || "").replace(/["'\\/]/g, "_");
|
|
26364
27061
|
n = Array.from(n, (ch) => {
|
|
26365
27062
|
const code = ch.charCodeAt(0);
|
|
26366
27063
|
return code < 32 || code === 127 ? "_" : ch;
|
|
@@ -26383,17 +27080,17 @@ function attachmentDirFor(todosDir2, scopeId, todoId) {
|
|
|
26383
27080
|
}
|
|
26384
27081
|
async function dirExists(p) {
|
|
26385
27082
|
try {
|
|
26386
|
-
return (await
|
|
27083
|
+
return (await stat7(p)).isDirectory();
|
|
26387
27084
|
} catch {
|
|
26388
27085
|
return false;
|
|
26389
27086
|
}
|
|
26390
27087
|
}
|
|
26391
27088
|
async function writeAttachment(todosDir2, scopeId, todoId, originalName, bytes) {
|
|
26392
27089
|
const dir = attachmentDirFor(todosDir2, scopeId, todoId);
|
|
26393
|
-
await
|
|
27090
|
+
await mkdir5(dir, { recursive: true });
|
|
26394
27091
|
const id = generateArtifactId();
|
|
26395
27092
|
const filename = sanitizeAttachmentName(originalName);
|
|
26396
|
-
await
|
|
27093
|
+
await writeFile7(resolve44(dir, `${id}__${filename}`), bytes);
|
|
26397
27094
|
return {
|
|
26398
27095
|
id,
|
|
26399
27096
|
filename,
|
|
@@ -26406,7 +27103,7 @@ async function listAttachments(todosDir2, scopeId, todoId) {
|
|
|
26406
27103
|
const dir = attachmentDirFor(todosDir2, scopeId, todoId);
|
|
26407
27104
|
let names;
|
|
26408
27105
|
try {
|
|
26409
|
-
names = await
|
|
27106
|
+
names = await readdir19(dir);
|
|
26410
27107
|
} catch {
|
|
26411
27108
|
return [];
|
|
26412
27109
|
}
|
|
@@ -26418,7 +27115,7 @@ async function listAttachments(todosDir2, scopeId, todoId) {
|
|
|
26418
27115
|
if (!ATTACHMENT_ID_RE.test(id)) continue;
|
|
26419
27116
|
const filename = stored.slice(sep2 + 2);
|
|
26420
27117
|
try {
|
|
26421
|
-
const st = await
|
|
27118
|
+
const st = await stat7(resolve44(dir, stored));
|
|
26422
27119
|
if (!st.isFile()) continue;
|
|
26423
27120
|
out.push({ id, filename, mime: mimeForName(filename), size: st.size, createdAt: st.mtime.toISOString() });
|
|
26424
27121
|
} catch {
|
|
@@ -26432,7 +27129,7 @@ async function readScopeAttachments(todosDir2, scopeId) {
|
|
|
26432
27129
|
const scopeDir = resolve44(attachmentsRootDir(todosDir2), scopeId);
|
|
26433
27130
|
let todoIds;
|
|
26434
27131
|
try {
|
|
26435
|
-
todoIds = await
|
|
27132
|
+
todoIds = await readdir19(scopeDir);
|
|
26436
27133
|
} catch {
|
|
26437
27134
|
return {};
|
|
26438
27135
|
}
|
|
@@ -26449,7 +27146,7 @@ async function resolveAttachmentFile(todosDir2, scopeId, todoId, attachmentId) {
|
|
|
26449
27146
|
const dir = attachmentDirFor(todosDir2, scopeId, todoId);
|
|
26450
27147
|
let names;
|
|
26451
27148
|
try {
|
|
26452
|
-
names = await
|
|
27149
|
+
names = await readdir19(dir);
|
|
26453
27150
|
} catch {
|
|
26454
27151
|
return null;
|
|
26455
27152
|
}
|
|
@@ -26477,7 +27174,7 @@ async function moveAttachments(srcTodosDir, srcScopeId, dstTodosDir, dstScopeId,
|
|
|
26477
27174
|
const src = attachmentDirFor(srcTodosDir, srcScopeId, todoId);
|
|
26478
27175
|
if (!await dirExists(src)) return;
|
|
26479
27176
|
const dst = attachmentDirFor(dstTodosDir, dstScopeId, todoId);
|
|
26480
|
-
await
|
|
27177
|
+
await mkdir5(dirname11(dst), { recursive: true });
|
|
26481
27178
|
try {
|
|
26482
27179
|
await rename5(src, dst);
|
|
26483
27180
|
} catch (err2) {
|
|
@@ -26619,7 +27316,7 @@ function touchItem3(item) {
|
|
|
26619
27316
|
item.updatedAt = now;
|
|
26620
27317
|
}
|
|
26621
27318
|
function createTodosRouter(todosDir2, broadcast, projectsDir2) {
|
|
26622
|
-
const router =
|
|
27319
|
+
const router = Router20();
|
|
26623
27320
|
installRecordsInvalidation(router);
|
|
26624
27321
|
function broadcastUpdate() {
|
|
26625
27322
|
broadcast({ type: "todos-updated", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
@@ -26753,7 +27450,7 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
|
|
|
26753
27450
|
router.get("/", async (_req, res) => {
|
|
26754
27451
|
try {
|
|
26755
27452
|
await ensureDir(todosDir2);
|
|
26756
|
-
const files = await
|
|
27453
|
+
const files = await readdir20(todosDir2).catch(() => []);
|
|
26757
27454
|
const workspaces = [];
|
|
26758
27455
|
for (const file of files) {
|
|
26759
27456
|
if (typeof file !== "string") continue;
|
|
@@ -26874,7 +27571,7 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
|
|
|
26874
27571
|
try {
|
|
26875
27572
|
const { archivePath: archivePath2 } = await Promise.resolve().then(() => (init_parser2(), parser_exports));
|
|
26876
27573
|
const { resolve: resolve112 } = await import("path");
|
|
26877
|
-
const { readFile:
|
|
27574
|
+
const { readFile: readFile85 } = await import("fs/promises");
|
|
26878
27575
|
const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
26879
27576
|
const workspace = getWorkspaceParam(req2.params.workspace);
|
|
26880
27577
|
const outcome = await wsLock(workspace, async () => {
|
|
@@ -26893,7 +27590,7 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
|
|
|
26893
27590
|
await ensureDir(resolve112(todosDir2, "archive"));
|
|
26894
27591
|
let archContent = "";
|
|
26895
27592
|
if (await fileExists(archFile)) {
|
|
26896
|
-
archContent = await
|
|
27593
|
+
archContent = await readFile85(archFile, "utf-8");
|
|
26897
27594
|
archContent = archContent.trimEnd() + "\n\n";
|
|
26898
27595
|
} else {
|
|
26899
27596
|
archContent = `---
|
|
@@ -27194,7 +27891,7 @@ workspace: ${workspace}
|
|
|
27194
27891
|
const { readConfig: readConfig3 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
27195
27892
|
const { assignmentsDir: assignmentsDirFn } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
27196
27893
|
const { fileExists: fileExists2, writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
27197
|
-
const { readFile:
|
|
27894
|
+
const { readFile: readFile85 } = await import("fs/promises");
|
|
27198
27895
|
const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
|
|
27199
27896
|
const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
|
|
27200
27897
|
let assignmentRef;
|
|
@@ -27215,7 +27912,7 @@ workspace: ${workspace}
|
|
|
27215
27912
|
}
|
|
27216
27913
|
const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
|
|
27217
27914
|
if (!await fileExists2(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
|
|
27218
|
-
let content = await
|
|
27915
|
+
let content = await readFile85(assignmentMdPath2, "utf-8");
|
|
27219
27916
|
content = appendTodosToAssignmentBody2(
|
|
27220
27917
|
content,
|
|
27221
27918
|
items.map((it) => ({
|
|
@@ -27332,7 +28029,7 @@ workspace: ${workspace}
|
|
|
27332
28029
|
return { status: 409, error: "attachments already exist in target" };
|
|
27333
28030
|
}
|
|
27334
28031
|
if (item.planDir && newPlanDir) {
|
|
27335
|
-
await
|
|
28032
|
+
await mkdir6(dirname12(newPlanDir), { recursive: true });
|
|
27336
28033
|
await rename6(item.planDir, newPlanDir);
|
|
27337
28034
|
item.planDir = newPlanDir;
|
|
27338
28035
|
}
|
|
@@ -27409,9 +28106,9 @@ init_parser2();
|
|
|
27409
28106
|
init_fs();
|
|
27410
28107
|
init_paths();
|
|
27411
28108
|
init_slug();
|
|
27412
|
-
import { Router as
|
|
27413
|
-
import { mkdir as
|
|
27414
|
-
import { resolve as resolve45, dirname as
|
|
28109
|
+
import { Router as Router21 } from "express";
|
|
28110
|
+
import { mkdir as mkdir7, readFile as readFile32, rename as rename7 } from "fs/promises";
|
|
28111
|
+
import { resolve as resolve45, dirname as dirname13 } from "path";
|
|
27415
28112
|
init_promote_todos();
|
|
27416
28113
|
init_api();
|
|
27417
28114
|
var WORKSPACE_REGEX2 = /^[a-z0-9_][a-z0-9-]*$/;
|
|
@@ -27433,7 +28130,7 @@ async function projectExists(projectsDir2, slug) {
|
|
|
27433
28130
|
async function ensureProjectTodosDir(projectsDir2, slug) {
|
|
27434
28131
|
const todosDir2 = projectTodosDir(projectsDir2, slug);
|
|
27435
28132
|
try {
|
|
27436
|
-
await
|
|
28133
|
+
await mkdir7(todosDir2, { recursive: false });
|
|
27437
28134
|
} catch (err2) {
|
|
27438
28135
|
const code = err2.code;
|
|
27439
28136
|
if (code === "EEXIST") return;
|
|
@@ -27445,7 +28142,7 @@ async function ensureProjectTodosDir(projectsDir2, slug) {
|
|
|
27445
28142
|
throw err2;
|
|
27446
28143
|
}
|
|
27447
28144
|
try {
|
|
27448
|
-
await
|
|
28145
|
+
await mkdir7(resolve45(todosDir2, "archive"), { recursive: false });
|
|
27449
28146
|
} catch (err2) {
|
|
27450
28147
|
const code = err2.code;
|
|
27451
28148
|
if (code === "EEXIST") return;
|
|
@@ -27461,7 +28158,7 @@ function notFound(res, slug) {
|
|
|
27461
28158
|
res.status(404).json({ error: `Project "${slug}" not found` });
|
|
27462
28159
|
}
|
|
27463
28160
|
function createProjectTodosRouter(projectsDir2, broadcast, workspaceTodosDir) {
|
|
27464
|
-
const router =
|
|
28161
|
+
const router = Router21({ mergeParams: true });
|
|
27465
28162
|
installRecordsInvalidation(router);
|
|
27466
28163
|
function broadcastUpdate(projectSlug) {
|
|
27467
28164
|
broadcast({ type: "todos-updated", projectSlug, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
@@ -27653,7 +28350,7 @@ function createProjectTodosRouter(projectsDir2, broadcast, workspaceTodosDir) {
|
|
|
27653
28350
|
const archFile = archivePath(todosDir2, slug, checklist.archiveInterval);
|
|
27654
28351
|
let archContent = "";
|
|
27655
28352
|
if (await fileExists(archFile)) {
|
|
27656
|
-
archContent = await
|
|
28353
|
+
archContent = await readFile32(archFile, "utf-8");
|
|
27657
28354
|
archContent = archContent.trimEnd() + "\n\n";
|
|
27658
28355
|
} else {
|
|
27659
28356
|
archContent = `---
|
|
@@ -28134,7 +28831,7 @@ workspace: ${slug}
|
|
|
28134
28831
|
}
|
|
28135
28832
|
const assignmentMdPath2 = resolve45(assignmentDir, "assignment.md");
|
|
28136
28833
|
if (!await fileExists(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
|
|
28137
|
-
let content = await
|
|
28834
|
+
let content = await readFile32(assignmentMdPath2, "utf-8");
|
|
28138
28835
|
content = appendTodosToAssignmentBody2(
|
|
28139
28836
|
content,
|
|
28140
28837
|
items.map((it) => ({
|
|
@@ -28273,7 +28970,7 @@ workspace: ${slug}
|
|
|
28273
28970
|
return { status: 409, error: "attachments already exist in target" };
|
|
28274
28971
|
}
|
|
28275
28972
|
if (item.planDir && newPlanDir) {
|
|
28276
|
-
await
|
|
28973
|
+
await mkdir7(dirname13(newPlanDir), { recursive: true });
|
|
28277
28974
|
await rename7(item.planDir, newPlanDir);
|
|
28278
28975
|
item.planDir = newPlanDir;
|
|
28279
28976
|
}
|
|
@@ -28336,8 +29033,8 @@ workspace: ${slug}
|
|
|
28336
29033
|
}
|
|
28337
29034
|
|
|
28338
29035
|
// src/dashboard/api-bundles.ts
|
|
28339
|
-
import { Router as
|
|
28340
|
-
import { readdir as
|
|
29036
|
+
import { Router as Router22 } from "express";
|
|
29037
|
+
import { readdir as readdir21 } from "fs/promises";
|
|
28341
29038
|
|
|
28342
29039
|
// src/todos/bundle-parser.ts
|
|
28343
29040
|
init_parser();
|
|
@@ -28345,7 +29042,7 @@ init_fs();
|
|
|
28345
29042
|
init_paths();
|
|
28346
29043
|
init_parser2();
|
|
28347
29044
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
28348
|
-
import { readFile as
|
|
29045
|
+
import { readFile as readFile33 } from "fs/promises";
|
|
28349
29046
|
var BUNDLE_ID_REGEX = /^[a-f0-9]{4}$/;
|
|
28350
29047
|
var SCOPE_VALUES = /* @__PURE__ */ new Set(["workspace", "project", "global"]);
|
|
28351
29048
|
var SCOPE_ID_REGEX = /^[a-z0-9_][a-z0-9_-]*$/;
|
|
@@ -28448,7 +29145,7 @@ ${lines}
|
|
|
28448
29145
|
async function readBundles(todosDir2) {
|
|
28449
29146
|
const path = bundlesPath(todosDir2);
|
|
28450
29147
|
if (!await fileExists(path)) return [];
|
|
28451
|
-
const content = await
|
|
29148
|
+
const content = await readFile33(path, "utf-8");
|
|
28452
29149
|
return parseBundles(content).bundles;
|
|
28453
29150
|
}
|
|
28454
29151
|
async function writeBundles(todosDir2, bundles) {
|
|
@@ -28487,7 +29184,7 @@ function annotate(bundle, items) {
|
|
|
28487
29184
|
}
|
|
28488
29185
|
function createBundlesRouter(todosDir2, broadcast) {
|
|
28489
29186
|
void broadcast;
|
|
28490
|
-
const router =
|
|
29187
|
+
const router = Router22();
|
|
28491
29188
|
function validateWorkspace(req2, res, next) {
|
|
28492
29189
|
const workspace = getWorkspaceParam2(req2.params.workspace);
|
|
28493
29190
|
if (workspace && !WORKSPACE_REGEX3.test(workspace)) {
|
|
@@ -28501,7 +29198,7 @@ function createBundlesRouter(todosDir2, broadcast) {
|
|
|
28501
29198
|
try {
|
|
28502
29199
|
await ensureDir(todosDir2);
|
|
28503
29200
|
const bundles = await readBundles(todosDir2);
|
|
28504
|
-
const workspaceFiles = await
|
|
29201
|
+
const workspaceFiles = await readdir21(todosDir2).catch(() => []);
|
|
28505
29202
|
const itemsByKey = /* @__PURE__ */ new Map();
|
|
28506
29203
|
for (const f of workspaceFiles) {
|
|
28507
29204
|
if (typeof f !== "string") continue;
|
|
@@ -28553,7 +29250,7 @@ function createBundlesRouter(todosDir2, broadcast) {
|
|
|
28553
29250
|
init_fs();
|
|
28554
29251
|
init_paths();
|
|
28555
29252
|
init_slug();
|
|
28556
|
-
import { Router as
|
|
29253
|
+
import { Router as Router23 } from "express";
|
|
28557
29254
|
import { resolve as resolve46 } from "path";
|
|
28558
29255
|
init_parser2();
|
|
28559
29256
|
function deriveStatus2(bundle, items) {
|
|
@@ -28583,7 +29280,7 @@ function notFound2(res, slug) {
|
|
|
28583
29280
|
}
|
|
28584
29281
|
function createProjectBundlesRouter(projectsDir2, broadcast) {
|
|
28585
29282
|
void broadcast;
|
|
28586
|
-
const router =
|
|
29283
|
+
const router = Router23({ mergeParams: true });
|
|
28587
29284
|
function validateProjectId(req2, res, next) {
|
|
28588
29285
|
const slug = getProjectIdParam2(req2.params.projectId);
|
|
28589
29286
|
if (!slug || !isValidSlug(slug)) {
|
|
@@ -28617,7 +29314,7 @@ function createProjectBundlesRouter(projectsDir2, broadcast) {
|
|
|
28617
29314
|
init_config2();
|
|
28618
29315
|
init_api();
|
|
28619
29316
|
init_scanner();
|
|
28620
|
-
import { Router as
|
|
29317
|
+
import { Router as Router24 } from "express";
|
|
28621
29318
|
|
|
28622
29319
|
// src/utils/github-backup.ts
|
|
28623
29320
|
init_paths();
|
|
@@ -28625,8 +29322,8 @@ init_fs();
|
|
|
28625
29322
|
init_config2();
|
|
28626
29323
|
import { execFile as execFile2 } from "child_process";
|
|
28627
29324
|
import { promisify as promisify2 } from "util";
|
|
28628
|
-
import { cp as cp2, mkdtemp, rm as rm5, readFile as
|
|
28629
|
-
import { resolve as resolve47, join as
|
|
29325
|
+
import { cp as cp2, mkdtemp, rm as rm5, readFile as readFile34, writeFile as writeFile8, unlink as unlink8, stat as stat8, open as open5, rename as rename8 } from "fs/promises";
|
|
29326
|
+
import { resolve as resolve47, join as join13 } from "path";
|
|
28630
29327
|
import { tmpdir } from "os";
|
|
28631
29328
|
var exec2 = promisify2(execFile2);
|
|
28632
29329
|
var VALID_CATEGORIES = ["projects", "playbooks", "todos", "servers", "config"];
|
|
@@ -28686,7 +29383,7 @@ async function acquireLock2() {
|
|
|
28686
29383
|
return lockPath;
|
|
28687
29384
|
} catch (err2) {
|
|
28688
29385
|
if (err2.code === "EEXIST") {
|
|
28689
|
-
const pid = await
|
|
29386
|
+
const pid = await readFile34(lockPath, "utf-8").catch(() => "");
|
|
28690
29387
|
throw new Error(
|
|
28691
29388
|
`Backup operation already in progress (lock file at ${lockPath}, pid ${pid.trim() || "unknown"}). If stale, delete the file and retry.`
|
|
28692
29389
|
);
|
|
@@ -28719,7 +29416,7 @@ async function cloneOrInit(repoUrl, destDir) {
|
|
|
28719
29416
|
}
|
|
28720
29417
|
async function copyRecursive(src, dest) {
|
|
28721
29418
|
if (!await fileExists(src)) return;
|
|
28722
|
-
const s = await
|
|
29419
|
+
const s = await stat8(src);
|
|
28723
29420
|
if (s.isDirectory()) {
|
|
28724
29421
|
await ensureDir(dest);
|
|
28725
29422
|
await cp2(src, dest, { recursive: true, force: true });
|
|
@@ -28733,7 +29430,7 @@ function resolveCategoriesStrict(csv) {
|
|
|
28733
29430
|
return parseCategoriesStrict(parts);
|
|
28734
29431
|
}
|
|
28735
29432
|
async function readSanitizedConfig(configPath2) {
|
|
28736
|
-
const content = await
|
|
29433
|
+
const content = await readFile34(configPath2, "utf-8");
|
|
28737
29434
|
return content.replace(/^(\s*lastBackup:\s*).*$/m, "$1null").replace(/^(\s*lastRestore:\s*).*$/m, "$1null");
|
|
28738
29435
|
}
|
|
28739
29436
|
async function backupToGithub(overrides) {
|
|
@@ -28756,11 +29453,11 @@ async function backupToGithub(overrides) {
|
|
|
28756
29453
|
let tmpDir = null;
|
|
28757
29454
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
28758
29455
|
try {
|
|
28759
|
-
tmpDir = await mkdtemp(
|
|
29456
|
+
tmpDir = await mkdtemp(join13(tmpdir(), "syntaur-backup-"));
|
|
28760
29457
|
await cloneOrInit(repo, tmpDir);
|
|
28761
29458
|
for (const category of categories) {
|
|
28762
29459
|
const { sourcePath, repoPath, isFile } = await resolveCategoryPath(category);
|
|
28763
|
-
const destPath =
|
|
29460
|
+
const destPath = join13(tmpDir, repoPath);
|
|
28764
29461
|
if (isFile) {
|
|
28765
29462
|
await rm5(destPath, { force: true });
|
|
28766
29463
|
} else {
|
|
@@ -28773,7 +29470,7 @@ async function backupToGithub(overrides) {
|
|
|
28773
29470
|
if (category === "config") {
|
|
28774
29471
|
const sanitized = await readSanitizedConfig(sourcePath);
|
|
28775
29472
|
await ensureDir(resolve47(destPath, ".."));
|
|
28776
|
-
await
|
|
29473
|
+
await writeFile8(destPath, sanitized, "utf-8");
|
|
28777
29474
|
} else {
|
|
28778
29475
|
await copyRecursive(sourcePath, destPath);
|
|
28779
29476
|
}
|
|
@@ -28888,7 +29585,7 @@ async function restoreFromGithub(overrides) {
|
|
|
28888
29585
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
28889
29586
|
try {
|
|
28890
29587
|
await updateBackupConfig({ lastRestore: timestamp });
|
|
28891
|
-
tmpDir = await mkdtemp(
|
|
29588
|
+
tmpDir = await mkdtemp(join13(tmpdir(), "syntaur-restore-"));
|
|
28892
29589
|
await cloneOrInit(repo, tmpDir);
|
|
28893
29590
|
for (const category of categories) {
|
|
28894
29591
|
if (category === "config") {
|
|
@@ -28897,7 +29594,7 @@ async function restoreFromGithub(overrides) {
|
|
|
28897
29594
|
}
|
|
28898
29595
|
try {
|
|
28899
29596
|
const { sourcePath: localPath, repoPath, isFile } = await resolveCategoryPath(category);
|
|
28900
|
-
const repoSrcPath =
|
|
29597
|
+
const repoSrcPath = join13(tmpDir, repoPath);
|
|
28901
29598
|
if (!await fileExists(repoSrcPath)) {
|
|
28902
29599
|
console.warn(`Category "${category}" not found in backup repo, skipping.`);
|
|
28903
29600
|
continue;
|
|
@@ -28940,7 +29637,7 @@ async function getBackupStatus() {
|
|
|
28940
29637
|
|
|
28941
29638
|
// src/dashboard/api-backup.ts
|
|
28942
29639
|
function createBackupRouter() {
|
|
28943
|
-
const router =
|
|
29640
|
+
const router = Router24();
|
|
28944
29641
|
router.get("/", async (_req, res) => {
|
|
28945
29642
|
try {
|
|
28946
29643
|
const status = await getBackupStatus();
|
|
@@ -30308,6 +31005,7 @@ function createDashboardServer(options) {
|
|
|
30308
31005
|
app.use("/api", createInboxRouter(projectsDir2, assignmentsDir2));
|
|
30309
31006
|
app.use("/api/agent-sessions", createAgentSessionsRouter(projectsDir2, broadcast, assignmentsDir2));
|
|
30310
31007
|
app.use("/api/config/agents", createAgentsRouter());
|
|
31008
|
+
app.use("/api/config/agent-discovery", createAgentDiscoveryConfigRouter());
|
|
30311
31009
|
app.use(
|
|
30312
31010
|
"/api/launch",
|
|
30313
31011
|
createLaunchPreflightRouter(projectsDir2, assignmentsDir2)
|
|
@@ -30505,7 +31203,7 @@ function createDashboardServer(options) {
|
|
|
30505
31203
|
});
|
|
30506
31204
|
server.listen(port, () => {
|
|
30507
31205
|
const portFile = resolve50(syntaurRoot(), "dashboard-port");
|
|
30508
|
-
|
|
31206
|
+
writeFile9(portFile, String(port), "utf-8").catch(() => {
|
|
30509
31207
|
});
|
|
30510
31208
|
resolvePromise();
|
|
30511
31209
|
});
|
|
@@ -30656,7 +31354,7 @@ async function dashboardCommand(options) {
|
|
|
30656
31354
|
port = availablePort;
|
|
30657
31355
|
}
|
|
30658
31356
|
const thisFile = fileURLToPath3(import.meta.url);
|
|
30659
|
-
const packageRoot = resolve51(
|
|
31357
|
+
const packageRoot = resolve51(dirname14(thisFile), "..");
|
|
30660
31358
|
const dashboardDist = resolve51(packageRoot, "dashboard", "dist");
|
|
30661
31359
|
const server = createDashboardServer({
|
|
30662
31360
|
port,
|
|
@@ -30883,8 +31581,8 @@ init_git_worktree();
|
|
|
30883
31581
|
init_recompute();
|
|
30884
31582
|
init_event_emit();
|
|
30885
31583
|
init_transitions();
|
|
30886
|
-
import { readFile as
|
|
30887
|
-
import { resolve as resolve54, basename as
|
|
31584
|
+
import { readFile as readFile37 } from "fs/promises";
|
|
31585
|
+
import { resolve as resolve54, basename as basename8 } from "path";
|
|
30888
31586
|
|
|
30889
31587
|
// src/utils/assignment-target.ts
|
|
30890
31588
|
init_paths();
|
|
@@ -30894,7 +31592,7 @@ init_slug();
|
|
|
30894
31592
|
init_assignment_resolver();
|
|
30895
31593
|
init_parser();
|
|
30896
31594
|
import { resolve as resolve53 } from "path";
|
|
30897
|
-
import { readFile as
|
|
31595
|
+
import { readFile as readFile35 } from "fs/promises";
|
|
30898
31596
|
var AssignmentTargetError = class extends Error {
|
|
30899
31597
|
};
|
|
30900
31598
|
function classifyContext(ctx) {
|
|
@@ -30907,7 +31605,7 @@ async function readAssignmentFrontmatterId(assignmentDir) {
|
|
|
30907
31605
|
const path = resolve53(assignmentDir, "assignment.md");
|
|
30908
31606
|
if (!await fileExists(path)) return null;
|
|
30909
31607
|
try {
|
|
30910
|
-
const content = await
|
|
31608
|
+
const content = await readFile35(path, "utf-8");
|
|
30911
31609
|
const [fm] = extractFrontmatter(content);
|
|
30912
31610
|
return getField(fm, "id");
|
|
30913
31611
|
} catch {
|
|
@@ -30918,7 +31616,7 @@ async function readContextJson(cwd) {
|
|
|
30918
31616
|
const path = resolve53(cwd, ".syntaur", "context.json");
|
|
30919
31617
|
if (!await fileExists(path)) return null;
|
|
30920
31618
|
try {
|
|
30921
|
-
const raw2 = await
|
|
31619
|
+
const raw2 = await readFile35(path, "utf-8");
|
|
30922
31620
|
return JSON.parse(raw2);
|
|
30923
31621
|
} catch {
|
|
30924
31622
|
return null;
|
|
@@ -31103,7 +31801,7 @@ init_session_id();
|
|
|
31103
31801
|
init_fs();
|
|
31104
31802
|
init_frontmatter();
|
|
31105
31803
|
init_recompute();
|
|
31106
|
-
import { readFile as
|
|
31804
|
+
import { readFile as readFile36 } from "fs/promises";
|
|
31107
31805
|
function computeDelta(stage, prevStage, fm) {
|
|
31108
31806
|
const writes = {};
|
|
31109
31807
|
if (stage === "implement") {
|
|
@@ -31121,7 +31819,7 @@ async function assertStageFactOnOpen(input4) {
|
|
|
31121
31819
|
const pre = computeDelta(
|
|
31122
31820
|
input4.stage,
|
|
31123
31821
|
input4.prevStage,
|
|
31124
|
-
parseAssignmentFrontmatter(await
|
|
31822
|
+
parseAssignmentFrontmatter(await readFile36(input4.assignmentPath, "utf-8"))
|
|
31125
31823
|
);
|
|
31126
31824
|
if (Object.keys(pre).length === 0) return;
|
|
31127
31825
|
const context = await resolveDeriveContext();
|
|
@@ -31171,7 +31869,7 @@ async function resolveTarget(assignment, options) {
|
|
|
31171
31869
|
async function inferActor(options) {
|
|
31172
31870
|
if (options.agent) return `agent:${options.agent}`;
|
|
31173
31871
|
try {
|
|
31174
|
-
const raw2 = await
|
|
31872
|
+
const raw2 = await readFile37(resolve54(process.cwd(), ".syntaur", "context.json"), "utf-8");
|
|
31175
31873
|
const ctx = JSON.parse(raw2);
|
|
31176
31874
|
if (ctx.sessionId) return `agent:${ctx.sessionId.slice(0, 8)}`;
|
|
31177
31875
|
} catch {
|
|
@@ -31180,10 +31878,10 @@ async function inferActor(options) {
|
|
|
31180
31878
|
}
|
|
31181
31879
|
async function emitDeriveEvent(target, type, actor, details) {
|
|
31182
31880
|
try {
|
|
31183
|
-
const fm = parseAssignmentFrontmatter(await
|
|
31881
|
+
const fm = parseAssignmentFrontmatter(await readFile37(target.assignmentPath, "utf-8"));
|
|
31184
31882
|
emitEvent({
|
|
31185
31883
|
assignmentId: fm.id,
|
|
31186
|
-
projectSlug: target.projectDir ?
|
|
31884
|
+
projectSlug: target.projectDir ? basename8(target.projectDir) : null,
|
|
31187
31885
|
type,
|
|
31188
31886
|
actor,
|
|
31189
31887
|
details
|
|
@@ -31241,7 +31939,7 @@ async function planApproveCommand(assignment, options) {
|
|
|
31241
31939
|
throw new Error("No plan file found (plan.md / plan-v*.md). Write a plan before approving.");
|
|
31242
31940
|
}
|
|
31243
31941
|
approvedFile = planFile;
|
|
31244
|
-
const planContent = await
|
|
31942
|
+
const planContent = await readFile37(resolve54(target2.assignmentDir, planFile), "utf-8");
|
|
31245
31943
|
return updatePlanApproval(content, {
|
|
31246
31944
|
file: planFile,
|
|
31247
31945
|
digest: planDigest(planContent),
|
|
@@ -31314,7 +32012,7 @@ async function attestCommand(assignment, fact, options) {
|
|
|
31314
32012
|
"No plan file found (plan.md / plan-v*.md). Write a plan before attesting a binds:plan fact."
|
|
31315
32013
|
);
|
|
31316
32014
|
}
|
|
31317
|
-
const planContent = await
|
|
32015
|
+
const planContent = await readFile37(resolve54(target2.assignmentDir, planFile), "utf-8");
|
|
31318
32016
|
record.file = planFile;
|
|
31319
32017
|
record.digest = planDigest(planContent);
|
|
31320
32018
|
} else if (binds === "commit") {
|
|
@@ -31405,13 +32103,13 @@ async function requestReviewCommand(assignment, options) {
|
|
|
31405
32103
|
}
|
|
31406
32104
|
const target = await resolveTarget(assignment, options);
|
|
31407
32105
|
const context = await resolveDeriveContext();
|
|
31408
|
-
const fm = parseAssignmentFrontmatter(await
|
|
32106
|
+
const fm = parseAssignmentFrontmatter(await readFile37(target.assignmentPath, "utf-8"));
|
|
31409
32107
|
await applyStageFact(assignment, options, target, fm, "review", "Review requested", context);
|
|
31410
32108
|
}
|
|
31411
32109
|
async function implementStartedCommand(assignment, options) {
|
|
31412
32110
|
const target = await resolveTarget(assignment, options);
|
|
31413
32111
|
const context = await resolveDeriveContext();
|
|
31414
|
-
const fm = parseAssignmentFrontmatter(await
|
|
32112
|
+
const fm = parseAssignmentFrontmatter(await readFile37(target.assignmentPath, "utf-8"));
|
|
31415
32113
|
if (fm.dependsOn.length > 0 && target.projectDir) {
|
|
31416
32114
|
const dep = await checkDependencies(target.projectDir, fm.dependsOn, context.terminalStatuses);
|
|
31417
32115
|
if (!dep.satisfied) {
|
|
@@ -31542,7 +32240,7 @@ init_timestamp();
|
|
|
31542
32240
|
init_assignment_resolver();
|
|
31543
32241
|
init_event_emit();
|
|
31544
32242
|
import { resolve as resolve55 } from "path";
|
|
31545
|
-
import { readFile as
|
|
32243
|
+
import { readFile as readFile38, writeFile as writeFile10 } from "fs/promises";
|
|
31546
32244
|
async function resolveTarget2(target, options) {
|
|
31547
32245
|
const config = await readConfig();
|
|
31548
32246
|
const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
|
|
@@ -31574,19 +32272,19 @@ async function resolveTarget2(target, options) {
|
|
|
31574
32272
|
return null;
|
|
31575
32273
|
}
|
|
31576
32274
|
async function writeArchiveState(filePath, archived, reason) {
|
|
31577
|
-
const content = await
|
|
32275
|
+
const content = await readFile38(filePath, "utf-8");
|
|
31578
32276
|
const updated = updateAssignmentFile(content, {
|
|
31579
32277
|
archived,
|
|
31580
32278
|
archivedAt: archived ? nowTimestamp() : null,
|
|
31581
32279
|
archivedReason: archived ? reason : null,
|
|
31582
32280
|
updated: nowTimestamp()
|
|
31583
32281
|
});
|
|
31584
|
-
await
|
|
32282
|
+
await writeFile10(filePath, updated, "utf-8");
|
|
31585
32283
|
}
|
|
31586
32284
|
async function emitArchiveEvent(resolved, type, reason) {
|
|
31587
32285
|
if (resolved.kind !== "assignment") return;
|
|
31588
32286
|
try {
|
|
31589
|
-
const fm = parseAssignmentFrontmatter(await
|
|
32287
|
+
const fm = parseAssignmentFrontmatter(await readFile38(resolved.filePath, "utf-8"));
|
|
31590
32288
|
emitEvent({
|
|
31591
32289
|
assignmentId: fm.id,
|
|
31592
32290
|
projectSlug: fm.project,
|
|
@@ -31657,7 +32355,7 @@ init_frontmatter();
|
|
|
31657
32355
|
init_timestamp();
|
|
31658
32356
|
init_event_emit();
|
|
31659
32357
|
import { resolve as resolve56 } from "path";
|
|
31660
|
-
import { readdir as
|
|
32358
|
+
import { readdir as readdir22, readFile as readFile39 } from "fs/promises";
|
|
31661
32359
|
var PROMOTABLE_STATUSES = /* @__PURE__ */ new Set(["pending"]);
|
|
31662
32360
|
function objectiveIsFleshedOut(content) {
|
|
31663
32361
|
const match = content.match(/##\s+Objective\s*\n([\s\S]*?)(?=\n##\s+|$)/);
|
|
@@ -31675,7 +32373,7 @@ async function collectCandidates(baseDirs) {
|
|
|
31675
32373
|
const candidates = [];
|
|
31676
32374
|
for (const baseDir of baseDirs) {
|
|
31677
32375
|
if (!await fileExists(baseDir)) continue;
|
|
31678
|
-
const projects = await
|
|
32376
|
+
const projects = await readdir22(baseDir, { withFileTypes: true });
|
|
31679
32377
|
for (const m of projects) {
|
|
31680
32378
|
if (!m.isDirectory()) continue;
|
|
31681
32379
|
if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
|
|
@@ -31683,7 +32381,7 @@ async function collectCandidates(baseDirs) {
|
|
|
31683
32381
|
if (await fileExists(directAssignmentMd)) {
|
|
31684
32382
|
const fm = await parseSafe(directAssignmentMd);
|
|
31685
32383
|
if (fm && PROMOTABLE_STATUSES.has(fm.status)) {
|
|
31686
|
-
const content = await
|
|
32384
|
+
const content = await readFile39(directAssignmentMd, "utf-8");
|
|
31687
32385
|
if (objectiveIsFleshedOut(content) && hasAcceptanceCriteria(content)) {
|
|
31688
32386
|
candidates.push({
|
|
31689
32387
|
projectSlug: null,
|
|
@@ -31698,7 +32396,7 @@ async function collectCandidates(baseDirs) {
|
|
|
31698
32396
|
}
|
|
31699
32397
|
const assignmentsDir2 = resolve56(baseDir, m.name, "assignments");
|
|
31700
32398
|
if (!await fileExists(assignmentsDir2)) continue;
|
|
31701
|
-
const entries = await
|
|
32399
|
+
const entries = await readdir22(assignmentsDir2, { withFileTypes: true });
|
|
31702
32400
|
for (const a of entries) {
|
|
31703
32401
|
if (!a.isDirectory()) continue;
|
|
31704
32402
|
if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
|
|
@@ -31706,7 +32404,7 @@ async function collectCandidates(baseDirs) {
|
|
|
31706
32404
|
if (!await fileExists(assignmentMd)) continue;
|
|
31707
32405
|
const fm = await parseSafe(assignmentMd);
|
|
31708
32406
|
if (!fm || !PROMOTABLE_STATUSES.has(fm.status)) continue;
|
|
31709
|
-
const content = await
|
|
32407
|
+
const content = await readFile39(assignmentMd, "utf-8");
|
|
31710
32408
|
if (!objectiveIsFleshedOut(content)) continue;
|
|
31711
32409
|
if (!hasAcceptanceCriteria(content)) continue;
|
|
31712
32410
|
candidates.push({
|
|
@@ -31723,7 +32421,7 @@ async function collectCandidates(baseDirs) {
|
|
|
31723
32421
|
}
|
|
31724
32422
|
async function parseSafe(path) {
|
|
31725
32423
|
try {
|
|
31726
|
-
const content = await
|
|
32424
|
+
const content = await readFile39(path, "utf-8");
|
|
31727
32425
|
return parseAssignmentFrontmatter(content);
|
|
31728
32426
|
} catch {
|
|
31729
32427
|
return null;
|
|
@@ -31753,7 +32451,7 @@ async function migrateStatusesCommand(options) {
|
|
|
31753
32451
|
let migrated = 0;
|
|
31754
32452
|
await withSuppressedEvents(async () => {
|
|
31755
32453
|
for (const c2 of candidates) {
|
|
31756
|
-
const content = await
|
|
32454
|
+
const content = await readFile39(c2.assignmentMd, "utf-8");
|
|
31757
32455
|
const updated = appendStatusHistoryEntry(
|
|
31758
32456
|
updateAssignmentFile(content, {
|
|
31759
32457
|
status: c2.toStatus,
|
|
@@ -31776,10 +32474,10 @@ init_frontmatter();
|
|
|
31776
32474
|
init_event_emit();
|
|
31777
32475
|
init_types();
|
|
31778
32476
|
import { resolve as resolve57 } from "path";
|
|
31779
|
-
import { readdir as
|
|
32477
|
+
import { readdir as readdir23, readFile as readFile40 } from "fs/promises";
|
|
31780
32478
|
async function parseSafe2(path) {
|
|
31781
32479
|
try {
|
|
31782
|
-
return parseAssignmentFrontmatter(await
|
|
32480
|
+
return parseAssignmentFrontmatter(await readFile40(path, "utf-8"));
|
|
31783
32481
|
} catch {
|
|
31784
32482
|
return null;
|
|
31785
32483
|
}
|
|
@@ -31802,7 +32500,7 @@ async function collectTargets(baseDirs, terminalStatuses3) {
|
|
|
31802
32500
|
const seen = /* @__PURE__ */ new Set();
|
|
31803
32501
|
for (const baseDir of baseDirs) {
|
|
31804
32502
|
if (!await fileExists(baseDir)) continue;
|
|
31805
|
-
const entries = await
|
|
32503
|
+
const entries = await readdir23(baseDir, { withFileTypes: true });
|
|
31806
32504
|
for (const m of entries) {
|
|
31807
32505
|
if (!m.isDirectory()) continue;
|
|
31808
32506
|
if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
|
|
@@ -31823,7 +32521,7 @@ async function collectTargets(baseDirs, terminalStatuses3) {
|
|
|
31823
32521
|
}
|
|
31824
32522
|
const assignmentsBase = resolve57(baseDir, m.name, "assignments");
|
|
31825
32523
|
if (!await fileExists(assignmentsBase)) continue;
|
|
31826
|
-
const slugs = await
|
|
32524
|
+
const slugs = await readdir23(assignmentsBase, { withFileTypes: true });
|
|
31827
32525
|
for (const a of slugs) {
|
|
31828
32526
|
if (!a.isDirectory()) continue;
|
|
31829
32527
|
if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
|
|
@@ -31871,7 +32569,7 @@ async function migrateStatusHistoryCommand(options) {
|
|
|
31871
32569
|
await withSuppressedEvents(async () => {
|
|
31872
32570
|
for (const t of targets) {
|
|
31873
32571
|
try {
|
|
31874
|
-
const content = await
|
|
32572
|
+
const content = await readFile40(t.assignmentMd, "utf-8");
|
|
31875
32573
|
if (parseAssignmentFrontmatter(content).statusHistory.length > 0) continue;
|
|
31876
32574
|
const seededContent = appendStatusHistoryEntry(content, {
|
|
31877
32575
|
at: t.seedAt,
|
|
@@ -31900,10 +32598,10 @@ init_config2();
|
|
|
31900
32598
|
init_parser();
|
|
31901
32599
|
init_events_db();
|
|
31902
32600
|
import { resolve as resolve58 } from "path";
|
|
31903
|
-
import { readdir as
|
|
32601
|
+
import { readdir as readdir24, readFile as readFile41 } from "fs/promises";
|
|
31904
32602
|
async function parseSafe3(path) {
|
|
31905
32603
|
try {
|
|
31906
|
-
return parseAssignmentFull(await
|
|
32604
|
+
return parseAssignmentFull(await readFile41(path, "utf-8"));
|
|
31907
32605
|
} catch {
|
|
31908
32606
|
return null;
|
|
31909
32607
|
}
|
|
@@ -31936,7 +32634,7 @@ async function collectTargets2(baseDirs) {
|
|
|
31936
32634
|
const seen = /* @__PURE__ */ new Set();
|
|
31937
32635
|
for (const baseDir of baseDirs) {
|
|
31938
32636
|
if (!await fileExists(baseDir)) continue;
|
|
31939
|
-
const entries = await
|
|
32637
|
+
const entries = await readdir24(baseDir, { withFileTypes: true });
|
|
31940
32638
|
for (const m of entries) {
|
|
31941
32639
|
if (!m.isDirectory()) continue;
|
|
31942
32640
|
if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
|
|
@@ -31960,7 +32658,7 @@ async function collectTargets2(baseDirs) {
|
|
|
31960
32658
|
}
|
|
31961
32659
|
const assignmentsBase = resolve58(baseDir, m.name, "assignments");
|
|
31962
32660
|
if (!await fileExists(assignmentsBase)) continue;
|
|
31963
|
-
const slugs = await
|
|
32661
|
+
const slugs = await readdir24(assignmentsBase, { withFileTypes: true });
|
|
31964
32662
|
for (const a of slugs) {
|
|
31965
32663
|
if (!a.isDirectory()) continue;
|
|
31966
32664
|
if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
|
|
@@ -32045,7 +32743,7 @@ init_frontmatter();
|
|
|
32045
32743
|
init_facts();
|
|
32046
32744
|
init_derive();
|
|
32047
32745
|
init_recompute();
|
|
32048
|
-
import { readdir as
|
|
32746
|
+
import { readdir as readdir25, readFile as readFile42 } from "fs/promises";
|
|
32049
32747
|
import { resolve as resolve59 } from "path";
|
|
32050
32748
|
var IMPLEMENTATION_STATUSES = /* @__PURE__ */ new Set(["in_progress", "review", "code_review"]);
|
|
32051
32749
|
var REVIEW_STATUSES = /* @__PURE__ */ new Set(["review", "code_review"]);
|
|
@@ -32053,14 +32751,14 @@ async function listTargets(projectsDir2, standaloneDir) {
|
|
|
32053
32751
|
const targets = [];
|
|
32054
32752
|
let projects = [];
|
|
32055
32753
|
try {
|
|
32056
|
-
projects = await
|
|
32754
|
+
projects = await readdir25(projectsDir2);
|
|
32057
32755
|
} catch {
|
|
32058
32756
|
}
|
|
32059
32757
|
for (const project of projects) {
|
|
32060
32758
|
const projectDir = resolve59(projectsDir2, project);
|
|
32061
32759
|
let slugs = [];
|
|
32062
32760
|
try {
|
|
32063
|
-
slugs = await
|
|
32761
|
+
slugs = await readdir25(resolve59(projectDir, "assignments"));
|
|
32064
32762
|
} catch {
|
|
32065
32763
|
continue;
|
|
32066
32764
|
}
|
|
@@ -32071,7 +32769,7 @@ async function listTargets(projectsDir2, standaloneDir) {
|
|
|
32071
32769
|
}
|
|
32072
32770
|
let ids = [];
|
|
32073
32771
|
try {
|
|
32074
|
-
ids = await
|
|
32772
|
+
ids = await readdir25(standaloneDir);
|
|
32075
32773
|
} catch {
|
|
32076
32774
|
}
|
|
32077
32775
|
for (const id of ids) {
|
|
@@ -32131,7 +32829,7 @@ async function migrateDeriveCommand(options) {
|
|
|
32131
32829
|
for (const target of targets) {
|
|
32132
32830
|
let content;
|
|
32133
32831
|
try {
|
|
32134
|
-
content = await
|
|
32832
|
+
content = await readFile42(target.path, "utf-8");
|
|
32135
32833
|
} catch {
|
|
32136
32834
|
continue;
|
|
32137
32835
|
}
|
|
@@ -32345,26 +33043,26 @@ init_config2();
|
|
|
32345
33043
|
init_fs();
|
|
32346
33044
|
import {
|
|
32347
33045
|
cp as cp3,
|
|
32348
|
-
readdir as
|
|
33046
|
+
readdir as readdir26,
|
|
32349
33047
|
symlink,
|
|
32350
33048
|
lstat,
|
|
32351
|
-
readFile as
|
|
33049
|
+
readFile as readFile43,
|
|
32352
33050
|
readlink,
|
|
32353
33051
|
rename as rename9,
|
|
32354
33052
|
rm as rm6,
|
|
32355
33053
|
unlink as unlink10,
|
|
32356
|
-
writeFile as
|
|
33054
|
+
writeFile as writeFile11
|
|
32357
33055
|
} from "fs/promises";
|
|
32358
33056
|
import { existsSync as existsSync4 } from "fs";
|
|
32359
|
-
import { homedir as
|
|
32360
|
-
import { basename as
|
|
33057
|
+
import { homedir as homedir10 } from "os";
|
|
33058
|
+
import { basename as basename9, dirname as dirname16, isAbsolute as isAbsolute8, relative as relative2, resolve as resolve64 } from "path";
|
|
32361
33059
|
|
|
32362
33060
|
// src/utils/package-root.ts
|
|
32363
33061
|
init_fs();
|
|
32364
|
-
import { dirname as
|
|
33062
|
+
import { dirname as dirname15, resolve as resolve63 } from "path";
|
|
32365
33063
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
32366
33064
|
async function findPackageRoot(expectedRelativePath) {
|
|
32367
|
-
let currentDir =
|
|
33065
|
+
let currentDir = dirname15(fileURLToPath4(import.meta.url));
|
|
32368
33066
|
while (true) {
|
|
32369
33067
|
const candidate = resolve63(currentDir, expectedRelativePath);
|
|
32370
33068
|
if (await fileExists(candidate)) {
|
|
@@ -32390,26 +33088,26 @@ function getPluginManifestRelativePath(pluginKind) {
|
|
|
32390
33088
|
return pluginKind === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json";
|
|
32391
33089
|
}
|
|
32392
33090
|
function getDefaultPluginTargetDir(pluginKind) {
|
|
32393
|
-
const home2 =
|
|
33091
|
+
const home2 = homedir10();
|
|
32394
33092
|
return pluginKind === "claude" ? resolve64(home2, ".claude", "plugins", "syntaur") : resolve64(home2, "plugins", "syntaur");
|
|
32395
33093
|
}
|
|
32396
33094
|
function getDefaultMarketplacePath() {
|
|
32397
|
-
return resolve64(
|
|
33095
|
+
return resolve64(homedir10(), ".agents", "plugins", "marketplace.json");
|
|
32398
33096
|
}
|
|
32399
33097
|
function getClaudeMarketplacesRoot() {
|
|
32400
|
-
return resolve64(
|
|
33098
|
+
return resolve64(homedir10(), ".claude", "plugins", "marketplaces");
|
|
32401
33099
|
}
|
|
32402
33100
|
function getClaudeKnownMarketplacesPath() {
|
|
32403
|
-
return resolve64(
|
|
33101
|
+
return resolve64(homedir10(), ".claude", "plugins", "known_marketplaces.json");
|
|
32404
33102
|
}
|
|
32405
33103
|
function getClaudeInstalledPluginsPath() {
|
|
32406
|
-
return resolve64(
|
|
33104
|
+
return resolve64(homedir10(), ".claude", "plugins", "installed_plugins.json");
|
|
32407
33105
|
}
|
|
32408
33106
|
function getInstallMarkerPath(targetDir) {
|
|
32409
33107
|
return resolve64(targetDir, INSTALL_MARKER_FILENAME);
|
|
32410
33108
|
}
|
|
32411
33109
|
async function readPackageManifest(packageRoot) {
|
|
32412
|
-
const raw2 = await
|
|
33110
|
+
const raw2 = await readFile43(resolve64(packageRoot, "package.json"), "utf-8");
|
|
32413
33111
|
return JSON.parse(raw2);
|
|
32414
33112
|
}
|
|
32415
33113
|
async function readJsonFileIfExists(pathValue) {
|
|
@@ -32417,7 +33115,7 @@ async function readJsonFileIfExists(pathValue) {
|
|
|
32417
33115
|
return null;
|
|
32418
33116
|
}
|
|
32419
33117
|
try {
|
|
32420
|
-
const raw2 = await
|
|
33118
|
+
const raw2 = await readFile43(pathValue, "utf-8");
|
|
32421
33119
|
return JSON.parse(raw2);
|
|
32422
33120
|
} catch {
|
|
32423
33121
|
return null;
|
|
@@ -32433,7 +33131,7 @@ async function readPluginManifestName(targetDir, pluginKind) {
|
|
|
32433
33131
|
if (!await fileExists(manifestPath)) {
|
|
32434
33132
|
return void 0;
|
|
32435
33133
|
}
|
|
32436
|
-
const raw2 = await
|
|
33134
|
+
const raw2 = await readFile43(manifestPath, "utf-8");
|
|
32437
33135
|
const parsed = JSON.parse(raw2);
|
|
32438
33136
|
return parsed.name;
|
|
32439
33137
|
}
|
|
@@ -32443,7 +33141,7 @@ async function readInstallMetadata(targetDir) {
|
|
|
32443
33141
|
return null;
|
|
32444
33142
|
}
|
|
32445
33143
|
try {
|
|
32446
|
-
const raw2 = await
|
|
33144
|
+
const raw2 = await readFile43(markerPath, "utf-8");
|
|
32447
33145
|
return JSON.parse(raw2);
|
|
32448
33146
|
} catch {
|
|
32449
33147
|
return null;
|
|
@@ -32456,7 +33154,7 @@ async function getInstallStatus(targetDir, pluginKind) {
|
|
|
32456
33154
|
const info = await lstat(targetDir);
|
|
32457
33155
|
if (info.isSymbolicLink()) {
|
|
32458
33156
|
const symlinkTarget = await readlink(targetDir);
|
|
32459
|
-
const resolvedTarget = resolve64(
|
|
33157
|
+
const resolvedTarget = resolve64(dirname16(targetDir), symlinkTarget);
|
|
32460
33158
|
const manifestName2 = await readPluginManifestName(resolvedTarget, pluginKind);
|
|
32461
33159
|
return {
|
|
32462
33160
|
exists: true,
|
|
@@ -32485,7 +33183,7 @@ async function writeInstallMetadata(targetDir, pluginKind, installMode, packageM
|
|
|
32485
33183
|
installMode,
|
|
32486
33184
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
32487
33185
|
};
|
|
32488
|
-
await
|
|
33186
|
+
await writeFile11(
|
|
32489
33187
|
getInstallMarkerPath(targetDir),
|
|
32490
33188
|
`${JSON.stringify(metadata, null, 2)}
|
|
32491
33189
|
`,
|
|
@@ -32493,15 +33191,15 @@ async function writeInstallMetadata(targetDir, pluginKind, installMode, packageM
|
|
|
32493
33191
|
);
|
|
32494
33192
|
}
|
|
32495
33193
|
async function installCopy(paths, pluginKind) {
|
|
32496
|
-
await ensureDir(
|
|
33194
|
+
await ensureDir(dirname16(paths.targetDir));
|
|
32497
33195
|
await cp3(paths.sourceDir, paths.targetDir, { recursive: true });
|
|
32498
33196
|
const packageManifest = await readPackageManifest(paths.packageRoot);
|
|
32499
33197
|
await writeInstallMetadata(paths.targetDir, pluginKind, "copy", packageManifest);
|
|
32500
33198
|
}
|
|
32501
33199
|
async function installLink(paths) {
|
|
32502
|
-
await ensureDir(
|
|
33200
|
+
await ensureDir(dirname16(paths.targetDir));
|
|
32503
33201
|
await rm6(paths.targetDir, { recursive: true, force: true });
|
|
32504
|
-
await ensureDir(
|
|
33202
|
+
await ensureDir(dirname16(paths.targetDir));
|
|
32505
33203
|
await symlink(resolve64(paths.sourceDir), paths.targetDir, "dir");
|
|
32506
33204
|
}
|
|
32507
33205
|
async function removeInstallMarker(targetDir) {
|
|
@@ -32513,7 +33211,7 @@ async function removeInstallMarker(targetDir) {
|
|
|
32513
33211
|
}
|
|
32514
33212
|
function normalizeAbsoluteInstallPath(pathValue, label) {
|
|
32515
33213
|
const expanded = expandHome(pathValue.trim());
|
|
32516
|
-
if (!
|
|
33214
|
+
if (!isAbsolute8(expanded)) {
|
|
32517
33215
|
throw new Error(`${label} must be an absolute path.`);
|
|
32518
33216
|
}
|
|
32519
33217
|
return resolve64(expanded);
|
|
@@ -32556,7 +33254,7 @@ async function readClaudeMarketplaceFile(manifestPath) {
|
|
|
32556
33254
|
};
|
|
32557
33255
|
}
|
|
32558
33256
|
async function writeClaudeMarketplaceFile(manifestPath, marketplace) {
|
|
32559
|
-
await ensureDir(
|
|
33257
|
+
await ensureDir(dirname16(manifestPath));
|
|
32560
33258
|
if (Array.isArray(marketplace.plugins)) {
|
|
32561
33259
|
marketplace.plugins = [...marketplace.plugins].sort((a, b) => {
|
|
32562
33260
|
const an = a?.name ?? "";
|
|
@@ -32566,10 +33264,10 @@ async function writeClaudeMarketplaceFile(manifestPath, marketplace) {
|
|
|
32566
33264
|
}
|
|
32567
33265
|
if (await fileExists(manifestPath)) {
|
|
32568
33266
|
try {
|
|
32569
|
-
const prev = await
|
|
33267
|
+
const prev = await readFile43(manifestPath, "utf-8");
|
|
32570
33268
|
JSON.parse(prev);
|
|
32571
33269
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
32572
|
-
await
|
|
33270
|
+
await writeFile11(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
|
|
32573
33271
|
} catch {
|
|
32574
33272
|
throw new Error(
|
|
32575
33273
|
`Refusing to overwrite ${manifestPath}: existing file is not valid JSON. Inspect and remove or repair it manually before re-running.`
|
|
@@ -32577,7 +33275,7 @@ async function writeClaudeMarketplaceFile(manifestPath, marketplace) {
|
|
|
32577
33275
|
}
|
|
32578
33276
|
}
|
|
32579
33277
|
const tmpPath = `${manifestPath}.tmp`;
|
|
32580
|
-
await
|
|
33278
|
+
await writeFile11(tmpPath, `${JSON.stringify(marketplace, null, 2)}
|
|
32581
33279
|
`, "utf-8");
|
|
32582
33280
|
await rename9(tmpPath, manifestPath);
|
|
32583
33281
|
}
|
|
@@ -32639,7 +33337,7 @@ async function listClaudeMarketplaceCandidates() {
|
|
|
32639
33337
|
const [knownMarketplaces, activeMarketplaceNames, entries] = await Promise.all([
|
|
32640
33338
|
readKnownClaudeMarketplaceRecords(),
|
|
32641
33339
|
readInstalledClaudeMarketplaceNames(),
|
|
32642
|
-
|
|
33340
|
+
readdir26(rootDir, { withFileTypes: true })
|
|
32643
33341
|
]);
|
|
32644
33342
|
const candidates = [];
|
|
32645
33343
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -32714,7 +33412,7 @@ async function registerKnownClaudeMarketplace(name, rootDir) {
|
|
|
32714
33412
|
const manifestPath = getClaudeKnownMarketplacesPath();
|
|
32715
33413
|
let existing = {};
|
|
32716
33414
|
if (await fileExists(manifestPath)) {
|
|
32717
|
-
const raw2 = await
|
|
33415
|
+
const raw2 = await readFile43(manifestPath, "utf-8");
|
|
32718
33416
|
try {
|
|
32719
33417
|
const parsed = JSON.parse(raw2);
|
|
32720
33418
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
@@ -32739,14 +33437,14 @@ async function registerKnownClaudeMarketplace(name, rootDir) {
|
|
|
32739
33437
|
};
|
|
32740
33438
|
existing[name].lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
32741
33439
|
existing[name].autoUpdate = true;
|
|
32742
|
-
await ensureDir(
|
|
33440
|
+
await ensureDir(dirname16(manifestPath));
|
|
32743
33441
|
if (await fileExists(manifestPath)) {
|
|
32744
|
-
const prev = await
|
|
33442
|
+
const prev = await readFile43(manifestPath, "utf-8");
|
|
32745
33443
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
32746
|
-
await
|
|
33444
|
+
await writeFile11(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
|
|
32747
33445
|
}
|
|
32748
33446
|
const tmpPath = `${manifestPath}.tmp`;
|
|
32749
|
-
await
|
|
33447
|
+
await writeFile11(tmpPath, `${JSON.stringify(existing, null, 2)}
|
|
32750
33448
|
`, "utf-8");
|
|
32751
33449
|
await rename9(tmpPath, manifestPath);
|
|
32752
33450
|
return { added: !had, updated: had };
|
|
@@ -32755,11 +33453,11 @@ async function ensureKnownClaudeMarketplaceForRoot(options) {
|
|
|
32755
33453
|
return registerKnownClaudeMarketplace(options.name, options.rootDir);
|
|
32756
33454
|
}
|
|
32757
33455
|
async function setSyntaurPluginEnabled(options) {
|
|
32758
|
-
const settingsPath = resolve64(
|
|
33456
|
+
const settingsPath = resolve64(homedir10(), ".claude", "settings.json");
|
|
32759
33457
|
const key = `syntaur@${options.marketplaceName}`;
|
|
32760
33458
|
let parsed = {};
|
|
32761
33459
|
if (await fileExists(settingsPath)) {
|
|
32762
|
-
const raw2 = await
|
|
33460
|
+
const raw2 = await readFile43(settingsPath, "utf-8");
|
|
32763
33461
|
try {
|
|
32764
33462
|
parsed = JSON.parse(raw2);
|
|
32765
33463
|
} catch {
|
|
@@ -32775,14 +33473,14 @@ async function setSyntaurPluginEnabled(options) {
|
|
|
32775
33473
|
}
|
|
32776
33474
|
enabledPlugins[key] = options.enabled;
|
|
32777
33475
|
parsed.enabledPlugins = enabledPlugins;
|
|
32778
|
-
await ensureDir(
|
|
33476
|
+
await ensureDir(dirname16(settingsPath));
|
|
32779
33477
|
if (await fileExists(settingsPath)) {
|
|
32780
33478
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
32781
|
-
const prev = await
|
|
32782
|
-
await
|
|
33479
|
+
const prev = await readFile43(settingsPath, "utf-8");
|
|
33480
|
+
await writeFile11(`${settingsPath}.bak-${stamp}`, prev, "utf-8");
|
|
32783
33481
|
}
|
|
32784
33482
|
const tmpPath = `${settingsPath}.tmp`;
|
|
32785
|
-
await
|
|
33483
|
+
await writeFile11(tmpPath, `${JSON.stringify(parsed, null, 2)}
|
|
32786
33484
|
`, "utf-8");
|
|
32787
33485
|
await rename9(tmpPath, settingsPath);
|
|
32788
33486
|
return { key, previous, current: options.enabled, changed: true };
|
|
@@ -32818,17 +33516,17 @@ async function ensureClaudeUserMarketplace() {
|
|
|
32818
33516
|
}
|
|
32819
33517
|
async function detectClaudeMarketplaceForTarget(targetDir) {
|
|
32820
33518
|
const normalizedTargetDir = normalizeAbsoluteInstallPath(targetDir, "Claude plugin target");
|
|
32821
|
-
const pluginsDir =
|
|
32822
|
-
if (
|
|
33519
|
+
const pluginsDir = dirname16(normalizedTargetDir);
|
|
33520
|
+
if (basename9(pluginsDir) !== "plugins") {
|
|
32823
33521
|
return null;
|
|
32824
33522
|
}
|
|
32825
|
-
const rootDir =
|
|
33523
|
+
const rootDir = dirname16(pluginsDir);
|
|
32826
33524
|
const manifestPath = resolve64(rootDir, ".claude-plugin", "marketplace.json");
|
|
32827
33525
|
if (!await fileExists(manifestPath)) {
|
|
32828
33526
|
return null;
|
|
32829
33527
|
}
|
|
32830
33528
|
const marketplace = await readClaudeMarketplaceFile(manifestPath);
|
|
32831
|
-
const name = typeof marketplace.name === "string" && marketplace.name.trim() !== "" ? marketplace.name :
|
|
33529
|
+
const name = typeof marketplace.name === "string" && marketplace.name.trim() !== "" ? marketplace.name : basename9(rootDir);
|
|
32832
33530
|
return {
|
|
32833
33531
|
name,
|
|
32834
33532
|
rootDir,
|
|
@@ -32988,7 +33686,7 @@ async function installManagedPlugin(options) {
|
|
|
32988
33686
|
};
|
|
32989
33687
|
}
|
|
32990
33688
|
function buildMarketplaceSourcePath(pluginTargetDir, marketplacePath) {
|
|
32991
|
-
const relPath = relative2(
|
|
33689
|
+
const relPath = relative2(dirname16(marketplacePath), pluginTargetDir).replaceAll("\\", "/");
|
|
32992
33690
|
if (relPath === "") {
|
|
32993
33691
|
return ".";
|
|
32994
33692
|
}
|
|
@@ -33016,7 +33714,7 @@ async function readMarketplaceFile(marketplacePath) {
|
|
|
33016
33714
|
plugins: []
|
|
33017
33715
|
};
|
|
33018
33716
|
}
|
|
33019
|
-
const raw2 = await
|
|
33717
|
+
const raw2 = await readFile43(marketplacePath, "utf-8");
|
|
33020
33718
|
const parsed = JSON.parse(raw2);
|
|
33021
33719
|
return {
|
|
33022
33720
|
name: parsed.name ?? "local",
|
|
@@ -33025,8 +33723,8 @@ async function readMarketplaceFile(marketplacePath) {
|
|
|
33025
33723
|
};
|
|
33026
33724
|
}
|
|
33027
33725
|
async function writeMarketplaceFile(marketplacePath, marketplace) {
|
|
33028
|
-
await ensureDir(
|
|
33029
|
-
await
|
|
33726
|
+
await ensureDir(dirname16(marketplacePath));
|
|
33727
|
+
await writeFile11(marketplacePath, `${JSON.stringify(marketplace, null, 2)}
|
|
33030
33728
|
`, "utf-8");
|
|
33031
33729
|
}
|
|
33032
33730
|
async function hasAnySyntaurMarketplaceEntry(marketplacePath) {
|
|
@@ -33258,24 +33956,24 @@ async function textPrompt(question, defaultValue) {
|
|
|
33258
33956
|
|
|
33259
33957
|
// src/utils/install-skills.ts
|
|
33260
33958
|
init_fs();
|
|
33261
|
-
import { readFile as
|
|
33262
|
-
import { resolve as resolve66, relative as relative3, join as
|
|
33263
|
-
import { homedir as
|
|
33959
|
+
import { readFile as readFile45, readdir as readdir27, mkdir as mkdir8, copyFile, rm as rm7, lstat as lstat2 } from "fs/promises";
|
|
33960
|
+
import { resolve as resolve66, relative as relative3, join as join14 } from "path";
|
|
33961
|
+
import { homedir as homedir12 } from "os";
|
|
33264
33962
|
|
|
33265
33963
|
// src/utils/plugin-state.ts
|
|
33266
33964
|
init_fs();
|
|
33267
|
-
import { readFile as
|
|
33965
|
+
import { readFile as readFile44 } from "fs/promises";
|
|
33268
33966
|
import { resolve as resolve65 } from "path";
|
|
33269
|
-
import { homedir as
|
|
33967
|
+
import { homedir as homedir11 } from "os";
|
|
33270
33968
|
function settingsPathFor(agent) {
|
|
33271
|
-
if (agent === "claude") return resolve65(
|
|
33969
|
+
if (agent === "claude") return resolve65(homedir11(), ".claude", "settings.json");
|
|
33272
33970
|
return null;
|
|
33273
33971
|
}
|
|
33274
33972
|
async function readJsonOrNull(path) {
|
|
33275
33973
|
if (!path) return null;
|
|
33276
33974
|
if (!await fileExists(path)) return null;
|
|
33277
33975
|
try {
|
|
33278
|
-
const raw2 = await
|
|
33976
|
+
const raw2 = await readFile44(path, "utf-8");
|
|
33279
33977
|
return JSON.parse(raw2);
|
|
33280
33978
|
} catch {
|
|
33281
33979
|
return null;
|
|
@@ -33328,15 +34026,15 @@ async function getSkillsDir() {
|
|
|
33328
34026
|
return resolve66(packageRoot, "skills");
|
|
33329
34027
|
}
|
|
33330
34028
|
function defaultSkillTargetDir(target) {
|
|
33331
|
-
if (target === "claude") return resolve66(
|
|
33332
|
-
return resolve66(
|
|
34029
|
+
if (target === "claude") return resolve66(homedir12(), ".claude", "skills");
|
|
34030
|
+
return resolve66(homedir12(), ".codex", "skills");
|
|
33333
34031
|
}
|
|
33334
34032
|
async function walkFiles(root) {
|
|
33335
34033
|
const out = [];
|
|
33336
34034
|
async function walk(dir) {
|
|
33337
|
-
const entries = await
|
|
34035
|
+
const entries = await readdir27(dir, { withFileTypes: true });
|
|
33338
34036
|
for (const entry of entries) {
|
|
33339
|
-
const full =
|
|
34037
|
+
const full = join14(dir, entry.name);
|
|
33340
34038
|
if (entry.isDirectory()) {
|
|
33341
34039
|
await walk(full);
|
|
33342
34040
|
} else if (entry.isFile()) {
|
|
@@ -33349,7 +34047,7 @@ async function walkFiles(root) {
|
|
|
33349
34047
|
}
|
|
33350
34048
|
async function filesEqual(a, b) {
|
|
33351
34049
|
try {
|
|
33352
|
-
const [ba, bb] = await Promise.all([
|
|
34050
|
+
const [ba, bb] = await Promise.all([readFile45(a), readFile45(b)]);
|
|
33353
34051
|
if (ba.length !== bb.length) return false;
|
|
33354
34052
|
return ba.equals(bb);
|
|
33355
34053
|
} catch {
|
|
@@ -33357,11 +34055,11 @@ async function filesEqual(a, b) {
|
|
|
33357
34055
|
}
|
|
33358
34056
|
}
|
|
33359
34057
|
async function copyDir(srcDir, destDir) {
|
|
33360
|
-
await
|
|
33361
|
-
const entries = await
|
|
34058
|
+
await mkdir8(destDir, { recursive: true });
|
|
34059
|
+
const entries = await readdir27(srcDir, { withFileTypes: true });
|
|
33362
34060
|
for (const entry of entries) {
|
|
33363
|
-
const src =
|
|
33364
|
-
const dest =
|
|
34061
|
+
const src = join14(srcDir, entry.name);
|
|
34062
|
+
const dest = join14(destDir, entry.name);
|
|
33365
34063
|
if (entry.isDirectory()) {
|
|
33366
34064
|
await copyDir(src, dest);
|
|
33367
34065
|
} else if (entry.isFile()) {
|
|
@@ -33374,7 +34072,7 @@ async function skillMatches(srcDir, destDir) {
|
|
|
33374
34072
|
const srcFiles = await walkFiles(srcDir);
|
|
33375
34073
|
for (const srcFile of srcFiles) {
|
|
33376
34074
|
const rel = relative3(srcDir, srcFile);
|
|
33377
|
-
const destFile =
|
|
34075
|
+
const destFile = join14(destDir, rel);
|
|
33378
34076
|
if (!await filesEqual(srcFile, destFile)) return false;
|
|
33379
34077
|
}
|
|
33380
34078
|
const destFiles = await walkFiles(destDir);
|
|
@@ -33383,8 +34081,8 @@ async function skillMatches(srcDir, destDir) {
|
|
|
33383
34081
|
}
|
|
33384
34082
|
async function isSymlink(path) {
|
|
33385
34083
|
try {
|
|
33386
|
-
const
|
|
33387
|
-
return
|
|
34084
|
+
const stat18 = await lstat2(path);
|
|
34085
|
+
return stat18.isSymbolicLink();
|
|
33388
34086
|
} catch {
|
|
33389
34087
|
return false;
|
|
33390
34088
|
}
|
|
@@ -33412,12 +34110,12 @@ async function installSkillDir(srcDir, destDir, skillName, force) {
|
|
|
33412
34110
|
return { skill: skillName, status: "differs-preserved", targetPath: destDir };
|
|
33413
34111
|
}
|
|
33414
34112
|
async function discoverSkillNames(sourceDir) {
|
|
33415
|
-
const entries = await
|
|
34113
|
+
const entries = await readdir27(sourceDir, { withFileTypes: true });
|
|
33416
34114
|
const names = [];
|
|
33417
34115
|
for (const entry of entries) {
|
|
33418
34116
|
if (!entry.isDirectory()) continue;
|
|
33419
34117
|
if (entry.name.startsWith(".")) continue;
|
|
33420
|
-
if (await fileExists(
|
|
34118
|
+
if (await fileExists(join14(sourceDir, entry.name, "SKILL.md"))) {
|
|
33421
34119
|
names.push(entry.name);
|
|
33422
34120
|
}
|
|
33423
34121
|
}
|
|
@@ -33442,10 +34140,10 @@ async function installSkillsWithReport(options) {
|
|
|
33442
34140
|
}
|
|
33443
34141
|
const skillNames = await discoverSkillNames(source);
|
|
33444
34142
|
const results = [];
|
|
33445
|
-
await
|
|
34143
|
+
await mkdir8(targetRoot, { recursive: true });
|
|
33446
34144
|
for (const skill of skillNames) {
|
|
33447
|
-
const srcDir =
|
|
33448
|
-
const destDir =
|
|
34145
|
+
const srcDir = join14(source, skill);
|
|
34146
|
+
const destDir = join14(targetRoot, skill);
|
|
33449
34147
|
results.push(await installSkillDir(srcDir, destDir, skill, force));
|
|
33450
34148
|
}
|
|
33451
34149
|
return { results };
|
|
@@ -33459,11 +34157,11 @@ async function installSkillsToDir(options) {
|
|
|
33459
34157
|
}
|
|
33460
34158
|
const force = options.force ?? false;
|
|
33461
34159
|
const skillNames = await discoverSkillNames(source);
|
|
33462
|
-
await
|
|
34160
|
+
await mkdir8(options.targetDir, { recursive: true });
|
|
33463
34161
|
const results = [];
|
|
33464
34162
|
for (const skill of skillNames) {
|
|
33465
|
-
const srcDir =
|
|
33466
|
-
const destDir =
|
|
34163
|
+
const srcDir = join14(source, skill);
|
|
34164
|
+
const destDir = join14(options.targetDir, skill);
|
|
33467
34165
|
results.push(await installSkillDir(srcDir, destDir, skill, force));
|
|
33468
34166
|
}
|
|
33469
34167
|
return results;
|
|
@@ -33484,12 +34182,12 @@ async function uninstallSkills(options) {
|
|
|
33484
34182
|
}
|
|
33485
34183
|
const removed = [];
|
|
33486
34184
|
for (const skill of known) {
|
|
33487
|
-
const destDir =
|
|
34185
|
+
const destDir = join14(targetRoot, skill);
|
|
33488
34186
|
if (!await fileExists(destDir)) continue;
|
|
33489
34187
|
if (await isSymlink(destDir)) continue;
|
|
33490
|
-
const skillMd =
|
|
34188
|
+
const skillMd = join14(destDir, "SKILL.md");
|
|
33491
34189
|
if (!await fileExists(skillMd)) continue;
|
|
33492
|
-
const content = await
|
|
34190
|
+
const content = await readFile45(skillMd, "utf-8").catch(() => "");
|
|
33493
34191
|
const match = content.match(/^name:\s*(\S+)\s*$/m);
|
|
33494
34192
|
if (!match || match[1] !== skill) continue;
|
|
33495
34193
|
await rm7(destDir, { recursive: true, force: true });
|
|
@@ -33684,20 +34382,20 @@ import { realpathSync as realpathSync3 } from "fs";
|
|
|
33684
34382
|
init_paths();
|
|
33685
34383
|
init_fs();
|
|
33686
34384
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
33687
|
-
import { readFile as
|
|
33688
|
-
import { dirname as
|
|
34385
|
+
import { readFile as readFile47 } from "fs/promises";
|
|
34386
|
+
import { dirname as dirname18, join as join16, resolve as resolve67 } from "path";
|
|
33689
34387
|
import { spawn as spawn6 } from "child_process";
|
|
33690
34388
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
33691
34389
|
|
|
33692
34390
|
// src/utils/version.ts
|
|
33693
34391
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
33694
|
-
import { readFile as
|
|
33695
|
-
import { dirname as
|
|
34392
|
+
import { readFile as readFile46 } from "fs/promises";
|
|
34393
|
+
import { dirname as dirname17, join as join15 } from "path";
|
|
33696
34394
|
async function readPackageVersion(scriptUrl) {
|
|
33697
34395
|
try {
|
|
33698
34396
|
const scriptPath = fileURLToPath5(scriptUrl);
|
|
33699
|
-
const pkgRoot =
|
|
33700
|
-
const raw2 = await
|
|
34397
|
+
const pkgRoot = dirname17(dirname17(scriptPath));
|
|
34398
|
+
const raw2 = await readFile46(join15(pkgRoot, "package.json"), "utf-8");
|
|
33701
34399
|
const parsed = JSON.parse(raw2);
|
|
33702
34400
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
33703
34401
|
} catch {
|
|
@@ -33727,7 +34425,7 @@ function isRunningViaNpx(scriptUrl) {
|
|
|
33727
34425
|
async function readState() {
|
|
33728
34426
|
if (!await fileExists(STATE_FILE)) return null;
|
|
33729
34427
|
try {
|
|
33730
|
-
const raw2 = await
|
|
34428
|
+
const raw2 = await readFile47(STATE_FILE, "utf-8");
|
|
33731
34429
|
return JSON.parse(raw2);
|
|
33732
34430
|
} catch {
|
|
33733
34431
|
return null;
|
|
@@ -33738,10 +34436,10 @@ async function writeState(state) {
|
|
|
33738
34436
|
`);
|
|
33739
34437
|
}
|
|
33740
34438
|
async function resolveNpmBin() {
|
|
33741
|
-
const nodeDir =
|
|
34439
|
+
const nodeDir = dirname18(process.execPath);
|
|
33742
34440
|
const isWin = process.platform === "win32";
|
|
33743
34441
|
const npmName = isWin ? "npm.cmd" : "npm";
|
|
33744
|
-
const nearNode =
|
|
34442
|
+
const nearNode = join16(nodeDir, npmName);
|
|
33745
34443
|
if (await fileExists(nearNode)) {
|
|
33746
34444
|
return { cmd: nearNode, shell: false };
|
|
33747
34445
|
}
|
|
@@ -33784,9 +34482,9 @@ async function readGlobalVersion() {
|
|
|
33784
34482
|
});
|
|
33785
34483
|
if (!rootPath) return null;
|
|
33786
34484
|
try {
|
|
33787
|
-
const manifestPath =
|
|
34485
|
+
const manifestPath = join16(rootPath, "syntaur", "package.json");
|
|
33788
34486
|
if (!await fileExists(manifestPath)) return null;
|
|
33789
|
-
const raw2 = await
|
|
34487
|
+
const raw2 = await readFile47(manifestPath, "utf-8");
|
|
33790
34488
|
const parsed = JSON.parse(raw2);
|
|
33791
34489
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
33792
34490
|
} catch {
|
|
@@ -33905,8 +34603,8 @@ async function maybePromptInstall(scriptUrl) {
|
|
|
33905
34603
|
|
|
33906
34604
|
// src/commands/update.ts
|
|
33907
34605
|
import { existsSync as existsSync5 } from "fs";
|
|
33908
|
-
import { join as
|
|
33909
|
-
import { homedir as
|
|
34606
|
+
import { join as join17 } from "path";
|
|
34607
|
+
import { homedir as homedir13 } from "os";
|
|
33910
34608
|
var PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
|
|
33911
34609
|
var LOCAL_MSG = "Running from a dev/linked checkout \u2014 `syntaur update` won't touch a linked install. Pull + rebuild in your repo, then `syntaur install-plugin --force` to refresh skills.";
|
|
33912
34610
|
var NPX_MSG = "Running via npx \u2014 there's no durable global install to update. Install durably first: `npm i -g syntaur`.";
|
|
@@ -33947,12 +34645,12 @@ var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise) => {
|
|
|
33947
34645
|
child.on("close", (code) => resolvePromise({ code: code ?? -1, stdout, stderr }));
|
|
33948
34646
|
});
|
|
33949
34647
|
function bunGlobalNodeModulesDir(env) {
|
|
33950
|
-
const globalDir = env.BUN_INSTALL_GLOBAL_DIR ??
|
|
33951
|
-
return
|
|
34648
|
+
const globalDir = env.BUN_INSTALL_GLOBAL_DIR ?? join17(env.BUN_INSTALL ?? join17(homedir13(), ".bun"), "install", "global");
|
|
34649
|
+
return join17(globalDir, "node_modules");
|
|
33952
34650
|
}
|
|
33953
34651
|
async function defaultResolveFreshBin(pm, runner, env) {
|
|
33954
34652
|
const binFromPkgRoot = (pkgRoot) => {
|
|
33955
|
-
const entry =
|
|
34653
|
+
const entry = join17(pkgRoot, "syntaur", "bin", "syntaur.js");
|
|
33956
34654
|
return existsSync5(entry) ? { cmd: process.execPath, baseArgs: [entry] } : null;
|
|
33957
34655
|
};
|
|
33958
34656
|
try {
|
|
@@ -33964,7 +34662,7 @@ async function defaultResolveFreshBin(pm, runner, env) {
|
|
|
33964
34662
|
if (pm === "yarn") {
|
|
33965
34663
|
const res = await runner("yarn", ["global", "dir"], { env, captureStdout: true });
|
|
33966
34664
|
const dir = res.stdout.trim();
|
|
33967
|
-
return dir ? binFromPkgRoot(
|
|
34665
|
+
return dir ? binFromPkgRoot(join17(dir, "node_modules")) : null;
|
|
33968
34666
|
}
|
|
33969
34667
|
return binFromPkgRoot(bunGlobalNodeModulesDir(env));
|
|
33970
34668
|
} catch {
|
|
@@ -34144,16 +34842,16 @@ async function refreshPluginSkills(options, pm, runner, getManagedDir, resolveFr
|
|
|
34144
34842
|
// src/commands/install-statusline.ts
|
|
34145
34843
|
init_paths();
|
|
34146
34844
|
init_fs();
|
|
34147
|
-
import { readFile as
|
|
34148
|
-
import { resolve as resolve69, dirname as
|
|
34149
|
-
import { homedir as
|
|
34845
|
+
import { readFile as readFile49, writeFile as writeFile13, copyFile as copyFile2, rm as rm8, stat as stat9, symlink as symlink2, unlink as unlink11, lstat as lstat3 } from "fs/promises";
|
|
34846
|
+
import { resolve as resolve69, dirname as dirname20 } from "path";
|
|
34847
|
+
import { homedir as homedir14 } from "os";
|
|
34150
34848
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
34151
34849
|
|
|
34152
34850
|
// src/commands/configure-statusline.ts
|
|
34153
34851
|
init_paths();
|
|
34154
34852
|
init_fs();
|
|
34155
|
-
import { readFile as
|
|
34156
|
-
import { resolve as resolve68, dirname as
|
|
34853
|
+
import { readFile as readFile48, writeFile as writeFile12 } from "fs/promises";
|
|
34854
|
+
import { resolve as resolve68, dirname as dirname19 } from "path";
|
|
34157
34855
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
34158
34856
|
import { checkbox, input as input2, confirm } from "@inquirer/prompts";
|
|
34159
34857
|
var AVAILABLE_SEGMENTS = [
|
|
@@ -34179,7 +34877,7 @@ function getConfigPath(installRoot) {
|
|
|
34179
34877
|
async function readConfig2(path) {
|
|
34180
34878
|
if (!await fileExists(path)) return null;
|
|
34181
34879
|
try {
|
|
34182
|
-
const raw2 = await
|
|
34880
|
+
const raw2 = await readFile48(path, "utf-8");
|
|
34183
34881
|
const parsed = JSON.parse(raw2);
|
|
34184
34882
|
if (!parsed || typeof parsed !== "object") return null;
|
|
34185
34883
|
const segments = Array.isArray(parsed.segments) ? parsed.segments.filter(isSegmentName) : [];
|
|
@@ -34274,7 +34972,7 @@ function renderPreview(config, statuslineScript, cwd) {
|
|
|
34274
34972
|
env: {
|
|
34275
34973
|
...process.env,
|
|
34276
34974
|
// Force the child to pick up the freshly-written config from install root.
|
|
34277
|
-
HOME:
|
|
34975
|
+
HOME: dirname19(dirname19(statuslineScript))
|
|
34278
34976
|
}
|
|
34279
34977
|
});
|
|
34280
34978
|
if (res.status !== 0) return null;
|
|
@@ -34325,8 +35023,8 @@ async function configureStatuslineCommand(options = {}) {
|
|
|
34325
35023
|
console.log("(preview mode \u2014 config NOT written)");
|
|
34326
35024
|
return;
|
|
34327
35025
|
}
|
|
34328
|
-
await ensureDir(
|
|
34329
|
-
await
|
|
35026
|
+
await ensureDir(dirname19(configPath2));
|
|
35027
|
+
await writeFile12(configPath2, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
34330
35028
|
console.log("Wrote statusline config:");
|
|
34331
35029
|
console.log(` path: ${configPath2}`);
|
|
34332
35030
|
console.log(` segments: ${config.segments.join(", ")}`);
|
|
@@ -34352,22 +35050,22 @@ async function configureStatuslineCommand(options = {}) {
|
|
|
34352
35050
|
async function writeDefaultConfigIfMissing(installRoot) {
|
|
34353
35051
|
const path = getConfigPath(installRoot);
|
|
34354
35052
|
if (await fileExists(path)) return;
|
|
34355
|
-
await ensureDir(
|
|
35053
|
+
await ensureDir(dirname19(path));
|
|
34356
35054
|
const defaultConfig = {
|
|
34357
35055
|
segments: ["git", "assignment", "session"],
|
|
34358
35056
|
separator: " \xB7 "
|
|
34359
35057
|
};
|
|
34360
|
-
await
|
|
35058
|
+
await writeFile12(path, JSON.stringify(defaultConfig, null, 2) + "\n", "utf-8");
|
|
34361
35059
|
}
|
|
34362
35060
|
|
|
34363
35061
|
// src/commands/install-statusline.ts
|
|
34364
35062
|
function getPackageStatuslineSource() {
|
|
34365
|
-
const here =
|
|
35063
|
+
const here = dirname20(fileURLToPath8(import.meta.url));
|
|
34366
35064
|
return resolve69(here, "..", "statusline", "statusline.sh");
|
|
34367
35065
|
}
|
|
34368
35066
|
async function readSettingsJson(settingsPath) {
|
|
34369
35067
|
if (!await fileExists(settingsPath)) return {};
|
|
34370
|
-
const raw2 = await
|
|
35068
|
+
const raw2 = await readFile49(settingsPath, "utf-8");
|
|
34371
35069
|
if (raw2.trim() === "") return {};
|
|
34372
35070
|
try {
|
|
34373
35071
|
const parsed = JSON.parse(raw2);
|
|
@@ -34379,8 +35077,8 @@ async function readSettingsJson(settingsPath) {
|
|
|
34379
35077
|
}
|
|
34380
35078
|
}
|
|
34381
35079
|
async function writeSettingsJson(settingsPath, data) {
|
|
34382
|
-
await ensureDir(
|
|
34383
|
-
await
|
|
35080
|
+
await ensureDir(dirname20(settingsPath));
|
|
35081
|
+
await writeFile13(settingsPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
34384
35082
|
}
|
|
34385
35083
|
async function resolveMode(mode, existingCommand, ourCommand) {
|
|
34386
35084
|
if (mode !== "ask") return mode;
|
|
@@ -34414,8 +35112,8 @@ function extractExistingCommand(settings) {
|
|
|
34414
35112
|
};
|
|
34415
35113
|
}
|
|
34416
35114
|
async function backupSettings(settingsSnapshot, backupPath) {
|
|
34417
|
-
await ensureDir(
|
|
34418
|
-
await
|
|
35115
|
+
await ensureDir(dirname20(backupPath));
|
|
35116
|
+
await writeFile13(
|
|
34419
35117
|
backupPath,
|
|
34420
35118
|
JSON.stringify(
|
|
34421
35119
|
{
|
|
@@ -34431,7 +35129,7 @@ async function backupSettings(settingsSnapshot, backupPath) {
|
|
|
34431
35129
|
);
|
|
34432
35130
|
}
|
|
34433
35131
|
async function installScript(sourceScript, destScript, link) {
|
|
34434
|
-
await ensureDir(
|
|
35132
|
+
await ensureDir(dirname20(destScript));
|
|
34435
35133
|
try {
|
|
34436
35134
|
const s = await lstat3(destScript);
|
|
34437
35135
|
if (s.isSymbolicLink() || s.isFile()) {
|
|
@@ -34447,7 +35145,7 @@ async function installScript(sourceScript, destScript, link) {
|
|
|
34447
35145
|
}
|
|
34448
35146
|
async function installStatuslineCommand(options = {}) {
|
|
34449
35147
|
const mode = options.mode ?? "ask";
|
|
34450
|
-
const settingsPath = options.settingsPath ?? resolve69(
|
|
35148
|
+
const settingsPath = options.settingsPath ?? resolve69(homedir14(), ".claude", "settings.json");
|
|
34451
35149
|
const installRoot = options.installRoot ?? syntaurRoot();
|
|
34452
35150
|
const sourceScript = options.sourceScript ?? getPackageStatuslineSource();
|
|
34453
35151
|
const destScript = resolve69(installRoot, "statusline.sh");
|
|
@@ -34494,13 +35192,13 @@ async function installStatuslineCommand(options = {}) {
|
|
|
34494
35192
|
# Executes the previously configured statusLine command.
|
|
34495
35193
|
exec ${existingCommand}
|
|
34496
35194
|
`;
|
|
34497
|
-
await
|
|
35195
|
+
await writeFile13(wrapperPath, wrapperBody, "utf-8");
|
|
34498
35196
|
await chmodExec(wrapperPath);
|
|
34499
35197
|
wrapTarget = wrapperPath;
|
|
34500
35198
|
}
|
|
34501
35199
|
}
|
|
34502
|
-
await ensureDir(
|
|
34503
|
-
await
|
|
35200
|
+
await ensureDir(dirname20(confPath));
|
|
35201
|
+
await writeFile13(
|
|
34504
35202
|
confPath,
|
|
34505
35203
|
wrapTarget ? `# Wrap target \u2014 the command below is invoked with the same stdin; its
|
|
34506
35204
|
# stdout becomes the leading segment of the statusline. Remove this
|
|
@@ -34537,13 +35235,13 @@ function parseWrapCommand(command) {
|
|
|
34537
35235
|
async function chmodExec(path) {
|
|
34538
35236
|
const fs = await import("fs/promises");
|
|
34539
35237
|
try {
|
|
34540
|
-
const s = await
|
|
35238
|
+
const s = await stat9(path);
|
|
34541
35239
|
await fs.chmod(path, s.mode | 73);
|
|
34542
35240
|
} catch {
|
|
34543
35241
|
}
|
|
34544
35242
|
}
|
|
34545
35243
|
async function uninstallStatuslineCommand(options = {}) {
|
|
34546
|
-
const settingsPath = options.settingsPath ?? resolve69(
|
|
35244
|
+
const settingsPath = options.settingsPath ?? resolve69(homedir14(), ".claude", "settings.json");
|
|
34547
35245
|
const installRoot = options.installRoot ?? syntaurRoot();
|
|
34548
35246
|
const destScript = resolve69(installRoot, "statusline.sh");
|
|
34549
35247
|
const confPath = resolve69(installRoot, "statusline.conf");
|
|
@@ -34555,7 +35253,7 @@ async function uninstallStatuslineCommand(options = {}) {
|
|
|
34555
35253
|
let restored = null;
|
|
34556
35254
|
if (await fileExists(backupPath)) {
|
|
34557
35255
|
try {
|
|
34558
|
-
const raw2 = await
|
|
35256
|
+
const raw2 = await readFile49(backupPath, "utf-8");
|
|
34559
35257
|
const parsed = JSON.parse(raw2);
|
|
34560
35258
|
const prev = parsed?.previousStatusLine;
|
|
34561
35259
|
if (prev && typeof prev === "object" && typeof prev.command === "string") {
|
|
@@ -34736,8 +35434,8 @@ init_config2();
|
|
|
34736
35434
|
// src/commands/cross-agent-install.ts
|
|
34737
35435
|
init_fs();
|
|
34738
35436
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
34739
|
-
import { dirname as
|
|
34740
|
-
import { cp as cp4, mkdir as
|
|
35437
|
+
import { dirname as dirname21, join as join18, resolve as resolve71 } from "path";
|
|
35438
|
+
import { cp as cp4, mkdir as mkdir10 } from "fs/promises";
|
|
34741
35439
|
|
|
34742
35440
|
// src/commands/setup-adapter.ts
|
|
34743
35441
|
init_paths();
|
|
@@ -34847,7 +35545,7 @@ async function installTier3Plugin(t, opts = {}) {
|
|
|
34847
35545
|
console.log(`${prefix}Tier 3 (${t.id}): ${plugin.source} -> ${installDir}`);
|
|
34848
35546
|
return "dry-run";
|
|
34849
35547
|
}
|
|
34850
|
-
if (await fileExists(
|
|
35548
|
+
if (await fileExists(join18(installDir, plugin.entry)) && !opts.force) {
|
|
34851
35549
|
console.log(
|
|
34852
35550
|
`Tier 3 (${t.id}): already installed at ${installDir} (use --force to overwrite).`
|
|
34853
35551
|
);
|
|
@@ -34855,7 +35553,7 @@ async function installTier3Plugin(t, opts = {}) {
|
|
|
34855
35553
|
}
|
|
34856
35554
|
try {
|
|
34857
35555
|
const sourceDir = resolve71(await findPackageRoot(plugin.source), plugin.source);
|
|
34858
|
-
await
|
|
35556
|
+
await mkdir10(dirname21(installDir), { recursive: true });
|
|
34859
35557
|
await cp4(sourceDir, installDir, { recursive: true, force: true });
|
|
34860
35558
|
console.log(`Tier 3 (${t.id}): installed ${plugin.kind} -> ${installDir}`);
|
|
34861
35559
|
return "installed";
|
|
@@ -35225,7 +35923,7 @@ init_cwd();
|
|
|
35225
35923
|
init_session_db();
|
|
35226
35924
|
init_agent_sessions();
|
|
35227
35925
|
import { resolve as resolve73 } from "path";
|
|
35228
|
-
import { readFile as
|
|
35926
|
+
import { readFile as readFile50 } from "fs/promises";
|
|
35229
35927
|
async function trackSessionCommand(options, deps = {}) {
|
|
35230
35928
|
if (!options.agent) {
|
|
35231
35929
|
throw new Error("--agent <name> is required.");
|
|
@@ -35242,7 +35940,7 @@ async function trackSessionCommand(options, deps = {}) {
|
|
|
35242
35940
|
const cwd = process.cwd();
|
|
35243
35941
|
let legacyHint;
|
|
35244
35942
|
try {
|
|
35245
|
-
const raw2 = await
|
|
35943
|
+
const raw2 = await readFile50(resolve73(cwd, ".syntaur", "context.json"), "utf-8");
|
|
35246
35944
|
const parsed = JSON.parse(raw2);
|
|
35247
35945
|
if (typeof parsed.sessionId === "string") legacyHint = parsed.sessionId;
|
|
35248
35946
|
} catch {
|
|
@@ -35406,8 +36104,8 @@ function formatInstallUrlHandlerError(err2) {
|
|
|
35406
36104
|
init_config2();
|
|
35407
36105
|
init_paths();
|
|
35408
36106
|
init_fs();
|
|
35409
|
-
import { resolve as resolve75, isAbsolute as
|
|
35410
|
-
import { readFile as
|
|
36107
|
+
import { resolve as resolve75, isAbsolute as isAbsolute9 } from "path";
|
|
36108
|
+
import { readFile as readFile51 } from "fs/promises";
|
|
35411
36109
|
import { select, confirm as confirm2, input as input3 } from "@inquirer/prompts";
|
|
35412
36110
|
async function browseCommand(options) {
|
|
35413
36111
|
const config = await readConfig();
|
|
@@ -35486,7 +36184,7 @@ async function ensureWorktree(opts) {
|
|
|
35486
36184
|
if (!await fileExists(assignmentPath)) {
|
|
35487
36185
|
return void 0;
|
|
35488
36186
|
}
|
|
35489
|
-
const content = await
|
|
36187
|
+
const content = await readFile51(assignmentPath, "utf-8");
|
|
35490
36188
|
const { parseAssignmentFrontmatter: parseAssignmentFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
|
|
35491
36189
|
const fm = parseAssignmentFrontmatter2(content);
|
|
35492
36190
|
const { workspace } = fm;
|
|
@@ -35556,7 +36254,7 @@ async function ensureWorktree(opts) {
|
|
|
35556
36254
|
async function runCreate(opts) {
|
|
35557
36255
|
const { createWorktreeAndRecord: createWorktreeAndRecord2, GitWorktreeError: GitWorktreeError2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
35558
36256
|
const expandedWorktree = expandHome(opts.worktreePath);
|
|
35559
|
-
const absWorktree =
|
|
36257
|
+
const absWorktree = isAbsolute9(expandedWorktree) ? expandedWorktree : resolve75(expandedWorktree);
|
|
35560
36258
|
try {
|
|
35561
36259
|
await createWorktreeAndRecord2({
|
|
35562
36260
|
assignmentPath: opts.assignmentPath,
|
|
@@ -35620,7 +36318,7 @@ init_paths();
|
|
|
35620
36318
|
init_fs();
|
|
35621
36319
|
init_parser();
|
|
35622
36320
|
init_config2();
|
|
35623
|
-
import { readdir as
|
|
36321
|
+
import { readdir as readdir28, readFile as readFile52 } from "fs/promises";
|
|
35624
36322
|
import { resolve as resolve77 } from "path";
|
|
35625
36323
|
async function listPlaybooksCommand(options = {}) {
|
|
35626
36324
|
const dir = playbooksDir();
|
|
@@ -35630,14 +36328,14 @@ async function listPlaybooksCommand(options = {}) {
|
|
|
35630
36328
|
}
|
|
35631
36329
|
const config = await readConfig();
|
|
35632
36330
|
const disabledSet = new Set(config.playbooks.disabled);
|
|
35633
|
-
const entries = await
|
|
36331
|
+
const entries = await readdir28(dir, { withFileTypes: true });
|
|
35634
36332
|
const mdFiles = entries.filter(
|
|
35635
36333
|
(e) => e.isFile() && e.name.endsWith(".md") && !e.name.startsWith("_") && e.name !== "manifest.md"
|
|
35636
36334
|
);
|
|
35637
36335
|
const rows = [];
|
|
35638
36336
|
for (const entry of mdFiles) {
|
|
35639
36337
|
const filePath = resolve77(dir, entry.name);
|
|
35640
|
-
const raw2 = await
|
|
36338
|
+
const raw2 = await readFile52(filePath, "utf-8");
|
|
35641
36339
|
const parsed = parsePlaybook(raw2);
|
|
35642
36340
|
const slug = parsed.slug || entry.name.replace(/\.md$/, "");
|
|
35643
36341
|
const disabled = disabledSet.has(slug);
|
|
@@ -35760,13 +36458,13 @@ init_fs();
|
|
|
35760
36458
|
init_config2();
|
|
35761
36459
|
init_slug();
|
|
35762
36460
|
import { Command as Command2 } from "commander";
|
|
35763
|
-
import { readFile as
|
|
36461
|
+
import { readFile as readFile54 } from "fs/promises";
|
|
35764
36462
|
import { resolve as resolve79 } from "path";
|
|
35765
36463
|
|
|
35766
36464
|
// src/commands/bundle.ts
|
|
35767
36465
|
init_paths();
|
|
35768
36466
|
import { Command } from "commander";
|
|
35769
|
-
import { mkdir as
|
|
36467
|
+
import { mkdir as mkdir11, readFile as readFile53, readdir as readdir29, rm as rm9, writeFile as writeFile14 } from "fs/promises";
|
|
35770
36468
|
import { resolve as resolve78 } from "path";
|
|
35771
36469
|
init_parser2();
|
|
35772
36470
|
init_fs();
|
|
@@ -36059,7 +36757,7 @@ bundleCommand.command("plan").description("Create or open the bundle's shared pl
|
|
|
36059
36757
|
}
|
|
36060
36758
|
const planDir = bundlePlanDir(sc.todosPath, sc.scopeId, id);
|
|
36061
36759
|
await ensureDir(planDir);
|
|
36062
|
-
const existing = (await
|
|
36760
|
+
const existing = (await readdir29(planDir).catch(() => [])).filter((f) => /^plan(?:-v\d+)?\.md$/.test(f));
|
|
36063
36761
|
const { target } = pickNextPlanFile(planDir, existing);
|
|
36064
36762
|
const checklist = await readChecklist(sc.todosPath, sc.checklistKey);
|
|
36065
36763
|
if (!await fileExists(target)) {
|
|
@@ -36128,8 +36826,8 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
36128
36826
|
}
|
|
36129
36827
|
const bundlesFilePath = bundlesPath(sc.todosPath);
|
|
36130
36828
|
const checklistFilePath = checklistPath(sc.todosPath, sc.checklistKey);
|
|
36131
|
-
const bundlesSnapshot = await fileExists(bundlesFilePath) ? await
|
|
36132
|
-
const checklistSnapshot = await fileExists(checklistFilePath) ? await
|
|
36829
|
+
const bundlesSnapshot = await fileExists(bundlesFilePath) ? await readFile53(bundlesFilePath, "utf-8") : null;
|
|
36830
|
+
const checklistSnapshot = await fileExists(checklistFilePath) ? await readFile53(checklistFilePath, "utf-8") : null;
|
|
36133
36831
|
const record = async () => {
|
|
36134
36832
|
bundle.branch = options.branch;
|
|
36135
36833
|
bundle.worktreePath = worktreePath;
|
|
@@ -36146,7 +36844,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
36146
36844
|
await writeBundles(sc.todosPath, bundles);
|
|
36147
36845
|
await writeChecklist(sc.todosPath, checklist);
|
|
36148
36846
|
const ctxDir = resolve78(worktreePath, ".syntaur");
|
|
36149
|
-
await
|
|
36847
|
+
await mkdir11(ctxDir, { recursive: true });
|
|
36150
36848
|
const payload = {
|
|
36151
36849
|
bundleId: bundle.id,
|
|
36152
36850
|
bundleSlug: bundle.slug,
|
|
@@ -36159,7 +36857,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
36159
36857
|
repository,
|
|
36160
36858
|
boundAt: nowISO()
|
|
36161
36859
|
};
|
|
36162
|
-
await
|
|
36860
|
+
await writeFile14(resolve78(ctxDir, "context.json"), JSON.stringify(payload, null, 2) + "\n");
|
|
36163
36861
|
} catch (err2) {
|
|
36164
36862
|
try {
|
|
36165
36863
|
if (bundlesSnapshot === null) {
|
|
@@ -36685,7 +37383,7 @@ todoCommand.command("archive").description("Archive completed todos and their lo
|
|
|
36685
37383
|
await ensureDir(resolve79(todosPath, "archive"));
|
|
36686
37384
|
let archContent = "";
|
|
36687
37385
|
if (await fileExists(archFile)) {
|
|
36688
|
-
archContent = await
|
|
37386
|
+
archContent = await readFile54(archFile, "utf-8");
|
|
36689
37387
|
archContent = archContent.trimEnd() + "\n\n";
|
|
36690
37388
|
} else {
|
|
36691
37389
|
archContent = `---
|
|
@@ -36863,12 +37561,12 @@ function describeScope(scope) {
|
|
|
36863
37561
|
}
|
|
36864
37562
|
async function injectPromotedTodos(assignmentDir, todos, scopeLabel) {
|
|
36865
37563
|
const { resolve: resolvePath2 } = await import("path");
|
|
36866
|
-
const { readFile:
|
|
37564
|
+
const { readFile: readFile85 } = await import("fs/promises");
|
|
36867
37565
|
const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
36868
37566
|
const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
|
|
36869
37567
|
const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
|
|
36870
37568
|
const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
|
|
36871
|
-
let content = await
|
|
37569
|
+
let content = await readFile85(assignmentMdPath2, "utf-8");
|
|
36872
37570
|
content = appendTodosToAssignmentBody2(
|
|
36873
37571
|
content,
|
|
36874
37572
|
todos.map((t) => ({
|
|
@@ -36913,8 +37611,8 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
|
|
|
36913
37611
|
}
|
|
36914
37612
|
const planDir = todoPlanDir(todosPath, workspace, id);
|
|
36915
37613
|
await ensureDir(planDir);
|
|
36916
|
-
const { readdir:
|
|
36917
|
-
const existingFiles = (await
|
|
37614
|
+
const { readdir: readdir42 } = await import("fs/promises");
|
|
37615
|
+
const existingFiles = (await readdir42(planDir).catch(() => [])).filter(
|
|
36918
37616
|
(f) => /^plan(?:-v\d+)?\.md$/.test(f)
|
|
36919
37617
|
);
|
|
36920
37618
|
let target;
|
|
@@ -37004,9 +37702,9 @@ async function moveTodo(id, options) {
|
|
|
37004
37702
|
if (await fileExists(newPlanDir)) {
|
|
37005
37703
|
throw new Error(`Plan directory already exists at target: ${newPlanDir}; refusing to move.`);
|
|
37006
37704
|
}
|
|
37007
|
-
const { rename: rename11, mkdir:
|
|
37008
|
-
const { dirname:
|
|
37009
|
-
await
|
|
37705
|
+
const { rename: rename11, mkdir: mkdir14 } = await import("fs/promises");
|
|
37706
|
+
const { dirname: dirname31 } = await import("path");
|
|
37707
|
+
await mkdir14(dirname31(newPlanDir), { recursive: true });
|
|
37010
37708
|
await rename11(item.planDir, newPlanDir);
|
|
37011
37709
|
item.planDir = newPlanDir;
|
|
37012
37710
|
}
|
|
@@ -37123,13 +37821,13 @@ backupCommand.command("config").description("Show or update backup configuration
|
|
|
37123
37821
|
|
|
37124
37822
|
// src/commands/doctor.ts
|
|
37125
37823
|
import { Command as Command4 } from "commander";
|
|
37126
|
-
import { readFile as
|
|
37127
|
-
import { isAbsolute as
|
|
37824
|
+
import { readFile as readFile66 } from "fs/promises";
|
|
37825
|
+
import { isAbsolute as isAbsolute12, resolve as resolve93 } from "path";
|
|
37128
37826
|
|
|
37129
37827
|
// src/utils/doctor/index.ts
|
|
37130
37828
|
import { fileURLToPath as fileURLToPath12 } from "url";
|
|
37131
|
-
import { readFile as
|
|
37132
|
-
import { dirname as
|
|
37829
|
+
import { readFile as readFile65 } from "fs/promises";
|
|
37830
|
+
import { dirname as dirname26, join as join24 } from "path";
|
|
37133
37831
|
|
|
37134
37832
|
// src/utils/doctor/context.ts
|
|
37135
37833
|
init_config2();
|
|
@@ -37174,10 +37872,10 @@ function closeCheckContext(ctx) {
|
|
|
37174
37872
|
// src/utils/doctor/checks/env.ts
|
|
37175
37873
|
init_fs();
|
|
37176
37874
|
init_paths();
|
|
37177
|
-
import { resolve as resolve81, isAbsolute as
|
|
37178
|
-
import { readFile as
|
|
37875
|
+
import { resolve as resolve81, isAbsolute as isAbsolute10 } from "path";
|
|
37876
|
+
import { readFile as readFile55, stat as stat10 } from "fs/promises";
|
|
37179
37877
|
import { fileURLToPath as fileURLToPath10 } from "url";
|
|
37180
|
-
import { dirname as
|
|
37878
|
+
import { dirname as dirname23, join as join20 } from "path";
|
|
37181
37879
|
var CATEGORY = "env";
|
|
37182
37880
|
var syntaurRootExists = {
|
|
37183
37881
|
id: "env.syntaur-root-exists",
|
|
@@ -37185,7 +37883,7 @@ var syntaurRootExists = {
|
|
|
37185
37883
|
title: "~/.syntaur/ directory exists",
|
|
37186
37884
|
async run(ctx) {
|
|
37187
37885
|
try {
|
|
37188
|
-
const s = await
|
|
37886
|
+
const s = await stat10(ctx.syntaurRoot);
|
|
37189
37887
|
if (!s.isDirectory()) {
|
|
37190
37888
|
return err(this, `${ctx.syntaurRoot} exists but is not a directory`, [
|
|
37191
37889
|
ctx.syntaurRoot
|
|
@@ -37232,7 +37930,7 @@ var configValid = {
|
|
|
37232
37930
|
autoFixable: false
|
|
37233
37931
|
};
|
|
37234
37932
|
}
|
|
37235
|
-
const content = await
|
|
37933
|
+
const content = await readFile55(configPath2, "utf-8");
|
|
37236
37934
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
37237
37935
|
if (!fmMatch || fmMatch[1].trim() === "") {
|
|
37238
37936
|
return {
|
|
@@ -37269,7 +37967,7 @@ var configValid = {
|
|
|
37269
37967
|
};
|
|
37270
37968
|
}
|
|
37271
37969
|
const expanded = expandHome(rawProjectDir);
|
|
37272
|
-
if (!
|
|
37970
|
+
if (!isAbsolute10(expanded)) {
|
|
37273
37971
|
return {
|
|
37274
37972
|
id: this.id,
|
|
37275
37973
|
category: this.category,
|
|
@@ -37508,14 +38206,14 @@ async function readLocalVersion() {
|
|
|
37508
38206
|
async function readLocalPkg() {
|
|
37509
38207
|
try {
|
|
37510
38208
|
const here = fileURLToPath10(import.meta.url);
|
|
37511
|
-
let dir =
|
|
38209
|
+
let dir = dirname23(here);
|
|
37512
38210
|
for (let i = 0; i < 6; i++) {
|
|
37513
|
-
const candidate =
|
|
38211
|
+
const candidate = join20(dir, "package.json");
|
|
37514
38212
|
try {
|
|
37515
|
-
const text = await
|
|
38213
|
+
const text = await readFile55(candidate, "utf-8");
|
|
37516
38214
|
return JSON.parse(text);
|
|
37517
38215
|
} catch {
|
|
37518
|
-
dir =
|
|
38216
|
+
dir = dirname23(dir);
|
|
37519
38217
|
}
|
|
37520
38218
|
}
|
|
37521
38219
|
return null;
|
|
@@ -37565,7 +38263,7 @@ function versionGte(a, b) {
|
|
|
37565
38263
|
// src/utils/doctor/checks/structure.ts
|
|
37566
38264
|
init_fs();
|
|
37567
38265
|
import { resolve as resolve82 } from "path";
|
|
37568
|
-
import { readdir as
|
|
38266
|
+
import { readdir as readdir30, stat as stat11 } from "fs/promises";
|
|
37569
38267
|
var CATEGORY2 = "structure";
|
|
37570
38268
|
var KNOWN_TOP_LEVEL = /* @__PURE__ */ new Set([
|
|
37571
38269
|
"projects",
|
|
@@ -37645,7 +38343,7 @@ var todosDirValid = {
|
|
|
37645
38343
|
autoFixable: false
|
|
37646
38344
|
};
|
|
37647
38345
|
}
|
|
37648
|
-
const s = await
|
|
38346
|
+
const s = await stat11(p);
|
|
37649
38347
|
if (!s.isDirectory()) {
|
|
37650
38348
|
return {
|
|
37651
38349
|
id: this.id,
|
|
@@ -37676,7 +38374,7 @@ var serversDirValid = {
|
|
|
37676
38374
|
autoFixable: false
|
|
37677
38375
|
};
|
|
37678
38376
|
}
|
|
37679
|
-
const s = await
|
|
38377
|
+
const s = await stat11(p);
|
|
37680
38378
|
if (!s.isDirectory()) {
|
|
37681
38379
|
return {
|
|
37682
38380
|
id: this.id,
|
|
@@ -37696,7 +38394,7 @@ var knownFilesRecognized = {
|
|
|
37696
38394
|
category: CATEGORY2,
|
|
37697
38395
|
title: "No unexpected top-level entries under ~/.syntaur/",
|
|
37698
38396
|
async run(ctx) {
|
|
37699
|
-
const entries = await
|
|
38397
|
+
const entries = await readdir30(ctx.syntaurRoot, { withFileTypes: true });
|
|
37700
38398
|
const unexpected = [];
|
|
37701
38399
|
for (const e of entries) {
|
|
37702
38400
|
if (e.name.startsWith(".")) continue;
|
|
@@ -37740,7 +38438,7 @@ function pass2(check) {
|
|
|
37740
38438
|
// src/utils/doctor/checks/project.ts
|
|
37741
38439
|
init_fs();
|
|
37742
38440
|
import { resolve as resolve83 } from "path";
|
|
37743
|
-
import { readdir as
|
|
38441
|
+
import { readdir as readdir31, stat as stat12 } from "fs/promises";
|
|
37744
38442
|
var CATEGORY3 = "project";
|
|
37745
38443
|
var REQUIRED_PROJECT_FILES = [
|
|
37746
38444
|
"project.md",
|
|
@@ -37764,7 +38462,7 @@ var PROJECT_MARKERS = ["project.md", "manifest.md", "assignments"];
|
|
|
37764
38462
|
async function listProjects2(ctx) {
|
|
37765
38463
|
const dir = ctx.config.defaultProjectDir;
|
|
37766
38464
|
if (!await fileExists(dir)) return [];
|
|
37767
|
-
const entries = await
|
|
38465
|
+
const entries = await readdir31(dir, { withFileTypes: true });
|
|
37768
38466
|
const result = [];
|
|
37769
38467
|
for (const e of entries) {
|
|
37770
38468
|
if (!e.isDirectory()) continue;
|
|
@@ -37826,7 +38524,7 @@ var manifestStale = {
|
|
|
37826
38524
|
for (const projectDir of projects) {
|
|
37827
38525
|
const manifestPath = resolve83(projectDir, "manifest.md");
|
|
37828
38526
|
if (!await fileExists(manifestPath)) continue;
|
|
37829
|
-
const manifestMtime = (await
|
|
38527
|
+
const manifestMtime = (await stat12(manifestPath)).mtimeMs;
|
|
37830
38528
|
const newestAssignment = await newestAssignmentMtime(projectDir);
|
|
37831
38529
|
if (newestAssignment === 0) continue;
|
|
37832
38530
|
if (newestAssignment > manifestMtime) {
|
|
@@ -37858,7 +38556,7 @@ var orphanFiles = {
|
|
|
37858
38556
|
const projects = await listProjects2(ctx);
|
|
37859
38557
|
const results = [];
|
|
37860
38558
|
for (const projectDir of projects) {
|
|
37861
|
-
const entries = await
|
|
38559
|
+
const entries = await readdir31(projectDir, { withFileTypes: true });
|
|
37862
38560
|
const orphans = [];
|
|
37863
38561
|
for (const e of entries) {
|
|
37864
38562
|
if (e.name.startsWith(".")) continue;
|
|
@@ -37888,7 +38586,7 @@ async function newestAssignmentMtime(projectDir) {
|
|
|
37888
38586
|
let newest = 0;
|
|
37889
38587
|
let entries;
|
|
37890
38588
|
try {
|
|
37891
|
-
entries = await
|
|
38589
|
+
entries = await readdir31(assignmentsRoot, { withFileTypes: true });
|
|
37892
38590
|
} catch {
|
|
37893
38591
|
return 0;
|
|
37894
38592
|
}
|
|
@@ -37896,7 +38594,7 @@ async function newestAssignmentMtime(projectDir) {
|
|
|
37896
38594
|
if (!e.isDirectory()) continue;
|
|
37897
38595
|
const assignmentMd = resolve83(assignmentsRoot, e.name, "assignment.md");
|
|
37898
38596
|
try {
|
|
37899
|
-
const s = await
|
|
38597
|
+
const s = await stat12(assignmentMd);
|
|
37900
38598
|
if (s.mtimeMs > newest) newest = s.mtimeMs;
|
|
37901
38599
|
} catch {
|
|
37902
38600
|
}
|
|
@@ -37920,7 +38618,7 @@ init_types();
|
|
|
37920
38618
|
init_paths();
|
|
37921
38619
|
init_assignment_walk();
|
|
37922
38620
|
import { resolve as resolve84 } from "path";
|
|
37923
|
-
import { readFile as
|
|
38621
|
+
import { readFile as readFile56, readdir as readdir32 } from "fs/promises";
|
|
37924
38622
|
var CATEGORY4 = "assignment";
|
|
37925
38623
|
var STATUSES_REQUIRING_HANDOFF = /* @__PURE__ */ new Set(["review", "completed"]);
|
|
37926
38624
|
var PRE_WORKSPACE_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -38268,7 +38966,7 @@ var draftMissingObjective = {
|
|
|
38268
38966
|
if (parsed.status !== "draft") continue;
|
|
38269
38967
|
let raw2;
|
|
38270
38968
|
try {
|
|
38271
|
-
raw2 = await
|
|
38969
|
+
raw2 = await readFile56(path, "utf-8");
|
|
38272
38970
|
} catch {
|
|
38273
38971
|
continue;
|
|
38274
38972
|
}
|
|
@@ -38305,12 +39003,12 @@ var readyToImplementMissingPlan = {
|
|
|
38305
39003
|
const parsed = await parseSafe4(path);
|
|
38306
39004
|
if (!parsed) continue;
|
|
38307
39005
|
if (parsed.status !== "ready_to_implement") continue;
|
|
38308
|
-
const entries = await
|
|
39006
|
+
const entries = await readdir32(a.assignmentDir).catch(() => []);
|
|
38309
39007
|
const planFiles = entries.filter((f) => /^plan(?:-v\d+)?\.md$/i.test(f));
|
|
38310
39008
|
let hasPlanContent = false;
|
|
38311
39009
|
for (const f of planFiles) {
|
|
38312
39010
|
try {
|
|
38313
|
-
const c2 = await
|
|
39011
|
+
const c2 = await readFile56(resolve84(a.assignmentDir, f), "utf-8");
|
|
38314
39012
|
if (c2.trim().length > 0) {
|
|
38315
39013
|
hasPlanContent = true;
|
|
38316
39014
|
break;
|
|
@@ -38353,7 +39051,7 @@ var assignmentChecks = [
|
|
|
38353
39051
|
];
|
|
38354
39052
|
async function parseSafe4(path) {
|
|
38355
39053
|
try {
|
|
38356
|
-
const content = await
|
|
39054
|
+
const content = await readFile56(path, "utf-8");
|
|
38357
39055
|
return parseAssignmentFull(content);
|
|
38358
39056
|
} catch {
|
|
38359
39057
|
return null;
|
|
@@ -38515,9 +39213,9 @@ function skipped(check, reason) {
|
|
|
38515
39213
|
|
|
38516
39214
|
// src/utils/doctor/checks/integrations.ts
|
|
38517
39215
|
init_fs();
|
|
38518
|
-
import { resolve as resolve86, dirname as
|
|
38519
|
-
import { readdir as
|
|
38520
|
-
import { homedir as
|
|
39216
|
+
import { resolve as resolve86, dirname as dirname24, basename as basename10 } from "path";
|
|
39217
|
+
import { readdir as readdir33, readFile as readFile57 } from "fs/promises";
|
|
39218
|
+
import { homedir as homedir16 } from "os";
|
|
38521
39219
|
var CATEGORY6 = "integrations";
|
|
38522
39220
|
var claudePluginLinked = {
|
|
38523
39221
|
id: "integrations.claude-plugin-linked",
|
|
@@ -38579,7 +39277,7 @@ var backupConfigured = {
|
|
|
38579
39277
|
if (ctx.config.backup?.repo) return pass6(this);
|
|
38580
39278
|
const projectsDir2 = ctx.config.defaultProjectDir;
|
|
38581
39279
|
if (!await fileExists(projectsDir2)) return skipped2(this, "no projects dir");
|
|
38582
|
-
const entries = await
|
|
39280
|
+
const entries = await readdir33(projectsDir2, { withFileTypes: true });
|
|
38583
39281
|
const hasProjects = entries.some((e) => e.isDirectory() && !e.name.startsWith(".") && !e.name.startsWith("_"));
|
|
38584
39282
|
if (!hasProjects) return skipped2(this, "no projects yet");
|
|
38585
39283
|
return {
|
|
@@ -38598,10 +39296,10 @@ var backupConfigured = {
|
|
|
38598
39296
|
}
|
|
38599
39297
|
};
|
|
38600
39298
|
async function readKnownMarketplaces() {
|
|
38601
|
-
const path = resolve86(
|
|
39299
|
+
const path = resolve86(homedir16(), ".claude", "plugins", "known_marketplaces.json");
|
|
38602
39300
|
if (!await fileExists(path)) return {};
|
|
38603
39301
|
try {
|
|
38604
|
-
const raw2 = await
|
|
39302
|
+
const raw2 = await readFile57(path, "utf-8");
|
|
38605
39303
|
return JSON.parse(raw2);
|
|
38606
39304
|
} catch {
|
|
38607
39305
|
return {};
|
|
@@ -38617,8 +39315,8 @@ var claudeMarketplaceRegistered = {
|
|
|
38617
39315
|
if (!await fileExists(dir)) {
|
|
38618
39316
|
return skipped2(this, "claudePluginDir does not exist (run install-plugin)");
|
|
38619
39317
|
}
|
|
38620
|
-
const pluginsParent =
|
|
38621
|
-
if (
|
|
39318
|
+
const pluginsParent = dirname24(dir);
|
|
39319
|
+
if (basename10(pluginsParent) !== "plugins") {
|
|
38622
39320
|
return {
|
|
38623
39321
|
id: this.id,
|
|
38624
39322
|
category: this.category,
|
|
@@ -38634,7 +39332,7 @@ var claudeMarketplaceRegistered = {
|
|
|
38634
39332
|
autoFixable: false
|
|
38635
39333
|
};
|
|
38636
39334
|
}
|
|
38637
|
-
const marketplaceRoot =
|
|
39335
|
+
const marketplaceRoot = dirname24(pluginsParent);
|
|
38638
39336
|
const marketplaceManifest = resolve86(marketplaceRoot, ".claude-plugin", "marketplace.json");
|
|
38639
39337
|
if (!await fileExists(marketplaceManifest)) {
|
|
38640
39338
|
return {
|
|
@@ -38654,7 +39352,7 @@ var claudeMarketplaceRegistered = {
|
|
|
38654
39352
|
}
|
|
38655
39353
|
let parsed = {};
|
|
38656
39354
|
try {
|
|
38657
|
-
parsed = JSON.parse(await
|
|
39355
|
+
parsed = JSON.parse(await readFile57(marketplaceManifest, "utf-8"));
|
|
38658
39356
|
} catch {
|
|
38659
39357
|
return {
|
|
38660
39358
|
id: this.id,
|
|
@@ -38666,7 +39364,7 @@ var claudeMarketplaceRegistered = {
|
|
|
38666
39364
|
autoFixable: false
|
|
38667
39365
|
};
|
|
38668
39366
|
}
|
|
38669
|
-
const marketplaceName = parsed.name ??
|
|
39367
|
+
const marketplaceName = parsed.name ?? basename10(marketplaceRoot);
|
|
38670
39368
|
const hasSyntaurEntry = (parsed.plugins ?? []).some((p) => p?.name === "syntaur");
|
|
38671
39369
|
const known = await readKnownMarketplaces();
|
|
38672
39370
|
const registered = known[marketplaceName]?.installLocation === marketplaceRoot || Object.values(known).some((v) => v.installLocation === marketplaceRoot);
|
|
@@ -38686,7 +39384,7 @@ var claudeMarketplaceRegistered = {
|
|
|
38686
39384
|
title: this.title,
|
|
38687
39385
|
status: "error",
|
|
38688
39386
|
detail: issues.join("; "),
|
|
38689
|
-
affected: [marketplaceManifest, resolve86(
|
|
39387
|
+
affected: [marketplaceManifest, resolve86(homedir16(), ".claude", "plugins", "known_marketplaces.json")],
|
|
38690
39388
|
remediation: {
|
|
38691
39389
|
kind: "manual",
|
|
38692
39390
|
suggestion: "Re-run install-plugin to ensure both files are in sync.",
|
|
@@ -38727,7 +39425,7 @@ init_fs();
|
|
|
38727
39425
|
init_parser();
|
|
38728
39426
|
init_types();
|
|
38729
39427
|
import { resolve as resolve87 } from "path";
|
|
38730
|
-
import { readFile as
|
|
39428
|
+
import { readFile as readFile58 } from "fs/promises";
|
|
38731
39429
|
var CATEGORY7 = "workspace";
|
|
38732
39430
|
var ASSIGNMENT_FIELDS2 = ["projectSlug", "assignmentSlug", "projectDir", "assignmentDir"];
|
|
38733
39431
|
var BUNDLE_FIELDS = ["bundleId", "bundleScope", "bundleScopeId"];
|
|
@@ -38759,7 +39457,7 @@ async function loadContext(ctx) {
|
|
|
38759
39457
|
return { data: null, path, exists: false, parseError: null };
|
|
38760
39458
|
}
|
|
38761
39459
|
try {
|
|
38762
|
-
const raw2 = await
|
|
39460
|
+
const raw2 = await readFile58(path, "utf-8");
|
|
38763
39461
|
return { data: JSON.parse(raw2), path, exists: true, parseError: null };
|
|
38764
39462
|
} catch (err2) {
|
|
38765
39463
|
return {
|
|
@@ -38871,7 +39569,7 @@ var contextTerminal = {
|
|
|
38871
39569
|
const assignmentMd = resolve87(data.assignmentDir, "assignment.md");
|
|
38872
39570
|
if (!await fileExists(assignmentMd)) return skipped3(this, "assignment file missing");
|
|
38873
39571
|
try {
|
|
38874
|
-
const content = await
|
|
39572
|
+
const content = await readFile58(assignmentMd, "utf-8");
|
|
38875
39573
|
const parsed = parseAssignmentFull(content);
|
|
38876
39574
|
const terminal = terminalStatuses2(ctx);
|
|
38877
39575
|
if (terminal.has(parsed.status)) {
|
|
@@ -38925,8 +39623,8 @@ function skipped3(check, reason) {
|
|
|
38925
39623
|
|
|
38926
39624
|
// src/utils/doctor/checks/agents.ts
|
|
38927
39625
|
init_config2();
|
|
38928
|
-
import { isAbsolute as
|
|
38929
|
-
import { access as
|
|
39626
|
+
import { isAbsolute as isAbsolute11 } from "path";
|
|
39627
|
+
import { access as access5, constants as fsConstants } from "fs/promises";
|
|
38930
39628
|
import { spawnSync as spawnSync8 } from "child_process";
|
|
38931
39629
|
var CATEGORY8 = "agents";
|
|
38932
39630
|
var agentsResolvable = {
|
|
@@ -38971,9 +39669,9 @@ async function checkAgent(agent) {
|
|
|
38971
39669
|
autoFixable: false
|
|
38972
39670
|
};
|
|
38973
39671
|
}
|
|
38974
|
-
if (
|
|
39672
|
+
if (isAbsolute11(agent.command)) {
|
|
38975
39673
|
try {
|
|
38976
|
-
await
|
|
39674
|
+
await access5(agent.command, fsConstants.X_OK);
|
|
38977
39675
|
return { ...base, status: "pass", autoFixable: false };
|
|
38978
39676
|
} catch (err2) {
|
|
38979
39677
|
const code = err2.code;
|
|
@@ -39017,7 +39715,7 @@ var agentChecks = [agentsResolvable];
|
|
|
39017
39715
|
// src/utils/doctor/checks/terminal.ts
|
|
39018
39716
|
init_config2();
|
|
39019
39717
|
import { spawnSync as spawnSync9 } from "child_process";
|
|
39020
|
-
import { readFile as
|
|
39718
|
+
import { readFile as readFile59 } from "fs/promises";
|
|
39021
39719
|
import { resolve as resolve88 } from "path";
|
|
39022
39720
|
init_paths();
|
|
39023
39721
|
init_fs();
|
|
@@ -39025,7 +39723,7 @@ var CATEGORY9 = "terminal";
|
|
|
39025
39723
|
async function readRawTerminalKey() {
|
|
39026
39724
|
const configPath2 = resolve88(syntaurRoot(), "config.md");
|
|
39027
39725
|
if (!await fileExists(configPath2)) return null;
|
|
39028
|
-
const content = await
|
|
39726
|
+
const content = await readFile59(configPath2, "utf-8");
|
|
39029
39727
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
39030
39728
|
if (!fmMatch) return null;
|
|
39031
39729
|
const line = fmMatch[1].split("\n").find((l) => /^terminal:\s*/.test(l));
|
|
@@ -39175,13 +39873,13 @@ var terminalChecks = [
|
|
|
39175
39873
|
|
|
39176
39874
|
// src/utils/doctor/checks/skills.ts
|
|
39177
39875
|
init_fs();
|
|
39178
|
-
import { resolve as resolve89, join as
|
|
39179
|
-
import { readdir as
|
|
39180
|
-
import { homedir as
|
|
39876
|
+
import { resolve as resolve89, join as join21 } from "path";
|
|
39877
|
+
import { readdir as readdir34, readFile as readFile60, lstat as lstat4 } from "fs/promises";
|
|
39878
|
+
import { homedir as homedir17 } from "os";
|
|
39181
39879
|
var CATEGORY10 = "skills";
|
|
39182
39880
|
var skillTargets = [
|
|
39183
|
-
{ agent: "claude", dir: resolve89(
|
|
39184
|
-
{ agent: "codex", dir: resolve89(
|
|
39881
|
+
{ agent: "claude", dir: resolve89(homedir17(), ".claude", "skills"), label: "~/.claude/skills" },
|
|
39882
|
+
{ agent: "codex", dir: resolve89(homedir17(), ".codex", "skills"), label: "~/.codex/skills" }
|
|
39185
39883
|
];
|
|
39186
39884
|
var skillsDedupCheck = {
|
|
39187
39885
|
id: "skills.dedup",
|
|
@@ -39196,21 +39894,21 @@ var skillsDedupCheck = {
|
|
|
39196
39894
|
const present = [];
|
|
39197
39895
|
let entries;
|
|
39198
39896
|
try {
|
|
39199
|
-
entries = await
|
|
39897
|
+
entries = await readdir34(dir, { withFileTypes: true });
|
|
39200
39898
|
} catch {
|
|
39201
39899
|
continue;
|
|
39202
39900
|
}
|
|
39203
39901
|
for (const entry of entries) {
|
|
39204
39902
|
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
|
|
39205
39903
|
if (!KNOWN_SKILLS.includes(entry.name)) continue;
|
|
39206
|
-
const skillMd =
|
|
39904
|
+
const skillMd = join21(dir, entry.name, "SKILL.md");
|
|
39207
39905
|
if (!await fileExists(skillMd)) continue;
|
|
39208
|
-
const content = await
|
|
39906
|
+
const content = await readFile60(skillMd, "utf-8").catch(() => "");
|
|
39209
39907
|
const match = content.match(/^name:\s*(\S+)\s*$/m);
|
|
39210
39908
|
if (!match || match[1] !== entry.name) continue;
|
|
39211
39909
|
let isSymlink2 = false;
|
|
39212
39910
|
try {
|
|
39213
|
-
isSymlink2 = (await lstat4(
|
|
39911
|
+
isSymlink2 = (await lstat4(join21(dir, entry.name))).isSymbolicLink();
|
|
39214
39912
|
} catch {
|
|
39215
39913
|
}
|
|
39216
39914
|
present.push({ name: entry.name, isSymlink: isSymlink2 });
|
|
@@ -39222,7 +39920,7 @@ var skillsDedupCheck = {
|
|
|
39222
39920
|
findings.push(
|
|
39223
39921
|
`${label}: ${nonSymlink.length} syntaur skill(s) installed globally while the syntaur plugin is enabled (${agent}) \u2014 duplicate registrations`
|
|
39224
39922
|
);
|
|
39225
|
-
for (const p of nonSymlink) affected.push(
|
|
39923
|
+
for (const p of nonSymlink) affected.push(join21(dir, p.name));
|
|
39226
39924
|
}
|
|
39227
39925
|
}
|
|
39228
39926
|
}
|
|
@@ -39255,12 +39953,12 @@ var skillsChecks = [skillsDedupCheck];
|
|
|
39255
39953
|
|
|
39256
39954
|
// src/utils/doctor/checks/cross-agent.ts
|
|
39257
39955
|
init_fs();
|
|
39258
|
-
import { join as
|
|
39259
|
-
import { readFile as
|
|
39956
|
+
import { join as join22, resolve as resolve90 } from "path";
|
|
39957
|
+
import { readFile as readFile62 } from "fs/promises";
|
|
39260
39958
|
|
|
39261
39959
|
// src/utils/skill-frontmatter.ts
|
|
39262
39960
|
import { createHash as createHash4 } from "crypto";
|
|
39263
|
-
import { readFile as
|
|
39961
|
+
import { readFile as readFile61 } from "fs/promises";
|
|
39264
39962
|
function stripQuotes(raw2) {
|
|
39265
39963
|
const t = raw2.trim();
|
|
39266
39964
|
if (t.length >= 2 && (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'"))) {
|
|
@@ -39304,7 +40002,7 @@ function readSkillIdentity(skillMdText) {
|
|
|
39304
40002
|
return { name, hasDescription };
|
|
39305
40003
|
}
|
|
39306
40004
|
async function sha256File(path) {
|
|
39307
|
-
return createHash4("sha256").update(await
|
|
40005
|
+
return createHash4("sha256").update(await readFile61(path)).digest("hex");
|
|
39308
40006
|
}
|
|
39309
40007
|
|
|
39310
40008
|
// src/utils/doctor/checks/cross-agent.ts
|
|
@@ -39314,14 +40012,14 @@ async function checkTargetSkillsIntegrity(installedDir, canonicalSkillsDir, know
|
|
|
39314
40012
|
const problems = [];
|
|
39315
40013
|
let valid = 0;
|
|
39316
40014
|
for (const skill of knownSkills) {
|
|
39317
|
-
const installedPath =
|
|
40015
|
+
const installedPath = join22(installedDir, skill, "SKILL.md");
|
|
39318
40016
|
if (!await fileExists(installedPath)) {
|
|
39319
40017
|
problems.push({ skill, kind: "missing" });
|
|
39320
40018
|
continue;
|
|
39321
40019
|
}
|
|
39322
40020
|
let text;
|
|
39323
40021
|
try {
|
|
39324
|
-
text = await
|
|
40022
|
+
text = await readFile62(installedPath, "utf-8");
|
|
39325
40023
|
} catch {
|
|
39326
40024
|
problems.push({ skill, kind: "invalid-frontmatter" });
|
|
39327
40025
|
continue;
|
|
@@ -39332,7 +40030,7 @@ async function checkTargetSkillsIntegrity(installedDir, canonicalSkillsDir, know
|
|
|
39332
40030
|
continue;
|
|
39333
40031
|
}
|
|
39334
40032
|
valid++;
|
|
39335
|
-
const canonicalPath2 =
|
|
40033
|
+
const canonicalPath2 = join22(canonicalSkillsDir, skill, "SKILL.md");
|
|
39336
40034
|
if (await fileExists(canonicalPath2)) {
|
|
39337
40035
|
const [installedHash, canonicalHash] = await Promise.all([
|
|
39338
40036
|
sha256File(installedPath),
|
|
@@ -39407,7 +40105,7 @@ var crossAgentSkillsCheck = {
|
|
|
39407
40105
|
}
|
|
39408
40106
|
if (t.tier3) {
|
|
39409
40107
|
const installDir = t.tier3.installDir();
|
|
39410
|
-
const installed2 = await fileExists(
|
|
40108
|
+
const installed2 = await fileExists(join22(installDir, t.tier3.entry));
|
|
39411
40109
|
lines.push(
|
|
39412
40110
|
`${t.displayName}: Tier-3 ${t.tier3.kind} ${installed2 ? "installed" : "absent"} (${installDir})`
|
|
39413
40111
|
);
|
|
@@ -39475,7 +40173,7 @@ var crossAgentChecks = [crossAgentSkillsCheck];
|
|
|
39475
40173
|
init_fs();
|
|
39476
40174
|
init_paths();
|
|
39477
40175
|
import { resolve as resolve91 } from "path";
|
|
39478
|
-
import { readdir as
|
|
40176
|
+
import { readdir as readdir35 } from "fs/promises";
|
|
39479
40177
|
import { spawnSync as spawnSync10 } from "child_process";
|
|
39480
40178
|
init_parser2();
|
|
39481
40179
|
var CATEGORY12 = "bundles";
|
|
@@ -39483,7 +40181,7 @@ async function listScopes(ctx) {
|
|
|
39483
40181
|
const out = [];
|
|
39484
40182
|
const td = todosDir();
|
|
39485
40183
|
if (await fileExists(td)) {
|
|
39486
|
-
const entries = await
|
|
40184
|
+
const entries = await readdir35(td).catch(() => []);
|
|
39487
40185
|
for (const f of entries) {
|
|
39488
40186
|
if (typeof f !== "string") continue;
|
|
39489
40187
|
if (!f.endsWith(".md") || f.endsWith("-log.md")) continue;
|
|
@@ -39499,7 +40197,7 @@ async function listScopes(ctx) {
|
|
|
39499
40197
|
}
|
|
39500
40198
|
}
|
|
39501
40199
|
if (await fileExists(ctx.config.defaultProjectDir)) {
|
|
39502
|
-
const projectEntries = await
|
|
40200
|
+
const projectEntries = await readdir35(ctx.config.defaultProjectDir, { withFileTypes: true }).catch(() => []);
|
|
39503
40201
|
for (const e of projectEntries) {
|
|
39504
40202
|
if (!e.isDirectory()) continue;
|
|
39505
40203
|
const slug = e.name;
|
|
@@ -39697,21 +40395,21 @@ var bundleChecks = [
|
|
|
39697
40395
|
];
|
|
39698
40396
|
|
|
39699
40397
|
// src/utils/doctor/checks/plugin.ts
|
|
39700
|
-
import { readFile as
|
|
39701
|
-
import { dirname as
|
|
40398
|
+
import { readFile as readFile63 } from "fs/promises";
|
|
40399
|
+
import { dirname as dirname25, join as join23 } from "path";
|
|
39702
40400
|
import { fileURLToPath as fileURLToPath11 } from "url";
|
|
39703
40401
|
var CATEGORY13 = "plugin";
|
|
39704
40402
|
var PLUGIN_KINDS = ["claude", "codex"];
|
|
39705
40403
|
async function readCliVersion() {
|
|
39706
40404
|
try {
|
|
39707
|
-
let dir =
|
|
40405
|
+
let dir = dirname25(fileURLToPath11(import.meta.url));
|
|
39708
40406
|
for (let i = 0; i < 8; i += 1) {
|
|
39709
40407
|
try {
|
|
39710
|
-
const parsed = JSON.parse(await
|
|
40408
|
+
const parsed = JSON.parse(await readFile63(join23(dir, "package.json"), "utf-8"));
|
|
39711
40409
|
if (typeof parsed.version === "string" && parsed.version.length > 0) return parsed.version;
|
|
39712
40410
|
} catch {
|
|
39713
40411
|
}
|
|
39714
|
-
dir =
|
|
40412
|
+
dir = dirname25(dir);
|
|
39715
40413
|
}
|
|
39716
40414
|
} catch {
|
|
39717
40415
|
}
|
|
@@ -39818,7 +40516,7 @@ var deriveConfigChecks = [deriveConfigValid];
|
|
|
39818
40516
|
// src/utils/doctor/checks/staleness.ts
|
|
39819
40517
|
init_config2();
|
|
39820
40518
|
import { resolve as resolve92 } from "path";
|
|
39821
|
-
import { readFile as
|
|
40519
|
+
import { readFile as readFile64 } from "fs/promises";
|
|
39822
40520
|
var CATEGORY15 = "staleness";
|
|
39823
40521
|
var stalenessConfigValid = {
|
|
39824
40522
|
id: "staleness.valid",
|
|
@@ -39827,7 +40525,7 @@ var stalenessConfigValid = {
|
|
|
39827
40525
|
async run(ctx) {
|
|
39828
40526
|
let content;
|
|
39829
40527
|
try {
|
|
39830
|
-
content = await
|
|
40528
|
+
content = await readFile64(resolve92(ctx.syntaurRoot, "config.md"), "utf-8");
|
|
39831
40529
|
} catch {
|
|
39832
40530
|
return {
|
|
39833
40531
|
id: this.id,
|
|
@@ -39977,14 +40675,14 @@ async function finalize(checks) {
|
|
|
39977
40675
|
async function readVersion() {
|
|
39978
40676
|
try {
|
|
39979
40677
|
const here = fileURLToPath12(import.meta.url);
|
|
39980
|
-
let dir =
|
|
40678
|
+
let dir = dirname26(here);
|
|
39981
40679
|
for (let i = 0; i < 6; i++) {
|
|
39982
40680
|
try {
|
|
39983
|
-
const raw2 = await
|
|
40681
|
+
const raw2 = await readFile65(join24(dir, "package.json"), "utf-8");
|
|
39984
40682
|
const parsed = JSON.parse(raw2);
|
|
39985
40683
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
39986
40684
|
} catch {
|
|
39987
|
-
dir =
|
|
40685
|
+
dir = dirname26(dir);
|
|
39988
40686
|
}
|
|
39989
40687
|
}
|
|
39990
40688
|
return null;
|
|
@@ -40077,7 +40775,7 @@ var REQUIRED_WORKSPACE_FIELDS = [
|
|
|
40077
40775
|
];
|
|
40078
40776
|
var ISO_DATE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
|
|
40079
40777
|
async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
|
|
40080
|
-
const absolute =
|
|
40778
|
+
const absolute = isAbsolute12(inputPath) ? inputPath : resolve93(cwd, inputPath);
|
|
40081
40779
|
const errors = [];
|
|
40082
40780
|
const warnings = [];
|
|
40083
40781
|
if (!await fileExists(absolute)) {
|
|
@@ -40090,7 +40788,7 @@ async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
|
|
|
40090
40788
|
}
|
|
40091
40789
|
let content;
|
|
40092
40790
|
try {
|
|
40093
|
-
content = await
|
|
40791
|
+
content = await readFile66(absolute, "utf-8");
|
|
40094
40792
|
} catch (err2) {
|
|
40095
40793
|
return {
|
|
40096
40794
|
ok: false,
|
|
@@ -40218,6 +40916,7 @@ note: ${FIX_NOOP_NOTE}
|
|
|
40218
40916
|
init_config2();
|
|
40219
40917
|
init_paths();
|
|
40220
40918
|
import { Command as Command5 } from "commander";
|
|
40919
|
+
import { readFile as readFile67 } from "fs/promises";
|
|
40221
40920
|
var agentsCommand = new Command5("agents").description(
|
|
40222
40921
|
"Manage configurable agents used by `syntaur browse` and future launch flows"
|
|
40223
40922
|
);
|
|
@@ -40237,6 +40936,8 @@ agentsCommand.command("list").description("List configured agents (or built-in d
|
|
|
40237
40936
|
if (agent.launchPrompt) flags.push(`launchPrompt=${truncateForList(agent.launchPrompt)}`);
|
|
40238
40937
|
if (agent.agentName) flags.push(`agentName=${agent.agentName}`);
|
|
40239
40938
|
if (agent.workdir) flags.push(`workdir=${truncateForList(agent.workdir)}`);
|
|
40939
|
+
if (agent.runner) flags.push(`runner=${agent.runner}`);
|
|
40940
|
+
if (agent.sourcePath) flags.push(`source=${truncateForList(agent.sourcePath)}`);
|
|
40240
40941
|
const flagStr = flags.length > 0 ? ` [${flags.join(", ")}]` : "";
|
|
40241
40942
|
const args = agent.args && agent.args.length > 0 ? ` ${agent.args.join(" ")}` : "";
|
|
40242
40943
|
console.log(` ${agent.id.padEnd(12)} ${agent.label.padEnd(20)} ${agent.command}${args}${flagStr}`);
|
|
@@ -40266,6 +40967,48 @@ agentsCommand.command("add").description("Add a new agent to ~/.syntaur/config.m
|
|
|
40266
40967
|
reportAndExit(error);
|
|
40267
40968
|
}
|
|
40268
40969
|
});
|
|
40970
|
+
async function readInstructions(spec) {
|
|
40971
|
+
if (!spec) return "";
|
|
40972
|
+
if (spec.startsWith("@")) return readFile67(expandHome(spec.slice(1)), "utf-8");
|
|
40973
|
+
return spec;
|
|
40974
|
+
}
|
|
40975
|
+
agentsCommand.command("new").description("Author a runner-native agent def on disk and register it").requiredOption("--name <name>", "Display name").requiredOption("--type <runner>", "Runner: claude | pi | codex").option("--model <model>", "Model (claude agent frontmatter)").option("--description <text>", "One-line description").option("--instructions <text|@file>", "System prompt / instructions body, or @path to read from a file").option("--location <path>", "claude: agents dir (default ~/.claude/agents); directory: parent dir to scaffold under").option("--dry-run", "Author the def but do not register it").action(async (options) => {
|
|
40976
|
+
try {
|
|
40977
|
+
const runner = options.type;
|
|
40978
|
+
if (runner !== "claude" && runner !== "pi" && runner !== "codex") {
|
|
40979
|
+
throw new AgentConfigError(`invalid --type "${options.type}" \u2014 must be claude, pi, or codex`);
|
|
40980
|
+
}
|
|
40981
|
+
const instructions = await readInstructions(options.instructions);
|
|
40982
|
+
const authored = await authorAgentDef({
|
|
40983
|
+
name: options.name,
|
|
40984
|
+
runner,
|
|
40985
|
+
model: options.model,
|
|
40986
|
+
description: options.description,
|
|
40987
|
+
instructions,
|
|
40988
|
+
location: options.location
|
|
40989
|
+
});
|
|
40990
|
+
console.log(`Authored ${runner} def at ${authored.path}`);
|
|
40991
|
+
if (options.dryRun) {
|
|
40992
|
+
console.log("(dry-run: not registered)");
|
|
40993
|
+
return;
|
|
40994
|
+
}
|
|
40995
|
+
const config = await readConfig();
|
|
40996
|
+
const base = getAgents(config);
|
|
40997
|
+
const agent = buildRegisteredAgent({
|
|
40998
|
+
name: options.name,
|
|
40999
|
+
runner,
|
|
41000
|
+
sourceKind: authored.sourceKind,
|
|
41001
|
+
sourcePath: authored.path,
|
|
41002
|
+
sourceRepo: authored.sourceRepo,
|
|
41003
|
+
description: options.description,
|
|
41004
|
+
existingIds: base.map((a) => a.id)
|
|
41005
|
+
});
|
|
41006
|
+
await writeAgentsConfig([...base, agent]);
|
|
41007
|
+
console.log(`Registered agent "${agent.id}" (${runner}).`);
|
|
41008
|
+
} catch (error) {
|
|
41009
|
+
reportAndExit(error);
|
|
41010
|
+
}
|
|
41011
|
+
});
|
|
40269
41012
|
agentsCommand.command("remove <id>").description("Remove an agent from ~/.syntaur/config.md").option("--dry-run", "Validate and print the proposed config without writing").action(async (id, options) => {
|
|
40270
41013
|
try {
|
|
40271
41014
|
const mutation = {
|
|
@@ -40505,7 +41248,7 @@ init_frontmatter();
|
|
|
40505
41248
|
init_event_emit();
|
|
40506
41249
|
init_templates();
|
|
40507
41250
|
import { resolve as resolve94 } from "path";
|
|
40508
|
-
import { readFile as
|
|
41251
|
+
import { readFile as readFile68 } from "fs/promises";
|
|
40509
41252
|
function shortId() {
|
|
40510
41253
|
return generateId().split("-")[0];
|
|
40511
41254
|
}
|
|
@@ -40554,7 +41297,7 @@ async function commentCommand(target, text, options = {}) {
|
|
|
40554
41297
|
let currentContent;
|
|
40555
41298
|
let currentCount = 0;
|
|
40556
41299
|
if (await fileExists(commentsPath)) {
|
|
40557
|
-
currentContent = await
|
|
41300
|
+
currentContent = await readFile68(commentsPath, "utf-8");
|
|
40558
41301
|
const countMatch = currentContent.match(/^entryCount:\s*(\d+)/m);
|
|
40559
41302
|
if (countMatch) currentCount = parseInt(countMatch[1], 10);
|
|
40560
41303
|
} else {
|
|
@@ -40584,7 +41327,7 @@ ${entry}`;
|
|
|
40584
41327
|
try {
|
|
40585
41328
|
const assignmentMd = resolve94(assignmentDir, "assignment.md");
|
|
40586
41329
|
if (await fileExists(assignmentMd)) {
|
|
40587
|
-
const fm = parseAssignmentFrontmatter(await
|
|
41330
|
+
const fm = parseAssignmentFrontmatter(await readFile68(assignmentMd, "utf-8"));
|
|
40588
41331
|
emitEvent({
|
|
40589
41332
|
assignmentId: fm.id,
|
|
40590
41333
|
projectSlug,
|
|
@@ -40608,8 +41351,8 @@ ${entry}`;
|
|
|
40608
41351
|
}
|
|
40609
41352
|
|
|
40610
41353
|
// src/commands/capture.ts
|
|
40611
|
-
import { resolve as resolve97, relative as relative4, dirname as
|
|
40612
|
-
import { copyFile as copyFile3, mkdir as
|
|
41354
|
+
import { resolve as resolve97, relative as relative4, dirname as dirname27 } from "path";
|
|
41355
|
+
import { copyFile as copyFile3, mkdir as mkdir13, realpath as realpath2, rm as rm14, stat as stat15, writeFile as writeFile16 } from "fs/promises";
|
|
40613
41356
|
import { existsSync as existsSync7 } from "fs";
|
|
40614
41357
|
init_session_id();
|
|
40615
41358
|
init_session_db();
|
|
@@ -40618,9 +41361,9 @@ init_fs();
|
|
|
40618
41361
|
|
|
40619
41362
|
// src/utils/screencapture.ts
|
|
40620
41363
|
import { spawn as spawn8 } from "child_process";
|
|
40621
|
-
import { mkdtemp as mkdtemp2, rm as rm10, stat as
|
|
41364
|
+
import { mkdtemp as mkdtemp2, rm as rm10, stat as stat13 } from "fs/promises";
|
|
40622
41365
|
import { tmpdir as tmpdir3 } from "os";
|
|
40623
|
-
import { join as
|
|
41366
|
+
import { join as join25 } from "path";
|
|
40624
41367
|
function argsFor(mode, pngPath) {
|
|
40625
41368
|
switch (mode) {
|
|
40626
41369
|
case "interactive":
|
|
@@ -40653,8 +41396,8 @@ async function captureScreenshot(mode) {
|
|
|
40653
41396
|
"screencapture is only available on macOS. Use --file <path> to attach an existing image."
|
|
40654
41397
|
);
|
|
40655
41398
|
}
|
|
40656
|
-
const tmpDir = await mkdtemp2(
|
|
40657
|
-
const pngPath =
|
|
41399
|
+
const tmpDir = await mkdtemp2(join25(tmpdir3(), "syntaur-screenshot-"));
|
|
41400
|
+
const pngPath = join25(tmpDir, "shot.png");
|
|
40658
41401
|
const cleanup = async () => {
|
|
40659
41402
|
await rm10(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
40660
41403
|
});
|
|
@@ -40676,7 +41419,7 @@ async function captureScreenshot(mode) {
|
|
|
40676
41419
|
}
|
|
40677
41420
|
let size = 0;
|
|
40678
41421
|
try {
|
|
40679
|
-
size = (await
|
|
41422
|
+
size = (await stat13(pngPath)).size;
|
|
40680
41423
|
} catch {
|
|
40681
41424
|
throw new Error("screencapture exited 0 but produced no image.");
|
|
40682
41425
|
}
|
|
@@ -40692,9 +41435,9 @@ async function captureScreenshot(mode) {
|
|
|
40692
41435
|
|
|
40693
41436
|
// src/utils/asciinema.ts
|
|
40694
41437
|
import { spawn as spawn9 } from "child_process";
|
|
40695
|
-
import { mkdtemp as mkdtemp3, readFile as
|
|
41438
|
+
import { mkdtemp as mkdtemp3, readFile as readFile69, rm as rm11 } from "fs/promises";
|
|
40696
41439
|
import { tmpdir as tmpdir4 } from "os";
|
|
40697
|
-
import { join as
|
|
41440
|
+
import { join as join26 } from "path";
|
|
40698
41441
|
var SAFE_RE = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
40699
41442
|
function shellQuote2(s) {
|
|
40700
41443
|
if (s.length === 0) return `''`;
|
|
@@ -40731,8 +41474,8 @@ function runAsciinema(args, stdio) {
|
|
|
40731
41474
|
});
|
|
40732
41475
|
}
|
|
40733
41476
|
async function captureAsciinema(opts) {
|
|
40734
|
-
const tmpDir = await mkdtemp3(
|
|
40735
|
-
const castPath =
|
|
41477
|
+
const tmpDir = await mkdtemp3(join26(tmpdir4(), "syntaur-asciinema-"));
|
|
41478
|
+
const castPath = join26(tmpDir, "session.cast");
|
|
40736
41479
|
const cleanup = async () => {
|
|
40737
41480
|
await rm11(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
40738
41481
|
});
|
|
@@ -40755,7 +41498,7 @@ async function captureAsciinema(opts) {
|
|
|
40755
41498
|
}
|
|
40756
41499
|
throw err2;
|
|
40757
41500
|
}
|
|
40758
|
-
const text = await
|
|
41501
|
+
const text = await readFile69(castPath, "utf8").catch(() => null);
|
|
40759
41502
|
if (text === null) {
|
|
40760
41503
|
throw new Error(
|
|
40761
41504
|
`asciinema produced no cast file at ${castPath} (exit ${exitCode}). Try running 'asciinema rec ${castPath}' directly to diagnose.`
|
|
@@ -40783,9 +41526,9 @@ async function captureAsciinema(opts) {
|
|
|
40783
41526
|
// src/utils/recording.ts
|
|
40784
41527
|
init_paths();
|
|
40785
41528
|
import { spawn as spawn10 } from "child_process";
|
|
40786
|
-
import { mkdir as
|
|
41529
|
+
import { mkdir as mkdir12, mkdtemp as mkdtemp4, open as open6, readFile as readFile70, rm as rm12, stat as stat14, unlink as unlink12, writeFile as writeFile15 } from "fs/promises";
|
|
40787
41530
|
import { tmpdir as tmpdir5 } from "os";
|
|
40788
|
-
import { join as
|
|
41531
|
+
import { join as join27, resolve as resolve95 } from "path";
|
|
40789
41532
|
import { setTimeout as sleep } from "timers/promises";
|
|
40790
41533
|
function sigintPollIntervalMs() {
|
|
40791
41534
|
const raw2 = process.env.SYNTAUR_RECORDING_POLL_INTERVAL_MS;
|
|
@@ -40857,7 +41600,7 @@ async function acquirePidfile(pidfile) {
|
|
|
40857
41600
|
} catch (err2) {
|
|
40858
41601
|
if (err2.code !== "EEXIST") throw err2;
|
|
40859
41602
|
if (attempt === 1) throw err2;
|
|
40860
|
-
const existing = (await
|
|
41603
|
+
const existing = (await readFile70(pidfile, "utf-8").catch(() => "")).trim();
|
|
40861
41604
|
if (existing.startsWith(STARTING_SENTINEL_PREFIX)) {
|
|
40862
41605
|
const parentPidRaw = existing.slice(STARTING_SENTINEL_PREFIX.length);
|
|
40863
41606
|
const parentPid = Number.parseInt(parentPidRaw, 10);
|
|
@@ -40899,7 +41642,7 @@ async function startRecording(input4) {
|
|
|
40899
41642
|
);
|
|
40900
41643
|
}
|
|
40901
41644
|
const root = syntaurRoot();
|
|
40902
|
-
await
|
|
41645
|
+
await mkdir12(root, { recursive: true });
|
|
40903
41646
|
const pidfile = pidfilePath();
|
|
40904
41647
|
const log = logPath2();
|
|
40905
41648
|
const sidecar = sidecarPath();
|
|
@@ -40910,8 +41653,8 @@ async function startRecording(input4) {
|
|
|
40910
41653
|
let acquiredPid = null;
|
|
40911
41654
|
try {
|
|
40912
41655
|
logHandle = await open6(log, "w");
|
|
40913
|
-
tmpDir = await mkdtemp4(
|
|
40914
|
-
const mp4Path =
|
|
41656
|
+
tmpDir = await mkdtemp4(join27(tmpdir5(), "syntaur-recording-"));
|
|
41657
|
+
const mp4Path = join27(tmpDir, "recording.mp4");
|
|
40915
41658
|
let child;
|
|
40916
41659
|
try {
|
|
40917
41660
|
child = spawn10("ffmpeg", ffmpegArgs(input4.device, input4.fps, mp4Path), {
|
|
@@ -40954,12 +41697,12 @@ async function startRecording(input4) {
|
|
|
40954
41697
|
const pid = await pidReady;
|
|
40955
41698
|
acquiredPid = pid;
|
|
40956
41699
|
child.unref();
|
|
40957
|
-
await
|
|
41700
|
+
await writeFile15(pidfile, String(pid));
|
|
40958
41701
|
await logHandle.close();
|
|
40959
41702
|
logHandle = null;
|
|
40960
41703
|
if (warmupMs > 0) await sleep(warmupMs);
|
|
40961
41704
|
if (!await isProcessAlive(pid)) {
|
|
40962
|
-
const tail = await
|
|
41705
|
+
const tail = await readFile70(log, "utf-8").then((s) => s.split("\n").slice(-20).join("\n")).catch(() => "");
|
|
40963
41706
|
acquiredPid = null;
|
|
40964
41707
|
throw new Error(
|
|
40965
41708
|
`ffmpeg exited during startup \u2014 likely macOS Screen Recording permission missing. Grant access to your terminal in System Settings \u2192 Privacy & Security \u2192 Screen Recording, then retry. Log: ${log}
|
|
@@ -40982,7 +41725,7 @@ ${tail}`
|
|
|
40982
41725
|
device: input4.device,
|
|
40983
41726
|
fps: input4.fps
|
|
40984
41727
|
};
|
|
40985
|
-
await
|
|
41728
|
+
await writeFile15(sidecar, JSON.stringify(sidecarData, null, 2));
|
|
40986
41729
|
return {
|
|
40987
41730
|
pid,
|
|
40988
41731
|
logPath: log,
|
|
@@ -41016,7 +41759,7 @@ ${tail}`
|
|
|
41016
41759
|
async function stopRecording() {
|
|
41017
41760
|
const pidfile = pidfilePath();
|
|
41018
41761
|
const sidecar = sidecarPath();
|
|
41019
|
-
const pidRaw = await
|
|
41762
|
+
const pidRaw = await readFile70(pidfile, "utf-8").catch(() => null);
|
|
41020
41763
|
if (pidRaw === null) {
|
|
41021
41764
|
throw new Error(
|
|
41022
41765
|
`No active recording found (no pidfile at ${pidfile}). Did you run --start?`
|
|
@@ -41026,7 +41769,7 @@ async function stopRecording() {
|
|
|
41026
41769
|
if (!Number.isInteger(pid) || pid <= 0) {
|
|
41027
41770
|
throw new Error(`Pidfile at ${pidfile} is corrupt (got "${pidRaw}").`);
|
|
41028
41771
|
}
|
|
41029
|
-
const sidecarRaw = await
|
|
41772
|
+
const sidecarRaw = await readFile70(sidecar, "utf-8").catch(() => null);
|
|
41030
41773
|
if (sidecarRaw === null) {
|
|
41031
41774
|
throw new Error(
|
|
41032
41775
|
`No recording sidecar at ${sidecar}. The recording state is inconsistent \u2014 delete ${pidfile} and re-run --start.`
|
|
@@ -41071,7 +41814,7 @@ async function stopRecording() {
|
|
|
41071
41814
|
if (alive) {
|
|
41072
41815
|
throw new Error(`ffmpeg (PID ${pid}) refused to die after SIGKILL`);
|
|
41073
41816
|
}
|
|
41074
|
-
const st = await
|
|
41817
|
+
const st = await stat14(sidecarData.mp4Path).catch(() => null);
|
|
41075
41818
|
if (st === null || st.size === 0) {
|
|
41076
41819
|
await unlink12(pidfile).catch(() => {
|
|
41077
41820
|
});
|
|
@@ -41159,9 +41902,9 @@ function listArtifactsByAssignment(assignmentId) {
|
|
|
41159
41902
|
|
|
41160
41903
|
// src/utils/transcribers/elevenlabs.ts
|
|
41161
41904
|
import { spawn as spawn11 } from "child_process";
|
|
41162
|
-
import { mkdtemp as mkdtemp5, readFile as
|
|
41905
|
+
import { mkdtemp as mkdtemp5, readFile as readFile71, rm as rm13 } from "fs/promises";
|
|
41163
41906
|
import { tmpdir as tmpdir6 } from "os";
|
|
41164
|
-
import { join as
|
|
41907
|
+
import { join as join28 } from "path";
|
|
41165
41908
|
var SCRIBE_URL = "https://api.elevenlabs.io/v1/speech-to-text";
|
|
41166
41909
|
var NO_AUDIO_MARKERS = [
|
|
41167
41910
|
"Stream map '0:a:0' matches no streams",
|
|
@@ -41223,7 +41966,7 @@ async function extractAudio(videoAbsPath, wavOut) {
|
|
|
41223
41966
|
throw new TranscribeFfmpegError(`ffmpeg failed (exit ${result.code}): ${tail}`);
|
|
41224
41967
|
}
|
|
41225
41968
|
async function callScribe(wavPath, apiKey, opts) {
|
|
41226
|
-
const audio = await
|
|
41969
|
+
const audio = await readFile71(wavPath);
|
|
41227
41970
|
const form = new FormData();
|
|
41228
41971
|
form.set("file", new Blob([new Uint8Array(audio)], { type: "audio/wav" }), "audio.wav");
|
|
41229
41972
|
form.set("model_id", "scribe_v1");
|
|
@@ -41251,8 +41994,8 @@ var elevenLabsScribe = {
|
|
|
41251
41994
|
"ELEVENLABS_API_KEY is not set. Export it (e.g. `export ELEVENLABS_API_KEY=\u2026`) and re-run. A config-file slot will land later."
|
|
41252
41995
|
);
|
|
41253
41996
|
}
|
|
41254
|
-
const tmp = await mkdtemp5(
|
|
41255
|
-
const wav =
|
|
41997
|
+
const tmp = await mkdtemp5(join28(tmpdir6(), "syntaur-transcribe-"));
|
|
41998
|
+
const wav = join28(tmp, "audio.wav");
|
|
41256
41999
|
try {
|
|
41257
42000
|
await extractAudio(videoAbsPath, wav);
|
|
41258
42001
|
return await callScribe(wav, apiKey, opts);
|
|
@@ -41538,7 +42281,7 @@ async function captureCommand(target, options = {}) {
|
|
|
41538
42281
|
criterionIndex = sidecar.criterionIndex;
|
|
41539
42282
|
stopNote = sidecar.note;
|
|
41540
42283
|
resolvedSource = mp4Path;
|
|
41541
|
-
const mp4TmpDir =
|
|
42284
|
+
const mp4TmpDir = dirname27(mp4Path);
|
|
41542
42285
|
shelloutCleanup = async () => {
|
|
41543
42286
|
await rm14(mp4TmpDir, { recursive: true, force: true }).catch(() => {
|
|
41544
42287
|
});
|
|
@@ -41559,7 +42302,7 @@ async function captureCommand(target, options = {}) {
|
|
|
41559
42302
|
`--file is unreadable: ${options.file} (${e instanceof Error ? e.message : String(e)})`
|
|
41560
42303
|
);
|
|
41561
42304
|
}
|
|
41562
|
-
const st = await
|
|
42305
|
+
const st = await stat15(real);
|
|
41563
42306
|
if (!st.isFile()) {
|
|
41564
42307
|
throw new Error(`--file is not a regular file: ${options.file}`);
|
|
41565
42308
|
}
|
|
@@ -41589,7 +42332,7 @@ async function captureCommand(target, options = {}) {
|
|
|
41589
42332
|
initProofDb();
|
|
41590
42333
|
const subdir = criterionIndex === null ? "untagged" : String(criterionIndex);
|
|
41591
42334
|
const destDir = resolve97(proofDir(resolved.assignmentDir), subdir);
|
|
41592
|
-
if (resolvedSource) await
|
|
42335
|
+
if (resolvedSource) await mkdir13(destDir, { recursive: true });
|
|
41593
42336
|
const ext = resolvedSource ? extensionForKind(kind) : null;
|
|
41594
42337
|
let id = null;
|
|
41595
42338
|
let relativeFilePath = null;
|
|
@@ -41650,7 +42393,7 @@ async function captureCommand(target, options = {}) {
|
|
|
41650
42393
|
try {
|
|
41651
42394
|
const json = await getTranscriber().transcribe(absPath);
|
|
41652
42395
|
const md = renderMarkdown(groupIntoPhrases(json.words ?? []));
|
|
41653
|
-
await
|
|
42396
|
+
await writeFile16(sidecarPath2, md, "utf8");
|
|
41654
42397
|
console.log(`transcript: ${sidecarPath2}`);
|
|
41655
42398
|
} catch (err2) {
|
|
41656
42399
|
if (err2 instanceof TranscribeFfmpegMissingError) {
|
|
@@ -41696,8 +42439,8 @@ async function captureCommand(target, options = {}) {
|
|
|
41696
42439
|
|
|
41697
42440
|
// src/commands/proof.ts
|
|
41698
42441
|
import { Command as Command6 } from "commander";
|
|
41699
|
-
import { readFile as
|
|
41700
|
-
import { resolve as resolve98, relative as relative5, isAbsolute as
|
|
42442
|
+
import { readFile as readFile72, writeFile as writeFile17, rename as rename10, stat as stat16 } from "fs/promises";
|
|
42443
|
+
import { resolve as resolve98, relative as relative5, isAbsolute as isAbsolute13, dirname as dirname28 } from "path";
|
|
41701
42444
|
import { randomBytes as randomBytes4 } from "crypto";
|
|
41702
42445
|
|
|
41703
42446
|
// src/utils/acceptance-criteria-parse.ts
|
|
@@ -41941,7 +42684,7 @@ async function readAssignmentMeta(assignmentDir) {
|
|
|
41941
42684
|
if (!await fileExists(path)) {
|
|
41942
42685
|
return { title: "", body: "" };
|
|
41943
42686
|
}
|
|
41944
|
-
const content = await
|
|
42687
|
+
const content = await readFile72(path, "utf-8");
|
|
41945
42688
|
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
41946
42689
|
let title = "";
|
|
41947
42690
|
if (fmMatch) {
|
|
@@ -41955,12 +42698,12 @@ async function readAssignmentMeta(assignmentDir) {
|
|
|
41955
42698
|
}
|
|
41956
42699
|
async function atomicWrite(destPath, content) {
|
|
41957
42700
|
const tmp = `${destPath}.${randomBytes4(4).toString("hex")}.tmp`;
|
|
41958
|
-
await
|
|
42701
|
+
await writeFile17(tmp, content, "utf-8");
|
|
41959
42702
|
await rename10(tmp, destPath);
|
|
41960
42703
|
}
|
|
41961
42704
|
function isWithin(root, target) {
|
|
41962
42705
|
const rel = relative5(root, target);
|
|
41963
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
42706
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute13(rel);
|
|
41964
42707
|
}
|
|
41965
42708
|
function groupArtifacts(rows, criterionCount) {
|
|
41966
42709
|
const artifactsByCriterion = /* @__PURE__ */ new Map();
|
|
@@ -41997,13 +42740,13 @@ async function loadInlineFiles(rows, assignmentDir) {
|
|
|
41997
42740
|
out.set(r.file_path, null);
|
|
41998
42741
|
continue;
|
|
41999
42742
|
}
|
|
42000
|
-
const st = await
|
|
42743
|
+
const st = await stat16(abs);
|
|
42001
42744
|
if (st.size > INLINE_TEXT_LIMIT_BYTES) {
|
|
42002
42745
|
out.set(r.file_path, null);
|
|
42003
42746
|
continue;
|
|
42004
42747
|
}
|
|
42005
42748
|
try {
|
|
42006
|
-
out.set(r.file_path, await
|
|
42749
|
+
out.set(r.file_path, await readFile72(abs, "utf-8"));
|
|
42007
42750
|
} catch {
|
|
42008
42751
|
out.set(r.file_path, null);
|
|
42009
42752
|
}
|
|
@@ -42016,13 +42759,13 @@ async function loadTranscriptSidecars(rows, assignmentDir) {
|
|
|
42016
42759
|
for (const r of rows) {
|
|
42017
42760
|
if (r.kind !== "video" || !r.file_path) continue;
|
|
42018
42761
|
const videoAbs = resolve98(assignmentDir, r.file_path);
|
|
42019
|
-
const sidecar = resolve98(
|
|
42762
|
+
const sidecar = resolve98(dirname28(videoAbs), `${r.id}.transcript.md`);
|
|
42020
42763
|
if (!isWithin(proofRoot, sidecar)) continue;
|
|
42021
42764
|
if (!await fileExists(sidecar)) continue;
|
|
42022
|
-
const st = await
|
|
42765
|
+
const st = await stat16(sidecar);
|
|
42023
42766
|
if (st.size > INLINE_TEXT_LIMIT_BYTES) continue;
|
|
42024
42767
|
try {
|
|
42025
|
-
out.set(r.id, await
|
|
42768
|
+
out.set(r.id, await readFile72(sidecar, "utf-8"));
|
|
42026
42769
|
} catch {
|
|
42027
42770
|
}
|
|
42028
42771
|
}
|
|
@@ -42918,7 +43661,7 @@ init_timestamp();
|
|
|
42918
43661
|
init_assignment_resolver();
|
|
42919
43662
|
init_assignment_todos();
|
|
42920
43663
|
import { resolve as resolve100 } from "path";
|
|
42921
|
-
import { readFile as
|
|
43664
|
+
import { readFile as readFile73 } from "fs/promises";
|
|
42922
43665
|
async function requestCommand(target, text, options = {}) {
|
|
42923
43666
|
if (!text || !text.trim()) {
|
|
42924
43667
|
throw new Error("Request text cannot be empty.");
|
|
@@ -42949,7 +43692,7 @@ async function requestCommand(target, text, options = {}) {
|
|
|
42949
43692
|
throw new Error(`assignment.md not found at ${assignmentMdPath2}`);
|
|
42950
43693
|
}
|
|
42951
43694
|
const source = options.from ?? process.env.SYNTAUR_ASSIGNMENT ?? "unknown";
|
|
42952
|
-
let content = await
|
|
43695
|
+
let content = await readFile73(assignmentMdPath2, "utf-8");
|
|
42953
43696
|
content = appendTodosToAssignmentBody(content, [
|
|
42954
43697
|
{ description: `${text.trim()} (from: ${source})` }
|
|
42955
43698
|
]);
|
|
@@ -42964,7 +43707,7 @@ init_paths();
|
|
|
42964
43707
|
init_config2();
|
|
42965
43708
|
init_recompute();
|
|
42966
43709
|
import { Command as Command10 } from "commander";
|
|
42967
|
-
import { readFile as
|
|
43710
|
+
import { readFile as readFile74, readdir as readdir36 } from "fs/promises";
|
|
42968
43711
|
import { resolve as resolve101 } from "path";
|
|
42969
43712
|
init_session_id();
|
|
42970
43713
|
async function resolveAssignmentDir(opts) {
|
|
@@ -42991,7 +43734,7 @@ async function resolveAssignmentDir(opts) {
|
|
|
42991
43734
|
var PLAN_PATTERN = /^plan(?:-v(\d+))?\.md$/;
|
|
42992
43735
|
async function listPlanFiles(assignmentDir) {
|
|
42993
43736
|
if (!await fileExists(assignmentDir)) return [];
|
|
42994
|
-
const entries = await
|
|
43737
|
+
const entries = await readdir36(assignmentDir, { withFileTypes: true });
|
|
42995
43738
|
const out = [];
|
|
42996
43739
|
for (const e of entries) {
|
|
42997
43740
|
if (!e.isFile()) continue;
|
|
@@ -43186,7 +43929,7 @@ async function runPlanCreate(options) {
|
|
|
43186
43929
|
"plan.md already exists. Use --force to overwrite, or `syntaur plan version` to create the next version."
|
|
43187
43930
|
);
|
|
43188
43931
|
}
|
|
43189
|
-
const assignmentMd = await
|
|
43932
|
+
const assignmentMd = await readFile74(assignmentMdPath2, "utf-8");
|
|
43190
43933
|
const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
|
|
43191
43934
|
const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
|
|
43192
43935
|
await writeFileForce(planPath, buildInitialPlanStub(slug));
|
|
@@ -43223,11 +43966,11 @@ async function runPlanVersion(options) {
|
|
|
43223
43966
|
if (await fileExists(newPath) && !options.force) {
|
|
43224
43967
|
throw new Error(`${next.fileName} already exists. Use --force to overwrite.`);
|
|
43225
43968
|
}
|
|
43226
|
-
const assignmentMd = await
|
|
43969
|
+
const assignmentMd = await readFile74(assignmentMdPath2, "utf-8");
|
|
43227
43970
|
const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
|
|
43228
43971
|
const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
|
|
43229
43972
|
const oldPlanPath = resolve101(assignmentDir, current.fileName);
|
|
43230
|
-
const oldPlanContent = await
|
|
43973
|
+
const oldPlanContent = await readFile74(oldPlanPath, "utf-8");
|
|
43231
43974
|
const oldBody = oldPlanContent.replace(/^---[\s\S]*?\n---\n?/, "");
|
|
43232
43975
|
const carriedTodos = extractUncheckedTodos(oldBody);
|
|
43233
43976
|
const stub = buildNewPlanStub({
|
|
@@ -43298,7 +44041,7 @@ init_cwd();
|
|
|
43298
44041
|
init_session_db();
|
|
43299
44042
|
init_agent_sessions();
|
|
43300
44043
|
import { Command as Command11 } from "commander";
|
|
43301
|
-
import { readFile as
|
|
44044
|
+
import { readFile as readFile75, readdir as readdir37, stat as stat17 } from "fs/promises";
|
|
43302
44045
|
import { resolve as resolve102 } from "path";
|
|
43303
44046
|
init_engagement_db();
|
|
43304
44047
|
init_parser();
|
|
@@ -43306,7 +44049,7 @@ async function readContext(cwd) {
|
|
|
43306
44049
|
const path = resolve102(cwd, ".syntaur", "context.json");
|
|
43307
44050
|
if (!await fileExists(path)) return null;
|
|
43308
44051
|
try {
|
|
43309
|
-
const raw2 = await
|
|
44052
|
+
const raw2 = await readFile75(path, "utf-8");
|
|
43310
44053
|
return JSON.parse(raw2);
|
|
43311
44054
|
} catch {
|
|
43312
44055
|
return null;
|
|
@@ -43315,13 +44058,13 @@ async function readContext(cwd) {
|
|
|
43315
44058
|
async function findLatestSessionSummary(assignmentDir) {
|
|
43316
44059
|
const sessionsRoot = resolve102(assignmentDir, "sessions");
|
|
43317
44060
|
if (!await fileExists(sessionsRoot)) return null;
|
|
43318
|
-
const entries = await
|
|
44061
|
+
const entries = await readdir37(sessionsRoot, { withFileTypes: true });
|
|
43319
44062
|
let best = null;
|
|
43320
44063
|
for (const entry of entries) {
|
|
43321
44064
|
if (!entry.isDirectory()) continue;
|
|
43322
44065
|
const summaryPath = resolve102(sessionsRoot, entry.name, "summary.md");
|
|
43323
44066
|
if (!await fileExists(summaryPath)) continue;
|
|
43324
|
-
const st = await
|
|
44067
|
+
const st = await stat17(summaryPath);
|
|
43325
44068
|
if (best === null || st.mtime.getTime() > best.mtime.getTime()) {
|
|
43326
44069
|
best = { sessionId: entry.name, path: summaryPath, mtime: st.mtime };
|
|
43327
44070
|
}
|
|
@@ -43331,7 +44074,7 @@ async function findLatestSessionSummary(assignmentDir) {
|
|
|
43331
44074
|
async function findOpenHandoff(assignmentDir) {
|
|
43332
44075
|
const handoffPath = resolve102(assignmentDir, "handoff.md");
|
|
43333
44076
|
if (!await fileExists(handoffPath)) return null;
|
|
43334
|
-
const content = await
|
|
44077
|
+
const content = await readFile75(handoffPath, "utf-8");
|
|
43335
44078
|
const body = content.replace(/^---[\s\S]*?\n---\n?/, "").trim();
|
|
43336
44079
|
if (body.length === 0) return null;
|
|
43337
44080
|
if (/^<!--[\s\S]*-->$/.test(body)) return null;
|
|
@@ -43341,7 +44084,7 @@ async function readAssignmentTitle(assignmentDir) {
|
|
|
43341
44084
|
const path = resolve102(assignmentDir, "assignment.md");
|
|
43342
44085
|
if (!await fileExists(path)) return null;
|
|
43343
44086
|
try {
|
|
43344
|
-
const content = await
|
|
44087
|
+
const content = await readFile75(path, "utf-8");
|
|
43345
44088
|
const [fm] = extractFrontmatter(content);
|
|
43346
44089
|
return getField(fm, "title");
|
|
43347
44090
|
} catch {
|
|
@@ -43558,13 +44301,13 @@ async function runSessionSave(options, cwd = process.cwd(), body) {
|
|
|
43558
44301
|
const now = nowTimestamp();
|
|
43559
44302
|
let created = now;
|
|
43560
44303
|
if (await fileExists(summaryPath)) {
|
|
43561
|
-
const existing = await
|
|
44304
|
+
const existing = await readFile75(summaryPath, "utf-8");
|
|
43562
44305
|
created = extractCreated(existing) ?? now;
|
|
43563
44306
|
}
|
|
43564
44307
|
let sectionBody2 = body;
|
|
43565
44308
|
if (sectionBody2 === void 0) {
|
|
43566
44309
|
if (options.fromFile) {
|
|
43567
|
-
sectionBody2 = await
|
|
44310
|
+
sectionBody2 = await readFile75(resolve102(cwd, options.fromFile), "utf-8");
|
|
43568
44311
|
} else {
|
|
43569
44312
|
sectionBody2 = await readStdin();
|
|
43570
44313
|
}
|
|
@@ -43792,7 +44535,7 @@ sessionCommand.command("boundary").description(
|
|
|
43792
44535
|
// src/commands/worktree.ts
|
|
43793
44536
|
init_git_worktree();
|
|
43794
44537
|
import { Command as Command12 } from "commander";
|
|
43795
|
-
import { readFile as
|
|
44538
|
+
import { readFile as readFile76 } from "fs/promises";
|
|
43796
44539
|
import { resolve as resolve103 } from "path";
|
|
43797
44540
|
init_fs();
|
|
43798
44541
|
init_paths();
|
|
@@ -43882,7 +44625,7 @@ async function runWorktreeRemove(options, cwd = process.cwd()) {
|
|
|
43882
44625
|
if (!await fileExists(assignmentPath)) {
|
|
43883
44626
|
throw new Error(`Assignment file not found: ${assignmentPath}`);
|
|
43884
44627
|
}
|
|
43885
|
-
const original = await
|
|
44628
|
+
const original = await readFile76(assignmentPath, "utf-8");
|
|
43886
44629
|
const fm = parseAssignmentFrontmatter(original);
|
|
43887
44630
|
const repository = options.repository ?? fm.workspace.repository ?? void 0;
|
|
43888
44631
|
const worktreePath = fm.workspace.worktreePath ?? void 0;
|
|
@@ -43948,7 +44691,7 @@ async function runWorktreeGc(options, cwd = process.cwd()) {
|
|
|
43948
44691
|
const owners = /* @__PURE__ */ new Map();
|
|
43949
44692
|
for (const entry of walk.withAssignmentMd) {
|
|
43950
44693
|
try {
|
|
43951
|
-
const content = await
|
|
44694
|
+
const content = await readFile76(resolve103(entry.assignmentDir, "assignment.md"), "utf-8");
|
|
43952
44695
|
const fm = parseAssignmentFrontmatter(content);
|
|
43953
44696
|
const wp = fm.workspace?.worktreePath;
|
|
43954
44697
|
if (!wp) continue;
|
|
@@ -44189,7 +44932,7 @@ worktreeCommand.command("gc").description(
|
|
|
44189
44932
|
// src/commands/open.ts
|
|
44190
44933
|
init_fs();
|
|
44191
44934
|
import { Command as Command13 } from "commander";
|
|
44192
|
-
import { readFile as
|
|
44935
|
+
import { readFile as readFile77 } from "fs/promises";
|
|
44193
44936
|
import { resolve as resolve104 } from "path";
|
|
44194
44937
|
init_frontmatter();
|
|
44195
44938
|
init_config2();
|
|
@@ -44255,7 +44998,7 @@ async function runOpen(assignmentArg, options) {
|
|
|
44255
44998
|
remediation: "check the assignment slug or --id"
|
|
44256
44999
|
});
|
|
44257
45000
|
}
|
|
44258
|
-
const fm = parseAssignmentFrontmatter(await
|
|
45001
|
+
const fm = parseAssignmentFrontmatter(await readFile77(assignmentPath, "utf-8"));
|
|
44259
45002
|
const worktreePath = fm.workspace?.worktreePath;
|
|
44260
45003
|
if (!worktreePath) {
|
|
44261
45004
|
throw new SyntaurError("No worktree recorded for this assignment.", {
|
|
@@ -44321,12 +45064,12 @@ init_fs();
|
|
|
44321
45064
|
init_slug();
|
|
44322
45065
|
import { Command as Command14 } from "commander";
|
|
44323
45066
|
import { resolve as resolve106 } from "path";
|
|
44324
|
-
import { readFile as
|
|
45067
|
+
import { readFile as readFile79, readdir as readdir39, rm as rm15 } from "fs/promises";
|
|
44325
45068
|
|
|
44326
45069
|
// src/utils/project-indexes.ts
|
|
44327
45070
|
init_parser();
|
|
44328
45071
|
init_fs();
|
|
44329
|
-
import { readdir as
|
|
45072
|
+
import { readdir as readdir38, readFile as readFile78 } from "fs/promises";
|
|
44330
45073
|
import { resolve as resolve105 } from "path";
|
|
44331
45074
|
function nowIso3() {
|
|
44332
45075
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
@@ -44336,7 +45079,7 @@ function readProjectSlug(projectDir) {
|
|
|
44336
45079
|
}
|
|
44337
45080
|
async function listSlugFiles(dir) {
|
|
44338
45081
|
if (!await fileExists(dir)) return [];
|
|
44339
|
-
const entries = await
|
|
45082
|
+
const entries = await readdir38(dir, { withFileTypes: true });
|
|
44340
45083
|
return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && !e.name.startsWith("_")).map((e) => e.name).sort();
|
|
44341
45084
|
}
|
|
44342
45085
|
function escapeCell(value) {
|
|
@@ -44362,7 +45105,7 @@ async function rebuildResourcesIndex(projectDir) {
|
|
|
44362
45105
|
lines.push("| Name | Category | Source | Related Assignments | Updated |");
|
|
44363
45106
|
lines.push("|------|----------|--------|---------------------|---------|");
|
|
44364
45107
|
for (const fileName of files) {
|
|
44365
|
-
const content = await
|
|
45108
|
+
const content = await readFile78(resolve105(dir, fileName), "utf-8");
|
|
44366
45109
|
const parsed = parseResource(content);
|
|
44367
45110
|
const slugBase = fileName.replace(/\.md$/, "");
|
|
44368
45111
|
const name = parsed.name || slugBase;
|
|
@@ -44393,7 +45136,7 @@ async function rebuildMemoriesIndex(projectDir) {
|
|
|
44393
45136
|
lines.push("| Name | Source | Scope | Source Assignment | Updated |");
|
|
44394
45137
|
lines.push("|------|--------|-------|-------------------|---------|");
|
|
44395
45138
|
for (const fileName of files) {
|
|
44396
|
-
const content = await
|
|
45139
|
+
const content = await readFile78(resolve105(dir, fileName), "utf-8");
|
|
44397
45140
|
const parsed = parseMemory(content);
|
|
44398
45141
|
const slugBase = fileName.replace(/\.md$/, "");
|
|
44399
45142
|
const name = parsed.name || slugBase;
|
|
@@ -44500,7 +45243,7 @@ async function runResourceAdd(options) {
|
|
|
44500
45243
|
async function listResourceSlugs(projectDir) {
|
|
44501
45244
|
const dir = resolve106(projectDir, "resources");
|
|
44502
45245
|
if (!await fileExists(dir)) return [];
|
|
44503
|
-
const entries = await
|
|
45246
|
+
const entries = await readdir39(dir, { withFileTypes: true });
|
|
44504
45247
|
return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_index.md").map((e) => e.name.slice(0, -3)).sort();
|
|
44505
45248
|
}
|
|
44506
45249
|
async function runResourceList(project) {
|
|
@@ -44508,7 +45251,7 @@ async function runResourceList(project) {
|
|
|
44508
45251
|
const slugs = await listResourceSlugs(projectDir);
|
|
44509
45252
|
const out = [];
|
|
44510
45253
|
for (const slug of slugs) {
|
|
44511
|
-
const parsed = parseResource(await
|
|
45254
|
+
const parsed = parseResource(await readFile79(resolve106(projectDir, "resources", `${slug}.md`), "utf-8"));
|
|
44512
45255
|
out.push({ slug, name: parsed.name, category: parsed.category, source: parsed.source, updated: parsed.updated });
|
|
44513
45256
|
}
|
|
44514
45257
|
return out;
|
|
@@ -44517,7 +45260,7 @@ async function runResourceShow(project, slug) {
|
|
|
44517
45260
|
const projectDir = await resolveProjectDir(project);
|
|
44518
45261
|
const filePath = resolve106(projectDir, "resources", `${slug}.md`);
|
|
44519
45262
|
if (!await fileExists(filePath)) throw new Error(`Resource "${slug}" not found in project "${project}".`);
|
|
44520
|
-
const parsed = parseResource(await
|
|
45263
|
+
const parsed = parseResource(await readFile79(filePath, "utf-8"));
|
|
44521
45264
|
return {
|
|
44522
45265
|
slug,
|
|
44523
45266
|
name: parsed.name,
|
|
@@ -44538,7 +45281,7 @@ async function runResourceUpdate(slug, options) {
|
|
|
44538
45281
|
if (options.name === void 0 && options.source === void 0 && options.category === void 0 && options.relatedAssignments === void 0) {
|
|
44539
45282
|
throw new Error("Provide at least one of --name, --source, --category, --related-assignments.");
|
|
44540
45283
|
}
|
|
44541
|
-
const original = await
|
|
45284
|
+
const original = await readFile79(filePath, "utf-8");
|
|
44542
45285
|
const content = editResourceFrontmatter(original, {
|
|
44543
45286
|
name: options.name,
|
|
44544
45287
|
category: options.category,
|
|
@@ -44635,7 +45378,7 @@ init_fs();
|
|
|
44635
45378
|
init_slug();
|
|
44636
45379
|
import { Command as Command15 } from "commander";
|
|
44637
45380
|
import { resolve as resolve107 } from "path";
|
|
44638
|
-
import { readFile as
|
|
45381
|
+
import { readFile as readFile80, readdir as readdir40, rm as rm16 } from "fs/promises";
|
|
44639
45382
|
init_parser();
|
|
44640
45383
|
function nowIso5() {
|
|
44641
45384
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
@@ -44733,7 +45476,7 @@ async function runMemoryAdd(options) {
|
|
|
44733
45476
|
async function listMemorySlugs(projectDir) {
|
|
44734
45477
|
const dir = resolve107(projectDir, "memories");
|
|
44735
45478
|
if (!await fileExists(dir)) return [];
|
|
44736
|
-
const entries = await
|
|
45479
|
+
const entries = await readdir40(dir, { withFileTypes: true });
|
|
44737
45480
|
return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_index.md").map((e) => e.name.slice(0, -3)).sort();
|
|
44738
45481
|
}
|
|
44739
45482
|
async function runMemoryList(project) {
|
|
@@ -44741,7 +45484,7 @@ async function runMemoryList(project) {
|
|
|
44741
45484
|
const slugs = await listMemorySlugs(projectDir);
|
|
44742
45485
|
const out = [];
|
|
44743
45486
|
for (const slug of slugs) {
|
|
44744
|
-
const parsed = parseMemory(await
|
|
45487
|
+
const parsed = parseMemory(await readFile80(resolve107(projectDir, "memories", `${slug}.md`), "utf-8"));
|
|
44745
45488
|
out.push({ slug, name: parsed.name, scope: parsed.scope, source: parsed.source, updated: parsed.updated });
|
|
44746
45489
|
}
|
|
44747
45490
|
return out;
|
|
@@ -44750,7 +45493,7 @@ async function runMemoryShow(project, slug) {
|
|
|
44750
45493
|
const projectDir = await resolveProjectDir2(project);
|
|
44751
45494
|
const filePath = resolve107(projectDir, "memories", `${slug}.md`);
|
|
44752
45495
|
if (!await fileExists(filePath)) throw new Error(`Memory "${slug}" not found in project "${project}".`);
|
|
44753
|
-
const parsed = parseMemory(await
|
|
45496
|
+
const parsed = parseMemory(await readFile80(filePath, "utf-8"));
|
|
44754
45497
|
return {
|
|
44755
45498
|
slug,
|
|
44756
45499
|
name: parsed.name,
|
|
@@ -44774,7 +45517,7 @@ async function runMemoryUpdate(slug, options) {
|
|
|
44774
45517
|
"Provide at least one of --name, --source, --scope, --source-assignment, --related-assignments."
|
|
44775
45518
|
);
|
|
44776
45519
|
}
|
|
44777
|
-
const original = await
|
|
45520
|
+
const original = await readFile80(filePath, "utf-8");
|
|
44778
45521
|
const content = editMemoryFrontmatter(original, {
|
|
44779
45522
|
name: options.name,
|
|
44780
45523
|
source: options.source,
|
|
@@ -44877,8 +45620,8 @@ init_derive();
|
|
|
44877
45620
|
init_recompute();
|
|
44878
45621
|
init_query();
|
|
44879
45622
|
import { Command as Command16 } from "commander";
|
|
44880
|
-
import { readFile as
|
|
44881
|
-
import { dirname as
|
|
45623
|
+
import { readFile as readFile81 } from "fs/promises";
|
|
45624
|
+
import { dirname as dirname30, resolve as resolve108 } from "path";
|
|
44882
45625
|
var AGE_PATTERN = /^(\d+)([dhwm])$/i;
|
|
44883
45626
|
function parseAgeToCutoff(age) {
|
|
44884
45627
|
const match = age.match(AGE_PATTERN);
|
|
@@ -44911,7 +45654,7 @@ async function loadTags(item) {
|
|
|
44911
45654
|
const path = assignmentMdPath(item);
|
|
44912
45655
|
if (!await fileExists(path)) return [];
|
|
44913
45656
|
try {
|
|
44914
|
-
const content = await
|
|
45657
|
+
const content = await readFile81(path, "utf-8");
|
|
44915
45658
|
return parseAssignmentFrontmatter(content).tags;
|
|
44916
45659
|
} catch {
|
|
44917
45660
|
return [];
|
|
@@ -44975,10 +45718,10 @@ async function loadQueryItem(item, terminalStatuses3, now, declarations) {
|
|
|
44975
45718
|
const path = assignmentMdPath(item);
|
|
44976
45719
|
if (!await fileExists(path)) return null;
|
|
44977
45720
|
try {
|
|
44978
|
-
const content = await
|
|
45721
|
+
const content = await readFile81(path, "utf-8");
|
|
44979
45722
|
const fm = parseAssignmentFrontmatter(content);
|
|
44980
45723
|
const body = content.replace(/^---\n[\s\S]*?\n---/, "");
|
|
44981
|
-
const assignmentDir =
|
|
45724
|
+
const assignmentDir = dirname30(path);
|
|
44982
45725
|
const projectDir = item.projectSlug ? resolve108(defaultProjectDir(), item.projectSlug) : null;
|
|
44983
45726
|
const facts = await computeFacts({ assignmentDir, frontmatter: fm, body, projectDir, terminalStatuses: terminalStatuses3, declarations });
|
|
44984
45727
|
const history = fm.statusHistory;
|
|
@@ -45754,7 +46497,7 @@ init_fs();
|
|
|
45754
46497
|
init_timestamp();
|
|
45755
46498
|
init_frontmatter();
|
|
45756
46499
|
import { Command as Command21 } from "commander";
|
|
45757
|
-
import { readFile as
|
|
46500
|
+
import { readFile as readFile82 } from "fs/promises";
|
|
45758
46501
|
import { resolve as resolve109 } from "path";
|
|
45759
46502
|
function renameAssignmentStatusRefs(content, id, newId, now) {
|
|
45760
46503
|
const fm = parseAssignmentFrontmatter(content);
|
|
@@ -45781,7 +46524,7 @@ function configPath() {
|
|
|
45781
46524
|
async function readStatusBlock() {
|
|
45782
46525
|
const p = configPath();
|
|
45783
46526
|
if (!await fileExists(p)) return null;
|
|
45784
|
-
const content = await
|
|
46527
|
+
const content = await readFile82(p, "utf-8");
|
|
45785
46528
|
return parseStatusConfig(content);
|
|
45786
46529
|
}
|
|
45787
46530
|
async function requireStatusBlock() {
|
|
@@ -46065,7 +46808,7 @@ async function runStatusRename(id, opts) {
|
|
|
46065
46808
|
printBlockDiff(before, after);
|
|
46066
46809
|
const now2 = nowTimestamp();
|
|
46067
46810
|
for (const a of affected) {
|
|
46068
|
-
const original = await
|
|
46811
|
+
const original = await readFile82(a.path, "utf-8");
|
|
46069
46812
|
const rewritten = renameAssignmentStatusRefs(original, id, newId, now2);
|
|
46070
46813
|
console.log(`
|
|
46071
46814
|
--- ${a.display}/assignment.md`);
|
|
@@ -46076,9 +46819,9 @@ async function runStatusRename(id, opts) {
|
|
|
46076
46819
|
}
|
|
46077
46820
|
const cfgPath = configPath();
|
|
46078
46821
|
const buffers = /* @__PURE__ */ new Map();
|
|
46079
|
-
buffers.set(cfgPath, await fileExists(cfgPath) ? await
|
|
46822
|
+
buffers.set(cfgPath, await fileExists(cfgPath) ? await readFile82(cfgPath, "utf-8") : "");
|
|
46080
46823
|
for (const a of affected) {
|
|
46081
|
-
buffers.set(a.path, await
|
|
46824
|
+
buffers.set(a.path, await readFile82(a.path, "utf-8"));
|
|
46082
46825
|
}
|
|
46083
46826
|
const now = nowTimestamp();
|
|
46084
46827
|
try {
|
|
@@ -46280,7 +47023,7 @@ init_config2();
|
|
|
46280
47023
|
init_timestamp();
|
|
46281
47024
|
init_frontmatter();
|
|
46282
47025
|
import { Command as Command22 } from "commander";
|
|
46283
|
-
import { readFile as
|
|
47026
|
+
import { readFile as readFile83 } from "fs/promises";
|
|
46284
47027
|
import { resolve as resolve110 } from "path";
|
|
46285
47028
|
init_session_id();
|
|
46286
47029
|
async function resolveAssignmentPath3(opts) {
|
|
@@ -46336,7 +47079,7 @@ async function runWorkspaceSet(options, cwd = process.cwd()) {
|
|
|
46336
47079
|
${pre.errors.map((e) => ` - ${e}`).join("\n")}`
|
|
46337
47080
|
);
|
|
46338
47081
|
}
|
|
46339
|
-
const original = await
|
|
47082
|
+
const original = await readFile83(path, "utf-8");
|
|
46340
47083
|
let next = updateAssignmentWorkspace(original, partial);
|
|
46341
47084
|
next = updateAssignmentFile(next, { updated: nowTimestamp() });
|
|
46342
47085
|
await writeFileForce(path, next);
|
|
@@ -46373,7 +47116,7 @@ init_config2();
|
|
|
46373
47116
|
init_timestamp();
|
|
46374
47117
|
init_templates();
|
|
46375
47118
|
import { Command as Command23 } from "commander";
|
|
46376
|
-
import { readFile as
|
|
47119
|
+
import { readFile as readFile84 } from "fs/promises";
|
|
46377
47120
|
import { resolve as resolve111 } from "path";
|
|
46378
47121
|
init_session_id();
|
|
46379
47122
|
async function resolveAssignmentDir2(opts) {
|
|
@@ -46457,7 +47200,7 @@ async function runProgressLog(text, options, cwd = process.cwd()) {
|
|
|
46457
47200
|
}
|
|
46458
47201
|
const path = resolve111(dir, "progress.md");
|
|
46459
47202
|
const now = nowTimestamp();
|
|
46460
|
-
const content = await fileExists(path) ? await
|
|
47203
|
+
const content = await fileExists(path) ? await readFile84(path, "utf-8") : renderProgress({ assignment: slug, timestamp: now });
|
|
46461
47204
|
const next = appendProgressEntry(content, text, now);
|
|
46462
47205
|
await writeFileForce(path, next);
|
|
46463
47206
|
return path;
|
|
@@ -46477,10 +47220,10 @@ progressCommand.command("log").description("Append a timestamped entry to the as
|
|
|
46477
47220
|
|
|
46478
47221
|
// src/cli-default-command.ts
|
|
46479
47222
|
init_config2();
|
|
46480
|
-
import { readdir as
|
|
47223
|
+
import { readdir as readdir41 } from "fs/promises";
|
|
46481
47224
|
async function hasAnyProjectContent(projectsDir2) {
|
|
46482
47225
|
try {
|
|
46483
|
-
const entries = await
|
|
47226
|
+
const entries = await readdir41(projectsDir2, { withFileTypes: true });
|
|
46484
47227
|
return entries.some((entry) => entry.isDirectory());
|
|
46485
47228
|
} catch {
|
|
46486
47229
|
return false;
|