syntaur 0.24.0 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dashboard/server.js +164 -129
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.js +984 -546
- package/dist/index.js.map +1 -1
- package/dist/launch/index.d.ts +3 -0
- package/dist/launch/index.js +69 -40
- package/dist/launch/index.js.map +1 -1
- package/package.json +1 -1
- package/platforms/README.md +29 -1
- package/scripts/install-macos-url-handler.mjs +14 -1
package/dist/index.js
CHANGED
|
@@ -93,9 +93,10 @@ __export(fs_exports, {
|
|
|
93
93
|
ensureDir: () => ensureDir,
|
|
94
94
|
fileExists: () => fileExists,
|
|
95
95
|
writeFileForce: () => writeFileForce,
|
|
96
|
+
writeFileReport: () => writeFileReport,
|
|
96
97
|
writeFileSafe: () => writeFileSafe
|
|
97
98
|
});
|
|
98
|
-
import { mkdir, writeFile, access, rename } from "fs/promises";
|
|
99
|
+
import { mkdir, writeFile, readFile, access, rename } from "fs/promises";
|
|
99
100
|
import { dirname, join } from "path";
|
|
100
101
|
async function ensureDir(dir) {
|
|
101
102
|
await mkdir(dir, { recursive: true });
|
|
@@ -126,6 +127,22 @@ async function writeFileForce(filePath, content) {
|
|
|
126
127
|
await writeFile(tempPath, content, "utf-8");
|
|
127
128
|
await rename(tempPath, filePath);
|
|
128
129
|
}
|
|
130
|
+
async function writeFileReport(filePath, content, options = {}) {
|
|
131
|
+
if (!await fileExists(filePath)) {
|
|
132
|
+
await ensureDir(dirname(filePath));
|
|
133
|
+
await writeFile(filePath, content, "utf-8");
|
|
134
|
+
return "written";
|
|
135
|
+
}
|
|
136
|
+
const current = await readFile(filePath, "utf-8").catch(() => null);
|
|
137
|
+
if (current === content) {
|
|
138
|
+
return "already-current";
|
|
139
|
+
}
|
|
140
|
+
if (!options.force) {
|
|
141
|
+
return "differs-preserved";
|
|
142
|
+
}
|
|
143
|
+
await writeFileForce(filePath, content);
|
|
144
|
+
return "overwritten";
|
|
145
|
+
}
|
|
129
146
|
var init_fs = __esm({
|
|
130
147
|
"src/utils/fs.ts"() {
|
|
131
148
|
"use strict";
|
|
@@ -471,7 +488,7 @@ var init_timestamp = __esm({
|
|
|
471
488
|
});
|
|
472
489
|
|
|
473
490
|
// src/utils/fs-migration.ts
|
|
474
|
-
import { readdir, readFile, rename as rename2, writeFile as writeFile2 } from "fs/promises";
|
|
491
|
+
import { readdir, readFile as readFile2, rename as rename2, writeFile as writeFile2 } from "fs/promises";
|
|
475
492
|
import { resolve as resolve2 } from "path";
|
|
476
493
|
async function migrateLegacyProjectFiles(projectsDir2) {
|
|
477
494
|
const result = {
|
|
@@ -540,7 +557,7 @@ async function migrateLegacyArchivedProjects(projectsDir2) {
|
|
|
540
557
|
const projectMd = resolve2(projectsDir2, entry.name, "project.md");
|
|
541
558
|
try {
|
|
542
559
|
if (!await fileExists(projectMd)) continue;
|
|
543
|
-
const content = await
|
|
560
|
+
const content = await readFile2(projectMd, "utf-8");
|
|
544
561
|
if (readFrontmatterField(content, "statusOverride") !== "archived") continue;
|
|
545
562
|
let next = setFrontmatterField(content, "archived", true);
|
|
546
563
|
if (readFrontmatterField(content, "archivedAt") === null) {
|
|
@@ -565,7 +582,7 @@ async function migrateLegacyConfig(configPath) {
|
|
|
565
582
|
if (!await fileExists(configPath)) return result;
|
|
566
583
|
let content;
|
|
567
584
|
try {
|
|
568
|
-
content = await
|
|
585
|
+
content = await readFile2(configPath, "utf-8");
|
|
569
586
|
} catch {
|
|
570
587
|
return result;
|
|
571
588
|
}
|
|
@@ -822,7 +839,7 @@ __export(config_exports, {
|
|
|
822
839
|
writeTerminalConfig: () => writeTerminalConfig,
|
|
823
840
|
writeThemeConfig: () => writeThemeConfig
|
|
824
841
|
});
|
|
825
|
-
import { readFile as
|
|
842
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
826
843
|
import { spawnSync } from "child_process";
|
|
827
844
|
import { resolve as resolve3, isAbsolute } from "path";
|
|
828
845
|
function parseAgentCommand(value, agentId) {
|
|
@@ -950,6 +967,18 @@ function parseFrontmatter(content) {
|
|
|
950
967
|
}
|
|
951
968
|
return result;
|
|
952
969
|
}
|
|
970
|
+
function parseInstalledAgents(fm) {
|
|
971
|
+
const prefix = "integrations.installedAgents.";
|
|
972
|
+
const installedAgents = {};
|
|
973
|
+
for (const [key, value] of Object.entries(fm)) {
|
|
974
|
+
if (!key.startsWith(prefix)) continue;
|
|
975
|
+
const id = key.slice(prefix.length);
|
|
976
|
+
if (!id) continue;
|
|
977
|
+
const scope = value === "project" ? "project" : "global";
|
|
978
|
+
installedAgents[id] = { scope };
|
|
979
|
+
}
|
|
980
|
+
return Object.keys(installedAgents).length > 0 ? { installedAgents } : {};
|
|
981
|
+
}
|
|
953
982
|
function parseStatusConfig(content) {
|
|
954
983
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
955
984
|
if (!match) return null;
|
|
@@ -1079,6 +1108,11 @@ function serializeIntegrationConfig(integrations) {
|
|
|
1079
1108
|
if (integrations.codexMarketplacePath) {
|
|
1080
1109
|
lines.push(` codexMarketplacePath: ${integrations.codexMarketplacePath}`);
|
|
1081
1110
|
}
|
|
1111
|
+
if (integrations.installedAgents) {
|
|
1112
|
+
for (const [id, rec] of Object.entries(integrations.installedAgents)) {
|
|
1113
|
+
lines.push(` installedAgents.${id}: ${rec.scope}`);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1082
1116
|
if (lines.length === 0) {
|
|
1083
1117
|
return null;
|
|
1084
1118
|
}
|
|
@@ -1147,7 +1181,7 @@ async function updatePlaybooksConfig(playbooks) {
|
|
|
1147
1181
|
disabled: Array.from(new Set(playbooks.disabled ?? current.disabled))
|
|
1148
1182
|
};
|
|
1149
1183
|
const playbooksBlock = serializePlaybooksConfig(nextPlaybooks);
|
|
1150
|
-
const existing = await fileExists(configPath) ? await
|
|
1184
|
+
const existing = await fileExists(configPath) ? await readFile3(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
|
|
1151
1185
|
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
1152
1186
|
if (!fmMatch) {
|
|
1153
1187
|
const bodyBlock = playbooksBlock ? `${playbooksBlock}
|
|
@@ -1199,7 +1233,7 @@ function serializeThemeConfig(theme) {
|
|
|
1199
1233
|
async function writeThemeConfig(theme) {
|
|
1200
1234
|
const configPath = resolve3(syntaurRoot(), "config.md");
|
|
1201
1235
|
const themeBlock = serializeThemeConfig(theme);
|
|
1202
|
-
const existing = await fileExists(configPath) ? await
|
|
1236
|
+
const existing = await fileExists(configPath) ? await readFile3(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
|
|
1203
1237
|
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
1204
1238
|
if (!fmMatch) {
|
|
1205
1239
|
const content = `---
|
|
@@ -1225,7 +1259,7 @@ ${normalizedFm}
|
|
|
1225
1259
|
async function deleteThemeConfig() {
|
|
1226
1260
|
const configPath = resolve3(syntaurRoot(), "config.md");
|
|
1227
1261
|
if (!await fileExists(configPath)) return;
|
|
1228
|
-
const existing = await
|
|
1262
|
+
const existing = await readFile3(configPath, "utf-8");
|
|
1229
1263
|
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
1230
1264
|
if (!fmMatch) return;
|
|
1231
1265
|
const fmBlock = fmMatch[2];
|
|
@@ -1245,7 +1279,7 @@ function stripTopLevelScalar(fmBlock, key) {
|
|
|
1245
1279
|
async function writeTerminalConfig(terminal) {
|
|
1246
1280
|
const configPath = resolve3(syntaurRoot(), "config.md");
|
|
1247
1281
|
const terminalLine = `terminal: ${terminal}`;
|
|
1248
|
-
const existing = await fileExists(configPath) ? await
|
|
1282
|
+
const existing = await fileExists(configPath) ? await readFile3(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
|
|
1249
1283
|
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
1250
1284
|
if (!fmMatch) {
|
|
1251
1285
|
const content = `---
|
|
@@ -1271,7 +1305,7 @@ ${normalizedFm}
|
|
|
1271
1305
|
async function deleteTerminalConfig() {
|
|
1272
1306
|
const configPath = resolve3(syntaurRoot(), "config.md");
|
|
1273
1307
|
if (!await fileExists(configPath)) return;
|
|
1274
|
-
const existing = await
|
|
1308
|
+
const existing = await readFile3(configPath, "utf-8");
|
|
1275
1309
|
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
1276
1310
|
if (!fmMatch) return;
|
|
1277
1311
|
const fmBlock = fmMatch[2];
|
|
@@ -1340,7 +1374,7 @@ async function writeHotkeyBindingsConfig(cfg) {
|
|
|
1340
1374
|
}
|
|
1341
1375
|
const configPath = resolve3(syntaurRoot(), "config.md");
|
|
1342
1376
|
const block = serializeHotkeyBindingsConfig({ bindings: cleaned });
|
|
1343
|
-
const existing = await fileExists(configPath) ? await
|
|
1377
|
+
const existing = await fileExists(configPath) ? await readFile3(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
|
|
1344
1378
|
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
1345
1379
|
if (!fmMatch) {
|
|
1346
1380
|
const content = `---
|
|
@@ -1366,7 +1400,7 @@ ${normalizedFm}
|
|
|
1366
1400
|
async function deleteHotkeyBindingsConfig() {
|
|
1367
1401
|
const configPath = resolve3(syntaurRoot(), "config.md");
|
|
1368
1402
|
if (!await fileExists(configPath)) return;
|
|
1369
|
-
const existing = await
|
|
1403
|
+
const existing = await readFile3(configPath, "utf-8");
|
|
1370
1404
|
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
1371
1405
|
if (!fmMatch) return;
|
|
1372
1406
|
const fmBlock = fmMatch[2];
|
|
@@ -1683,7 +1717,7 @@ async function writeAgentsConfig(agents) {
|
|
|
1683
1717
|
validateAgentList(agents);
|
|
1684
1718
|
const configPath = resolve3(syntaurRoot(), "config.md");
|
|
1685
1719
|
const agentsBlock = serializeAgentsConfig(agents);
|
|
1686
|
-
const existing = await fileExists(configPath) ? await
|
|
1720
|
+
const existing = await fileExists(configPath) ? await readFile3(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
|
|
1687
1721
|
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
1688
1722
|
if (!fmMatch) {
|
|
1689
1723
|
const content = `---
|
|
@@ -1708,7 +1742,7 @@ ${newFm}
|
|
|
1708
1742
|
async function deleteAgentsConfig() {
|
|
1709
1743
|
const configPath = resolve3(syntaurRoot(), "config.md");
|
|
1710
1744
|
if (!await fileExists(configPath)) return;
|
|
1711
|
-
const existing = await
|
|
1745
|
+
const existing = await readFile3(configPath, "utf-8");
|
|
1712
1746
|
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
1713
1747
|
if (!fmMatch) return;
|
|
1714
1748
|
const fmBlock = fmMatch[2];
|
|
@@ -1732,7 +1766,7 @@ ${statusBlock}
|
|
|
1732
1766
|
await writeFileForce(configPath, content);
|
|
1733
1767
|
return;
|
|
1734
1768
|
}
|
|
1735
|
-
const existing = await
|
|
1769
|
+
const existing = await readFile3(configPath, "utf-8");
|
|
1736
1770
|
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
1737
1771
|
if (!fmMatch) {
|
|
1738
1772
|
const content = `---
|
|
@@ -1776,7 +1810,7 @@ ${statusBlock}
|
|
|
1776
1810
|
async function deleteStatusConfig() {
|
|
1777
1811
|
const configPath = resolve3(syntaurRoot(), "config.md");
|
|
1778
1812
|
if (!await fileExists(configPath)) return;
|
|
1779
|
-
const existing = await
|
|
1813
|
+
const existing = await readFile3(configPath, "utf-8");
|
|
1780
1814
|
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
1781
1815
|
if (!fmMatch) return;
|
|
1782
1816
|
const fmBlock = fmMatch[2];
|
|
@@ -1794,7 +1828,7 @@ async function updateIntegrationConfig(integrations) {
|
|
|
1794
1828
|
...integrations
|
|
1795
1829
|
};
|
|
1796
1830
|
const integrationBlock = serializeIntegrationConfig(nextIntegrations);
|
|
1797
|
-
const existing = await fileExists(configPath) ? await
|
|
1831
|
+
const existing = await fileExists(configPath) ? await readFile3(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
|
|
1798
1832
|
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
1799
1833
|
if (!fmMatch) {
|
|
1800
1834
|
const content = `---
|
|
@@ -1824,7 +1858,7 @@ async function updateOnboardingConfig(onboarding) {
|
|
|
1824
1858
|
...onboarding
|
|
1825
1859
|
};
|
|
1826
1860
|
const onboardingBlock = serializeOnboardingConfig(nextOnboarding);
|
|
1827
|
-
const existing = await fileExists(configPath) ? await
|
|
1861
|
+
const existing = await fileExists(configPath) ? await readFile3(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
|
|
1828
1862
|
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
1829
1863
|
if (!fmMatch) {
|
|
1830
1864
|
const content = `---
|
|
@@ -1858,7 +1892,7 @@ async function updateBackupConfig(backup) {
|
|
|
1858
1892
|
...backup
|
|
1859
1893
|
};
|
|
1860
1894
|
const backupBlock = serializeBackupConfig(nextBackup);
|
|
1861
|
-
const existing = await fileExists(configPath) ? await
|
|
1895
|
+
const existing = await fileExists(configPath) ? await readFile3(configPath, "utf-8") : renderConfig({ defaultProjectDir: defaultProjectDir() });
|
|
1862
1896
|
const fmMatch = existing.match(/^(---\n)([\s\S]*?)\n(---)/);
|
|
1863
1897
|
if (!fmMatch) {
|
|
1864
1898
|
const content = `---
|
|
@@ -1890,7 +1924,7 @@ async function readConfig() {
|
|
|
1890
1924
|
migratedConfigPaths.add(configPath);
|
|
1891
1925
|
await migrateLegacyConfig(configPath);
|
|
1892
1926
|
}
|
|
1893
|
-
const content = await
|
|
1927
|
+
const content = await readFile3(configPath, "utf-8");
|
|
1894
1928
|
const fm = parseFrontmatter(content);
|
|
1895
1929
|
if (Object.keys(fm).length === 0) {
|
|
1896
1930
|
console.warn("Warning: ~/.syntaur/config.md has malformed frontmatter, using defaults");
|
|
@@ -1929,7 +1963,8 @@ async function readConfig() {
|
|
|
1929
1963
|
codexMarketplacePath: parseOptionalAbsolutePath(
|
|
1930
1964
|
fm["integrations.codexMarketplacePath"],
|
|
1931
1965
|
"integrations.codexMarketplacePath"
|
|
1932
|
-
)
|
|
1966
|
+
),
|
|
1967
|
+
...parseInstalledAgents(fm)
|
|
1933
1968
|
},
|
|
1934
1969
|
backup: fm["backup.repo"] || fm["backup.categories"] ? {
|
|
1935
1970
|
repo: fm["backup.repo"] && fm["backup.repo"] !== "null" ? fm["backup.repo"] : null,
|
|
@@ -2094,7 +2129,7 @@ var init_slug = __esm({
|
|
|
2094
2129
|
|
|
2095
2130
|
// src/utils/playbooks.ts
|
|
2096
2131
|
import { resolve as resolve4 } from "path";
|
|
2097
|
-
import { readdir as readdir2, readFile as
|
|
2132
|
+
import { readdir as readdir2, readFile as readFile4, unlink } from "fs/promises";
|
|
2098
2133
|
function escapeRegExp(value) {
|
|
2099
2134
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2100
2135
|
}
|
|
@@ -2120,7 +2155,7 @@ async function resolvePlaybookSlug(playbooksDir3, slug) {
|
|
|
2120
2155
|
for (const entry of entries) {
|
|
2121
2156
|
if (!isVisiblePlaybookFile(entry.name, entry.isFile())) continue;
|
|
2122
2157
|
const filePath = resolve4(playbooksDir3, entry.name);
|
|
2123
|
-
const raw = await
|
|
2158
|
+
const raw = await readFile4(filePath, "utf-8");
|
|
2124
2159
|
const parsed = parsePlaybook(raw);
|
|
2125
2160
|
const canonical = parsed.slug || entry.name.replace(/\.md$/, "");
|
|
2126
2161
|
if (canonical === slug) {
|
|
@@ -2168,7 +2203,7 @@ async function rebuildPlaybookManifest(playbooksDir3) {
|
|
|
2168
2203
|
const rows = [];
|
|
2169
2204
|
for (const entry of entries) {
|
|
2170
2205
|
if (!isVisiblePlaybookFile(entry.name, entry.isFile())) continue;
|
|
2171
|
-
const raw = await
|
|
2206
|
+
const raw = await readFile4(resolve4(playbooksDir3, entry.name), "utf-8");
|
|
2172
2207
|
const parsed = parsePlaybook(raw);
|
|
2173
2208
|
const slug = parsed.slug || entry.name.replace(/\.md$/, "");
|
|
2174
2209
|
if (disabledSet.has(slug)) continue;
|
|
@@ -2246,7 +2281,7 @@ async function renamePlaybook(playbooksDir3, oldSlug, newSlug) {
|
|
|
2246
2281
|
);
|
|
2247
2282
|
}
|
|
2248
2283
|
}
|
|
2249
|
-
const raw = await
|
|
2284
|
+
const raw = await readFile4(oldPath, "utf-8");
|
|
2250
2285
|
let next = setFrontmatterField2(raw, "slug", newSlug);
|
|
2251
2286
|
next = setFrontmatterField2(next, "updated", `"${nowTimestamp()}"`);
|
|
2252
2287
|
await writeFileForce(newPath, next);
|
|
@@ -3173,6 +3208,24 @@ var init_opencode_config = __esm({
|
|
|
3173
3208
|
}
|
|
3174
3209
|
});
|
|
3175
3210
|
|
|
3211
|
+
// src/templates/hermes-soul.ts
|
|
3212
|
+
function renderHermesSoul(params2) {
|
|
3213
|
+
const body = renderCodexAgents(params2);
|
|
3214
|
+
return `# SOUL -- Syntaur Protocol Operator
|
|
3215
|
+
|
|
3216
|
+
This agent follows the Syntaur protocol for multi-agent project coordination.
|
|
3217
|
+
Hermes loads this file as part of its identity / system context; treat the
|
|
3218
|
+
Write Boundary Rules and Lifecycle sections below as binding.
|
|
3219
|
+
|
|
3220
|
+
${body}`;
|
|
3221
|
+
}
|
|
3222
|
+
var init_hermes_soul = __esm({
|
|
3223
|
+
"src/templates/hermes-soul.ts"() {
|
|
3224
|
+
"use strict";
|
|
3225
|
+
init_codex_agents();
|
|
3226
|
+
}
|
|
3227
|
+
});
|
|
3228
|
+
|
|
3176
3229
|
// src/templates/index.ts
|
|
3177
3230
|
var init_templates = __esm({
|
|
3178
3231
|
"src/templates/index.ts"() {
|
|
@@ -3193,6 +3246,7 @@ var init_templates = __esm({
|
|
|
3193
3246
|
init_cursor_rules();
|
|
3194
3247
|
init_codex_agents();
|
|
3195
3248
|
init_opencode_config();
|
|
3249
|
+
init_hermes_soul();
|
|
3196
3250
|
}
|
|
3197
3251
|
});
|
|
3198
3252
|
|
|
@@ -3745,7 +3799,7 @@ __export(parser_exports, {
|
|
|
3745
3799
|
writeChecklist: () => writeChecklist
|
|
3746
3800
|
});
|
|
3747
3801
|
import { randomBytes } from "crypto";
|
|
3748
|
-
import { readFile as
|
|
3802
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
3749
3803
|
import { resolve as resolve8 } from "path";
|
|
3750
3804
|
function generateShortId() {
|
|
3751
3805
|
return randomBytes(2).toString("hex");
|
|
@@ -4042,7 +4096,7 @@ async function readChecklist(todosDir2, workspace) {
|
|
|
4042
4096
|
if (!await fileExists(path)) {
|
|
4043
4097
|
return { workspace, archiveInterval: "weekly", items: [] };
|
|
4044
4098
|
}
|
|
4045
|
-
const content = await
|
|
4099
|
+
const content = await readFile6(path, "utf-8");
|
|
4046
4100
|
return parseChecklist(content);
|
|
4047
4101
|
}
|
|
4048
4102
|
async function writeChecklist(todosDir2, checklist) {
|
|
@@ -4055,7 +4109,7 @@ async function readLog(todosDir2, workspace) {
|
|
|
4055
4109
|
if (!await fileExists(path)) {
|
|
4056
4110
|
return { workspace, entries: [] };
|
|
4057
4111
|
}
|
|
4058
|
-
const content = await
|
|
4112
|
+
const content = await readFile6(path, "utf-8");
|
|
4059
4113
|
return parseLog(content);
|
|
4060
4114
|
}
|
|
4061
4115
|
async function appendLogEntry(todosDir2, workspace, entry) {
|
|
@@ -4063,7 +4117,7 @@ async function appendLogEntry(todosDir2, workspace, entry) {
|
|
|
4063
4117
|
const path = logPath(todosDir2, workspace);
|
|
4064
4118
|
let content;
|
|
4065
4119
|
if (await fileExists(path)) {
|
|
4066
|
-
content = await
|
|
4120
|
+
content = await readFile6(path, "utf-8");
|
|
4067
4121
|
content = content.trimEnd() + "\n\n" + serializeLogEntry(entry) + "\n";
|
|
4068
4122
|
} else {
|
|
4069
4123
|
const fm = `---
|
|
@@ -4231,7 +4285,7 @@ var init_linked_todos = __esm({
|
|
|
4231
4285
|
|
|
4232
4286
|
// src/lifecycle/transitions.ts
|
|
4233
4287
|
import { resolve as resolve10 } from "path";
|
|
4234
|
-
import { readFile as
|
|
4288
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
4235
4289
|
function linkedAssignmentRef(frontmatter) {
|
|
4236
4290
|
return frontmatter.project ? `${frontmatter.project}/${frontmatter.slug}` : frontmatter.id;
|
|
4237
4291
|
}
|
|
@@ -4251,7 +4305,7 @@ async function readAssignment(filePath) {
|
|
|
4251
4305
|
if (!await fileExists(filePath)) {
|
|
4252
4306
|
throw new Error(`Assignment file not found: ${filePath}`);
|
|
4253
4307
|
}
|
|
4254
|
-
const content = await
|
|
4308
|
+
const content = await readFile7(filePath, "utf-8");
|
|
4255
4309
|
const frontmatter = parseAssignmentFrontmatter(content);
|
|
4256
4310
|
return { content, frontmatter };
|
|
4257
4311
|
}
|
|
@@ -4264,7 +4318,7 @@ async function checkDependencies(projectDir, dependsOn, terminalStatuses3) {
|
|
|
4264
4318
|
unmet.push(`${depSlug} (file not found)`);
|
|
4265
4319
|
continue;
|
|
4266
4320
|
}
|
|
4267
|
-
const depContent = await
|
|
4321
|
+
const depContent = await readFile7(depPath, "utf-8");
|
|
4268
4322
|
const depFrontmatter = parseAssignmentFrontmatter(depContent);
|
|
4269
4323
|
if (!terminals.has(depFrontmatter.status)) {
|
|
4270
4324
|
unmet.push(`${depSlug} (status: ${depFrontmatter.status})`);
|
|
@@ -4417,7 +4471,7 @@ var init_lifecycle = __esm({
|
|
|
4417
4471
|
|
|
4418
4472
|
// src/utils/assignment-resolver.ts
|
|
4419
4473
|
import { resolve as resolve11 } from "path";
|
|
4420
|
-
import { readdir as readdir5, readFile as
|
|
4474
|
+
import { readdir as readdir5, readFile as readFile8 } from "fs/promises";
|
|
4421
4475
|
async function resolveAssignmentById(projectsDir2, assignmentsDir2, id) {
|
|
4422
4476
|
let standaloneMatch = null;
|
|
4423
4477
|
let projectMatch = null;
|
|
@@ -4426,7 +4480,7 @@ async function resolveAssignmentById(projectsDir2, assignmentsDir2, id) {
|
|
|
4426
4480
|
if (await fileExists(standalonePath)) {
|
|
4427
4481
|
let workspaceGroup = null;
|
|
4428
4482
|
try {
|
|
4429
|
-
const content = await
|
|
4483
|
+
const content = await readFile8(standalonePath, "utf-8");
|
|
4430
4484
|
const [fm] = extractFrontmatter(content);
|
|
4431
4485
|
workspaceGroup = getField(fm, "workspaceGroup");
|
|
4432
4486
|
} catch {
|
|
@@ -4454,7 +4508,7 @@ async function resolveAssignmentById(projectsDir2, assignmentsDir2, id) {
|
|
|
4454
4508
|
const aPath = resolve11(assignmentsPath, a.name, "assignment.md");
|
|
4455
4509
|
if (!await fileExists(aPath)) continue;
|
|
4456
4510
|
try {
|
|
4457
|
-
const content = await
|
|
4511
|
+
const content = await readFile8(aPath, "utf-8");
|
|
4458
4512
|
const [fm] = extractFrontmatter(content);
|
|
4459
4513
|
const fileId = getField(fm, "id");
|
|
4460
4514
|
if (fileId === id) {
|
|
@@ -5106,8 +5160,8 @@ async function migrateFromMarkdown(projectsDir2) {
|
|
|
5106
5160
|
return allSessions.length;
|
|
5107
5161
|
}
|
|
5108
5162
|
async function parseMarkdownSessionsIndex(filePath, projectSlug) {
|
|
5109
|
-
const { readFile:
|
|
5110
|
-
const raw = await
|
|
5163
|
+
const { readFile: readFile56 } = await import("fs/promises");
|
|
5164
|
+
const raw = await readFile56(filePath, "utf-8");
|
|
5111
5165
|
const sessions = [];
|
|
5112
5166
|
const lines = raw.split("\n");
|
|
5113
5167
|
let inTable = false;
|
|
@@ -5177,7 +5231,7 @@ CREATE INDEX IF NOT EXISTS idx_sessions_assignment ON sessions(project_slug, ass
|
|
|
5177
5231
|
});
|
|
5178
5232
|
|
|
5179
5233
|
// src/dashboard/agent-sessions.ts
|
|
5180
|
-
import { readFile as
|
|
5234
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
5181
5235
|
import { resolve as resolve13 } from "path";
|
|
5182
5236
|
function rowToSession(row) {
|
|
5183
5237
|
return {
|
|
@@ -5265,7 +5319,7 @@ async function deleteSessions(sessionIds) {
|
|
|
5265
5319
|
}
|
|
5266
5320
|
async function readAssignmentStatusFromPath(assignmentMdPath2) {
|
|
5267
5321
|
if (!await fileExists(assignmentMdPath2)) return null;
|
|
5268
|
-
const raw = await
|
|
5322
|
+
const raw = await readFile9(assignmentMdPath2, "utf-8");
|
|
5269
5323
|
const match = raw.match(/^status:\s*(.+)$/m);
|
|
5270
5324
|
return match ? match[1].trim() : null;
|
|
5271
5325
|
}
|
|
@@ -5350,7 +5404,7 @@ var init_overviewCopy = __esm({
|
|
|
5350
5404
|
});
|
|
5351
5405
|
|
|
5352
5406
|
// src/dashboard/servers.ts
|
|
5353
|
-
import { readdir as readdir7, readFile as
|
|
5407
|
+
import { readdir as readdir7, readFile as readFile10, unlink as unlink2 } from "fs/promises";
|
|
5354
5408
|
import { resolve as resolve14 } from "path";
|
|
5355
5409
|
function sanitizeSessionName(name) {
|
|
5356
5410
|
return name.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
@@ -5410,7 +5464,7 @@ async function listSessionFiles(dir) {
|
|
|
5410
5464
|
async function readSessionFile(dir, name) {
|
|
5411
5465
|
const filePath = resolve14(dir, `${sanitizeSessionName(name)}.md`);
|
|
5412
5466
|
if (!await fileExists(filePath)) return null;
|
|
5413
|
-
const raw = await
|
|
5467
|
+
const raw = await readFile10(filePath, "utf-8");
|
|
5414
5468
|
const [frontmatter] = extractFrontmatter(raw);
|
|
5415
5469
|
if (!frontmatter) return null;
|
|
5416
5470
|
const session = getField(frontmatter, "session") ?? name;
|
|
@@ -5539,8 +5593,8 @@ function scanKey(serversDir2, projectsDir2, assignmentsDir2) {
|
|
|
5539
5593
|
return `${serversDir2}\0${projectsDir2}\0${assignmentsDir2 ?? ""}`;
|
|
5540
5594
|
}
|
|
5541
5595
|
function delay(ms) {
|
|
5542
|
-
return new Promise((
|
|
5543
|
-
const timer2 = setTimeout(
|
|
5596
|
+
return new Promise((resolve82) => {
|
|
5597
|
+
const timer2 = setTimeout(resolve82, ms);
|
|
5544
5598
|
if (typeof timer2.unref === "function") {
|
|
5545
5599
|
timer2.unref();
|
|
5546
5600
|
}
|
|
@@ -5983,7 +6037,7 @@ var init_scanner = __esm({
|
|
|
5983
6037
|
});
|
|
5984
6038
|
|
|
5985
6039
|
// src/dashboard/api.ts
|
|
5986
|
-
import { readdir as readdir8, readFile as
|
|
6040
|
+
import { readdir as readdir8, readFile as readFile11, writeFile as writeFile3 } from "fs/promises";
|
|
5987
6041
|
import { resolve as resolve16, dirname as dirname3, basename } from "path";
|
|
5988
6042
|
function clearFrontmatterField(content, key) {
|
|
5989
6043
|
const fieldRegex = new RegExp(`^(${escapeRegExp2(key)}:)\\s*.*$`, "m");
|
|
@@ -6071,7 +6125,7 @@ async function computeStandaloneRecords(assignmentsDir2) {
|
|
|
6071
6125
|
const assignmentMdPath2 = resolve16(assignmentDir, "assignment.md");
|
|
6072
6126
|
if (!await fileExists(assignmentMdPath2)) continue;
|
|
6073
6127
|
try {
|
|
6074
|
-
const content = await
|
|
6128
|
+
const content = await readFile11(assignmentMdPath2, "utf-8");
|
|
6075
6129
|
const record = parseAssignmentFull(content);
|
|
6076
6130
|
records.push({ assignmentDir, id: entry.name, record });
|
|
6077
6131
|
} catch {
|
|
@@ -6147,7 +6201,7 @@ async function listProjects(projectsDir2) {
|
|
|
6147
6201
|
async function readWorkspaceRegistry(projectsDir2) {
|
|
6148
6202
|
const registryPath = resolve16(dirname3(projectsDir2), "workspaces.json");
|
|
6149
6203
|
try {
|
|
6150
|
-
const raw = await
|
|
6204
|
+
const raw = await readFile11(registryPath, "utf-8");
|
|
6151
6205
|
const parsed = JSON.parse(raw);
|
|
6152
6206
|
return Array.isArray(parsed) ? parsed.filter((w) => typeof w === "string") : [];
|
|
6153
6207
|
} catch {
|
|
@@ -6236,7 +6290,7 @@ async function deleteWorkspace(projectsDir2, name, opts = {}) {
|
|
|
6236
6290
|
const timestamp = nowTimestamp();
|
|
6237
6291
|
for (const slug of projectsReferencing) {
|
|
6238
6292
|
const path = resolve16(projectsDir2, slug, "project.md");
|
|
6239
|
-
const raw = await
|
|
6293
|
+
const raw = await readFile11(path, "utf-8");
|
|
6240
6294
|
let next = clearFrontmatterField(raw, "workspace");
|
|
6241
6295
|
next = setUpdatedField(next, timestamp);
|
|
6242
6296
|
await writeFileForce(path, next);
|
|
@@ -6245,7 +6299,7 @@ async function deleteWorkspace(projectsDir2, name, opts = {}) {
|
|
|
6245
6299
|
for (const id of standalonesReferencing) {
|
|
6246
6300
|
if (!opts.assignmentsDir) break;
|
|
6247
6301
|
const path = resolve16(opts.assignmentsDir, id, "assignment.md");
|
|
6248
|
-
const raw = await
|
|
6302
|
+
const raw = await readFile11(path, "utf-8");
|
|
6249
6303
|
let next = clearFrontmatterField(raw, "workspaceGroup");
|
|
6250
6304
|
next = setUpdatedField(next, timestamp);
|
|
6251
6305
|
await writeFileForce(path, next);
|
|
@@ -6482,7 +6536,7 @@ async function getEditableDocument(projectsDir2, documentType, projectSlug, assi
|
|
|
6482
6536
|
if (!filePath || !await fileExists(filePath)) {
|
|
6483
6537
|
return null;
|
|
6484
6538
|
}
|
|
6485
|
-
const content = await
|
|
6539
|
+
const content = await readFile11(filePath, "utf-8");
|
|
6486
6540
|
const title = getEditableDocumentTitle(documentType, projectSlug, assignmentSlug);
|
|
6487
6541
|
return {
|
|
6488
6542
|
documentType,
|
|
@@ -6508,7 +6562,7 @@ async function getEditableDocumentById(projectsDir2, assignmentsDir2, documentTy
|
|
|
6508
6562
|
if (!fileName) return null;
|
|
6509
6563
|
const filePath = resolve16(resolved.assignmentDir, fileName);
|
|
6510
6564
|
if (!await fileExists(filePath)) return null;
|
|
6511
|
-
const content = await
|
|
6565
|
+
const content = await readFile11(filePath, "utf-8");
|
|
6512
6566
|
const label = resolved.id;
|
|
6513
6567
|
const title = documentType === "assignment" ? `Edit Assignment: ${label}` : documentType === "plan" ? `Edit Plan: ${label}` : documentType === "scratchpad" ? `Edit Scratchpad: ${label}` : documentType === "handoff" ? `Append Handoff: ${label}` : `Append Decision: ${label}`;
|
|
6514
6568
|
return {
|
|
@@ -6527,7 +6581,7 @@ async function getProjectDetail(projectsDir2, slug) {
|
|
|
6527
6581
|
if (!await fileExists(projectMdPath)) {
|
|
6528
6582
|
return null;
|
|
6529
6583
|
}
|
|
6530
|
-
const projectContent = await
|
|
6584
|
+
const projectContent = await readFile11(projectMdPath, "utf-8");
|
|
6531
6585
|
const project = parseProject(projectContent);
|
|
6532
6586
|
const assignments = await listAssignmentRecords(projectPath);
|
|
6533
6587
|
const rollup = await buildProjectRollup(projectPath, project, assignments);
|
|
@@ -6564,18 +6618,18 @@ async function getAssignmentDetail(projectsDir2, projectSlug, assignmentSlug) {
|
|
|
6564
6618
|
if (!await fileExists(assignmentMdPath2)) {
|
|
6565
6619
|
return null;
|
|
6566
6620
|
}
|
|
6567
|
-
const assignmentContent = await
|
|
6621
|
+
const assignmentContent = await readFile11(assignmentMdPath2, "utf-8");
|
|
6568
6622
|
const assignment = parseAssignmentFull(assignmentContent);
|
|
6569
6623
|
let projectWorkspace = null;
|
|
6570
6624
|
const projectMdPath = resolve16(projectsDir2, projectSlug, "project.md");
|
|
6571
6625
|
if (await fileExists(projectMdPath)) {
|
|
6572
|
-
const projectContent = await
|
|
6626
|
+
const projectContent = await readFile11(projectMdPath, "utf-8");
|
|
6573
6627
|
projectWorkspace = parseProject(projectContent).workspace;
|
|
6574
6628
|
}
|
|
6575
6629
|
let plan = null;
|
|
6576
6630
|
const planPath = resolve16(assignmentDir, "plan.md");
|
|
6577
6631
|
if (await fileExists(planPath)) {
|
|
6578
|
-
const planContent = await
|
|
6632
|
+
const planContent = await readFile11(planPath, "utf-8");
|
|
6579
6633
|
const parsed = parsePlan(planContent);
|
|
6580
6634
|
plan = {
|
|
6581
6635
|
status: parsed.status,
|
|
@@ -6586,7 +6640,7 @@ async function getAssignmentDetail(projectsDir2, projectSlug, assignmentSlug) {
|
|
|
6586
6640
|
let scratchpad = null;
|
|
6587
6641
|
const scratchpadPath = resolve16(assignmentDir, "scratchpad.md");
|
|
6588
6642
|
if (await fileExists(scratchpadPath)) {
|
|
6589
|
-
const scratchpadContent = await
|
|
6643
|
+
const scratchpadContent = await readFile11(scratchpadPath, "utf-8");
|
|
6590
6644
|
const parsed = parseScratchpad(scratchpadContent);
|
|
6591
6645
|
scratchpad = {
|
|
6592
6646
|
updated: parsed.updated,
|
|
@@ -6596,7 +6650,7 @@ async function getAssignmentDetail(projectsDir2, projectSlug, assignmentSlug) {
|
|
|
6596
6650
|
let handoff = null;
|
|
6597
6651
|
const handoffPath = resolve16(assignmentDir, "handoff.md");
|
|
6598
6652
|
if (await fileExists(handoffPath)) {
|
|
6599
|
-
const handoffContent = await
|
|
6653
|
+
const handoffContent = await readFile11(handoffPath, "utf-8");
|
|
6600
6654
|
const parsed = parseHandoff(handoffContent);
|
|
6601
6655
|
handoff = {
|
|
6602
6656
|
updated: parsed.updated,
|
|
@@ -6607,7 +6661,7 @@ async function getAssignmentDetail(projectsDir2, projectSlug, assignmentSlug) {
|
|
|
6607
6661
|
let decisionRecord = null;
|
|
6608
6662
|
const decisionRecordPath = resolve16(assignmentDir, "decision-record.md");
|
|
6609
6663
|
if (await fileExists(decisionRecordPath)) {
|
|
6610
|
-
const decisionRecordContent = await
|
|
6664
|
+
const decisionRecordContent = await readFile11(decisionRecordPath, "utf-8");
|
|
6611
6665
|
const parsed = parseDecisionRecord(decisionRecordContent);
|
|
6612
6666
|
decisionRecord = {
|
|
6613
6667
|
updated: parsed.updated,
|
|
@@ -6618,7 +6672,7 @@ async function getAssignmentDetail(projectsDir2, projectSlug, assignmentSlug) {
|
|
|
6618
6672
|
let progress = null;
|
|
6619
6673
|
const progressPath = resolve16(assignmentDir, "progress.md");
|
|
6620
6674
|
if (await fileExists(progressPath)) {
|
|
6621
|
-
const progressContent = await
|
|
6675
|
+
const progressContent = await readFile11(progressPath, "utf-8");
|
|
6622
6676
|
const parsed = parseProgress(progressContent);
|
|
6623
6677
|
progress = {
|
|
6624
6678
|
updated: parsed.updated,
|
|
@@ -6629,7 +6683,7 @@ async function getAssignmentDetail(projectsDir2, projectSlug, assignmentSlug) {
|
|
|
6629
6683
|
let comments = null;
|
|
6630
6684
|
const commentsPath = resolve16(assignmentDir, "comments.md");
|
|
6631
6685
|
if (await fileExists(commentsPath)) {
|
|
6632
|
-
const commentsContent = await
|
|
6686
|
+
const commentsContent = await readFile11(commentsPath, "utf-8");
|
|
6633
6687
|
const parsed = parseComments(commentsContent);
|
|
6634
6688
|
comments = {
|
|
6635
6689
|
updated: parsed.updated,
|
|
@@ -6783,7 +6837,7 @@ async function countMentionsInAssignment(sourceDir, target) {
|
|
|
6783
6837
|
const bodies = [];
|
|
6784
6838
|
const assignmentMd = resolve16(sourceDir, "assignment.md");
|
|
6785
6839
|
if (await fileExists(assignmentMd)) {
|
|
6786
|
-
const content = await
|
|
6840
|
+
const content = await readFile11(assignmentMd, "utf-8");
|
|
6787
6841
|
const todosMatch = content.match(/^## Todos\s*$([\s\S]*?)(?=^## |$(?![\r\n]))/m);
|
|
6788
6842
|
if (todosMatch) bodies.push(todosMatch[1]);
|
|
6789
6843
|
}
|
|
@@ -6791,7 +6845,7 @@ async function countMentionsInAssignment(sourceDir, target) {
|
|
|
6791
6845
|
const path = resolve16(sourceDir, filename);
|
|
6792
6846
|
if (await fileExists(path)) {
|
|
6793
6847
|
try {
|
|
6794
|
-
bodies.push(await
|
|
6848
|
+
bodies.push(await readFile11(path, "utf-8"));
|
|
6795
6849
|
} catch {
|
|
6796
6850
|
}
|
|
6797
6851
|
}
|
|
@@ -6851,42 +6905,42 @@ async function buildStandaloneAssignmentDetail(resolved) {
|
|
|
6851
6905
|
const assignmentDir = resolved.assignmentDir;
|
|
6852
6906
|
const assignmentMdPath2 = resolve16(assignmentDir, "assignment.md");
|
|
6853
6907
|
if (!await fileExists(assignmentMdPath2)) return null;
|
|
6854
|
-
const assignmentContent = await
|
|
6908
|
+
const assignmentContent = await readFile11(assignmentMdPath2, "utf-8");
|
|
6855
6909
|
const assignment = parseAssignmentFull(assignmentContent);
|
|
6856
6910
|
let plan = null;
|
|
6857
6911
|
const planPath = resolve16(assignmentDir, "plan.md");
|
|
6858
6912
|
if (await fileExists(planPath)) {
|
|
6859
|
-
const parsed = parsePlan(await
|
|
6913
|
+
const parsed = parsePlan(await readFile11(planPath, "utf-8"));
|
|
6860
6914
|
plan = { status: parsed.status, updated: parsed.updated, body: parsed.body };
|
|
6861
6915
|
}
|
|
6862
6916
|
let scratchpad = null;
|
|
6863
6917
|
const scratchpadPath = resolve16(assignmentDir, "scratchpad.md");
|
|
6864
6918
|
if (await fileExists(scratchpadPath)) {
|
|
6865
|
-
const parsed = parseScratchpad(await
|
|
6919
|
+
const parsed = parseScratchpad(await readFile11(scratchpadPath, "utf-8"));
|
|
6866
6920
|
scratchpad = { updated: parsed.updated, body: parsed.body };
|
|
6867
6921
|
}
|
|
6868
6922
|
let handoff = null;
|
|
6869
6923
|
const handoffPath = resolve16(assignmentDir, "handoff.md");
|
|
6870
6924
|
if (await fileExists(handoffPath)) {
|
|
6871
|
-
const parsed = parseHandoff(await
|
|
6925
|
+
const parsed = parseHandoff(await readFile11(handoffPath, "utf-8"));
|
|
6872
6926
|
handoff = { updated: parsed.updated, handoffCount: parsed.handoffCount, body: parsed.body };
|
|
6873
6927
|
}
|
|
6874
6928
|
let decisionRecord = null;
|
|
6875
6929
|
const decisionRecordPath = resolve16(assignmentDir, "decision-record.md");
|
|
6876
6930
|
if (await fileExists(decisionRecordPath)) {
|
|
6877
|
-
const parsed = parseDecisionRecord(await
|
|
6931
|
+
const parsed = parseDecisionRecord(await readFile11(decisionRecordPath, "utf-8"));
|
|
6878
6932
|
decisionRecord = { updated: parsed.updated, decisionCount: parsed.decisionCount, body: parsed.body };
|
|
6879
6933
|
}
|
|
6880
6934
|
let progress = null;
|
|
6881
6935
|
const progressPath = resolve16(assignmentDir, "progress.md");
|
|
6882
6936
|
if (await fileExists(progressPath)) {
|
|
6883
|
-
const parsed = parseProgress(await
|
|
6937
|
+
const parsed = parseProgress(await readFile11(progressPath, "utf-8"));
|
|
6884
6938
|
progress = { updated: parsed.updated, entryCount: parsed.entryCount, entries: parsed.entries };
|
|
6885
6939
|
}
|
|
6886
6940
|
let comments = null;
|
|
6887
6941
|
const commentsPath = resolve16(assignmentDir, "comments.md");
|
|
6888
6942
|
if (await fileExists(commentsPath)) {
|
|
6889
|
-
const parsed = parseComments(await
|
|
6943
|
+
const parsed = parseComments(await readFile11(commentsPath, "utf-8"));
|
|
6890
6944
|
comments = { updated: parsed.updated, entryCount: parsed.entryCount, entries: parsed.entries };
|
|
6891
6945
|
}
|
|
6892
6946
|
const detail = {
|
|
@@ -6952,7 +7006,7 @@ async function computeProjectRecords(projectsDir2, traces) {
|
|
|
6952
7006
|
return null;
|
|
6953
7007
|
}
|
|
6954
7008
|
const t0 = traces ? performance.now() : 0;
|
|
6955
|
-
const projectContent = await
|
|
7009
|
+
const projectContent = await readFile11(projectMdPath, "utf-8");
|
|
6956
7010
|
const project = parseProject(projectContent);
|
|
6957
7011
|
if (traces) accumulatePhase(traces, "parse-project-md", performance.now() - t0);
|
|
6958
7012
|
const t1 = traces ? performance.now() : 0;
|
|
@@ -7006,7 +7060,7 @@ async function listAssignmentRecords(projectPath, traces) {
|
|
|
7006
7060
|
return null;
|
|
7007
7061
|
}
|
|
7008
7062
|
const t0 = traces ? performance.now() : 0;
|
|
7009
|
-
const content = await
|
|
7063
|
+
const content = await readFile11(assignmentMd, "utf-8");
|
|
7010
7064
|
const parsed = parseAssignmentFull(content);
|
|
7011
7065
|
if (traces) accumulatePhase(traces, "read-assignment-md", performance.now() - t0);
|
|
7012
7066
|
return parsed;
|
|
@@ -7028,7 +7082,7 @@ async function listResources(projectPath) {
|
|
|
7028
7082
|
continue;
|
|
7029
7083
|
}
|
|
7030
7084
|
const filePath = resolve16(resourcesDir, entry.name);
|
|
7031
|
-
const content = await
|
|
7085
|
+
const content = await readFile11(filePath, "utf-8");
|
|
7032
7086
|
const parsed = parseResource(content);
|
|
7033
7087
|
results.push({
|
|
7034
7088
|
name: parsed.name,
|
|
@@ -7054,7 +7108,7 @@ async function listMemories(projectPath) {
|
|
|
7054
7108
|
continue;
|
|
7055
7109
|
}
|
|
7056
7110
|
const filePath = resolve16(memoriesDir, entry.name);
|
|
7057
|
-
const content = await
|
|
7111
|
+
const content = await readFile11(filePath, "utf-8");
|
|
7058
7112
|
const parsed = parseMemory(content);
|
|
7059
7113
|
results.push({
|
|
7060
7114
|
name: parsed.name,
|
|
@@ -7117,7 +7171,7 @@ async function getMemoryDetail(projectsDir2, projectSlug, itemSlug) {
|
|
|
7117
7171
|
if (!projectRecord) return null;
|
|
7118
7172
|
const filePath = resolve16(projectRecord.projectPath, "memories", `${itemSlug}.md`);
|
|
7119
7173
|
if (!await fileExists(filePath)) return null;
|
|
7120
|
-
const content = await
|
|
7174
|
+
const content = await readFile11(filePath, "utf-8");
|
|
7121
7175
|
const parsed = parseMemory(content);
|
|
7122
7176
|
return {
|
|
7123
7177
|
name: parsed.name,
|
|
@@ -7143,7 +7197,7 @@ async function getResourceDetail(projectsDir2, projectSlug, itemSlug) {
|
|
|
7143
7197
|
if (!projectRecord) return null;
|
|
7144
7198
|
const filePath = resolve16(projectRecord.projectPath, "resources", `${itemSlug}.md`);
|
|
7145
7199
|
if (!await fileExists(filePath)) return null;
|
|
7146
|
-
const content = await
|
|
7200
|
+
const content = await readFile11(filePath, "utf-8");
|
|
7147
7201
|
const parsed = parseResource(content);
|
|
7148
7202
|
return {
|
|
7149
7203
|
name: parsed.name,
|
|
@@ -7161,7 +7215,7 @@ async function getResourceDetail(projectsDir2, projectSlug, itemSlug) {
|
|
|
7161
7215
|
async function loadDependencyGraph(projectPath, assignments) {
|
|
7162
7216
|
const statusPath = resolve16(projectPath, "_status.md");
|
|
7163
7217
|
if (await fileExists(statusPath)) {
|
|
7164
|
-
const statusContent = await
|
|
7218
|
+
const statusContent = await readFile11(statusPath, "utf-8");
|
|
7165
7219
|
const parsed = parseStatus(statusContent);
|
|
7166
7220
|
const derivedGraph = extractMermaidGraph(parsed.body);
|
|
7167
7221
|
if (derivedGraph) {
|
|
@@ -7328,7 +7382,7 @@ async function getUnmetDependencies(projectPath, dependsOn, terminalStatuses3, d
|
|
|
7328
7382
|
unmet.push(`${dependency} (missing)`);
|
|
7329
7383
|
continue;
|
|
7330
7384
|
}
|
|
7331
|
-
const content = await
|
|
7385
|
+
const content = await readFile11(dependencyPath, "utf-8");
|
|
7332
7386
|
const parsed = parseAssignmentFull(content);
|
|
7333
7387
|
if (!terminals.has(parsed.status)) {
|
|
7334
7388
|
unmet.push(`${dependency} (${parsed.status})`);
|
|
@@ -7623,7 +7677,7 @@ async function countOpenQuestions(projectPath, assignmentSlug) {
|
|
|
7623
7677
|
return 0;
|
|
7624
7678
|
}
|
|
7625
7679
|
try {
|
|
7626
|
-
const content = await
|
|
7680
|
+
const content = await readFile11(commentsPath, "utf-8");
|
|
7627
7681
|
const parsed = parseComments(content);
|
|
7628
7682
|
return parsed.entries.filter(
|
|
7629
7683
|
(e) => e.type === "question" && e.resolved !== true
|
|
@@ -7696,7 +7750,7 @@ async function listPlaybooks(playbooksDir3) {
|
|
|
7696
7750
|
for (const entry of entries) {
|
|
7697
7751
|
if (!entry.isFile() || !entry.name.endsWith(".md") || entry.name.startsWith("_") || entry.name === "manifest.md") continue;
|
|
7698
7752
|
const filePath = resolve16(playbooksDir3, entry.name);
|
|
7699
|
-
const raw = await
|
|
7753
|
+
const raw = await readFile11(filePath, "utf-8");
|
|
7700
7754
|
const parsed = parsePlaybook(raw);
|
|
7701
7755
|
const slug = parsed.slug || entry.name.replace(/\.md$/, "");
|
|
7702
7756
|
playbooks.push({
|
|
@@ -7881,7 +7935,7 @@ __export(git_worktree_exports, {
|
|
|
7881
7935
|
removeWorktree: () => removeWorktree
|
|
7882
7936
|
});
|
|
7883
7937
|
import { spawn } from "child_process";
|
|
7884
|
-
import { readFile as
|
|
7938
|
+
import { readFile as readFile14 } from "fs/promises";
|
|
7885
7939
|
function run(command, args, cwd) {
|
|
7886
7940
|
return new Promise((resolvePromise) => {
|
|
7887
7941
|
const child = spawn(command, args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -7959,7 +8013,7 @@ async function createWorktreeAndRecord(opts) {
|
|
|
7959
8013
|
const { assignmentPath, repository, branch, worktreePath, parentBranch } = opts;
|
|
7960
8014
|
await createWorktree({ repository, branch, worktreePath, parentBranch });
|
|
7961
8015
|
try {
|
|
7962
|
-
const content = await
|
|
8016
|
+
const content = await readFile14(assignmentPath, "utf-8");
|
|
7963
8017
|
const updated = updateAssignmentWorkspace(content, {
|
|
7964
8018
|
repository,
|
|
7965
8019
|
worktreePath,
|
|
@@ -8428,15 +8482,15 @@ import {
|
|
|
8428
8482
|
unlinkSync
|
|
8429
8483
|
} from "fs";
|
|
8430
8484
|
import { fileURLToPath as fileURLToPath9, pathToFileURL } from "url";
|
|
8431
|
-
import { dirname as dirname16, resolve as
|
|
8432
|
-
import { homedir as
|
|
8433
|
-
import { spawnSync as
|
|
8485
|
+
import { dirname as dirname16, resolve as resolve49, join as join9 } from "path";
|
|
8486
|
+
import { homedir as homedir9, tmpdir as tmpdir2 } from "os";
|
|
8487
|
+
import { spawnSync as spawnSync7 } from "child_process";
|
|
8434
8488
|
function syntaurRootMjs() {
|
|
8435
8489
|
const override = process.env.SYNTAUR_HOME;
|
|
8436
8490
|
if (override && override.length > 0) {
|
|
8437
8491
|
return override;
|
|
8438
8492
|
}
|
|
8439
|
-
return join9(
|
|
8493
|
+
return join9(homedir9(), ".syntaur");
|
|
8440
8494
|
}
|
|
8441
8495
|
async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
8442
8496
|
const { throwOnFailure } = options;
|
|
@@ -8450,7 +8504,7 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
|
8450
8504
|
}
|
|
8451
8505
|
const stateRoot = syntaurRootMjs();
|
|
8452
8506
|
mkdirSync2(stateRoot, { recursive: true });
|
|
8453
|
-
const lockPath =
|
|
8507
|
+
const lockPath = resolve49(stateRoot, "install-url-handler.lock");
|
|
8454
8508
|
let lockFd;
|
|
8455
8509
|
try {
|
|
8456
8510
|
lockFd = openSync(lockPath, "wx");
|
|
@@ -8466,11 +8520,11 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
|
8466
8520
|
throw err2;
|
|
8467
8521
|
}
|
|
8468
8522
|
try {
|
|
8469
|
-
const pkgRoot =
|
|
8470
|
-
const cliBin = realpathSync3(
|
|
8523
|
+
const pkgRoot = resolve49(dirname16(fileURLToPath9(import.meta.url)), "..");
|
|
8524
|
+
const cliBin = realpathSync3(resolve49(pkgRoot, "bin/syntaur.js"));
|
|
8471
8525
|
const nodeBin = process.execPath;
|
|
8472
8526
|
const bundleParent = join9(
|
|
8473
|
-
|
|
8527
|
+
homedir9(),
|
|
8474
8528
|
"Library",
|
|
8475
8529
|
"Application Support",
|
|
8476
8530
|
"Syntaur"
|
|
@@ -8490,7 +8544,7 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
|
8490
8544
|
renderAppleScript({ nodeBin, cliBin, installedTerminals }),
|
|
8491
8545
|
"utf-8"
|
|
8492
8546
|
);
|
|
8493
|
-
const compile =
|
|
8547
|
+
const compile = spawnSync7(
|
|
8494
8548
|
OSACOMPILE,
|
|
8495
8549
|
["-o", bundlePath, scriptPath],
|
|
8496
8550
|
{ stdio: "pipe", encoding: "utf-8" }
|
|
@@ -8534,7 +8588,7 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
|
8534
8588
|
["Add :CFBundleURLTypes:0:CFBundleURLSchemes array", null],
|
|
8535
8589
|
[`Add :CFBundleURLTypes:0:CFBundleURLSchemes:0 string ${URL_SCHEME}`, null]
|
|
8536
8590
|
]);
|
|
8537
|
-
const sign =
|
|
8591
|
+
const sign = spawnSync7(
|
|
8538
8592
|
"/usr/bin/codesign",
|
|
8539
8593
|
["--force", "--deep", "--sign", "-", bundlePath],
|
|
8540
8594
|
{ stdio: "pipe", encoding: "utf-8" }
|
|
@@ -8546,7 +8600,7 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
|
8546
8600
|
}
|
|
8547
8601
|
console.warn(`syntaur: ${msg} \u2014 macOS may deny Automation permission.`);
|
|
8548
8602
|
}
|
|
8549
|
-
const ls =
|
|
8603
|
+
const ls = spawnSync7(LSREGISTER, ["-f", bundlePath], {
|
|
8550
8604
|
stdio: "pipe",
|
|
8551
8605
|
encoding: "utf-8"
|
|
8552
8606
|
});
|
|
@@ -8595,9 +8649,9 @@ function detectInstalledTerminals() {
|
|
|
8595
8649
|
ghostty: "Ghostty.app",
|
|
8596
8650
|
warp: "Warp.app"
|
|
8597
8651
|
};
|
|
8598
|
-
const appDirs = ["/Applications", join9(
|
|
8652
|
+
const appDirs = ["/Applications", join9(homedir9(), "Applications")];
|
|
8599
8653
|
for (const [id, bundleId] of Object.entries(bundleIds)) {
|
|
8600
|
-
const r =
|
|
8654
|
+
const r = spawnSync7(
|
|
8601
8655
|
"mdfind",
|
|
8602
8656
|
[`kMDItemCFBundleIdentifier == '${bundleId}'`],
|
|
8603
8657
|
{ encoding: "utf-8" }
|
|
@@ -8619,9 +8673,17 @@ function buildTerminalDispatch(installedTerminals) {
|
|
|
8619
8673
|
branches.push({
|
|
8620
8674
|
id: "terminal-app",
|
|
8621
8675
|
block: [
|
|
8676
|
+
' set wasRunning to application "Terminal" is running',
|
|
8622
8677
|
' tell application "Terminal"',
|
|
8623
8678
|
" activate",
|
|
8624
|
-
"
|
|
8679
|
+
" if wasRunning then",
|
|
8680
|
+
" do script shellCmd",
|
|
8681
|
+
" else",
|
|
8682
|
+
" repeat until (count of windows) > 0",
|
|
8683
|
+
" delay 0.1",
|
|
8684
|
+
" end repeat",
|
|
8685
|
+
" do script shellCmd in window 1",
|
|
8686
|
+
" end if",
|
|
8625
8687
|
" end tell"
|
|
8626
8688
|
]
|
|
8627
8689
|
});
|
|
@@ -8757,13 +8819,13 @@ function runPlistBuddy(plistPath, steps) {
|
|
|
8757
8819
|
for (const step of steps) {
|
|
8758
8820
|
if (Array.isArray(step)) {
|
|
8759
8821
|
const [primary, fallback] = step;
|
|
8760
|
-
const a =
|
|
8822
|
+
const a = spawnSync7("/usr/libexec/PlistBuddy", ["-c", primary, plistPath], {
|
|
8761
8823
|
stdio: "pipe",
|
|
8762
8824
|
encoding: "utf-8"
|
|
8763
8825
|
});
|
|
8764
8826
|
if (a.status === 0) continue;
|
|
8765
8827
|
if (fallback === null) continue;
|
|
8766
|
-
const b =
|
|
8828
|
+
const b = spawnSync7("/usr/libexec/PlistBuddy", ["-c", fallback, plistPath], {
|
|
8767
8829
|
stdio: "pipe",
|
|
8768
8830
|
encoding: "utf-8"
|
|
8769
8831
|
});
|
|
@@ -8773,7 +8835,7 @@ function runPlistBuddy(plistPath, steps) {
|
|
|
8773
8835
|
);
|
|
8774
8836
|
}
|
|
8775
8837
|
} else {
|
|
8776
|
-
const r =
|
|
8838
|
+
const r = spawnSync7("/usr/libexec/PlistBuddy", ["-c", step, plistPath], {
|
|
8777
8839
|
stdio: "pipe",
|
|
8778
8840
|
encoding: "utf-8"
|
|
8779
8841
|
});
|
|
@@ -9317,7 +9379,7 @@ init_fs();
|
|
|
9317
9379
|
init_config();
|
|
9318
9380
|
init_playbooks();
|
|
9319
9381
|
import { resolve as resolve5, dirname as dirname2 } from "path";
|
|
9320
|
-
import { readdir as readdir3, readFile as
|
|
9382
|
+
import { readdir as readdir3, readFile as readFile5 } from "fs/promises";
|
|
9321
9383
|
import { fileURLToPath } from "url";
|
|
9322
9384
|
async function initCommand(options) {
|
|
9323
9385
|
const root = syntaurRoot();
|
|
@@ -9369,7 +9431,7 @@ async function seedDefaultPlaybooks(playbooksDir3) {
|
|
|
9369
9431
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
9370
9432
|
const targetPath = resolve5(playbooksDir3, entry.name);
|
|
9371
9433
|
if (await fileExists(targetPath)) continue;
|
|
9372
|
-
const content = await
|
|
9434
|
+
const content = await readFile5(resolve5(examplesDir, entry.name), "utf-8");
|
|
9373
9435
|
await writeFileSafe(targetPath, content);
|
|
9374
9436
|
count++;
|
|
9375
9437
|
}
|
|
@@ -9931,7 +9993,7 @@ function mergePatch(current, patch) {
|
|
|
9931
9993
|
// src/utils/view-prefs.ts
|
|
9932
9994
|
init_paths();
|
|
9933
9995
|
init_fs();
|
|
9934
|
-
import { readFile as
|
|
9996
|
+
import { readFile as readFile12, rename as rename3, unlink as unlink3 } from "fs/promises";
|
|
9935
9997
|
import { resolve as resolve17 } from "path";
|
|
9936
9998
|
function corruptFilePath() {
|
|
9937
9999
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
@@ -9954,7 +10016,7 @@ async function readViewPrefsFile() {
|
|
|
9954
10016
|
}
|
|
9955
10017
|
let raw;
|
|
9956
10018
|
try {
|
|
9957
|
-
raw = await
|
|
10019
|
+
raw = await readFile12(path, "utf-8");
|
|
9958
10020
|
} catch {
|
|
9959
10021
|
return { ...DEFAULT_VIEW_PREFS_FILE };
|
|
9960
10022
|
}
|
|
@@ -10137,7 +10199,7 @@ function isDashboardSlot(value) {
|
|
|
10137
10199
|
// src/utils/saved-views.ts
|
|
10138
10200
|
init_paths();
|
|
10139
10201
|
init_fs();
|
|
10140
|
-
import { readFile as
|
|
10202
|
+
import { readFile as readFile13, rename as rename4, unlink as unlink4 } from "fs/promises";
|
|
10141
10203
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
10142
10204
|
import { resolve as resolve18 } from "path";
|
|
10143
10205
|
function corruptFilePath2() {
|
|
@@ -10167,7 +10229,7 @@ async function readSavedViewsFile() {
|
|
|
10167
10229
|
}
|
|
10168
10230
|
let raw;
|
|
10169
10231
|
try {
|
|
10170
|
-
raw = await
|
|
10232
|
+
raw = await readFile13(path, "utf-8");
|
|
10171
10233
|
} catch {
|
|
10172
10234
|
return cloneDefault();
|
|
10173
10235
|
}
|
|
@@ -10487,7 +10549,7 @@ init_fs();
|
|
|
10487
10549
|
init_git_worktree();
|
|
10488
10550
|
import { Router as Router2 } from "express";
|
|
10489
10551
|
import { resolve as resolve21, basename as basename3, isAbsolute as isAbsolute2 } from "path";
|
|
10490
|
-
import { rm, readFile as
|
|
10552
|
+
import { rm, readFile as readFile16, open as fsOpen, stat as fsStat, realpath as fsRealpath } from "fs/promises";
|
|
10491
10553
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
10492
10554
|
|
|
10493
10555
|
// src/utils/worktree-defaults.ts
|
|
@@ -10563,7 +10625,7 @@ function validateBranchName(name) {
|
|
|
10563
10625
|
// src/dashboard/repository-candidates.ts
|
|
10564
10626
|
init_fs();
|
|
10565
10627
|
init_parser();
|
|
10566
|
-
import { readdir as readdir9, readFile as
|
|
10628
|
+
import { readdir as readdir9, readFile as readFile15 } from "fs/promises";
|
|
10567
10629
|
import { resolve as resolve20 } from "path";
|
|
10568
10630
|
function toSourceAssignment(parsed, fallbackId) {
|
|
10569
10631
|
const repository = parsed.workspace.repository?.trim();
|
|
@@ -10583,7 +10645,7 @@ async function getProjectRepositoryCandidates(projectsDir2, projectSlug) {
|
|
|
10583
10645
|
const out = [];
|
|
10584
10646
|
const projectPath = resolve20(projectsDir2, projectSlug, "project.md");
|
|
10585
10647
|
if (await fileExists(projectPath)) {
|
|
10586
|
-
const project = parseProject(await
|
|
10648
|
+
const project = parseProject(await readFile15(projectPath, "utf-8"));
|
|
10587
10649
|
for (const raw of project.repositories) {
|
|
10588
10650
|
const path = raw.trim();
|
|
10589
10651
|
if (!path) continue;
|
|
@@ -10600,7 +10662,7 @@ async function getProjectRepositoryCandidates(projectsDir2, projectSlug) {
|
|
|
10600
10662
|
if (!entry.isDirectory()) continue;
|
|
10601
10663
|
const assignmentMd = resolve20(assignmentsDir2, entry.name, "assignment.md");
|
|
10602
10664
|
if (!await fileExists(assignmentMd)) continue;
|
|
10603
|
-
const parsed = parseAssignmentFull(await
|
|
10665
|
+
const parsed = parseAssignmentFull(await readFile15(assignmentMd, "utf-8"));
|
|
10604
10666
|
const repo = parsed.workspace.repository?.trim();
|
|
10605
10667
|
if (!repo) continue;
|
|
10606
10668
|
const abs = resolve20(repo);
|
|
@@ -10623,7 +10685,7 @@ async function getStandaloneRepositoryCandidates(assignmentsDir2, excludeAssignm
|
|
|
10623
10685
|
if (entry.name === excludeAssignmentId) continue;
|
|
10624
10686
|
const assignmentMd = resolve20(assignmentsDir2, entry.name, "assignment.md");
|
|
10625
10687
|
if (!await fileExists(assignmentMd)) continue;
|
|
10626
|
-
const parsed = parseAssignmentFull(await
|
|
10688
|
+
const parsed = parseAssignmentFull(await readFile15(assignmentMd, "utf-8"));
|
|
10627
10689
|
const repo = parsed.workspace.repository?.trim();
|
|
10628
10690
|
if (!repo) continue;
|
|
10629
10691
|
const abs = resolve20(repo);
|
|
@@ -10644,7 +10706,7 @@ async function getProjectSourceAssignments(projectsDir2, projectSlug, excludeSlu
|
|
|
10644
10706
|
if (entry.name === excludeSlug) continue;
|
|
10645
10707
|
const assignmentMd = resolve20(assignmentsDir2, entry.name, "assignment.md");
|
|
10646
10708
|
if (!await fileExists(assignmentMd)) continue;
|
|
10647
|
-
const parsed = parseAssignmentFull(await
|
|
10709
|
+
const parsed = parseAssignmentFull(await readFile15(assignmentMd, "utf-8"));
|
|
10648
10710
|
const source = toSourceAssignment(parsed, entry.name);
|
|
10649
10711
|
if (!source) continue;
|
|
10650
10712
|
if (seen.has(entry.name)) continue;
|
|
@@ -10663,7 +10725,7 @@ async function getStandaloneSourceAssignments(assignmentsDir2, excludeAssignment
|
|
|
10663
10725
|
if (entry.name === excludeAssignmentId) continue;
|
|
10664
10726
|
const assignmentMd = resolve20(assignmentsDir2, entry.name, "assignment.md");
|
|
10665
10727
|
if (!await fileExists(assignmentMd)) continue;
|
|
10666
|
-
const parsed = parseAssignmentFull(await
|
|
10728
|
+
const parsed = parseAssignmentFull(await readFile15(assignmentMd, "utf-8"));
|
|
10667
10729
|
const source = toSourceAssignment(parsed, entry.name);
|
|
10668
10730
|
if (!source) continue;
|
|
10669
10731
|
if (seen.has(entry.name)) continue;
|
|
@@ -10834,7 +10896,7 @@ async function readCurrentDocument(filePath) {
|
|
|
10834
10896
|
if (!await fileExists(filePath)) {
|
|
10835
10897
|
return null;
|
|
10836
10898
|
}
|
|
10837
|
-
return
|
|
10899
|
+
return readFile16(filePath, "utf-8");
|
|
10838
10900
|
}
|
|
10839
10901
|
var worktreeInFlight = /* @__PURE__ */ new Set();
|
|
10840
10902
|
async function assertRepoRoot(repoInput) {
|
|
@@ -10888,7 +10950,7 @@ async function handleWorktreeCreate(req, res, ctx) {
|
|
|
10888
10950
|
}
|
|
10889
10951
|
worktreeInFlight.add(ctx.assignmentPath);
|
|
10890
10952
|
try {
|
|
10891
|
-
const parsed = parseAssignmentFull(await
|
|
10953
|
+
const parsed = parseAssignmentFull(await readFile16(ctx.assignmentPath, "utf-8"));
|
|
10892
10954
|
if (parsed.workspace.worktreePath) {
|
|
10893
10955
|
res.status(409).json({ error: "Worktree already configured for this assignment" });
|
|
10894
10956
|
return;
|
|
@@ -11258,7 +11320,7 @@ ${body.startsWith("\n") ? body.slice(1) : body}${body.endsWith("\n") ? "" : "\n"
|
|
|
11258
11320
|
}
|
|
11259
11321
|
const nextContentRaw = requireContent(req, res);
|
|
11260
11322
|
if (!nextContentRaw) return;
|
|
11261
|
-
const currentContent = await
|
|
11323
|
+
const currentContent = await readFile16(filePath, "utf-8");
|
|
11262
11324
|
const frontmatterBlock = extractFrontmatterBlock(currentContent);
|
|
11263
11325
|
if (!frontmatterBlock) {
|
|
11264
11326
|
res.status(500).json({ error: `${kind} file is malformed (no frontmatter)` });
|
|
@@ -11709,7 +11771,7 @@ ${nextBody}${nextBody.endsWith("\n") ? "" : "\n"}`;
|
|
|
11709
11771
|
let currentContent;
|
|
11710
11772
|
let currentCount = 0;
|
|
11711
11773
|
if (await fileExists(commentsPath)) {
|
|
11712
|
-
currentContent = await
|
|
11774
|
+
currentContent = await readFile16(commentsPath, "utf-8");
|
|
11713
11775
|
const countMatch = currentContent.match(/^entryCount:\s*(\d+)/m);
|
|
11714
11776
|
if (countMatch) currentCount = parseInt(countMatch[1], 10);
|
|
11715
11777
|
} else {
|
|
@@ -11766,7 +11828,7 @@ ${entry}`;
|
|
|
11766
11828
|
res.status(400).json({ error: "resolved (boolean) is required" });
|
|
11767
11829
|
return;
|
|
11768
11830
|
}
|
|
11769
|
-
const content = await
|
|
11831
|
+
const content = await readFile16(commentsPath, "utf-8");
|
|
11770
11832
|
const parsed = parseComments(content);
|
|
11771
11833
|
const target = parsed.entries.find((e) => e.id === commentId);
|
|
11772
11834
|
if (!target) {
|
|
@@ -11813,7 +11875,7 @@ ${entry}`;
|
|
|
11813
11875
|
});
|
|
11814
11876
|
return;
|
|
11815
11877
|
}
|
|
11816
|
-
let content = await
|
|
11878
|
+
let content = await readFile16(projectPath, "utf-8");
|
|
11817
11879
|
content = setTopLevelField(content, "workspace", workspace ?? null);
|
|
11818
11880
|
content = setTopLevelField(content, "updated", nowTimestamp());
|
|
11819
11881
|
await writeFileForce(projectPath, content);
|
|
@@ -11850,7 +11912,7 @@ ${entry}`;
|
|
|
11850
11912
|
return;
|
|
11851
11913
|
}
|
|
11852
11914
|
const assignmentPath = resolve21(resolved.assignmentDir, "assignment.md");
|
|
11853
|
-
let content = await
|
|
11915
|
+
let content = await readFile16(assignmentPath, "utf-8");
|
|
11854
11916
|
content = setTopLevelField(content, "workspaceGroup", workspaceGroup ?? null);
|
|
11855
11917
|
content = setTopLevelField(content, "updated", nowTimestamp());
|
|
11856
11918
|
await writeFileForce(assignmentPath, content);
|
|
@@ -12067,7 +12129,7 @@ ${entry}`;
|
|
|
12067
12129
|
return;
|
|
12068
12130
|
}
|
|
12069
12131
|
const assignmentPath = resolve21(resolved.assignmentDir, "assignment.md");
|
|
12070
|
-
const parsedForSlug = parseAssignmentFull(await
|
|
12132
|
+
const parsedForSlug = parseAssignmentFull(await readFile16(assignmentPath, "utf-8"));
|
|
12071
12133
|
const assignmentSlugForBranch = parsedForSlug.slug || resolved.id;
|
|
12072
12134
|
await handleWorktreeCreate(req, res, {
|
|
12073
12135
|
assignmentPath,
|
|
@@ -12096,7 +12158,7 @@ ${entry}`;
|
|
|
12096
12158
|
res.status(400).json({ error: `Invalid status. Must be one of: ${validStatuses.join(", ")}, or null to clear.` });
|
|
12097
12159
|
return;
|
|
12098
12160
|
}
|
|
12099
|
-
let content = await
|
|
12161
|
+
let content = await readFile16(projectPath, "utf-8");
|
|
12100
12162
|
content = setTopLevelField(content, "statusOverride", status ?? null);
|
|
12101
12163
|
content = setTopLevelField(content, "updated", nowTimestamp());
|
|
12102
12164
|
await writeFileForce(projectPath, content);
|
|
@@ -12129,7 +12191,7 @@ ${entry}`;
|
|
|
12129
12191
|
res.status(400).json({ error: `Invalid status. Must be one of: ${validStatuses.join(", ")}.` });
|
|
12130
12192
|
return;
|
|
12131
12193
|
}
|
|
12132
|
-
let content = await
|
|
12194
|
+
let content = await readFile16(assignmentPath, "utf-8");
|
|
12133
12195
|
content = setTopLevelField(content, "status", status);
|
|
12134
12196
|
content = setTopLevelField(content, "updated", nowTimestamp());
|
|
12135
12197
|
if (status !== "blocked") {
|
|
@@ -12155,7 +12217,7 @@ ${entry}`;
|
|
|
12155
12217
|
res.status(404).json({ error: `Project "${projectSlug}" not found` });
|
|
12156
12218
|
return;
|
|
12157
12219
|
}
|
|
12158
|
-
const content = await
|
|
12220
|
+
const content = await readFile16(projectPath, "utf-8");
|
|
12159
12221
|
await writeFileForce(projectPath, applyArchiveFields(content, true, archiveReason(req.body)));
|
|
12160
12222
|
const project = await getProjectDetail(projectsDir2, projectSlug);
|
|
12161
12223
|
res.json({ project });
|
|
@@ -12172,7 +12234,7 @@ ${entry}`;
|
|
|
12172
12234
|
res.status(404).json({ error: `Project "${projectSlug}" not found` });
|
|
12173
12235
|
return;
|
|
12174
12236
|
}
|
|
12175
|
-
const content = await
|
|
12237
|
+
const content = await readFile16(projectPath, "utf-8");
|
|
12176
12238
|
await writeFileForce(projectPath, applyArchiveFields(content, false, null));
|
|
12177
12239
|
const project = await getProjectDetail(projectsDir2, projectSlug);
|
|
12178
12240
|
res.json({ project });
|
|
@@ -12189,7 +12251,7 @@ ${entry}`;
|
|
|
12189
12251
|
res.status(404).json({ error: "Assignment not found" });
|
|
12190
12252
|
return;
|
|
12191
12253
|
}
|
|
12192
|
-
const content = await
|
|
12254
|
+
const content = await readFile16(assignmentPath, "utf-8");
|
|
12193
12255
|
await writeFileForce(assignmentPath, applyArchiveFields(content, archived, archived ? archiveReason(req.body) : null));
|
|
12194
12256
|
const assignment = await getAssignmentDetail(projectsDir2, projectSlug, assignmentSlug);
|
|
12195
12257
|
res.json({ assignment });
|
|
@@ -12222,7 +12284,7 @@ ${entry}`;
|
|
|
12222
12284
|
return;
|
|
12223
12285
|
}
|
|
12224
12286
|
const assignmentPath = resolve21(resolved.assignmentDir, "assignment.md");
|
|
12225
|
-
const content = await
|
|
12287
|
+
const content = await readFile16(assignmentPath, "utf-8");
|
|
12226
12288
|
await writeFileForce(assignmentPath, applyArchiveFields(content, archived, archived ? archiveReason(req.body) : null));
|
|
12227
12289
|
const assignment = await getAssignmentDetailById(projectsDir2, assignmentsDir2, id);
|
|
12228
12290
|
res.json({ assignment });
|
|
@@ -12263,7 +12325,7 @@ ${entry}`;
|
|
|
12263
12325
|
res.status(400).json({ error: validation.error });
|
|
12264
12326
|
return;
|
|
12265
12327
|
}
|
|
12266
|
-
let content = await
|
|
12328
|
+
let content = await readFile16(assignmentPath, "utf-8");
|
|
12267
12329
|
content = setTopLevelField(content, "assignee", validation.value);
|
|
12268
12330
|
content = setTopLevelField(content, "updated", nowTimestamp());
|
|
12269
12331
|
await writeFileForce(assignmentPath, content);
|
|
@@ -12294,7 +12356,7 @@ ${entry}`;
|
|
|
12294
12356
|
res.status(400).json({ error: validation.error });
|
|
12295
12357
|
return;
|
|
12296
12358
|
}
|
|
12297
|
-
let content = await
|
|
12359
|
+
let content = await readFile16(assignmentPath, "utf-8");
|
|
12298
12360
|
content = setTopLevelField(content, "title", validation.value);
|
|
12299
12361
|
content = setTopLevelField(content, "updated", nowTimestamp());
|
|
12300
12362
|
await writeFileForce(assignmentPath, content);
|
|
@@ -12812,7 +12874,7 @@ ${entry}`;
|
|
|
12812
12874
|
res.status(400).json({ error: `Invalid status. Must be one of: ${validStatuses.join(", ")}.` });
|
|
12813
12875
|
return;
|
|
12814
12876
|
}
|
|
12815
|
-
let content = await
|
|
12877
|
+
let content = await readFile16(assignmentPath, "utf-8");
|
|
12816
12878
|
content = setTopLevelField(content, "status", status);
|
|
12817
12879
|
content = setTopLevelField(content, "updated", nowTimestamp());
|
|
12818
12880
|
if (status !== "blocked") {
|
|
@@ -12848,7 +12910,7 @@ ${entry}`;
|
|
|
12848
12910
|
res.status(400).json({ error: validation.error });
|
|
12849
12911
|
return;
|
|
12850
12912
|
}
|
|
12851
|
-
let content = await
|
|
12913
|
+
let content = await readFile16(assignmentPath, "utf-8");
|
|
12852
12914
|
content = setTopLevelField(content, "assignee", validation.value);
|
|
12853
12915
|
content = setTopLevelField(content, "updated", nowTimestamp());
|
|
12854
12916
|
await writeFileForce(assignmentPath, content);
|
|
@@ -12881,7 +12943,7 @@ ${entry}`;
|
|
|
12881
12943
|
res.status(400).json({ error: validation.error });
|
|
12882
12944
|
return;
|
|
12883
12945
|
}
|
|
12884
|
-
let content = await
|
|
12946
|
+
let content = await readFile16(assignmentPath, "utf-8");
|
|
12885
12947
|
content = setTopLevelField(content, "title", validation.value);
|
|
12886
12948
|
content = setTopLevelField(content, "updated", nowTimestamp());
|
|
12887
12949
|
await writeFileForce(assignmentPath, content);
|
|
@@ -13018,7 +13080,7 @@ async function appendCommentTo(assignmentDir, assignmentRef, req, res, reloadDet
|
|
|
13018
13080
|
let currentContent;
|
|
13019
13081
|
let currentCount = 0;
|
|
13020
13082
|
if (await fileExists(commentsPath)) {
|
|
13021
|
-
currentContent = await
|
|
13083
|
+
currentContent = await readFile16(commentsPath, "utf-8");
|
|
13022
13084
|
const countMatch = currentContent.match(/^entryCount:\s*(\d+)/m);
|
|
13023
13085
|
if (countMatch) currentCount = parseInt(countMatch[1], 10);
|
|
13024
13086
|
} else {
|
|
@@ -13058,7 +13120,7 @@ async function toggleCommentResolvedAt(assignmentDir, commentId, req, res, reloa
|
|
|
13058
13120
|
res.status(400).json({ error: "resolved (boolean) is required" });
|
|
13059
13121
|
return;
|
|
13060
13122
|
}
|
|
13061
|
-
const content = await
|
|
13123
|
+
const content = await readFile16(commentsPath, "utf-8");
|
|
13062
13124
|
const parsed = parseComments(content);
|
|
13063
13125
|
const target = parsed.entries.find((e) => e.id === commentId);
|
|
13064
13126
|
if (!target) {
|
|
@@ -13844,7 +13906,7 @@ import { Router as Router8 } from "express";
|
|
|
13844
13906
|
|
|
13845
13907
|
// src/utils/status-config-resolution.ts
|
|
13846
13908
|
init_frontmatter();
|
|
13847
|
-
import { readFile as
|
|
13909
|
+
import { readFile as readFile17, writeFile as writeFile4, rm as rm2 } from "fs/promises";
|
|
13848
13910
|
import { dirname as dirname5 } from "path";
|
|
13849
13911
|
|
|
13850
13912
|
// src/utils/assignment-walk.ts
|
|
@@ -13927,7 +13989,7 @@ async function scanAssignmentsByStatus(projectsDir2, standaloneDir, ids) {
|
|
|
13927
13989
|
const assignmentPath = `${entry.assignmentDir}/assignment.md`;
|
|
13928
13990
|
let content;
|
|
13929
13991
|
try {
|
|
13930
|
-
content = await
|
|
13992
|
+
content = await readFile17(assignmentPath, "utf-8");
|
|
13931
13993
|
} catch (err2) {
|
|
13932
13994
|
const code = err2?.code;
|
|
13933
13995
|
if (code === "ENOENT") {
|
|
@@ -13990,7 +14052,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
|
|
|
13990
14052
|
const list = affected.get(r.id) ?? [];
|
|
13991
14053
|
for (const a of list) {
|
|
13992
14054
|
try {
|
|
13993
|
-
const content = await
|
|
14055
|
+
const content = await readFile17(a.path, "utf-8");
|
|
13994
14056
|
buffer.set(a.path, content);
|
|
13995
14057
|
} catch (err2) {
|
|
13996
14058
|
const code = err2?.code;
|
|
@@ -14018,7 +14080,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
|
|
|
14018
14080
|
for (const a of list) {
|
|
14019
14081
|
let current;
|
|
14020
14082
|
try {
|
|
14021
|
-
current = await
|
|
14083
|
+
current = await readFile17(a.path, "utf-8");
|
|
14022
14084
|
} catch (err2) {
|
|
14023
14085
|
const code = err2?.code;
|
|
14024
14086
|
if (code === "ENOENT") {
|
|
@@ -14067,7 +14129,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
|
|
|
14067
14129
|
const list = affected.get(r.id) ?? [];
|
|
14068
14130
|
for (const a of list) {
|
|
14069
14131
|
try {
|
|
14070
|
-
const current = await
|
|
14132
|
+
const current = await readFile17(a.path, "utf-8");
|
|
14071
14133
|
const fm = parseAssignmentFrontmatter(current);
|
|
14072
14134
|
if (fm.status !== r.id) {
|
|
14073
14135
|
console.warn(
|
|
@@ -15456,7 +15518,7 @@ init_playbook();
|
|
|
15456
15518
|
init_playbooks();
|
|
15457
15519
|
import { Router as Router11 } from "express";
|
|
15458
15520
|
import { resolve as resolve26 } from "path";
|
|
15459
|
-
import { readFile as
|
|
15521
|
+
import { readFile as readFile18 } from "fs/promises";
|
|
15460
15522
|
function statusForPlaybookError(code) {
|
|
15461
15523
|
switch (code) {
|
|
15462
15524
|
case "manifest":
|
|
@@ -15538,7 +15600,7 @@ function createPlaybooksRouter(playbooksDir3) {
|
|
|
15538
15600
|
return;
|
|
15539
15601
|
}
|
|
15540
15602
|
const filePath = resolve26(playbooksDir3, resolved.filename);
|
|
15541
|
-
const content = await
|
|
15603
|
+
const content = await readFile18(filePath, "utf-8");
|
|
15542
15604
|
res.json({
|
|
15543
15605
|
documentType: "playbook",
|
|
15544
15606
|
title: `Edit Playbook: ${resolved.slug}`,
|
|
@@ -15889,8 +15951,8 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
|
|
|
15889
15951
|
router.post("/:workspace/archive", async (req, res) => {
|
|
15890
15952
|
try {
|
|
15891
15953
|
const { archivePath: archivePath2 } = await Promise.resolve().then(() => (init_parser2(), parser_exports));
|
|
15892
|
-
const { resolve:
|
|
15893
|
-
const { readFile:
|
|
15954
|
+
const { resolve: resolve82 } = await import("path");
|
|
15955
|
+
const { readFile: readFile56 } = await import("fs/promises");
|
|
15894
15956
|
const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
15895
15957
|
const workspace = getWorkspaceParam(req.params.workspace);
|
|
15896
15958
|
const checklist = await readChecklist(todosDir2, workspace);
|
|
@@ -15906,10 +15968,10 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
|
|
|
15906
15968
|
(e) => e.itemIds.every((id) => completedIds.has(id))
|
|
15907
15969
|
);
|
|
15908
15970
|
const archFile = archivePath2(todosDir2, workspace, checklist.archiveInterval);
|
|
15909
|
-
await ensureDir(
|
|
15971
|
+
await ensureDir(resolve82(todosDir2, "archive"));
|
|
15910
15972
|
let archContent = "";
|
|
15911
15973
|
if (await fileExists(archFile)) {
|
|
15912
|
-
archContent = await
|
|
15974
|
+
archContent = await readFile56(archFile, "utf-8");
|
|
15913
15975
|
archContent = archContent.trimEnd() + "\n\n";
|
|
15914
15976
|
} else {
|
|
15915
15977
|
archContent = `---
|
|
@@ -16191,7 +16253,7 @@ workspace: ${workspace}
|
|
|
16191
16253
|
const { readConfig: readConfig3 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
16192
16254
|
const { assignmentsDir: assignmentsDirFn } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
16193
16255
|
const { fileExists: fileExists2, writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
16194
|
-
const { readFile:
|
|
16256
|
+
const { readFile: readFile56 } = await import("fs/promises");
|
|
16195
16257
|
const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
|
|
16196
16258
|
const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
|
|
16197
16259
|
let assignmentRef;
|
|
@@ -16212,7 +16274,7 @@ workspace: ${workspace}
|
|
|
16212
16274
|
}
|
|
16213
16275
|
const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
|
|
16214
16276
|
if (!await fileExists2(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
|
|
16215
|
-
let content = await
|
|
16277
|
+
let content = await readFile56(assignmentMdPath2, "utf-8");
|
|
16216
16278
|
content = appendTodosToAssignmentBody2(
|
|
16217
16279
|
content,
|
|
16218
16280
|
items.map((it) => ({
|
|
@@ -16400,7 +16462,7 @@ init_fs();
|
|
|
16400
16462
|
init_paths();
|
|
16401
16463
|
init_slug();
|
|
16402
16464
|
import { Router as Router13 } from "express";
|
|
16403
|
-
import { mkdir as mkdir3, readFile as
|
|
16465
|
+
import { mkdir as mkdir3, readFile as readFile19, rename as rename6 } from "fs/promises";
|
|
16404
16466
|
import { resolve as resolve27, dirname as dirname7 } from "path";
|
|
16405
16467
|
init_promote_todos();
|
|
16406
16468
|
init_api();
|
|
@@ -16625,7 +16687,7 @@ function createProjectTodosRouter(projectsDir2, broadcast, workspaceTodosDir) {
|
|
|
16625
16687
|
const archFile = archivePath(todosDir2, slug, checklist.archiveInterval);
|
|
16626
16688
|
let archContent = "";
|
|
16627
16689
|
if (await fileExists(archFile)) {
|
|
16628
|
-
archContent = await
|
|
16690
|
+
archContent = await readFile19(archFile, "utf-8");
|
|
16629
16691
|
archContent = archContent.trimEnd() + "\n\n";
|
|
16630
16692
|
} else {
|
|
16631
16693
|
archContent = `---
|
|
@@ -17082,7 +17144,7 @@ workspace: ${slug}
|
|
|
17082
17144
|
}
|
|
17083
17145
|
const assignmentMdPath2 = resolve27(assignmentDir, "assignment.md");
|
|
17084
17146
|
if (!await fileExists(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
|
|
17085
|
-
let content = await
|
|
17147
|
+
let content = await readFile19(assignmentMdPath2, "utf-8");
|
|
17086
17148
|
content = appendTodosToAssignmentBody2(
|
|
17087
17149
|
content,
|
|
17088
17150
|
items.map((it) => ({
|
|
@@ -17286,7 +17348,7 @@ init_fs();
|
|
|
17286
17348
|
init_paths();
|
|
17287
17349
|
init_parser2();
|
|
17288
17350
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
17289
|
-
import { readFile as
|
|
17351
|
+
import { readFile as readFile20 } from "fs/promises";
|
|
17290
17352
|
var BUNDLE_ID_REGEX = /^[a-f0-9]{4}$/;
|
|
17291
17353
|
var SCOPE_VALUES = /* @__PURE__ */ new Set(["workspace", "project", "global"]);
|
|
17292
17354
|
var SCOPE_ID_REGEX = /^[a-z0-9_][a-z0-9_-]*$/;
|
|
@@ -17389,7 +17451,7 @@ ${lines}
|
|
|
17389
17451
|
async function readBundles(todosDir2) {
|
|
17390
17452
|
const path = bundlesPath(todosDir2);
|
|
17391
17453
|
if (!await fileExists(path)) return [];
|
|
17392
|
-
const content = await
|
|
17454
|
+
const content = await readFile20(path, "utf-8");
|
|
17393
17455
|
return parseBundles(content).bundles;
|
|
17394
17456
|
}
|
|
17395
17457
|
async function writeBundles(todosDir2, bundles) {
|
|
@@ -17566,7 +17628,7 @@ init_fs();
|
|
|
17566
17628
|
init_config2();
|
|
17567
17629
|
import { execFile as execFile2 } from "child_process";
|
|
17568
17630
|
import { promisify as promisify2 } from "util";
|
|
17569
|
-
import { cp, mkdtemp, rm as rm3, readFile as
|
|
17631
|
+
import { cp, mkdtemp, rm as rm3, readFile as readFile21, writeFile as writeFile5, unlink as unlink5, stat, open as open2, rename as rename7 } from "fs/promises";
|
|
17570
17632
|
import { resolve as resolve29, join as join3 } from "path";
|
|
17571
17633
|
import { tmpdir } from "os";
|
|
17572
17634
|
var exec2 = promisify2(execFile2);
|
|
@@ -17627,7 +17689,7 @@ async function acquireLock() {
|
|
|
17627
17689
|
return lockPath;
|
|
17628
17690
|
} catch (err2) {
|
|
17629
17691
|
if (err2.code === "EEXIST") {
|
|
17630
|
-
const pid = await
|
|
17692
|
+
const pid = await readFile21(lockPath, "utf-8").catch(() => "");
|
|
17631
17693
|
throw new Error(
|
|
17632
17694
|
`Backup operation already in progress (lock file at ${lockPath}, pid ${pid.trim() || "unknown"}). If stale, delete the file and retry.`
|
|
17633
17695
|
);
|
|
@@ -17674,7 +17736,7 @@ function resolveCategoriesStrict(csv) {
|
|
|
17674
17736
|
return parseCategoriesStrict(parts);
|
|
17675
17737
|
}
|
|
17676
17738
|
async function readSanitizedConfig(configPath) {
|
|
17677
|
-
const content = await
|
|
17739
|
+
const content = await readFile21(configPath, "utf-8");
|
|
17678
17740
|
return content.replace(/^(\s*lastBackup:\s*).*$/m, "$1null").replace(/^(\s*lastRestore:\s*).*$/m, "$1null");
|
|
17679
17741
|
}
|
|
17680
17742
|
async function backupToGithub(overrides) {
|
|
@@ -19066,7 +19128,7 @@ init_frontmatter();
|
|
|
19066
19128
|
init_timestamp();
|
|
19067
19129
|
init_assignment_resolver();
|
|
19068
19130
|
import { resolve as resolve33 } from "path";
|
|
19069
|
-
import { readFile as
|
|
19131
|
+
import { readFile as readFile22, writeFile as writeFile7 } from "fs/promises";
|
|
19070
19132
|
async function resolveTarget(target, options) {
|
|
19071
19133
|
const config = await readConfig();
|
|
19072
19134
|
const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
|
|
@@ -19098,7 +19160,7 @@ async function resolveTarget(target, options) {
|
|
|
19098
19160
|
return null;
|
|
19099
19161
|
}
|
|
19100
19162
|
async function writeArchiveState(filePath, archived, reason) {
|
|
19101
|
-
const content = await
|
|
19163
|
+
const content = await readFile22(filePath, "utf-8");
|
|
19102
19164
|
const updated = updateAssignmentFile(content, {
|
|
19103
19165
|
archived,
|
|
19104
19166
|
archivedAt: archived ? nowTimestamp() : null,
|
|
@@ -19167,7 +19229,7 @@ init_config2();
|
|
|
19167
19229
|
init_frontmatter();
|
|
19168
19230
|
init_timestamp();
|
|
19169
19231
|
import { resolve as resolve34 } from "path";
|
|
19170
|
-
import { readdir as readdir13, readFile as
|
|
19232
|
+
import { readdir as readdir13, readFile as readFile23 } from "fs/promises";
|
|
19171
19233
|
var PROMOTABLE_STATUSES = /* @__PURE__ */ new Set(["pending"]);
|
|
19172
19234
|
function objectiveIsFleshedOut(content) {
|
|
19173
19235
|
const match = content.match(/##\s+Objective\s*\n([\s\S]*?)(?=\n##\s+|$)/);
|
|
@@ -19193,7 +19255,7 @@ async function collectCandidates(baseDirs) {
|
|
|
19193
19255
|
if (await fileExists(directAssignmentMd)) {
|
|
19194
19256
|
const fm = await parseSafe(directAssignmentMd);
|
|
19195
19257
|
if (fm && PROMOTABLE_STATUSES.has(fm.status)) {
|
|
19196
|
-
const content = await
|
|
19258
|
+
const content = await readFile23(directAssignmentMd, "utf-8");
|
|
19197
19259
|
if (objectiveIsFleshedOut(content) && hasAcceptanceCriteria(content)) {
|
|
19198
19260
|
candidates.push({
|
|
19199
19261
|
projectSlug: null,
|
|
@@ -19216,7 +19278,7 @@ async function collectCandidates(baseDirs) {
|
|
|
19216
19278
|
if (!await fileExists(assignmentMd)) continue;
|
|
19217
19279
|
const fm = await parseSafe(assignmentMd);
|
|
19218
19280
|
if (!fm || !PROMOTABLE_STATUSES.has(fm.status)) continue;
|
|
19219
|
-
const content = await
|
|
19281
|
+
const content = await readFile23(assignmentMd, "utf-8");
|
|
19220
19282
|
if (!objectiveIsFleshedOut(content)) continue;
|
|
19221
19283
|
if (!hasAcceptanceCriteria(content)) continue;
|
|
19222
19284
|
candidates.push({
|
|
@@ -19233,7 +19295,7 @@ async function collectCandidates(baseDirs) {
|
|
|
19233
19295
|
}
|
|
19234
19296
|
async function parseSafe(path) {
|
|
19235
19297
|
try {
|
|
19236
|
-
const content = await
|
|
19298
|
+
const content = await readFile23(path, "utf-8");
|
|
19237
19299
|
return parseAssignmentFrontmatter(content);
|
|
19238
19300
|
} catch {
|
|
19239
19301
|
return null;
|
|
@@ -19262,7 +19324,7 @@ async function migrateStatusesCommand(options) {
|
|
|
19262
19324
|
const now = nowTimestamp();
|
|
19263
19325
|
let migrated = 0;
|
|
19264
19326
|
for (const c2 of candidates) {
|
|
19265
|
-
const content = await
|
|
19327
|
+
const content = await readFile23(c2.assignmentMd, "utf-8");
|
|
19266
19328
|
const updated = updateAssignmentFile(content, {
|
|
19267
19329
|
status: c2.toStatus,
|
|
19268
19330
|
updated: now
|
|
@@ -19320,7 +19382,7 @@ import {
|
|
|
19320
19382
|
readdir as readdir14,
|
|
19321
19383
|
symlink,
|
|
19322
19384
|
lstat,
|
|
19323
|
-
readFile as
|
|
19385
|
+
readFile as readFile24,
|
|
19324
19386
|
readlink,
|
|
19325
19387
|
rename as rename8,
|
|
19326
19388
|
rm as rm4,
|
|
@@ -19362,8 +19424,8 @@ function getPluginManifestRelativePath(pluginKind) {
|
|
|
19362
19424
|
return pluginKind === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json";
|
|
19363
19425
|
}
|
|
19364
19426
|
function getDefaultPluginTargetDir(pluginKind) {
|
|
19365
|
-
const
|
|
19366
|
-
return pluginKind === "claude" ? resolve36(
|
|
19427
|
+
const home2 = homedir3();
|
|
19428
|
+
return pluginKind === "claude" ? resolve36(home2, ".claude", "plugins", "syntaur") : resolve36(home2, "plugins", "syntaur");
|
|
19367
19429
|
}
|
|
19368
19430
|
function getDefaultMarketplacePath() {
|
|
19369
19431
|
return resolve36(homedir3(), ".agents", "plugins", "marketplace.json");
|
|
@@ -19381,7 +19443,7 @@ function getInstallMarkerPath(targetDir) {
|
|
|
19381
19443
|
return resolve36(targetDir, INSTALL_MARKER_FILENAME);
|
|
19382
19444
|
}
|
|
19383
19445
|
async function readPackageManifest(packageRoot) {
|
|
19384
|
-
const raw = await
|
|
19446
|
+
const raw = await readFile24(resolve36(packageRoot, "package.json"), "utf-8");
|
|
19385
19447
|
return JSON.parse(raw);
|
|
19386
19448
|
}
|
|
19387
19449
|
async function readJsonFileIfExists(pathValue) {
|
|
@@ -19389,7 +19451,7 @@ async function readJsonFileIfExists(pathValue) {
|
|
|
19389
19451
|
return null;
|
|
19390
19452
|
}
|
|
19391
19453
|
try {
|
|
19392
|
-
const raw = await
|
|
19454
|
+
const raw = await readFile24(pathValue, "utf-8");
|
|
19393
19455
|
return JSON.parse(raw);
|
|
19394
19456
|
} catch {
|
|
19395
19457
|
return null;
|
|
@@ -19405,7 +19467,7 @@ async function readPluginManifestName(targetDir, pluginKind) {
|
|
|
19405
19467
|
if (!await fileExists(manifestPath)) {
|
|
19406
19468
|
return void 0;
|
|
19407
19469
|
}
|
|
19408
|
-
const raw = await
|
|
19470
|
+
const raw = await readFile24(manifestPath, "utf-8");
|
|
19409
19471
|
const parsed = JSON.parse(raw);
|
|
19410
19472
|
return parsed.name;
|
|
19411
19473
|
}
|
|
@@ -19415,7 +19477,7 @@ async function readInstallMetadata(targetDir) {
|
|
|
19415
19477
|
return null;
|
|
19416
19478
|
}
|
|
19417
19479
|
try {
|
|
19418
|
-
const raw = await
|
|
19480
|
+
const raw = await readFile24(markerPath, "utf-8");
|
|
19419
19481
|
return JSON.parse(raw);
|
|
19420
19482
|
} catch {
|
|
19421
19483
|
return null;
|
|
@@ -19538,7 +19600,7 @@ async function writeClaudeMarketplaceFile(manifestPath, marketplace) {
|
|
|
19538
19600
|
}
|
|
19539
19601
|
if (await fileExists(manifestPath)) {
|
|
19540
19602
|
try {
|
|
19541
|
-
const prev = await
|
|
19603
|
+
const prev = await readFile24(manifestPath, "utf-8");
|
|
19542
19604
|
JSON.parse(prev);
|
|
19543
19605
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
19544
19606
|
await writeFile8(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
|
|
@@ -19686,7 +19748,7 @@ async function registerKnownClaudeMarketplace(name, rootDir) {
|
|
|
19686
19748
|
const manifestPath = getClaudeKnownMarketplacesPath();
|
|
19687
19749
|
let existing = {};
|
|
19688
19750
|
if (await fileExists(manifestPath)) {
|
|
19689
|
-
const raw = await
|
|
19751
|
+
const raw = await readFile24(manifestPath, "utf-8");
|
|
19690
19752
|
try {
|
|
19691
19753
|
const parsed = JSON.parse(raw);
|
|
19692
19754
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
@@ -19713,7 +19775,7 @@ async function registerKnownClaudeMarketplace(name, rootDir) {
|
|
|
19713
19775
|
existing[name].autoUpdate = true;
|
|
19714
19776
|
await ensureDir(dirname10(manifestPath));
|
|
19715
19777
|
if (await fileExists(manifestPath)) {
|
|
19716
|
-
const prev = await
|
|
19778
|
+
const prev = await readFile24(manifestPath, "utf-8");
|
|
19717
19779
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
19718
19780
|
await writeFile8(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
|
|
19719
19781
|
}
|
|
@@ -19731,7 +19793,7 @@ async function setSyntaurPluginEnabled(options) {
|
|
|
19731
19793
|
const key = `syntaur@${options.marketplaceName}`;
|
|
19732
19794
|
let parsed = {};
|
|
19733
19795
|
if (await fileExists(settingsPath)) {
|
|
19734
|
-
const raw = await
|
|
19796
|
+
const raw = await readFile24(settingsPath, "utf-8");
|
|
19735
19797
|
try {
|
|
19736
19798
|
parsed = JSON.parse(raw);
|
|
19737
19799
|
} catch {
|
|
@@ -19750,7 +19812,7 @@ async function setSyntaurPluginEnabled(options) {
|
|
|
19750
19812
|
await ensureDir(dirname10(settingsPath));
|
|
19751
19813
|
if (await fileExists(settingsPath)) {
|
|
19752
19814
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
19753
|
-
const prev = await
|
|
19815
|
+
const prev = await readFile24(settingsPath, "utf-8");
|
|
19754
19816
|
await writeFile8(`${settingsPath}.bak-${stamp}`, prev, "utf-8");
|
|
19755
19817
|
}
|
|
19756
19818
|
const tmpPath = `${settingsPath}.tmp`;
|
|
@@ -19988,7 +20050,7 @@ async function readMarketplaceFile(marketplacePath) {
|
|
|
19988
20050
|
plugins: []
|
|
19989
20051
|
};
|
|
19990
20052
|
}
|
|
19991
|
-
const raw = await
|
|
20053
|
+
const raw = await readFile24(marketplacePath, "utf-8");
|
|
19992
20054
|
const parsed = JSON.parse(raw);
|
|
19993
20055
|
return {
|
|
19994
20056
|
name: parsed.name ?? "local",
|
|
@@ -20224,13 +20286,13 @@ async function textPrompt(question, defaultValue) {
|
|
|
20224
20286
|
|
|
20225
20287
|
// src/utils/install-skills.ts
|
|
20226
20288
|
init_fs();
|
|
20227
|
-
import { readFile as
|
|
20289
|
+
import { readFile as readFile26, readdir as readdir15, mkdir as mkdir4, copyFile, rm as rm5, lstat as lstat2 } from "fs/promises";
|
|
20228
20290
|
import { resolve as resolve38, relative as relative3, join as join4 } from "path";
|
|
20229
20291
|
import { homedir as homedir5 } from "os";
|
|
20230
20292
|
|
|
20231
20293
|
// src/utils/plugin-state.ts
|
|
20232
20294
|
init_fs();
|
|
20233
|
-
import { readFile as
|
|
20295
|
+
import { readFile as readFile25 } from "fs/promises";
|
|
20234
20296
|
import { resolve as resolve37 } from "path";
|
|
20235
20297
|
import { homedir as homedir4 } from "os";
|
|
20236
20298
|
function settingsPathFor(agent) {
|
|
@@ -20241,7 +20303,7 @@ async function readJsonOrNull(path) {
|
|
|
20241
20303
|
if (!path) return null;
|
|
20242
20304
|
if (!await fileExists(path)) return null;
|
|
20243
20305
|
try {
|
|
20244
|
-
const raw = await
|
|
20306
|
+
const raw = await readFile25(path, "utf-8");
|
|
20245
20307
|
return JSON.parse(raw);
|
|
20246
20308
|
} catch {
|
|
20247
20309
|
return null;
|
|
@@ -20315,7 +20377,7 @@ async function walkFiles(root) {
|
|
|
20315
20377
|
}
|
|
20316
20378
|
async function filesEqual(a, b) {
|
|
20317
20379
|
try {
|
|
20318
|
-
const [ba, bb] = await Promise.all([
|
|
20380
|
+
const [ba, bb] = await Promise.all([readFile26(a), readFile26(b)]);
|
|
20319
20381
|
if (ba.length !== bb.length) return false;
|
|
20320
20382
|
return ba.equals(bb);
|
|
20321
20383
|
} catch {
|
|
@@ -20416,6 +20478,24 @@ async function installSkillsWithReport(options) {
|
|
|
20416
20478
|
}
|
|
20417
20479
|
return { results };
|
|
20418
20480
|
}
|
|
20481
|
+
async function installSkillsToDir(options) {
|
|
20482
|
+
const source = options.sourceDir ?? await getSkillsDir();
|
|
20483
|
+
if (!await fileExists(source)) {
|
|
20484
|
+
throw new Error(
|
|
20485
|
+
`Syntaur skills not found at ${source}. Reinstall syntaur: npm install -g syntaur@latest`
|
|
20486
|
+
);
|
|
20487
|
+
}
|
|
20488
|
+
const force = options.force ?? false;
|
|
20489
|
+
const skillNames = await discoverSkillNames(source);
|
|
20490
|
+
await mkdir4(options.targetDir, { recursive: true });
|
|
20491
|
+
const results = [];
|
|
20492
|
+
for (const skill of skillNames) {
|
|
20493
|
+
const srcDir = join4(source, skill);
|
|
20494
|
+
const destDir = join4(options.targetDir, skill);
|
|
20495
|
+
results.push(await installSkillDir(srcDir, destDir, skill, force));
|
|
20496
|
+
}
|
|
20497
|
+
return results;
|
|
20498
|
+
}
|
|
20419
20499
|
async function uninstallSkills(options) {
|
|
20420
20500
|
const targetRoot = options.targetDir ?? defaultSkillTargetDir(options.target);
|
|
20421
20501
|
if (!await fileExists(targetRoot)) return [];
|
|
@@ -20437,7 +20517,7 @@ async function uninstallSkills(options) {
|
|
|
20437
20517
|
if (await isSymlink(destDir)) continue;
|
|
20438
20518
|
const skillMd = join4(destDir, "SKILL.md");
|
|
20439
20519
|
if (!await fileExists(skillMd)) continue;
|
|
20440
|
-
const content = await
|
|
20520
|
+
const content = await readFile26(skillMd, "utf-8").catch(() => "");
|
|
20441
20521
|
const match = content.match(/^name:\s*(\S+)\s*$/m);
|
|
20442
20522
|
if (!match || match[1] !== skill) continue;
|
|
20443
20523
|
await rm5(destDir, { recursive: true, force: true });
|
|
@@ -20965,7 +21045,7 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
|
|
|
20965
21045
|
`Spawn failed: ${msg}. Verify the terminal is installed and on PATH.`
|
|
20966
21046
|
);
|
|
20967
21047
|
}
|
|
20968
|
-
await new Promise((
|
|
21048
|
+
await new Promise((resolve82, reject) => {
|
|
20969
21049
|
let settled = false;
|
|
20970
21050
|
let stderr = "";
|
|
20971
21051
|
const finishOk = () => {
|
|
@@ -20975,7 +21055,7 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
|
|
|
20975
21055
|
child.unref();
|
|
20976
21056
|
} catch {
|
|
20977
21057
|
}
|
|
20978
|
-
|
|
21058
|
+
resolve82();
|
|
20979
21059
|
};
|
|
20980
21060
|
const finishErr = (remediation) => {
|
|
20981
21061
|
if (settled) return;
|
|
@@ -21017,13 +21097,29 @@ function buildTerminalInvocation(plan) {
|
|
|
21017
21097
|
return {
|
|
21018
21098
|
command: "osascript",
|
|
21019
21099
|
args: [
|
|
21100
|
+
"-e",
|
|
21101
|
+
'set wasRunning to application "Terminal" is running',
|
|
21020
21102
|
"-e",
|
|
21021
21103
|
'tell application "Terminal"',
|
|
21022
21104
|
"-e",
|
|
21023
21105
|
"activate",
|
|
21024
21106
|
"-e",
|
|
21107
|
+
"if wasRunning then",
|
|
21108
|
+
"-e",
|
|
21025
21109
|
`do script ${appleScriptString(cdAndRun)}`,
|
|
21026
21110
|
"-e",
|
|
21111
|
+
"else",
|
|
21112
|
+
"-e",
|
|
21113
|
+
"repeat until (count of windows) > 0",
|
|
21114
|
+
"-e",
|
|
21115
|
+
"delay 0.1",
|
|
21116
|
+
"-e",
|
|
21117
|
+
"end repeat",
|
|
21118
|
+
"-e",
|
|
21119
|
+
`do script ${appleScriptString(cdAndRun)} in window 1`,
|
|
21120
|
+
"-e",
|
|
21121
|
+
"end if",
|
|
21122
|
+
"-e",
|
|
21027
21123
|
"end tell"
|
|
21028
21124
|
]
|
|
21029
21125
|
};
|
|
@@ -21130,7 +21226,7 @@ function normalizeSlashes(p) {
|
|
|
21130
21226
|
}
|
|
21131
21227
|
function detectInstallKind(scriptUrl, opts = {}) {
|
|
21132
21228
|
const realpath3 = opts.realpath ?? realpathSync.native;
|
|
21133
|
-
const
|
|
21229
|
+
const readFile56 = opts.readFile ?? ((p) => readFileSync(p, "utf-8"));
|
|
21134
21230
|
const ua = opts.envUserAgent !== void 0 ? opts.envUserAgent : process.env.npm_config_user_agent ?? "";
|
|
21135
21231
|
const resolved = resolveScriptPath(scriptUrl, realpath3);
|
|
21136
21232
|
if (resolved === null) {
|
|
@@ -21151,7 +21247,7 @@ function detectInstallKind(scriptUrl, opts = {}) {
|
|
|
21151
21247
|
const pkgJsonPath = join5(dir, "package.json");
|
|
21152
21248
|
let raw;
|
|
21153
21249
|
try {
|
|
21154
|
-
raw =
|
|
21250
|
+
raw = readFile56(pkgJsonPath);
|
|
21155
21251
|
} catch {
|
|
21156
21252
|
const parent2 = dirname11(dir);
|
|
21157
21253
|
if (parent2 === dir) break;
|
|
@@ -21236,20 +21332,20 @@ async function maybeNudgeForNpxInstall(scriptUrl) {
|
|
|
21236
21332
|
init_paths();
|
|
21237
21333
|
init_fs();
|
|
21238
21334
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
21239
|
-
import { readFile as
|
|
21335
|
+
import { readFile as readFile28 } from "fs/promises";
|
|
21240
21336
|
import { dirname as dirname13, join as join7, resolve as resolve41 } from "path";
|
|
21241
21337
|
import { spawn as spawn5 } from "child_process";
|
|
21242
21338
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
21243
21339
|
|
|
21244
21340
|
// src/utils/version.ts
|
|
21245
21341
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
21246
|
-
import { readFile as
|
|
21342
|
+
import { readFile as readFile27 } from "fs/promises";
|
|
21247
21343
|
import { dirname as dirname12, join as join6 } from "path";
|
|
21248
21344
|
async function readPackageVersion(scriptUrl) {
|
|
21249
21345
|
try {
|
|
21250
21346
|
const scriptPath = fileURLToPath5(scriptUrl);
|
|
21251
21347
|
const pkgRoot = dirname12(dirname12(scriptPath));
|
|
21252
|
-
const raw = await
|
|
21348
|
+
const raw = await readFile27(join6(pkgRoot, "package.json"), "utf-8");
|
|
21253
21349
|
const parsed = JSON.parse(raw);
|
|
21254
21350
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
21255
21351
|
} catch {
|
|
@@ -21279,7 +21375,7 @@ function isRunningViaNpx(scriptUrl) {
|
|
|
21279
21375
|
async function readState() {
|
|
21280
21376
|
if (!await fileExists(STATE_FILE)) return null;
|
|
21281
21377
|
try {
|
|
21282
|
-
const raw = await
|
|
21378
|
+
const raw = await readFile28(STATE_FILE, "utf-8");
|
|
21283
21379
|
return JSON.parse(raw);
|
|
21284
21380
|
} catch {
|
|
21285
21381
|
return null;
|
|
@@ -21338,7 +21434,7 @@ async function readGlobalVersion() {
|
|
|
21338
21434
|
try {
|
|
21339
21435
|
const manifestPath = join7(rootPath, "syntaur", "package.json");
|
|
21340
21436
|
if (!await fileExists(manifestPath)) return null;
|
|
21341
|
-
const raw = await
|
|
21437
|
+
const raw = await readFile28(manifestPath, "utf-8");
|
|
21342
21438
|
const parsed = JSON.parse(raw);
|
|
21343
21439
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
21344
21440
|
} catch {
|
|
@@ -21696,7 +21792,7 @@ async function refreshPluginSkills(options, pm, runner, getManagedDir, resolveFr
|
|
|
21696
21792
|
// src/commands/install-statusline.ts
|
|
21697
21793
|
init_paths();
|
|
21698
21794
|
init_fs();
|
|
21699
|
-
import { readFile as
|
|
21795
|
+
import { readFile as readFile30, writeFile as writeFile11, copyFile as copyFile2, rm as rm6, stat as stat2, symlink as symlink2, unlink as unlink8, lstat as lstat3 } from "fs/promises";
|
|
21700
21796
|
import { resolve as resolve43, dirname as dirname15 } from "path";
|
|
21701
21797
|
import { homedir as homedir7 } from "os";
|
|
21702
21798
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
@@ -21704,7 +21800,7 @@ import { fileURLToPath as fileURLToPath8 } from "url";
|
|
|
21704
21800
|
// src/commands/configure-statusline.ts
|
|
21705
21801
|
init_paths();
|
|
21706
21802
|
init_fs();
|
|
21707
|
-
import { readFile as
|
|
21803
|
+
import { readFile as readFile29, writeFile as writeFile10 } from "fs/promises";
|
|
21708
21804
|
import { resolve as resolve42, dirname as dirname14 } from "path";
|
|
21709
21805
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
21710
21806
|
import { checkbox, input as input2, confirm } from "@inquirer/prompts";
|
|
@@ -21731,7 +21827,7 @@ function getConfigPath(installRoot) {
|
|
|
21731
21827
|
async function readConfig2(path) {
|
|
21732
21828
|
if (!await fileExists(path)) return null;
|
|
21733
21829
|
try {
|
|
21734
|
-
const raw = await
|
|
21830
|
+
const raw = await readFile29(path, "utf-8");
|
|
21735
21831
|
const parsed = JSON.parse(raw);
|
|
21736
21832
|
if (!parsed || typeof parsed !== "object") return null;
|
|
21737
21833
|
const segments = Array.isArray(parsed.segments) ? parsed.segments.filter(isSegmentName) : [];
|
|
@@ -21919,7 +22015,7 @@ function getPackageStatuslineSource() {
|
|
|
21919
22015
|
}
|
|
21920
22016
|
async function readSettingsJson(settingsPath) {
|
|
21921
22017
|
if (!await fileExists(settingsPath)) return {};
|
|
21922
|
-
const raw = await
|
|
22018
|
+
const raw = await readFile30(settingsPath, "utf-8");
|
|
21923
22019
|
if (raw.trim() === "") return {};
|
|
21924
22020
|
try {
|
|
21925
22021
|
const parsed = JSON.parse(raw);
|
|
@@ -22107,7 +22203,7 @@ async function uninstallStatuslineCommand(options = {}) {
|
|
|
22107
22203
|
let restored = null;
|
|
22108
22204
|
if (await fileExists(backupPath)) {
|
|
22109
22205
|
try {
|
|
22110
|
-
const raw = await
|
|
22206
|
+
const raw = await readFile30(backupPath, "utf-8");
|
|
22111
22207
|
const parsed = JSON.parse(raw);
|
|
22112
22208
|
const prev = parsed?.previousStatusLine;
|
|
22113
22209
|
if (prev && typeof prev === "object" && typeof prev.command === "string") {
|
|
@@ -22284,6 +22380,353 @@ async function uninstallSkillsCommand(options) {
|
|
|
22284
22380
|
// src/commands/setup.ts
|
|
22285
22381
|
import { execSync } from "child_process";
|
|
22286
22382
|
init_config2();
|
|
22383
|
+
|
|
22384
|
+
// src/commands/cross-agent-install.ts
|
|
22385
|
+
init_fs();
|
|
22386
|
+
import { spawnSync as spawnSync6 } from "child_process";
|
|
22387
|
+
import { resolve as resolve46 } from "path";
|
|
22388
|
+
import { readFile as readFile31 } from "fs/promises";
|
|
22389
|
+
|
|
22390
|
+
// src/commands/setup-adapter.ts
|
|
22391
|
+
init_paths();
|
|
22392
|
+
init_fs();
|
|
22393
|
+
init_config2();
|
|
22394
|
+
init_slug();
|
|
22395
|
+
import { resolve as resolve45 } from "path";
|
|
22396
|
+
|
|
22397
|
+
// src/targets/registry.ts
|
|
22398
|
+
init_fs();
|
|
22399
|
+
import { homedir as homedir8 } from "os";
|
|
22400
|
+
import { resolve as resolve44 } from "path";
|
|
22401
|
+
function home(...segments) {
|
|
22402
|
+
return resolve44(homedir8(), ...segments);
|
|
22403
|
+
}
|
|
22404
|
+
function hermesHome() {
|
|
22405
|
+
const env = process.env.HERMES_HOME;
|
|
22406
|
+
return env && env.length > 0 ? resolve44(env) : home(".hermes");
|
|
22407
|
+
}
|
|
22408
|
+
function hermesSkillsDir() {
|
|
22409
|
+
return resolve44(hermesHome(), "skills");
|
|
22410
|
+
}
|
|
22411
|
+
function isHermesHomeCustom() {
|
|
22412
|
+
return hermesHome() !== home(".hermes");
|
|
22413
|
+
}
|
|
22414
|
+
function codexHome() {
|
|
22415
|
+
const env = process.env.CODEX_HOME;
|
|
22416
|
+
return env && env.length > 0 ? resolve44(env) : home(".codex");
|
|
22417
|
+
}
|
|
22418
|
+
var detectDir = (dir) => () => fileExists(dir);
|
|
22419
|
+
var AGENT_TARGETS = [
|
|
22420
|
+
{
|
|
22421
|
+
id: "cursor",
|
|
22422
|
+
displayName: "Cursor",
|
|
22423
|
+
skillsShAgentId: "cursor",
|
|
22424
|
+
detect: detectDir(home(".cursor")),
|
|
22425
|
+
skillsDir: { global: home(".cursor", "skills") },
|
|
22426
|
+
instructions: {
|
|
22427
|
+
files: [
|
|
22428
|
+
{ path: ".cursor/rules/syntaur-protocol.mdc", renderer: "cursorProtocol" },
|
|
22429
|
+
{ path: ".cursor/rules/syntaur-assignment.mdc", renderer: "cursorAssignment" }
|
|
22430
|
+
]
|
|
22431
|
+
}
|
|
22432
|
+
},
|
|
22433
|
+
{
|
|
22434
|
+
// codex is BOTH an adapter (writes AGENTS.md) AND a native plugin.
|
|
22435
|
+
id: "codex",
|
|
22436
|
+
displayName: "Codex",
|
|
22437
|
+
skillsShAgentId: "codex",
|
|
22438
|
+
nativePlugin: "codex",
|
|
22439
|
+
detect: detectDir(codexHome()),
|
|
22440
|
+
skillsDir: { global: resolve44(codexHome(), "skills") },
|
|
22441
|
+
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] }
|
|
22442
|
+
},
|
|
22443
|
+
{
|
|
22444
|
+
id: "opencode",
|
|
22445
|
+
displayName: "OpenCode",
|
|
22446
|
+
skillsShAgentId: "opencode",
|
|
22447
|
+
detect: detectDir(home(".config", "opencode")),
|
|
22448
|
+
skillsDir: { global: home(".config", "opencode", "skills") },
|
|
22449
|
+
instructions: {
|
|
22450
|
+
files: [
|
|
22451
|
+
{ path: "AGENTS.md", renderer: "codexAgents" },
|
|
22452
|
+
{ path: "opencode.json", renderer: "openCodeConfig" }
|
|
22453
|
+
]
|
|
22454
|
+
}
|
|
22455
|
+
},
|
|
22456
|
+
{
|
|
22457
|
+
// claude has NO adapter today (not in the old SUPPORTED_FRAMEWORKS) — the
|
|
22458
|
+
// full plugin path owns its skills/hooks/commands. Native-plugin only.
|
|
22459
|
+
id: "claude",
|
|
22460
|
+
displayName: "Claude Code",
|
|
22461
|
+
skillsShAgentId: "claude-code",
|
|
22462
|
+
nativePlugin: "claude",
|
|
22463
|
+
detect: detectDir(home(".claude")),
|
|
22464
|
+
skillsDir: { global: home(".claude", "skills") }
|
|
22465
|
+
},
|
|
22466
|
+
{
|
|
22467
|
+
id: "pi",
|
|
22468
|
+
displayName: "Pi",
|
|
22469
|
+
skillsShAgentId: "pi",
|
|
22470
|
+
detect: detectDir(home(".pi")),
|
|
22471
|
+
skillsDir: { global: home(".pi", "agent", "skills") },
|
|
22472
|
+
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] }
|
|
22473
|
+
},
|
|
22474
|
+
{
|
|
22475
|
+
id: "openclaw",
|
|
22476
|
+
displayName: "OpenClaw",
|
|
22477
|
+
skillsShAgentId: "openclaw",
|
|
22478
|
+
detect: detectDir(home(".openclaw")),
|
|
22479
|
+
skillsDir: { global: home(".openclaw", "skills") },
|
|
22480
|
+
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] }
|
|
22481
|
+
},
|
|
22482
|
+
{
|
|
22483
|
+
id: "hermes",
|
|
22484
|
+
displayName: "Hermes Agent",
|
|
22485
|
+
skillsShAgentId: "hermes-agent",
|
|
22486
|
+
detect: () => fileExists(hermesHome()),
|
|
22487
|
+
skillsDir: { global: hermesSkillsDir() },
|
|
22488
|
+
instructions: { files: [{ path: "SOUL.md", renderer: "hermesSoul" }] }
|
|
22489
|
+
}
|
|
22490
|
+
];
|
|
22491
|
+
var AGENT_TARGETS_BY_ID = Object.fromEntries(
|
|
22492
|
+
AGENT_TARGETS.map((t) => [t.id, t])
|
|
22493
|
+
);
|
|
22494
|
+
function getAgentTarget(id) {
|
|
22495
|
+
return AGENT_TARGETS_BY_ID[id];
|
|
22496
|
+
}
|
|
22497
|
+
function agentTargetIds() {
|
|
22498
|
+
return AGENT_TARGETS.map((t) => t.id);
|
|
22499
|
+
}
|
|
22500
|
+
function adapterTargets() {
|
|
22501
|
+
return AGENT_TARGETS.filter((t) => t.instructions !== void 0);
|
|
22502
|
+
}
|
|
22503
|
+
|
|
22504
|
+
// src/targets/renderers.ts
|
|
22505
|
+
init_cursor_rules();
|
|
22506
|
+
init_codex_agents();
|
|
22507
|
+
init_opencode_config();
|
|
22508
|
+
init_hermes_soul();
|
|
22509
|
+
var RENDERERS = {
|
|
22510
|
+
codexAgents: (ctx) => renderCodexAgents(ctx),
|
|
22511
|
+
cursorProtocol: () => renderCursorProtocol(),
|
|
22512
|
+
cursorAssignment: (ctx) => renderCursorAssignment(ctx),
|
|
22513
|
+
openCodeConfig: (ctx) => renderOpenCodeConfig({ projectDir: ctx.projectDir }),
|
|
22514
|
+
hermesSoul: (ctx) => renderHermesSoul(ctx)
|
|
22515
|
+
};
|
|
22516
|
+
|
|
22517
|
+
// src/commands/setup-adapter.ts
|
|
22518
|
+
async function setupAdapterCommand(framework, options) {
|
|
22519
|
+
const target = getAgentTarget(framework);
|
|
22520
|
+
if (!target || !target.instructions) {
|
|
22521
|
+
const supported = adapterTargets().map((t) => t.id).join(", ");
|
|
22522
|
+
throw new Error(
|
|
22523
|
+
`Unsupported framework "${framework}". Supported: ${supported}`
|
|
22524
|
+
);
|
|
22525
|
+
}
|
|
22526
|
+
if (!options.project) {
|
|
22527
|
+
throw new Error("--project <slug> is required.");
|
|
22528
|
+
}
|
|
22529
|
+
if (!options.assignment) {
|
|
22530
|
+
throw new Error("--assignment <slug> is required.");
|
|
22531
|
+
}
|
|
22532
|
+
if (!isValidSlug(options.project)) {
|
|
22533
|
+
throw new Error(
|
|
22534
|
+
`Invalid project slug "${options.project}". Slugs must be lowercase, hyphen-separated, with no special characters.`
|
|
22535
|
+
);
|
|
22536
|
+
}
|
|
22537
|
+
if (!isValidSlug(options.assignment)) {
|
|
22538
|
+
throw new Error(
|
|
22539
|
+
`Invalid assignment slug "${options.assignment}". Slugs must be lowercase, hyphen-separated, with no special characters.`
|
|
22540
|
+
);
|
|
22541
|
+
}
|
|
22542
|
+
const config = await readConfig();
|
|
22543
|
+
const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
|
|
22544
|
+
const projectDir = resolve45(baseDir, options.project);
|
|
22545
|
+
const assignmentDir = resolve45(projectDir, "assignments", options.assignment);
|
|
22546
|
+
const projectMdPath = resolve45(projectDir, "project.md");
|
|
22547
|
+
if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
|
|
22548
|
+
throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
|
|
22549
|
+
}
|
|
22550
|
+
const assignmentMdPath2 = resolve45(assignmentDir, "assignment.md");
|
|
22551
|
+
if (!await fileExists(assignmentDir) || !await fileExists(assignmentMdPath2)) {
|
|
22552
|
+
throw new Error(
|
|
22553
|
+
`Assignment "${options.assignment}" not found at ${assignmentDir}.`
|
|
22554
|
+
);
|
|
22555
|
+
}
|
|
22556
|
+
const cwd = process.cwd();
|
|
22557
|
+
const rendererParams = {
|
|
22558
|
+
projectSlug: options.project,
|
|
22559
|
+
assignmentSlug: options.assignment,
|
|
22560
|
+
projectDir,
|
|
22561
|
+
assignmentDir
|
|
22562
|
+
};
|
|
22563
|
+
const writtenFiles = [];
|
|
22564
|
+
const upToDateFiles = [];
|
|
22565
|
+
const skippedFiles = [];
|
|
22566
|
+
for (const file of target.instructions.files) {
|
|
22567
|
+
const filePath = resolve45(cwd, file.path);
|
|
22568
|
+
const content = RENDERERS[file.renderer](rendererParams);
|
|
22569
|
+
const status = await writeFileReport(filePath, content, {
|
|
22570
|
+
force: options.force
|
|
22571
|
+
});
|
|
22572
|
+
if (status === "differs-preserved") {
|
|
22573
|
+
skippedFiles.push(filePath);
|
|
22574
|
+
} else if (status === "already-current") {
|
|
22575
|
+
upToDateFiles.push(filePath);
|
|
22576
|
+
} else {
|
|
22577
|
+
writtenFiles.push(filePath);
|
|
22578
|
+
}
|
|
22579
|
+
}
|
|
22580
|
+
if (writtenFiles.length > 0) {
|
|
22581
|
+
console.log(`Generated ${target.id} adapter files:`);
|
|
22582
|
+
for (const f of writtenFiles) {
|
|
22583
|
+
console.log(` ${f}`);
|
|
22584
|
+
}
|
|
22585
|
+
}
|
|
22586
|
+
if (upToDateFiles.length > 0) {
|
|
22587
|
+
console.log(`Already up-to-date:`);
|
|
22588
|
+
for (const f of upToDateFiles) {
|
|
22589
|
+
console.log(` ${f}`);
|
|
22590
|
+
}
|
|
22591
|
+
}
|
|
22592
|
+
if (skippedFiles.length > 0) {
|
|
22593
|
+
console.log(`Skipped (exists with different content, use --force to overwrite):`);
|
|
22594
|
+
for (const f of skippedFiles) {
|
|
22595
|
+
console.log(` ${f}`);
|
|
22596
|
+
}
|
|
22597
|
+
}
|
|
22598
|
+
if (writtenFiles.length === 0 && skippedFiles.length === 0 && upToDateFiles.length > 0) {
|
|
22599
|
+
console.log(`No changes. All ${target.id} adapter files are already up-to-date.`);
|
|
22600
|
+
}
|
|
22601
|
+
}
|
|
22602
|
+
|
|
22603
|
+
// src/commands/cross-agent-install.ts
|
|
22604
|
+
init_config2();
|
|
22605
|
+
var DEFAULT_SKILLS_SOURCE = "prong-horn/syntaur";
|
|
22606
|
+
function parseTargetIds(options) {
|
|
22607
|
+
const raw = [options.target, options.agent].filter(Boolean).join(",");
|
|
22608
|
+
const ids = raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
22609
|
+
return [...new Set(ids)];
|
|
22610
|
+
}
|
|
22611
|
+
function isNpxAvailable() {
|
|
22612
|
+
try {
|
|
22613
|
+
const r = spawnSync6("npx", ["--version"], { stdio: "ignore" });
|
|
22614
|
+
return !r.error && r.status === 0;
|
|
22615
|
+
} catch {
|
|
22616
|
+
return false;
|
|
22617
|
+
}
|
|
22618
|
+
}
|
|
22619
|
+
async function readAssignmentContext() {
|
|
22620
|
+
const p = resolve46(process.cwd(), ".syntaur", "context.json");
|
|
22621
|
+
if (!await fileExists(p)) return null;
|
|
22622
|
+
try {
|
|
22623
|
+
return JSON.parse(await readFile31(p, "utf-8"));
|
|
22624
|
+
} catch {
|
|
22625
|
+
return null;
|
|
22626
|
+
}
|
|
22627
|
+
}
|
|
22628
|
+
async function crossAgentInstallCommand(options) {
|
|
22629
|
+
const ids = parseTargetIds(options);
|
|
22630
|
+
if (ids.length === 0) {
|
|
22631
|
+
throw new Error("No agents specified. Use --target <id> or --agent <id>.");
|
|
22632
|
+
}
|
|
22633
|
+
const targets = [];
|
|
22634
|
+
for (const id of ids) {
|
|
22635
|
+
const t = getAgentTarget(id);
|
|
22636
|
+
if (!t) {
|
|
22637
|
+
throw new Error(
|
|
22638
|
+
`Unknown agent "${id}". Known agents: ${agentTargetIds().join(", ")}`
|
|
22639
|
+
);
|
|
22640
|
+
}
|
|
22641
|
+
if (t.nativePlugin) {
|
|
22642
|
+
throw new Error(
|
|
22643
|
+
`"${id}" installs as a native Syntaur plugin, not via cross-agent install. Use \`syntaur setup --${t.nativePlugin}\` (or \`syntaur ${t.nativePlugin === "claude" ? "install-plugin" : "install-codex-plugin"}\`).`
|
|
22644
|
+
);
|
|
22645
|
+
}
|
|
22646
|
+
targets.push(t);
|
|
22647
|
+
}
|
|
22648
|
+
const dryRun = Boolean(options.dryRun);
|
|
22649
|
+
const force = Boolean(options.force);
|
|
22650
|
+
const scope = "global";
|
|
22651
|
+
const prefix = dryRun ? "[dry-run] " : "";
|
|
22652
|
+
if (!dryRun && !await isSyntaurDataInstalled()) {
|
|
22653
|
+
await initCommand({});
|
|
22654
|
+
}
|
|
22655
|
+
const skillsShIds = targets.map((t) => t.skillsShAgentId ?? t.id);
|
|
22656
|
+
const argv = ["skills", "add", DEFAULT_SKILLS_SOURCE, "--agent", ...skillsShIds];
|
|
22657
|
+
console.log(`${prefix}Tier 1 (skills): npx ${argv.join(" ")}`);
|
|
22658
|
+
let tier1Done = false;
|
|
22659
|
+
if (!dryRun) {
|
|
22660
|
+
if (isNpxAvailable()) {
|
|
22661
|
+
const r = spawnSync6("npx", argv, { stdio: "inherit" });
|
|
22662
|
+
tier1Done = !r.error && r.status === 0;
|
|
22663
|
+
if (!tier1Done) {
|
|
22664
|
+
console.log("`npx skills add` failed; falling back to offline copy.");
|
|
22665
|
+
}
|
|
22666
|
+
} else {
|
|
22667
|
+
console.log("npx not available; using offline skill copy.");
|
|
22668
|
+
}
|
|
22669
|
+
}
|
|
22670
|
+
for (const t of targets) {
|
|
22671
|
+
const globalDir = t.id === "hermes" ? hermesSkillsDir() : t.skillsDir?.global;
|
|
22672
|
+
if (!globalDir) continue;
|
|
22673
|
+
const offlineNeeded = !tier1Done;
|
|
22674
|
+
const hermesCustom = t.id === "hermes" && isHermesHomeCustom();
|
|
22675
|
+
if (!offlineNeeded && !hermesCustom) continue;
|
|
22676
|
+
if (dryRun) {
|
|
22677
|
+
const label = hermesCustom ? "offline copy (always \u2014 custom $HERMES_HOME)" : "offline copy (fallback if npx unavailable)";
|
|
22678
|
+
console.log(`${prefix}${label} -> ${globalDir}`);
|
|
22679
|
+
continue;
|
|
22680
|
+
}
|
|
22681
|
+
const reason = hermesCustom && tier1Done ? " ($HERMES_HOME reconcile)" : "";
|
|
22682
|
+
await installSkillsToDir({ targetDir: globalDir, force });
|
|
22683
|
+
console.log(`Copied skills -> ${globalDir}${reason}`);
|
|
22684
|
+
}
|
|
22685
|
+
const adapterTargets2 = targets.filter((t) => t.instructions);
|
|
22686
|
+
if (adapterTargets2.length > 0) {
|
|
22687
|
+
const ctx = await readAssignmentContext();
|
|
22688
|
+
const haveCtx = Boolean(ctx?.projectSlug && ctx?.assignmentSlug);
|
|
22689
|
+
for (const t of adapterTargets2) {
|
|
22690
|
+
if (dryRun) {
|
|
22691
|
+
for (const f of t.instructions.files) {
|
|
22692
|
+
console.log(
|
|
22693
|
+
`${prefix}Tier 2 (${t.id}): ${resolve46(process.cwd(), f.path)}`
|
|
22694
|
+
);
|
|
22695
|
+
}
|
|
22696
|
+
continue;
|
|
22697
|
+
}
|
|
22698
|
+
if (!haveCtx) {
|
|
22699
|
+
console.log(
|
|
22700
|
+
`No project-nested assignment context in cwd; skipping Tier-2 files for ${t.id}.`
|
|
22701
|
+
);
|
|
22702
|
+
continue;
|
|
22703
|
+
}
|
|
22704
|
+
try {
|
|
22705
|
+
await setupAdapterCommand(t.id, {
|
|
22706
|
+
project: ctx.projectSlug,
|
|
22707
|
+
assignment: ctx.assignmentSlug,
|
|
22708
|
+
force
|
|
22709
|
+
});
|
|
22710
|
+
} catch (err2) {
|
|
22711
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
22712
|
+
console.log(`Tier 2 for ${t.id} skipped: ${msg}`);
|
|
22713
|
+
}
|
|
22714
|
+
}
|
|
22715
|
+
}
|
|
22716
|
+
if (!dryRun) {
|
|
22717
|
+
const current = (await readConfig()).integrations.installedAgents ?? {};
|
|
22718
|
+
const next = { ...current };
|
|
22719
|
+
for (const t of targets) {
|
|
22720
|
+
next[t.id] = { scope };
|
|
22721
|
+
}
|
|
22722
|
+
await updateIntegrationConfig({ installedAgents: next });
|
|
22723
|
+
}
|
|
22724
|
+
console.log(
|
|
22725
|
+
`${prefix}Done. Agents: ${targets.map((t) => t.displayName).join(", ")}.`
|
|
22726
|
+
);
|
|
22727
|
+
}
|
|
22728
|
+
|
|
22729
|
+
// src/commands/setup.ts
|
|
22287
22730
|
function isCliInstalled(command) {
|
|
22288
22731
|
try {
|
|
22289
22732
|
execSync(`which ${command}`, { stdio: "ignore" });
|
|
@@ -22301,6 +22744,15 @@ function printNonInteractiveSetupHelp() {
|
|
|
22301
22744
|
console.error(` npx syntaur@latest setup --yes --dashboard`);
|
|
22302
22745
|
}
|
|
22303
22746
|
async function setupCommand(options) {
|
|
22747
|
+
if (options.dryRun && !options.target && !options.agent) {
|
|
22748
|
+
throw new Error(
|
|
22749
|
+
"--dry-run only applies to cross-agent install. Pass --target <id> or --agent <id>."
|
|
22750
|
+
);
|
|
22751
|
+
}
|
|
22752
|
+
if (options.target || options.agent) {
|
|
22753
|
+
await crossAgentInstallCommand(options);
|
|
22754
|
+
return;
|
|
22755
|
+
}
|
|
22304
22756
|
const initialized = await isSyntaurDataInstalled();
|
|
22305
22757
|
const interactive = isInteractiveTerminal();
|
|
22306
22758
|
if (!initialized) {
|
|
@@ -22385,7 +22837,7 @@ async function setupCommand(options) {
|
|
|
22385
22837
|
}
|
|
22386
22838
|
|
|
22387
22839
|
// src/commands/uninstall.ts
|
|
22388
|
-
import { resolve as
|
|
22840
|
+
import { resolve as resolve47 } from "path";
|
|
22389
22841
|
init_paths();
|
|
22390
22842
|
function expandTargets(options) {
|
|
22391
22843
|
if (options.all) {
|
|
@@ -22465,7 +22917,7 @@ async function uninstallCommand(options) {
|
|
|
22465
22917
|
const configuredProjectDir = await getConfiguredProjectDir();
|
|
22466
22918
|
await removeSyntaurData();
|
|
22467
22919
|
console.log(`Removed ${syntaurRoot()}`);
|
|
22468
|
-
if (configuredProjectDir &&
|
|
22920
|
+
if (configuredProjectDir && resolve47(configuredProjectDir) !== resolve47(syntaurRoot(), "projects")) {
|
|
22469
22921
|
console.warn(
|
|
22470
22922
|
`Warning: config.md pointed to an external project directory (${configuredProjectDir}). That directory was not removed automatically.`
|
|
22471
22923
|
);
|
|
@@ -22476,114 +22928,11 @@ async function uninstallCommand(options) {
|
|
|
22476
22928
|
}
|
|
22477
22929
|
}
|
|
22478
22930
|
|
|
22479
|
-
// src/commands/setup-adapter.ts
|
|
22480
|
-
init_paths();
|
|
22481
|
-
init_fs();
|
|
22482
|
-
init_config2();
|
|
22483
|
-
init_slug();
|
|
22484
|
-
init_cursor_rules();
|
|
22485
|
-
init_codex_agents();
|
|
22486
|
-
init_opencode_config();
|
|
22487
|
-
import { resolve as resolve45 } from "path";
|
|
22488
|
-
var SUPPORTED_FRAMEWORKS = ["cursor", "codex", "opencode"];
|
|
22489
|
-
async function setupAdapterCommand(framework, options) {
|
|
22490
|
-
if (!SUPPORTED_FRAMEWORKS.includes(framework)) {
|
|
22491
|
-
throw new Error(
|
|
22492
|
-
`Unsupported framework "${framework}". Supported: ${SUPPORTED_FRAMEWORKS.join(", ")}`
|
|
22493
|
-
);
|
|
22494
|
-
}
|
|
22495
|
-
if (!options.project) {
|
|
22496
|
-
throw new Error("--project <slug> is required.");
|
|
22497
|
-
}
|
|
22498
|
-
if (!options.assignment) {
|
|
22499
|
-
throw new Error("--assignment <slug> is required.");
|
|
22500
|
-
}
|
|
22501
|
-
if (!isValidSlug(options.project)) {
|
|
22502
|
-
throw new Error(
|
|
22503
|
-
`Invalid project slug "${options.project}". Slugs must be lowercase, hyphen-separated, with no special characters.`
|
|
22504
|
-
);
|
|
22505
|
-
}
|
|
22506
|
-
if (!isValidSlug(options.assignment)) {
|
|
22507
|
-
throw new Error(
|
|
22508
|
-
`Invalid assignment slug "${options.assignment}". Slugs must be lowercase, hyphen-separated, with no special characters.`
|
|
22509
|
-
);
|
|
22510
|
-
}
|
|
22511
|
-
const config = await readConfig();
|
|
22512
|
-
const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
|
|
22513
|
-
const projectDir = resolve45(baseDir, options.project);
|
|
22514
|
-
const assignmentDir = resolve45(
|
|
22515
|
-
projectDir,
|
|
22516
|
-
"assignments",
|
|
22517
|
-
options.assignment
|
|
22518
|
-
);
|
|
22519
|
-
const projectMdPath = resolve45(projectDir, "project.md");
|
|
22520
|
-
if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
|
|
22521
|
-
throw new Error(
|
|
22522
|
-
`Project "${options.project}" not found at ${projectDir}.`
|
|
22523
|
-
);
|
|
22524
|
-
}
|
|
22525
|
-
const assignmentMdPath2 = resolve45(assignmentDir, "assignment.md");
|
|
22526
|
-
if (!await fileExists(assignmentDir) || !await fileExists(assignmentMdPath2)) {
|
|
22527
|
-
throw new Error(
|
|
22528
|
-
`Assignment "${options.assignment}" not found at ${assignmentDir}.`
|
|
22529
|
-
);
|
|
22530
|
-
}
|
|
22531
|
-
const cwd = process.cwd();
|
|
22532
|
-
const writtenFiles = [];
|
|
22533
|
-
const skippedFiles = [];
|
|
22534
|
-
const rendererParams = {
|
|
22535
|
-
projectSlug: options.project,
|
|
22536
|
-
assignmentSlug: options.assignment,
|
|
22537
|
-
projectDir,
|
|
22538
|
-
assignmentDir
|
|
22539
|
-
};
|
|
22540
|
-
async function writeAdapterFile(filePath, content) {
|
|
22541
|
-
if (options.force) {
|
|
22542
|
-
await writeFileForce(filePath, content);
|
|
22543
|
-
writtenFiles.push(filePath);
|
|
22544
|
-
} else {
|
|
22545
|
-
if (await writeFileSafe(filePath, content)) {
|
|
22546
|
-
writtenFiles.push(filePath);
|
|
22547
|
-
} else {
|
|
22548
|
-
skippedFiles.push(filePath);
|
|
22549
|
-
}
|
|
22550
|
-
}
|
|
22551
|
-
}
|
|
22552
|
-
if (framework === "cursor") {
|
|
22553
|
-
const protocolPath = resolve45(cwd, ".cursor", "rules", "syntaur-protocol.mdc");
|
|
22554
|
-
const assignmentPath = resolve45(cwd, ".cursor", "rules", "syntaur-assignment.mdc");
|
|
22555
|
-
await writeAdapterFile(protocolPath, renderCursorProtocol());
|
|
22556
|
-
await writeAdapterFile(assignmentPath, renderCursorAssignment(rendererParams));
|
|
22557
|
-
} else if (framework === "codex" || framework === "opencode") {
|
|
22558
|
-
const agentsPath = resolve45(cwd, "AGENTS.md");
|
|
22559
|
-
await writeAdapterFile(agentsPath, renderCodexAgents(rendererParams));
|
|
22560
|
-
if (framework === "opencode") {
|
|
22561
|
-
const configPath = resolve45(cwd, "opencode.json");
|
|
22562
|
-
await writeAdapterFile(configPath, renderOpenCodeConfig({ projectDir }));
|
|
22563
|
-
}
|
|
22564
|
-
}
|
|
22565
|
-
if (writtenFiles.length > 0) {
|
|
22566
|
-
console.log(`Generated ${framework} adapter files:`);
|
|
22567
|
-
for (const f of writtenFiles) {
|
|
22568
|
-
console.log(` ${f}`);
|
|
22569
|
-
}
|
|
22570
|
-
}
|
|
22571
|
-
if (skippedFiles.length > 0) {
|
|
22572
|
-
console.log(`Skipped (already exist, use --force to overwrite):`);
|
|
22573
|
-
for (const f of skippedFiles) {
|
|
22574
|
-
console.log(` ${f}`);
|
|
22575
|
-
}
|
|
22576
|
-
}
|
|
22577
|
-
if (writtenFiles.length === 0 && skippedFiles.length > 0) {
|
|
22578
|
-
console.log(`No files written. All target files already exist.`);
|
|
22579
|
-
}
|
|
22580
|
-
}
|
|
22581
|
-
|
|
22582
22931
|
// src/commands/track-session.ts
|
|
22583
22932
|
init_paths();
|
|
22584
22933
|
init_fs();
|
|
22585
22934
|
init_config2();
|
|
22586
|
-
import { resolve as
|
|
22935
|
+
import { resolve as resolve48 } from "path";
|
|
22587
22936
|
init_session_db();
|
|
22588
22937
|
init_agent_sessions();
|
|
22589
22938
|
async function trackSessionCommand(options) {
|
|
@@ -22598,7 +22947,7 @@ async function trackSessionCommand(options) {
|
|
|
22598
22947
|
if (options.project) {
|
|
22599
22948
|
const config = await readConfig();
|
|
22600
22949
|
const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
|
|
22601
|
-
const projectDir =
|
|
22950
|
+
const projectDir = resolve48(baseDir, options.project);
|
|
22602
22951
|
if (!await fileExists(projectDir)) {
|
|
22603
22952
|
throw new Error(
|
|
22604
22953
|
`Project "${options.project}" not found at ${projectDir}.`
|
|
@@ -22730,8 +23079,8 @@ function formatInstallUrlHandlerError(err2) {
|
|
|
22730
23079
|
init_config2();
|
|
22731
23080
|
init_paths();
|
|
22732
23081
|
init_fs();
|
|
22733
|
-
import { resolve as
|
|
22734
|
-
import { readFile as
|
|
23082
|
+
import { resolve as resolve50, isAbsolute as isAbsolute7 } from "path";
|
|
23083
|
+
import { readFile as readFile32 } from "fs/promises";
|
|
22735
23084
|
import { select, confirm as confirm2, input as input3 } from "@inquirer/prompts";
|
|
22736
23085
|
async function browseCommand(options) {
|
|
22737
23086
|
const config = await readConfig();
|
|
@@ -22800,7 +23149,7 @@ async function pickAgent2(agents) {
|
|
|
22800
23149
|
return picked;
|
|
22801
23150
|
}
|
|
22802
23151
|
async function ensureWorktree(opts) {
|
|
22803
|
-
const assignmentPath =
|
|
23152
|
+
const assignmentPath = resolve50(
|
|
22804
23153
|
opts.projectsDir,
|
|
22805
23154
|
opts.projectSlug,
|
|
22806
23155
|
"assignments",
|
|
@@ -22810,7 +23159,7 @@ async function ensureWorktree(opts) {
|
|
|
22810
23159
|
if (!await fileExists(assignmentPath)) {
|
|
22811
23160
|
return void 0;
|
|
22812
23161
|
}
|
|
22813
|
-
const content = await
|
|
23162
|
+
const content = await readFile32(assignmentPath, "utf-8");
|
|
22814
23163
|
const { parseAssignmentFrontmatter: parseAssignmentFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
|
|
22815
23164
|
const fm = parseAssignmentFrontmatter2(content);
|
|
22816
23165
|
const { workspace } = fm;
|
|
@@ -22880,7 +23229,7 @@ async function ensureWorktree(opts) {
|
|
|
22880
23229
|
async function runCreate(opts) {
|
|
22881
23230
|
const { createWorktreeAndRecord: createWorktreeAndRecord2, GitWorktreeError: GitWorktreeError2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22882
23231
|
const expandedWorktree = expandHome(opts.worktreePath);
|
|
22883
|
-
const absWorktree = isAbsolute7(expandedWorktree) ? expandedWorktree :
|
|
23232
|
+
const absWorktree = isAbsolute7(expandedWorktree) ? expandedWorktree : resolve50(expandedWorktree);
|
|
22884
23233
|
try {
|
|
22885
23234
|
await createWorktreeAndRecord2({
|
|
22886
23235
|
assignmentPath: opts.assignmentPath,
|
|
@@ -22909,7 +23258,7 @@ init_paths();
|
|
|
22909
23258
|
init_fs();
|
|
22910
23259
|
init_playbook();
|
|
22911
23260
|
init_playbooks();
|
|
22912
|
-
import { resolve as
|
|
23261
|
+
import { resolve as resolve51 } from "path";
|
|
22913
23262
|
async function createPlaybookCommand(name, options) {
|
|
22914
23263
|
if (!name.trim()) {
|
|
22915
23264
|
throw new Error("Playbook name cannot be empty.");
|
|
@@ -22922,7 +23271,7 @@ async function createPlaybookCommand(name, options) {
|
|
|
22922
23271
|
}
|
|
22923
23272
|
const dir = playbooksDir();
|
|
22924
23273
|
await ensureDir(dir);
|
|
22925
|
-
const filePath =
|
|
23274
|
+
const filePath = resolve51(dir, `${slug}.md`);
|
|
22926
23275
|
if (await fileExists(filePath)) {
|
|
22927
23276
|
throw new Error(
|
|
22928
23277
|
`Playbook "${slug}" already exists at ${filePath}
|
|
@@ -22944,8 +23293,8 @@ init_paths();
|
|
|
22944
23293
|
init_fs();
|
|
22945
23294
|
init_parser();
|
|
22946
23295
|
init_config2();
|
|
22947
|
-
import { readdir as readdir16, readFile as
|
|
22948
|
-
import { resolve as
|
|
23296
|
+
import { readdir as readdir16, readFile as readFile33 } from "fs/promises";
|
|
23297
|
+
import { resolve as resolve52 } from "path";
|
|
22949
23298
|
async function listPlaybooksCommand(options = {}) {
|
|
22950
23299
|
const dir = playbooksDir();
|
|
22951
23300
|
if (!await fileExists(dir)) {
|
|
@@ -22960,8 +23309,8 @@ async function listPlaybooksCommand(options = {}) {
|
|
|
22960
23309
|
);
|
|
22961
23310
|
const rows = [];
|
|
22962
23311
|
for (const entry of mdFiles) {
|
|
22963
|
-
const filePath =
|
|
22964
|
-
const raw = await
|
|
23312
|
+
const filePath = resolve52(dir, entry.name);
|
|
23313
|
+
const raw = await readFile33(filePath, "utf-8");
|
|
22965
23314
|
const parsed = parsePlaybook(raw);
|
|
22966
23315
|
const slug = parsed.slug || entry.name.replace(/\.md$/, "");
|
|
22967
23316
|
const disabled = disabledSet.has(slug);
|
|
@@ -23084,14 +23433,14 @@ init_fs();
|
|
|
23084
23433
|
init_config2();
|
|
23085
23434
|
init_slug();
|
|
23086
23435
|
import { Command as Command2 } from "commander";
|
|
23087
|
-
import { readFile as
|
|
23088
|
-
import { resolve as
|
|
23436
|
+
import { readFile as readFile35 } from "fs/promises";
|
|
23437
|
+
import { resolve as resolve54 } from "path";
|
|
23089
23438
|
|
|
23090
23439
|
// src/commands/bundle.ts
|
|
23091
23440
|
init_paths();
|
|
23092
23441
|
import { Command } from "commander";
|
|
23093
|
-
import { mkdir as mkdir7, readFile as
|
|
23094
|
-
import { resolve as
|
|
23442
|
+
import { mkdir as mkdir7, readFile as readFile34, readdir as readdir17, rm as rm7, writeFile as writeFile12 } from "fs/promises";
|
|
23443
|
+
import { resolve as resolve53 } from "path";
|
|
23095
23444
|
init_parser2();
|
|
23096
23445
|
init_fs();
|
|
23097
23446
|
init_config2();
|
|
@@ -23109,7 +23458,7 @@ async function resolveBundleScope(options) {
|
|
|
23109
23458
|
throw new Error(`Invalid project slug: "${options.project}".`);
|
|
23110
23459
|
}
|
|
23111
23460
|
const config = await readConfig();
|
|
23112
|
-
const projectMd =
|
|
23461
|
+
const projectMd = resolve53(config.defaultProjectDir, options.project, "project.md");
|
|
23113
23462
|
if (!await fileExists(projectMd)) {
|
|
23114
23463
|
throw new Error(`Project "${options.project}" not found.`);
|
|
23115
23464
|
}
|
|
@@ -23179,10 +23528,10 @@ function pickNextPlanFile(planDir, existingFiles) {
|
|
|
23179
23528
|
const m = f.match(/^plan-v(\d+)\.md$/);
|
|
23180
23529
|
if (m) versions.add(parseInt(m[1], 10));
|
|
23181
23530
|
}
|
|
23182
|
-
if (versions.size === 0) return { target:
|
|
23531
|
+
if (versions.size === 0) return { target: resolve53(planDir, "plan.md"), version: 1 };
|
|
23183
23532
|
let n = 2;
|
|
23184
23533
|
while (versions.has(n)) n++;
|
|
23185
|
-
return { target:
|
|
23534
|
+
return { target: resolve53(planDir, `plan-v${n}.md`), version: n };
|
|
23186
23535
|
}
|
|
23187
23536
|
function dedupePreserveOrder(ids) {
|
|
23188
23537
|
const out = [];
|
|
@@ -23266,7 +23615,7 @@ bundleCommand.command("new").description("Create a new bundle from 2+ existing t
|
|
|
23266
23615
|
if (options.plan) {
|
|
23267
23616
|
const planDir = bundlePlanDir(sc.todosPath, sc.scopeId, id);
|
|
23268
23617
|
await ensureDir(planDir);
|
|
23269
|
-
const target =
|
|
23618
|
+
const target = resolve53(planDir, "plan.md");
|
|
23270
23619
|
const memberLines = items.map((it) => `- ${it.description} [t:${it.id}]`).join("\n");
|
|
23271
23620
|
const stub = [
|
|
23272
23621
|
"---",
|
|
@@ -23442,7 +23791,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
23442
23791
|
}
|
|
23443
23792
|
const repository = options.repository ?? process.cwd();
|
|
23444
23793
|
const parentBranch = options.parentBranch ?? "main";
|
|
23445
|
-
const worktreePath = options.worktreePath ??
|
|
23794
|
+
const worktreePath = options.worktreePath ?? resolve53(repository, ".worktrees", options.branch);
|
|
23446
23795
|
const checklist = await readChecklist(sc.todosPath, sc.checklistKey);
|
|
23447
23796
|
for (const memberId of bundle.todoIds) {
|
|
23448
23797
|
const item = checklist.items.find((i) => i.id === memberId);
|
|
@@ -23452,8 +23801,8 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
23452
23801
|
}
|
|
23453
23802
|
const bundlesFilePath = bundlesPath(sc.todosPath);
|
|
23454
23803
|
const checklistFilePath = checklistPath(sc.todosPath, sc.checklistKey);
|
|
23455
|
-
const bundlesSnapshot = await fileExists(bundlesFilePath) ? await
|
|
23456
|
-
const checklistSnapshot = await fileExists(checklistFilePath) ? await
|
|
23804
|
+
const bundlesSnapshot = await fileExists(bundlesFilePath) ? await readFile34(bundlesFilePath, "utf-8") : null;
|
|
23805
|
+
const checklistSnapshot = await fileExists(checklistFilePath) ? await readFile34(checklistFilePath, "utf-8") : null;
|
|
23457
23806
|
const record = async () => {
|
|
23458
23807
|
bundle.branch = options.branch;
|
|
23459
23808
|
bundle.worktreePath = worktreePath;
|
|
@@ -23469,7 +23818,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
23469
23818
|
try {
|
|
23470
23819
|
await writeBundles(sc.todosPath, bundles);
|
|
23471
23820
|
await writeChecklist(sc.todosPath, checklist);
|
|
23472
|
-
const ctxDir =
|
|
23821
|
+
const ctxDir = resolve53(worktreePath, ".syntaur");
|
|
23473
23822
|
await mkdir7(ctxDir, { recursive: true });
|
|
23474
23823
|
const payload = {
|
|
23475
23824
|
bundleId: bundle.id,
|
|
@@ -23483,7 +23832,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
23483
23832
|
repository,
|
|
23484
23833
|
boundAt: nowISO()
|
|
23485
23834
|
};
|
|
23486
|
-
await writeFile12(
|
|
23835
|
+
await writeFile12(resolve53(ctxDir, "context.json"), JSON.stringify(payload, null, 2) + "\n");
|
|
23487
23836
|
} catch (err2) {
|
|
23488
23837
|
try {
|
|
23489
23838
|
if (bundlesSnapshot === null) {
|
|
@@ -23673,7 +24022,7 @@ async function resolveScope(options) {
|
|
|
23673
24022
|
throw new Error(`Invalid project slug: "${options.project}".`);
|
|
23674
24023
|
}
|
|
23675
24024
|
const config = await readConfig();
|
|
23676
|
-
const projectMd =
|
|
24025
|
+
const projectMd = resolve54(config.defaultProjectDir, options.project, "project.md");
|
|
23677
24026
|
if (!await fileExists(projectMd)) {
|
|
23678
24027
|
throw new Error(`Project "${options.project}" not found.`);
|
|
23679
24028
|
}
|
|
@@ -23996,10 +24345,10 @@ todoCommand.command("archive").description("Archive completed todos and their lo
|
|
|
23996
24345
|
(e) => e.itemIds.every((id) => completedIds.has(id))
|
|
23997
24346
|
);
|
|
23998
24347
|
const archFile = archivePath(todosPath, workspace, checklist.archiveInterval);
|
|
23999
|
-
await ensureDir(
|
|
24348
|
+
await ensureDir(resolve54(todosPath, "archive"));
|
|
24000
24349
|
let archContent = "";
|
|
24001
24350
|
if (await fileExists(archFile)) {
|
|
24002
|
-
archContent = await
|
|
24351
|
+
archContent = await readFile35(archFile, "utf-8");
|
|
24003
24352
|
archContent = archContent.trimEnd() + "\n\n";
|
|
24004
24353
|
} else {
|
|
24005
24354
|
archContent = `---
|
|
@@ -24176,12 +24525,12 @@ function describeScope(scope) {
|
|
|
24176
24525
|
}
|
|
24177
24526
|
async function injectPromotedTodos(assignmentDir, todos, scopeLabel) {
|
|
24178
24527
|
const { resolve: resolvePath2 } = await import("path");
|
|
24179
|
-
const { readFile:
|
|
24528
|
+
const { readFile: readFile56 } = await import("fs/promises");
|
|
24180
24529
|
const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
24181
24530
|
const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
|
|
24182
24531
|
const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
|
|
24183
24532
|
const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
|
|
24184
|
-
let content = await
|
|
24533
|
+
let content = await readFile56(assignmentMdPath2, "utf-8");
|
|
24185
24534
|
content = appendTodosToAssignmentBody2(
|
|
24186
24535
|
content,
|
|
24187
24536
|
todos.map((t) => ({
|
|
@@ -24232,7 +24581,7 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
|
|
|
24232
24581
|
);
|
|
24233
24582
|
let target;
|
|
24234
24583
|
if (existingFiles.length === 0) {
|
|
24235
|
-
target =
|
|
24584
|
+
target = resolve54(planDir, "plan.md");
|
|
24236
24585
|
} else {
|
|
24237
24586
|
const versions = /* @__PURE__ */ new Set();
|
|
24238
24587
|
for (const f of existingFiles) {
|
|
@@ -24242,7 +24591,7 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
|
|
|
24242
24591
|
}
|
|
24243
24592
|
let n = 2;
|
|
24244
24593
|
while (versions.has(n)) n++;
|
|
24245
|
-
target =
|
|
24594
|
+
target = resolve54(planDir, `plan-v${n}.md`);
|
|
24246
24595
|
}
|
|
24247
24596
|
if (!await fileExists(target)) {
|
|
24248
24597
|
const stub = `---
|
|
@@ -24431,24 +24780,24 @@ backupCommand.command("config").description("Show or update backup configuration
|
|
|
24431
24780
|
|
|
24432
24781
|
// src/commands/doctor.ts
|
|
24433
24782
|
import { Command as Command4 } from "commander";
|
|
24434
|
-
import { readFile as
|
|
24435
|
-
import { isAbsolute as isAbsolute10, resolve as
|
|
24783
|
+
import { readFile as readFile43 } from "fs/promises";
|
|
24784
|
+
import { isAbsolute as isAbsolute10, resolve as resolve67 } from "path";
|
|
24436
24785
|
|
|
24437
24786
|
// src/utils/doctor/index.ts
|
|
24438
24787
|
import { fileURLToPath as fileURLToPath11 } from "url";
|
|
24439
|
-
import { readFile as
|
|
24440
|
-
import { dirname as dirname19, join as
|
|
24788
|
+
import { readFile as readFile42 } from "fs/promises";
|
|
24789
|
+
import { dirname as dirname19, join as join13 } from "path";
|
|
24441
24790
|
|
|
24442
24791
|
// src/utils/doctor/context.ts
|
|
24443
24792
|
init_config2();
|
|
24444
24793
|
init_paths();
|
|
24445
24794
|
init_fs();
|
|
24446
24795
|
import Database4 from "better-sqlite3";
|
|
24447
|
-
import { resolve as
|
|
24796
|
+
import { resolve as resolve55 } from "path";
|
|
24448
24797
|
async function buildCheckContext(cwd = process.cwd()) {
|
|
24449
24798
|
const config = await readConfig();
|
|
24450
24799
|
const root = syntaurRoot();
|
|
24451
|
-
const dbPath =
|
|
24800
|
+
const dbPath = resolve55(root, "syntaur.db");
|
|
24452
24801
|
let db5 = null;
|
|
24453
24802
|
let dbError = null;
|
|
24454
24803
|
if (await fileExists(dbPath)) {
|
|
@@ -24482,8 +24831,8 @@ function closeCheckContext(ctx) {
|
|
|
24482
24831
|
// src/utils/doctor/checks/env.ts
|
|
24483
24832
|
init_fs();
|
|
24484
24833
|
init_paths();
|
|
24485
|
-
import { resolve as
|
|
24486
|
-
import { readFile as
|
|
24834
|
+
import { resolve as resolve56, isAbsolute as isAbsolute8 } from "path";
|
|
24835
|
+
import { readFile as readFile36, stat as stat3 } from "fs/promises";
|
|
24487
24836
|
import { fileURLToPath as fileURLToPath10 } from "url";
|
|
24488
24837
|
import { dirname as dirname17, join as join10 } from "path";
|
|
24489
24838
|
var CATEGORY = "env";
|
|
@@ -24523,7 +24872,7 @@ var configValid = {
|
|
|
24523
24872
|
category: CATEGORY,
|
|
24524
24873
|
title: "~/.syntaur/config.md is valid",
|
|
24525
24874
|
async run(ctx) {
|
|
24526
|
-
const configPath =
|
|
24875
|
+
const configPath = resolve56(ctx.syntaurRoot, "config.md");
|
|
24527
24876
|
if (!await fileExists(configPath)) {
|
|
24528
24877
|
return {
|
|
24529
24878
|
id: this.id,
|
|
@@ -24540,7 +24889,7 @@ var configValid = {
|
|
|
24540
24889
|
autoFixable: false
|
|
24541
24890
|
};
|
|
24542
24891
|
}
|
|
24543
|
-
const content = await
|
|
24892
|
+
const content = await readFile36(configPath, "utf-8");
|
|
24544
24893
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
24545
24894
|
if (!fmMatch || fmMatch[1].trim() === "") {
|
|
24546
24895
|
return {
|
|
@@ -24820,7 +25169,7 @@ async function readLocalPkg() {
|
|
|
24820
25169
|
for (let i = 0; i < 6; i++) {
|
|
24821
25170
|
const candidate = join10(dir, "package.json");
|
|
24822
25171
|
try {
|
|
24823
|
-
const text = await
|
|
25172
|
+
const text = await readFile36(candidate, "utf-8");
|
|
24824
25173
|
return JSON.parse(text);
|
|
24825
25174
|
} catch {
|
|
24826
25175
|
dir = dirname17(dir);
|
|
@@ -24872,7 +25221,7 @@ function versionGte(a, b) {
|
|
|
24872
25221
|
|
|
24873
25222
|
// src/utils/doctor/checks/structure.ts
|
|
24874
25223
|
init_fs();
|
|
24875
|
-
import { resolve as
|
|
25224
|
+
import { resolve as resolve57 } from "path";
|
|
24876
25225
|
import { readdir as readdir18, stat as stat4 } from "fs/promises";
|
|
24877
25226
|
var CATEGORY2 = "structure";
|
|
24878
25227
|
var KNOWN_TOP_LEVEL = /* @__PURE__ */ new Set([
|
|
@@ -24892,7 +25241,7 @@ var projectsDir = {
|
|
|
24892
25241
|
category: CATEGORY2,
|
|
24893
25242
|
title: "projects/ directory exists",
|
|
24894
25243
|
async run(ctx) {
|
|
24895
|
-
const p =
|
|
25244
|
+
const p = resolve57(ctx.syntaurRoot, "projects");
|
|
24896
25245
|
if (!await fileExists(p)) {
|
|
24897
25246
|
return {
|
|
24898
25247
|
id: this.id,
|
|
@@ -24917,7 +25266,7 @@ var playbooksDir2 = {
|
|
|
24917
25266
|
category: CATEGORY2,
|
|
24918
25267
|
title: "playbooks/ directory exists",
|
|
24919
25268
|
async run(ctx) {
|
|
24920
|
-
const p =
|
|
25269
|
+
const p = resolve57(ctx.syntaurRoot, "playbooks");
|
|
24921
25270
|
if (!await fileExists(p)) {
|
|
24922
25271
|
return {
|
|
24923
25272
|
id: this.id,
|
|
@@ -24942,7 +25291,7 @@ var todosDirValid = {
|
|
|
24942
25291
|
category: CATEGORY2,
|
|
24943
25292
|
title: "todos/ directory is readable (if present)",
|
|
24944
25293
|
async run(ctx) {
|
|
24945
|
-
const p =
|
|
25294
|
+
const p = resolve57(ctx.syntaurRoot, "todos");
|
|
24946
25295
|
if (!await fileExists(p)) {
|
|
24947
25296
|
return {
|
|
24948
25297
|
id: this.id,
|
|
@@ -24973,7 +25322,7 @@ var serversDirValid = {
|
|
|
24973
25322
|
category: CATEGORY2,
|
|
24974
25323
|
title: "servers/ directory is readable (if present)",
|
|
24975
25324
|
async run(ctx) {
|
|
24976
|
-
const p =
|
|
25325
|
+
const p = resolve57(ctx.syntaurRoot, "servers");
|
|
24977
25326
|
if (!await fileExists(p)) {
|
|
24978
25327
|
return {
|
|
24979
25328
|
id: this.id,
|
|
@@ -25018,7 +25367,7 @@ var knownFilesRecognized = {
|
|
|
25018
25367
|
title: this.title,
|
|
25019
25368
|
status: "warn",
|
|
25020
25369
|
detail: `unexpected top-level entries: ${unexpected.join(", ")}`,
|
|
25021
|
-
affected: unexpected.map((n) =>
|
|
25370
|
+
affected: unexpected.map((n) => resolve57(ctx.syntaurRoot, n)),
|
|
25022
25371
|
remediation: {
|
|
25023
25372
|
kind: "manual",
|
|
25024
25373
|
suggestion: "Review these entries \u2014 they may be leftover state from older versions",
|
|
@@ -25047,7 +25396,7 @@ function pass2(check) {
|
|
|
25047
25396
|
|
|
25048
25397
|
// src/utils/doctor/checks/project.ts
|
|
25049
25398
|
init_fs();
|
|
25050
|
-
import { resolve as
|
|
25399
|
+
import { resolve as resolve58 } from "path";
|
|
25051
25400
|
import { readdir as readdir19, stat as stat5 } from "fs/promises";
|
|
25052
25401
|
var CATEGORY3 = "project";
|
|
25053
25402
|
var REQUIRED_PROJECT_FILES = [
|
|
@@ -25077,10 +25426,10 @@ async function listProjects2(ctx) {
|
|
|
25077
25426
|
for (const e of entries) {
|
|
25078
25427
|
if (!e.isDirectory()) continue;
|
|
25079
25428
|
if (e.name.startsWith(".") || e.name.startsWith("_")) continue;
|
|
25080
|
-
const projectDir =
|
|
25429
|
+
const projectDir = resolve58(dir, e.name);
|
|
25081
25430
|
let looksLikeProject = false;
|
|
25082
25431
|
for (const marker of PROJECT_MARKERS) {
|
|
25083
|
-
if (await fileExists(
|
|
25432
|
+
if (await fileExists(resolve58(projectDir, marker))) {
|
|
25084
25433
|
looksLikeProject = true;
|
|
25085
25434
|
break;
|
|
25086
25435
|
}
|
|
@@ -25099,7 +25448,7 @@ var requiredFiles = {
|
|
|
25099
25448
|
for (const projectDir of projects) {
|
|
25100
25449
|
const missing = [];
|
|
25101
25450
|
for (const rel of REQUIRED_PROJECT_FILES) {
|
|
25102
|
-
const p =
|
|
25451
|
+
const p = resolve58(projectDir, rel);
|
|
25103
25452
|
if (!await fileExists(p)) missing.push(rel);
|
|
25104
25453
|
}
|
|
25105
25454
|
if (missing.length === 0) continue;
|
|
@@ -25109,7 +25458,7 @@ var requiredFiles = {
|
|
|
25109
25458
|
title: this.title,
|
|
25110
25459
|
status: "error",
|
|
25111
25460
|
detail: `project at ${projectDir} is missing: ${missing.join(", ")}`,
|
|
25112
|
-
affected: missing.map((m) =>
|
|
25461
|
+
affected: missing.map((m) => resolve58(projectDir, m)),
|
|
25113
25462
|
remediation: {
|
|
25114
25463
|
kind: "manual",
|
|
25115
25464
|
suggestion: "Recreate the missing scaffold files from templates",
|
|
@@ -25132,7 +25481,7 @@ var manifestStale = {
|
|
|
25132
25481
|
const projects = await listProjects2(ctx);
|
|
25133
25482
|
const results = [];
|
|
25134
25483
|
for (const projectDir of projects) {
|
|
25135
|
-
const manifestPath =
|
|
25484
|
+
const manifestPath = resolve58(projectDir, "manifest.md");
|
|
25136
25485
|
if (!await fileExists(manifestPath)) continue;
|
|
25137
25486
|
const manifestMtime = (await stat5(manifestPath)).mtimeMs;
|
|
25138
25487
|
const newestAssignment = await newestAssignmentMtime(projectDir);
|
|
@@ -25181,7 +25530,7 @@ var orphanFiles = {
|
|
|
25181
25530
|
title: this.title,
|
|
25182
25531
|
status: "warn",
|
|
25183
25532
|
detail: `project at ${projectDir} has unexpected entries: ${orphans.join(", ")}`,
|
|
25184
|
-
affected: orphans.map((o) =>
|
|
25533
|
+
affected: orphans.map((o) => resolve58(projectDir, o)),
|
|
25185
25534
|
autoFixable: false
|
|
25186
25535
|
});
|
|
25187
25536
|
}
|
|
@@ -25191,7 +25540,7 @@ var orphanFiles = {
|
|
|
25191
25540
|
};
|
|
25192
25541
|
var projectChecks = [requiredFiles, manifestStale, orphanFiles];
|
|
25193
25542
|
async function newestAssignmentMtime(projectDir) {
|
|
25194
|
-
const assignmentsRoot =
|
|
25543
|
+
const assignmentsRoot = resolve58(projectDir, "assignments");
|
|
25195
25544
|
if (!await fileExists(assignmentsRoot)) return 0;
|
|
25196
25545
|
let newest = 0;
|
|
25197
25546
|
let entries;
|
|
@@ -25202,7 +25551,7 @@ async function newestAssignmentMtime(projectDir) {
|
|
|
25202
25551
|
}
|
|
25203
25552
|
for (const e of entries) {
|
|
25204
25553
|
if (!e.isDirectory()) continue;
|
|
25205
|
-
const assignmentMd =
|
|
25554
|
+
const assignmentMd = resolve58(assignmentsRoot, e.name, "assignment.md");
|
|
25206
25555
|
try {
|
|
25207
25556
|
const s = await stat5(assignmentMd);
|
|
25208
25557
|
if (s.mtimeMs > newest) newest = s.mtimeMs;
|
|
@@ -25226,8 +25575,8 @@ init_fs();
|
|
|
25226
25575
|
init_parser();
|
|
25227
25576
|
init_types();
|
|
25228
25577
|
init_paths();
|
|
25229
|
-
import { resolve as
|
|
25230
|
-
import { readFile as
|
|
25578
|
+
import { resolve as resolve59 } from "path";
|
|
25579
|
+
import { readFile as readFile37, readdir as readdir20 } from "fs/promises";
|
|
25231
25580
|
var CATEGORY4 = "assignment";
|
|
25232
25581
|
var STATUSES_REQUIRING_HANDOFF = /* @__PURE__ */ new Set(["review", "completed"]);
|
|
25233
25582
|
var PRE_WORKSPACE_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -25321,7 +25670,7 @@ var invalidStatus = {
|
|
|
25321
25670
|
const allowed = configuredStatuses(ctx);
|
|
25322
25671
|
const results = [];
|
|
25323
25672
|
for (const a of withAssignmentMd) {
|
|
25324
|
-
const path =
|
|
25673
|
+
const path = resolve59(a.assignmentDir, "assignment.md");
|
|
25325
25674
|
const parsed = await parseSafe2(path);
|
|
25326
25675
|
if (!parsed) continue;
|
|
25327
25676
|
if (!allowed.has(parsed.status)) {
|
|
@@ -25354,7 +25703,7 @@ var workspaceMissing = {
|
|
|
25354
25703
|
const terminal = terminalStatuses(ctx);
|
|
25355
25704
|
const results = [];
|
|
25356
25705
|
for (const a of withAssignmentMd) {
|
|
25357
|
-
const path =
|
|
25706
|
+
const path = resolve59(a.assignmentDir, "assignment.md");
|
|
25358
25707
|
const parsed = await parseSafe2(path);
|
|
25359
25708
|
if (!parsed) continue;
|
|
25360
25709
|
if (terminal.has(parsed.status)) continue;
|
|
@@ -25401,12 +25750,12 @@ var requiredFilesByStatus = {
|
|
|
25401
25750
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
25402
25751
|
const results = [];
|
|
25403
25752
|
for (const a of withAssignmentMd) {
|
|
25404
|
-
const assignmentPath =
|
|
25753
|
+
const assignmentPath = resolve59(a.assignmentDir, "assignment.md");
|
|
25405
25754
|
const parsed = await parseSafe2(assignmentPath);
|
|
25406
25755
|
if (!parsed) continue;
|
|
25407
25756
|
const missing = [];
|
|
25408
25757
|
if (STATUSES_REQUIRING_HANDOFF.has(parsed.status)) {
|
|
25409
|
-
const handoffPath =
|
|
25758
|
+
const handoffPath = resolve59(a.assignmentDir, "handoff.md");
|
|
25410
25759
|
if (!await fileExists(handoffPath)) missing.push("handoff.md");
|
|
25411
25760
|
}
|
|
25412
25761
|
if (missing.length === 0) continue;
|
|
@@ -25416,7 +25765,7 @@ var requiredFilesByStatus = {
|
|
|
25416
25765
|
title: this.title,
|
|
25417
25766
|
status: "warn",
|
|
25418
25767
|
detail: `${a.projectSlug}/${a.assignmentSlug} (status: ${parsed.status}) is missing ${missing.join(", ")}`,
|
|
25419
|
-
affected: missing.map((m) =>
|
|
25768
|
+
affected: missing.map((m) => resolve59(a.assignmentDir, m)),
|
|
25420
25769
|
remediation: {
|
|
25421
25770
|
kind: "manual",
|
|
25422
25771
|
suggestion: `Create the missing ${missing.join(" and ")} files for this assignment`,
|
|
@@ -25439,7 +25788,7 @@ var companionFilesScaffolded = {
|
|
|
25439
25788
|
for (const a of withAssignmentMd) {
|
|
25440
25789
|
const missing = [];
|
|
25441
25790
|
for (const filename of ["progress.md", "comments.md"]) {
|
|
25442
|
-
if (!await fileExists(
|
|
25791
|
+
if (!await fileExists(resolve59(a.assignmentDir, filename))) {
|
|
25443
25792
|
missing.push(filename);
|
|
25444
25793
|
}
|
|
25445
25794
|
}
|
|
@@ -25451,7 +25800,7 @@ var companionFilesScaffolded = {
|
|
|
25451
25800
|
title: this.title,
|
|
25452
25801
|
status: "warn",
|
|
25453
25802
|
detail: `${label} is missing ${missing.join(" and ")} (pre-v2.0 assignment \u2014 not required, but scaffolding them keeps the dashboard and CLIs consistent)`,
|
|
25454
|
-
affected: missing.map((m) =>
|
|
25803
|
+
affected: missing.map((m) => resolve59(a.assignmentDir, m)),
|
|
25455
25804
|
remediation: {
|
|
25456
25805
|
kind: "manual",
|
|
25457
25806
|
suggestion: `Create ${missing.join(" and ")} with the renderProgress/renderComments templates, or re-scaffold via the CLI`,
|
|
@@ -25484,7 +25833,7 @@ var typeDefinition = {
|
|
|
25484
25833
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
25485
25834
|
const results = [];
|
|
25486
25835
|
for (const a of withAssignmentMd) {
|
|
25487
|
-
const path =
|
|
25836
|
+
const path = resolve59(a.assignmentDir, "assignment.md");
|
|
25488
25837
|
const parsed = await parseSafe2(path);
|
|
25489
25838
|
if (!parsed) continue;
|
|
25490
25839
|
if (!parsed.type) continue;
|
|
@@ -25518,7 +25867,7 @@ var projectFrontmatterMatchesContainer = {
|
|
|
25518
25867
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
25519
25868
|
const results = [];
|
|
25520
25869
|
for (const a of withAssignmentMd) {
|
|
25521
|
-
const path =
|
|
25870
|
+
const path = resolve59(a.assignmentDir, "assignment.md");
|
|
25522
25871
|
const parsed = await parseSafe2(path);
|
|
25523
25872
|
if (!parsed) continue;
|
|
25524
25873
|
if (a.standalone) {
|
|
@@ -25569,13 +25918,13 @@ var draftMissingObjective = {
|
|
|
25569
25918
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
25570
25919
|
const results = [];
|
|
25571
25920
|
for (const a of withAssignmentMd) {
|
|
25572
|
-
const path =
|
|
25921
|
+
const path = resolve59(a.assignmentDir, "assignment.md");
|
|
25573
25922
|
const parsed = await parseSafe2(path);
|
|
25574
25923
|
if (!parsed) continue;
|
|
25575
25924
|
if (parsed.status !== "draft") continue;
|
|
25576
25925
|
let raw;
|
|
25577
25926
|
try {
|
|
25578
|
-
raw = await
|
|
25927
|
+
raw = await readFile37(path, "utf-8");
|
|
25579
25928
|
} catch {
|
|
25580
25929
|
continue;
|
|
25581
25930
|
}
|
|
@@ -25608,7 +25957,7 @@ var readyToImplementMissingPlan = {
|
|
|
25608
25957
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
25609
25958
|
const results = [];
|
|
25610
25959
|
for (const a of withAssignmentMd) {
|
|
25611
|
-
const path =
|
|
25960
|
+
const path = resolve59(a.assignmentDir, "assignment.md");
|
|
25612
25961
|
const parsed = await parseSafe2(path);
|
|
25613
25962
|
if (!parsed) continue;
|
|
25614
25963
|
if (parsed.status !== "ready_to_implement") continue;
|
|
@@ -25617,7 +25966,7 @@ var readyToImplementMissingPlan = {
|
|
|
25617
25966
|
let hasPlanContent = false;
|
|
25618
25967
|
for (const f of planFiles) {
|
|
25619
25968
|
try {
|
|
25620
|
-
const c2 = await
|
|
25969
|
+
const c2 = await readFile37(resolve59(a.assignmentDir, f), "utf-8");
|
|
25621
25970
|
if (c2.trim().length > 0) {
|
|
25622
25971
|
hasPlanContent = true;
|
|
25623
25972
|
break;
|
|
@@ -25633,7 +25982,7 @@ var readyToImplementMissingPlan = {
|
|
|
25633
25982
|
title: this.title,
|
|
25634
25983
|
status: "warn",
|
|
25635
25984
|
detail: `${label} (status: ready_to_implement) has no plan.md or plan-v<N>.md`,
|
|
25636
|
-
affected: [
|
|
25985
|
+
affected: [resolve59(a.assignmentDir, "plan.md")],
|
|
25637
25986
|
remediation: {
|
|
25638
25987
|
kind: "manual",
|
|
25639
25988
|
suggestion: `Write a plan with '/plan-assignment' (or 'syntaur plan'), then re-mark ready_to_implement`,
|
|
@@ -25660,7 +26009,7 @@ var assignmentChecks = [
|
|
|
25660
26009
|
];
|
|
25661
26010
|
async function parseSafe2(path) {
|
|
25662
26011
|
try {
|
|
25663
|
-
const content = await
|
|
26012
|
+
const content = await readFile37(path, "utf-8");
|
|
25664
26013
|
return parseAssignmentFull(content);
|
|
25665
26014
|
} catch {
|
|
25666
26015
|
return null;
|
|
@@ -25679,7 +26028,7 @@ function pass4(check, detail) {
|
|
|
25679
26028
|
|
|
25680
26029
|
// src/utils/doctor/checks/dashboard.ts
|
|
25681
26030
|
init_fs();
|
|
25682
|
-
import { resolve as
|
|
26031
|
+
import { resolve as resolve60 } from "path";
|
|
25683
26032
|
var CATEGORY5 = "dashboard";
|
|
25684
26033
|
var dbReachable = {
|
|
25685
26034
|
id: "dashboard.db-reachable",
|
|
@@ -25693,7 +26042,7 @@ var dbReachable = {
|
|
|
25693
26042
|
title: this.title,
|
|
25694
26043
|
status: "error",
|
|
25695
26044
|
detail: `could not open syntaur.db: ${ctx.dbError ?? "unknown error"}`,
|
|
25696
|
-
affected: [
|
|
26045
|
+
affected: [resolve60(ctx.syntaurRoot, "syntaur.db")],
|
|
25697
26046
|
remediation: {
|
|
25698
26047
|
kind: "manual",
|
|
25699
26048
|
suggestion: "Start the dashboard once (`syntaur dashboard`) to initialize the DB, or restore it from backup",
|
|
@@ -25711,7 +26060,7 @@ var dbReachable = {
|
|
|
25711
26060
|
title: this.title,
|
|
25712
26061
|
status: "error",
|
|
25713
26062
|
detail: 'syntaur.db is missing the expected "sessions" table',
|
|
25714
|
-
affected: [
|
|
26063
|
+
affected: [resolve60(ctx.syntaurRoot, "syntaur.db")],
|
|
25715
26064
|
autoFixable: false
|
|
25716
26065
|
};
|
|
25717
26066
|
}
|
|
@@ -25723,7 +26072,7 @@ var dbReachable = {
|
|
|
25723
26072
|
title: this.title,
|
|
25724
26073
|
status: "error",
|
|
25725
26074
|
detail: `syntaur.db query failed: ${err2 instanceof Error ? err2.message : String(err2)}`,
|
|
25726
|
-
affected: [
|
|
26075
|
+
affected: [resolve60(ctx.syntaurRoot, "syntaur.db")],
|
|
25727
26076
|
autoFixable: false
|
|
25728
26077
|
};
|
|
25729
26078
|
}
|
|
@@ -25749,7 +26098,7 @@ var ghostSessions = {
|
|
|
25749
26098
|
const results = [];
|
|
25750
26099
|
for (const row of rows) {
|
|
25751
26100
|
if (!row.project_slug) continue;
|
|
25752
|
-
const projectPath =
|
|
26101
|
+
const projectPath = resolve60(projectsDir2, row.project_slug, "project.md");
|
|
25753
26102
|
if (!await fileExists(projectPath)) {
|
|
25754
26103
|
results.push({
|
|
25755
26104
|
id: this.id,
|
|
@@ -25768,7 +26117,7 @@ var ghostSessions = {
|
|
|
25768
26117
|
continue;
|
|
25769
26118
|
}
|
|
25770
26119
|
if (row.assignment_slug) {
|
|
25771
|
-
const assignmentPath =
|
|
26120
|
+
const assignmentPath = resolve60(
|
|
25772
26121
|
projectsDir2,
|
|
25773
26122
|
row.project_slug,
|
|
25774
26123
|
"assignments",
|
|
@@ -25820,9 +26169,9 @@ function skipped(check, reason) {
|
|
|
25820
26169
|
|
|
25821
26170
|
// src/utils/doctor/checks/integrations.ts
|
|
25822
26171
|
init_fs();
|
|
25823
|
-
import { resolve as
|
|
25824
|
-
import { readdir as readdir21, readFile as
|
|
25825
|
-
import { homedir as
|
|
26172
|
+
import { resolve as resolve61, dirname as dirname18, basename as basename5 } from "path";
|
|
26173
|
+
import { readdir as readdir21, readFile as readFile38 } from "fs/promises";
|
|
26174
|
+
import { homedir as homedir10 } from "os";
|
|
25826
26175
|
var CATEGORY6 = "integrations";
|
|
25827
26176
|
var claudePluginLinked = {
|
|
25828
26177
|
id: "integrations.claude-plugin-linked",
|
|
@@ -25903,10 +26252,10 @@ var backupConfigured = {
|
|
|
25903
26252
|
}
|
|
25904
26253
|
};
|
|
25905
26254
|
async function readKnownMarketplaces() {
|
|
25906
|
-
const path =
|
|
26255
|
+
const path = resolve61(homedir10(), ".claude", "plugins", "known_marketplaces.json");
|
|
25907
26256
|
if (!await fileExists(path)) return {};
|
|
25908
26257
|
try {
|
|
25909
|
-
const raw = await
|
|
26258
|
+
const raw = await readFile38(path, "utf-8");
|
|
25910
26259
|
return JSON.parse(raw);
|
|
25911
26260
|
} catch {
|
|
25912
26261
|
return {};
|
|
@@ -25940,7 +26289,7 @@ var claudeMarketplaceRegistered = {
|
|
|
25940
26289
|
};
|
|
25941
26290
|
}
|
|
25942
26291
|
const marketplaceRoot = dirname18(pluginsParent);
|
|
25943
|
-
const marketplaceManifest =
|
|
26292
|
+
const marketplaceManifest = resolve61(marketplaceRoot, ".claude-plugin", "marketplace.json");
|
|
25944
26293
|
if (!await fileExists(marketplaceManifest)) {
|
|
25945
26294
|
return {
|
|
25946
26295
|
id: this.id,
|
|
@@ -25959,7 +26308,7 @@ var claudeMarketplaceRegistered = {
|
|
|
25959
26308
|
}
|
|
25960
26309
|
let parsed = {};
|
|
25961
26310
|
try {
|
|
25962
|
-
parsed = JSON.parse(await
|
|
26311
|
+
parsed = JSON.parse(await readFile38(marketplaceManifest, "utf-8"));
|
|
25963
26312
|
} catch {
|
|
25964
26313
|
return {
|
|
25965
26314
|
id: this.id,
|
|
@@ -25991,7 +26340,7 @@ var claudeMarketplaceRegistered = {
|
|
|
25991
26340
|
title: this.title,
|
|
25992
26341
|
status: "error",
|
|
25993
26342
|
detail: issues.join("; "),
|
|
25994
|
-
affected: [marketplaceManifest,
|
|
26343
|
+
affected: [marketplaceManifest, resolve61(homedir10(), ".claude", "plugins", "known_marketplaces.json")],
|
|
25995
26344
|
remediation: {
|
|
25996
26345
|
kind: "manual",
|
|
25997
26346
|
suggestion: "Re-run install-plugin to ensure both files are in sync.",
|
|
@@ -26031,8 +26380,8 @@ function skipped2(check, reason) {
|
|
|
26031
26380
|
init_fs();
|
|
26032
26381
|
init_parser();
|
|
26033
26382
|
init_types();
|
|
26034
|
-
import { resolve as
|
|
26035
|
-
import { readFile as
|
|
26383
|
+
import { resolve as resolve62 } from "path";
|
|
26384
|
+
import { readFile as readFile39 } from "fs/promises";
|
|
26036
26385
|
var CATEGORY7 = "workspace";
|
|
26037
26386
|
var ASSIGNMENT_FIELDS = ["projectSlug", "assignmentSlug", "projectDir", "assignmentDir"];
|
|
26038
26387
|
var BUNDLE_FIELDS = ["bundleId", "bundleScope", "bundleScopeId"];
|
|
@@ -26053,12 +26402,12 @@ function isStandaloneSession(ctx) {
|
|
|
26053
26402
|
return !hasAnyAssignmentField(ctx) && !hasAnyBundleField(ctx) && typeof ctx.sessionId === "string" && ctx.sessionId.length > 0;
|
|
26054
26403
|
}
|
|
26055
26404
|
async function loadContext(ctx) {
|
|
26056
|
-
const path =
|
|
26405
|
+
const path = resolve62(ctx.cwd, ".syntaur", "context.json");
|
|
26057
26406
|
if (!await fileExists(path)) {
|
|
26058
26407
|
return { data: null, path, exists: false, parseError: null };
|
|
26059
26408
|
}
|
|
26060
26409
|
try {
|
|
26061
|
-
const raw = await
|
|
26410
|
+
const raw = await readFile39(path, "utf-8");
|
|
26062
26411
|
return { data: JSON.parse(raw), path, exists: true, parseError: null };
|
|
26063
26412
|
} catch (err2) {
|
|
26064
26413
|
return {
|
|
@@ -26152,7 +26501,7 @@ var contextAssignmentResolves = {
|
|
|
26152
26501
|
if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to resolve");
|
|
26153
26502
|
if (isBundleContext(data)) return skipped3(this, "bundle context \u2014 no assignment to resolve");
|
|
26154
26503
|
if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
|
|
26155
|
-
const assignmentMd =
|
|
26504
|
+
const assignmentMd = resolve62(data.assignmentDir, "assignment.md");
|
|
26156
26505
|
if (!await fileExists(assignmentMd)) {
|
|
26157
26506
|
return {
|
|
26158
26507
|
id: this.id,
|
|
@@ -26182,10 +26531,10 @@ var contextTerminal = {
|
|
|
26182
26531
|
if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to check");
|
|
26183
26532
|
if (isBundleContext(data)) return skipped3(this, "bundle context \u2014 no assignment to check");
|
|
26184
26533
|
if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
|
|
26185
|
-
const assignmentMd =
|
|
26534
|
+
const assignmentMd = resolve62(data.assignmentDir, "assignment.md");
|
|
26186
26535
|
if (!await fileExists(assignmentMd)) return skipped3(this, "assignment file missing");
|
|
26187
26536
|
try {
|
|
26188
|
-
const content = await
|
|
26537
|
+
const content = await readFile39(assignmentMd, "utf-8");
|
|
26189
26538
|
const parsed = parseAssignmentFull(content);
|
|
26190
26539
|
const terminal = terminalStatuses2(ctx);
|
|
26191
26540
|
if (terminal.has(parsed.status)) {
|
|
@@ -26241,7 +26590,7 @@ function skipped3(check, reason) {
|
|
|
26241
26590
|
init_config2();
|
|
26242
26591
|
import { isAbsolute as isAbsolute9 } from "path";
|
|
26243
26592
|
import { access as access2, constants as fsConstants } from "fs/promises";
|
|
26244
|
-
import { spawnSync as
|
|
26593
|
+
import { spawnSync as spawnSync8 } from "child_process";
|
|
26245
26594
|
var CATEGORY8 = "agents";
|
|
26246
26595
|
var agentsResolvable = {
|
|
26247
26596
|
id: "agents.commands-resolvable",
|
|
@@ -26305,7 +26654,7 @@ async function checkAgent(agent) {
|
|
|
26305
26654
|
};
|
|
26306
26655
|
}
|
|
26307
26656
|
}
|
|
26308
|
-
const result =
|
|
26657
|
+
const result = spawnSync8("which", [agent.command], { encoding: "utf-8" });
|
|
26309
26658
|
if (result.status === 0 && result.stdout.trim().length > 0) {
|
|
26310
26659
|
return {
|
|
26311
26660
|
...base,
|
|
@@ -26330,16 +26679,16 @@ var agentChecks = [agentsResolvable];
|
|
|
26330
26679
|
|
|
26331
26680
|
// src/utils/doctor/checks/terminal.ts
|
|
26332
26681
|
init_config2();
|
|
26333
|
-
import { spawnSync as
|
|
26334
|
-
import { readFile as
|
|
26335
|
-
import { resolve as
|
|
26682
|
+
import { spawnSync as spawnSync9 } from "child_process";
|
|
26683
|
+
import { readFile as readFile40 } from "fs/promises";
|
|
26684
|
+
import { resolve as resolve63 } from "path";
|
|
26336
26685
|
init_paths();
|
|
26337
26686
|
init_fs();
|
|
26338
26687
|
var CATEGORY9 = "terminal";
|
|
26339
26688
|
async function readRawTerminalKey() {
|
|
26340
|
-
const configPath =
|
|
26689
|
+
const configPath = resolve63(syntaurRoot(), "config.md");
|
|
26341
26690
|
if (!await fileExists(configPath)) return null;
|
|
26342
|
-
const content = await
|
|
26691
|
+
const content = await readFile40(configPath, "utf-8");
|
|
26343
26692
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
26344
26693
|
if (!fmMatch) return null;
|
|
26345
26694
|
const line = fmMatch[1].split("\n").find((l) => /^terminal:\s*/.test(l));
|
|
@@ -26452,7 +26801,7 @@ var kittyRemoteControl = {
|
|
|
26452
26801
|
autoFixable: false
|
|
26453
26802
|
};
|
|
26454
26803
|
}
|
|
26455
|
-
const result =
|
|
26804
|
+
const result = spawnSync9("kitty", ["@", "ls"], {
|
|
26456
26805
|
encoding: "utf-8",
|
|
26457
26806
|
timeout: 2e3
|
|
26458
26807
|
});
|
|
@@ -26489,13 +26838,13 @@ var terminalChecks = [
|
|
|
26489
26838
|
|
|
26490
26839
|
// src/utils/doctor/checks/skills.ts
|
|
26491
26840
|
init_fs();
|
|
26492
|
-
import { resolve as
|
|
26493
|
-
import { readdir as readdir22, readFile as
|
|
26494
|
-
import { homedir as
|
|
26841
|
+
import { resolve as resolve64, join as join11 } from "path";
|
|
26842
|
+
import { readdir as readdir22, readFile as readFile41, lstat as lstat4 } from "fs/promises";
|
|
26843
|
+
import { homedir as homedir11 } from "os";
|
|
26495
26844
|
var CATEGORY10 = "skills";
|
|
26496
26845
|
var skillTargets = [
|
|
26497
|
-
{ agent: "claude", dir:
|
|
26498
|
-
{ agent: "codex", dir:
|
|
26846
|
+
{ agent: "claude", dir: resolve64(homedir11(), ".claude", "skills"), label: "~/.claude/skills" },
|
|
26847
|
+
{ agent: "codex", dir: resolve64(homedir11(), ".codex", "skills"), label: "~/.codex/skills" }
|
|
26499
26848
|
];
|
|
26500
26849
|
var skillsDedupCheck = {
|
|
26501
26850
|
id: "skills.dedup",
|
|
@@ -26519,7 +26868,7 @@ var skillsDedupCheck = {
|
|
|
26519
26868
|
if (!KNOWN_SKILLS.includes(entry.name)) continue;
|
|
26520
26869
|
const skillMd = join11(dir, entry.name, "SKILL.md");
|
|
26521
26870
|
if (!await fileExists(skillMd)) continue;
|
|
26522
|
-
const content = await
|
|
26871
|
+
const content = await readFile41(skillMd, "utf-8").catch(() => "");
|
|
26523
26872
|
const match = content.match(/^name:\s*(\S+)\s*$/m);
|
|
26524
26873
|
if (!match || match[1] !== entry.name) continue;
|
|
26525
26874
|
let isSymlink2 = false;
|
|
@@ -26567,14 +26916,101 @@ var skillsDedupCheck = {
|
|
|
26567
26916
|
};
|
|
26568
26917
|
var skillsChecks = [skillsDedupCheck];
|
|
26569
26918
|
|
|
26919
|
+
// src/utils/doctor/checks/cross-agent.ts
|
|
26920
|
+
init_fs();
|
|
26921
|
+
import { join as join12, resolve as resolve65 } from "path";
|
|
26922
|
+
var CATEGORY11 = "cross-agent";
|
|
26923
|
+
async function countSyntaurSkills(dir) {
|
|
26924
|
+
if (!await fileExists(dir)) return 0;
|
|
26925
|
+
let n = 0;
|
|
26926
|
+
for (const skill of KNOWN_SKILLS) {
|
|
26927
|
+
if (await fileExists(join12(dir, skill, "SKILL.md"))) n++;
|
|
26928
|
+
}
|
|
26929
|
+
return n;
|
|
26930
|
+
}
|
|
26931
|
+
var crossAgentSkillsCheck = {
|
|
26932
|
+
id: "cross-agent.skills",
|
|
26933
|
+
category: CATEGORY11,
|
|
26934
|
+
title: "Cross-agent targets have Syntaur skills + protocol files",
|
|
26935
|
+
async run(ctx) {
|
|
26936
|
+
const installed = ctx.config.integrations.installedAgents ?? {};
|
|
26937
|
+
const total = KNOWN_SKILLS.length;
|
|
26938
|
+
const lines = [];
|
|
26939
|
+
const problems = [];
|
|
26940
|
+
const affected = [];
|
|
26941
|
+
let considered = 0;
|
|
26942
|
+
for (const t of AGENT_TARGETS) {
|
|
26943
|
+
if (t.nativePlugin) continue;
|
|
26944
|
+
const dir = t.skillsDir?.global;
|
|
26945
|
+
if (!dir) continue;
|
|
26946
|
+
const recorded = Boolean(installed[t.id]);
|
|
26947
|
+
const detected = await t.detect();
|
|
26948
|
+
if (!recorded && !detected) continue;
|
|
26949
|
+
considered++;
|
|
26950
|
+
const present = await countSyntaurSkills(dir);
|
|
26951
|
+
lines.push(`${t.displayName}: ${present}/${total} skills (${dir})`);
|
|
26952
|
+
if (recorded && present < total) {
|
|
26953
|
+
problems.push(
|
|
26954
|
+
`${t.displayName}: ${present === 0 ? "no Syntaur skills" : `incomplete skills (${present}/${total})`}`
|
|
26955
|
+
);
|
|
26956
|
+
affected.push(dir);
|
|
26957
|
+
}
|
|
26958
|
+
if (recorded && t.instructions) {
|
|
26959
|
+
for (const f of t.instructions.files) {
|
|
26960
|
+
const p = resolve65(ctx.cwd, f.path);
|
|
26961
|
+
if (!await fileExists(p)) {
|
|
26962
|
+
problems.push(`${t.displayName}: missing protocol file ${f.path} in cwd`);
|
|
26963
|
+
affected.push(p);
|
|
26964
|
+
}
|
|
26965
|
+
}
|
|
26966
|
+
}
|
|
26967
|
+
}
|
|
26968
|
+
if (considered === 0) {
|
|
26969
|
+
return {
|
|
26970
|
+
id: this.id,
|
|
26971
|
+
category: this.category,
|
|
26972
|
+
title: this.title,
|
|
26973
|
+
status: "skipped",
|
|
26974
|
+
detail: "No cross-agent targets detected or recorded.",
|
|
26975
|
+
autoFixable: false
|
|
26976
|
+
};
|
|
26977
|
+
}
|
|
26978
|
+
if (problems.length > 0) {
|
|
26979
|
+
return {
|
|
26980
|
+
id: this.id,
|
|
26981
|
+
category: this.category,
|
|
26982
|
+
title: this.title,
|
|
26983
|
+
status: "warn",
|
|
26984
|
+
detail: `${problems.join("; ")}. (${lines.join("; ")})`,
|
|
26985
|
+
affected,
|
|
26986
|
+
remediation: {
|
|
26987
|
+
kind: "manual",
|
|
26988
|
+
suggestion: "Re-run `syntaur setup --target <id>` (from the assignment workspace, to also write protocol files) to complete the install.",
|
|
26989
|
+
command: null
|
|
26990
|
+
},
|
|
26991
|
+
autoFixable: false
|
|
26992
|
+
};
|
|
26993
|
+
}
|
|
26994
|
+
return {
|
|
26995
|
+
id: this.id,
|
|
26996
|
+
category: this.category,
|
|
26997
|
+
title: this.title,
|
|
26998
|
+
status: "pass",
|
|
26999
|
+
detail: lines.join("; "),
|
|
27000
|
+
autoFixable: false
|
|
27001
|
+
};
|
|
27002
|
+
}
|
|
27003
|
+
};
|
|
27004
|
+
var crossAgentChecks = [crossAgentSkillsCheck];
|
|
27005
|
+
|
|
26570
27006
|
// src/utils/doctor/checks/bundles.ts
|
|
26571
27007
|
init_fs();
|
|
26572
27008
|
init_paths();
|
|
26573
|
-
import { resolve as
|
|
27009
|
+
import { resolve as resolve66 } from "path";
|
|
26574
27010
|
import { readdir as readdir23 } from "fs/promises";
|
|
26575
|
-
import { spawnSync as
|
|
27011
|
+
import { spawnSync as spawnSync10 } from "child_process";
|
|
26576
27012
|
init_parser2();
|
|
26577
|
-
var
|
|
27013
|
+
var CATEGORY12 = "bundles";
|
|
26578
27014
|
async function listScopes(ctx) {
|
|
26579
27015
|
const out = [];
|
|
26580
27016
|
const td = todosDir();
|
|
@@ -26600,7 +27036,7 @@ async function listScopes(ctx) {
|
|
|
26600
27036
|
if (!e.isDirectory()) continue;
|
|
26601
27037
|
const slug = e.name;
|
|
26602
27038
|
if (typeof slug !== "string" || slug.startsWith(".")) continue;
|
|
26603
|
-
const projectMd =
|
|
27039
|
+
const projectMd = resolve66(ctx.config.defaultProjectDir, slug, "project.md");
|
|
26604
27040
|
if (!await fileExists(projectMd)) continue;
|
|
26605
27041
|
out.push({
|
|
26606
27042
|
scopeLabel: `project:${slug}`,
|
|
@@ -26655,7 +27091,7 @@ async function gatherBundlesByScope(scopes) {
|
|
|
26655
27091
|
}
|
|
26656
27092
|
var orphanBundleId = {
|
|
26657
27093
|
id: "bundles.orphan-bundleid",
|
|
26658
|
-
category:
|
|
27094
|
+
category: CATEGORY12,
|
|
26659
27095
|
title: "Every todo with a bundleId points at an existing bundle in the same scope",
|
|
26660
27096
|
async run(ctx) {
|
|
26661
27097
|
const scopes = await listScopes(ctx);
|
|
@@ -26678,7 +27114,7 @@ var orphanBundleId = {
|
|
|
26678
27114
|
};
|
|
26679
27115
|
var missingMembers = {
|
|
26680
27116
|
id: "bundles.missing-members",
|
|
26681
|
-
category:
|
|
27117
|
+
category: CATEGORY12,
|
|
26682
27118
|
title: "Every bundle member exists in the bundle's scope checklist",
|
|
26683
27119
|
async run(ctx) {
|
|
26684
27120
|
const scopes = await listScopes(ctx);
|
|
@@ -26697,7 +27133,7 @@ var missingMembers = {
|
|
|
26697
27133
|
};
|
|
26698
27134
|
var scopeMismatch = {
|
|
26699
27135
|
id: "bundles.scope-mismatch",
|
|
26700
|
-
category:
|
|
27136
|
+
category: CATEGORY12,
|
|
26701
27137
|
title: "Every bundle member's bundleId matches the bundle id",
|
|
26702
27138
|
async run(ctx) {
|
|
26703
27139
|
const scopes = await listScopes(ctx);
|
|
@@ -26715,7 +27151,7 @@ var scopeMismatch = {
|
|
|
26715
27151
|
};
|
|
26716
27152
|
var minMembers = {
|
|
26717
27153
|
id: "bundles.min-members",
|
|
26718
|
-
category:
|
|
27154
|
+
category: CATEGORY12,
|
|
26719
27155
|
title: "Every bundle has at least 2 members",
|
|
26720
27156
|
async run(ctx) {
|
|
26721
27157
|
const scopes = await listScopes(ctx);
|
|
@@ -26731,7 +27167,7 @@ var minMembers = {
|
|
|
26731
27167
|
};
|
|
26732
27168
|
var stalePlanDir = {
|
|
26733
27169
|
id: "bundles.stale-plan-dir",
|
|
26734
|
-
category:
|
|
27170
|
+
category: CATEGORY12,
|
|
26735
27171
|
title: "Every bundle's persisted planDir still exists on disk",
|
|
26736
27172
|
async run(ctx) {
|
|
26737
27173
|
const scopes = await listScopes(ctx);
|
|
@@ -26755,7 +27191,7 @@ var stalePlanDir = {
|
|
|
26755
27191
|
};
|
|
26756
27192
|
var staleWorktree = {
|
|
26757
27193
|
id: "bundles.stale-worktree",
|
|
26758
|
-
category:
|
|
27194
|
+
category: CATEGORY12,
|
|
26759
27195
|
title: "Every bundle's persisted worktree still exists in the repo",
|
|
26760
27196
|
async run(ctx) {
|
|
26761
27197
|
const scopes = await listScopes(ctx);
|
|
@@ -26765,7 +27201,7 @@ var staleWorktree = {
|
|
|
26765
27201
|
if (bs.bundle.worktreePath === null || bs.bundle.repository === null) continue;
|
|
26766
27202
|
const onDisk = await fileExists(bs.bundle.worktreePath);
|
|
26767
27203
|
let gitKnowsIt = false;
|
|
26768
|
-
const gitOut =
|
|
27204
|
+
const gitOut = spawnSync10("git", ["-C", bs.bundle.repository, "worktree", "list", "--porcelain"], { encoding: "utf-8" });
|
|
26769
27205
|
if (gitOut.status === 0) {
|
|
26770
27206
|
gitKnowsIt = gitOut.stdout.split("\n").some((l) => l.trim() === `worktree ${bs.bundle.worktreePath}`);
|
|
26771
27207
|
}
|
|
@@ -26805,6 +27241,7 @@ function allChecks() {
|
|
|
26805
27241
|
...agentChecks,
|
|
26806
27242
|
...terminalChecks,
|
|
26807
27243
|
...skillsChecks,
|
|
27244
|
+
...crossAgentChecks,
|
|
26808
27245
|
...bundleChecks
|
|
26809
27246
|
];
|
|
26810
27247
|
}
|
|
@@ -26891,7 +27328,7 @@ async function readVersion() {
|
|
|
26891
27328
|
let dir = dirname19(here);
|
|
26892
27329
|
for (let i = 0; i < 6; i++) {
|
|
26893
27330
|
try {
|
|
26894
|
-
const raw = await
|
|
27331
|
+
const raw = await readFile42(join13(dir, "package.json"), "utf-8");
|
|
26895
27332
|
const parsed = JSON.parse(raw);
|
|
26896
27333
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
26897
27334
|
} catch {
|
|
@@ -26988,7 +27425,7 @@ var REQUIRED_WORKSPACE_FIELDS = [
|
|
|
26988
27425
|
];
|
|
26989
27426
|
var ISO_DATE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
|
|
26990
27427
|
async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
|
|
26991
|
-
const absolute = isAbsolute10(inputPath) ? inputPath :
|
|
27428
|
+
const absolute = isAbsolute10(inputPath) ? inputPath : resolve67(cwd, inputPath);
|
|
26992
27429
|
const errors = [];
|
|
26993
27430
|
const warnings = [];
|
|
26994
27431
|
if (!await fileExists(absolute)) {
|
|
@@ -27001,7 +27438,7 @@ async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
|
|
|
27001
27438
|
}
|
|
27002
27439
|
let content;
|
|
27003
27440
|
try {
|
|
27004
|
-
content = await
|
|
27441
|
+
content = await readFile43(absolute, "utf-8");
|
|
27005
27442
|
} catch (err2) {
|
|
27006
27443
|
return {
|
|
27007
27444
|
ok: false,
|
|
@@ -27325,8 +27762,8 @@ init_uuid();
|
|
|
27325
27762
|
init_timestamp();
|
|
27326
27763
|
init_assignment_resolver();
|
|
27327
27764
|
init_templates();
|
|
27328
|
-
import { resolve as
|
|
27329
|
-
import { readFile as
|
|
27765
|
+
import { resolve as resolve68 } from "path";
|
|
27766
|
+
import { readFile as readFile44 } from "fs/promises";
|
|
27330
27767
|
function shortId() {
|
|
27331
27768
|
return generateId().split("-")[0];
|
|
27332
27769
|
}
|
|
@@ -27356,7 +27793,7 @@ async function commentCommand(target, text, options = {}) {
|
|
|
27356
27793
|
if (!isValidSlug(target)) {
|
|
27357
27794
|
throw new Error(`Invalid assignment slug "${target}".`);
|
|
27358
27795
|
}
|
|
27359
|
-
assignmentDir =
|
|
27796
|
+
assignmentDir = resolve68(baseDir, options.project, "assignments", target);
|
|
27360
27797
|
assignmentRef = target;
|
|
27361
27798
|
} else {
|
|
27362
27799
|
const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
|
|
@@ -27366,13 +27803,13 @@ async function commentCommand(target, text, options = {}) {
|
|
|
27366
27803
|
assignmentDir = resolved.assignmentDir;
|
|
27367
27804
|
assignmentRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
|
|
27368
27805
|
}
|
|
27369
|
-
const commentsPath =
|
|
27806
|
+
const commentsPath = resolve68(assignmentDir, "comments.md");
|
|
27370
27807
|
const timestamp = nowTimestamp();
|
|
27371
27808
|
const author = options.author ?? process.env.USER ?? "unknown";
|
|
27372
27809
|
let currentContent;
|
|
27373
27810
|
let currentCount = 0;
|
|
27374
27811
|
if (await fileExists(commentsPath)) {
|
|
27375
|
-
currentContent = await
|
|
27812
|
+
currentContent = await readFile44(commentsPath, "utf-8");
|
|
27376
27813
|
const countMatch = currentContent.match(/^entryCount:\s*(\d+)/m);
|
|
27377
27814
|
if (countMatch) currentCount = parseInt(countMatch[1], 10);
|
|
27378
27815
|
} else {
|
|
@@ -27406,7 +27843,7 @@ ${entry}`;
|
|
|
27406
27843
|
}
|
|
27407
27844
|
|
|
27408
27845
|
// src/commands/capture.ts
|
|
27409
|
-
import { resolve as
|
|
27846
|
+
import { resolve as resolve72, relative as relative4, dirname as dirname20 } from "path";
|
|
27410
27847
|
import { copyFile as copyFile3, mkdir as mkdir9, realpath as realpath2, rm as rm12, stat as stat8, writeFile as writeFile14 } from "fs/promises";
|
|
27411
27848
|
import { existsSync as existsSync6 } from "fs";
|
|
27412
27849
|
|
|
@@ -27417,8 +27854,8 @@ init_config2();
|
|
|
27417
27854
|
init_slug();
|
|
27418
27855
|
init_assignment_resolver();
|
|
27419
27856
|
init_parser();
|
|
27420
|
-
import { resolve as
|
|
27421
|
-
import { readFile as
|
|
27857
|
+
import { resolve as resolve69 } from "path";
|
|
27858
|
+
import { readFile as readFile45 } from "fs/promises";
|
|
27422
27859
|
var AssignmentTargetError = class extends Error {
|
|
27423
27860
|
};
|
|
27424
27861
|
function classifyContext(ctx) {
|
|
@@ -27430,10 +27867,10 @@ function classifyContext(ctx) {
|
|
|
27430
27867
|
return "empty";
|
|
27431
27868
|
}
|
|
27432
27869
|
async function readAssignmentFrontmatterId(assignmentDir) {
|
|
27433
|
-
const path =
|
|
27870
|
+
const path = resolve69(assignmentDir, "assignment.md");
|
|
27434
27871
|
if (!await fileExists(path)) return null;
|
|
27435
27872
|
try {
|
|
27436
|
-
const content = await
|
|
27873
|
+
const content = await readFile45(path, "utf-8");
|
|
27437
27874
|
const [fm] = extractFrontmatter(content);
|
|
27438
27875
|
return getField(fm, "id");
|
|
27439
27876
|
} catch {
|
|
@@ -27441,10 +27878,10 @@ async function readAssignmentFrontmatterId(assignmentDir) {
|
|
|
27441
27878
|
}
|
|
27442
27879
|
}
|
|
27443
27880
|
async function readContextJson(cwd) {
|
|
27444
|
-
const path =
|
|
27881
|
+
const path = resolve69(cwd, ".syntaur", "context.json");
|
|
27445
27882
|
if (!await fileExists(path)) return null;
|
|
27446
27883
|
try {
|
|
27447
|
-
const raw = await
|
|
27884
|
+
const raw = await readFile45(path, "utf-8");
|
|
27448
27885
|
return JSON.parse(raw);
|
|
27449
27886
|
} catch {
|
|
27450
27887
|
return null;
|
|
@@ -27465,15 +27902,15 @@ async function resolveAssignmentTarget(input4, opts = {}) {
|
|
|
27465
27902
|
if (!isValidSlug(input4)) {
|
|
27466
27903
|
throw new AssignmentTargetError(`Invalid assignment slug "${input4}".`);
|
|
27467
27904
|
}
|
|
27468
|
-
const projectDir =
|
|
27469
|
-
const projectMdPath =
|
|
27905
|
+
const projectDir = resolve69(baseDir, opts.project);
|
|
27906
|
+
const projectMdPath = resolve69(projectDir, "project.md");
|
|
27470
27907
|
if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
|
|
27471
27908
|
throw new AssignmentTargetError(
|
|
27472
27909
|
`Project "${opts.project}" not found at ${projectDir}.`
|
|
27473
27910
|
);
|
|
27474
27911
|
}
|
|
27475
|
-
const assignmentDir =
|
|
27476
|
-
const assignmentMdPath2 =
|
|
27912
|
+
const assignmentDir = resolve69(projectDir, "assignments", input4);
|
|
27913
|
+
const assignmentMdPath2 = resolve69(assignmentDir, "assignment.md");
|
|
27477
27914
|
if (!await fileExists(assignmentMdPath2)) {
|
|
27478
27915
|
throw new AssignmentTargetError(
|
|
27479
27916
|
`Assignment "${input4}" not found in project "${opts.project}".`
|
|
@@ -27512,7 +27949,7 @@ async function resolveAssignmentTarget(input4, opts = {}) {
|
|
|
27512
27949
|
}
|
|
27513
27950
|
if (ctx.assignmentDir) {
|
|
27514
27951
|
const dir = expandHome(ctx.assignmentDir);
|
|
27515
|
-
const assignmentMdPath2 =
|
|
27952
|
+
const assignmentMdPath2 = resolve69(dir, "assignment.md");
|
|
27516
27953
|
if (!await fileExists(assignmentMdPath2)) {
|
|
27517
27954
|
throw new AssignmentTargetError(
|
|
27518
27955
|
`.syntaur/context.json points to a missing assignment dir: ${dir}.`
|
|
@@ -27541,8 +27978,8 @@ async function resolveAssignmentTarget(input4, opts = {}) {
|
|
|
27541
27978
|
`.syntaur/context.json contains invalid slugs: project="${ctx.projectSlug}" assignment="${ctx.assignmentSlug}".`
|
|
27542
27979
|
);
|
|
27543
27980
|
}
|
|
27544
|
-
const assignmentDir =
|
|
27545
|
-
const assignmentMdPath2 =
|
|
27981
|
+
const assignmentDir = resolve69(baseDir, ctx.projectSlug, "assignments", ctx.assignmentSlug);
|
|
27982
|
+
const assignmentMdPath2 = resolve69(assignmentDir, "assignment.md");
|
|
27546
27983
|
if (!await fileExists(assignmentMdPath2)) {
|
|
27547
27984
|
throw new AssignmentTargetError(
|
|
27548
27985
|
`.syntaur/context.json points to a missing assignment: ${assignmentDir}.`
|
|
@@ -27605,7 +28042,7 @@ init_fs();
|
|
|
27605
28042
|
import { spawn as spawn7 } from "child_process";
|
|
27606
28043
|
import { mkdtemp as mkdtemp2, rm as rm8, stat as stat6 } from "fs/promises";
|
|
27607
28044
|
import { tmpdir as tmpdir3 } from "os";
|
|
27608
|
-
import { join as
|
|
28045
|
+
import { join as join14 } from "path";
|
|
27609
28046
|
function argsFor(mode, pngPath) {
|
|
27610
28047
|
switch (mode) {
|
|
27611
28048
|
case "interactive":
|
|
@@ -27638,8 +28075,8 @@ async function captureScreenshot(mode) {
|
|
|
27638
28075
|
"screencapture is only available on macOS. Use --file <path> to attach an existing image."
|
|
27639
28076
|
);
|
|
27640
28077
|
}
|
|
27641
|
-
const tmpDir = await mkdtemp2(
|
|
27642
|
-
const pngPath =
|
|
28078
|
+
const tmpDir = await mkdtemp2(join14(tmpdir3(), "syntaur-screenshot-"));
|
|
28079
|
+
const pngPath = join14(tmpDir, "shot.png");
|
|
27643
28080
|
const cleanup = async () => {
|
|
27644
28081
|
await rm8(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
27645
28082
|
});
|
|
@@ -27677,9 +28114,9 @@ async function captureScreenshot(mode) {
|
|
|
27677
28114
|
|
|
27678
28115
|
// src/utils/asciinema.ts
|
|
27679
28116
|
import { spawn as spawn8 } from "child_process";
|
|
27680
|
-
import { mkdtemp as mkdtemp3, readFile as
|
|
28117
|
+
import { mkdtemp as mkdtemp3, readFile as readFile46, rm as rm9 } from "fs/promises";
|
|
27681
28118
|
import { tmpdir as tmpdir4 } from "os";
|
|
27682
|
-
import { join as
|
|
28119
|
+
import { join as join15 } from "path";
|
|
27683
28120
|
var SAFE_RE = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
27684
28121
|
function shellQuote2(s) {
|
|
27685
28122
|
if (s.length === 0) return `''`;
|
|
@@ -27716,8 +28153,8 @@ function runAsciinema(args, stdio) {
|
|
|
27716
28153
|
});
|
|
27717
28154
|
}
|
|
27718
28155
|
async function captureAsciinema(opts) {
|
|
27719
|
-
const tmpDir = await mkdtemp3(
|
|
27720
|
-
const castPath =
|
|
28156
|
+
const tmpDir = await mkdtemp3(join15(tmpdir4(), "syntaur-asciinema-"));
|
|
28157
|
+
const castPath = join15(tmpDir, "session.cast");
|
|
27721
28158
|
const cleanup = async () => {
|
|
27722
28159
|
await rm9(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
27723
28160
|
});
|
|
@@ -27740,7 +28177,7 @@ async function captureAsciinema(opts) {
|
|
|
27740
28177
|
}
|
|
27741
28178
|
throw err2;
|
|
27742
28179
|
}
|
|
27743
|
-
const text = await
|
|
28180
|
+
const text = await readFile46(castPath, "utf8").catch(() => null);
|
|
27744
28181
|
if (text === null) {
|
|
27745
28182
|
throw new Error(
|
|
27746
28183
|
`asciinema produced no cast file at ${castPath} (exit ${exitCode}). Try running 'asciinema rec ${castPath}' directly to diagnose.`
|
|
@@ -27768,9 +28205,9 @@ async function captureAsciinema(opts) {
|
|
|
27768
28205
|
// src/utils/recording.ts
|
|
27769
28206
|
init_paths();
|
|
27770
28207
|
import { spawn as spawn9 } from "child_process";
|
|
27771
|
-
import { mkdir as mkdir8, mkdtemp as mkdtemp4, open as open3, readFile as
|
|
28208
|
+
import { mkdir as mkdir8, mkdtemp as mkdtemp4, open as open3, readFile as readFile47, rm as rm10, stat as stat7, unlink as unlink9, writeFile as writeFile13 } from "fs/promises";
|
|
27772
28209
|
import { tmpdir as tmpdir5 } from "os";
|
|
27773
|
-
import { join as
|
|
28210
|
+
import { join as join16, resolve as resolve70 } from "path";
|
|
27774
28211
|
import { setTimeout as sleep } from "timers/promises";
|
|
27775
28212
|
function sigintPollIntervalMs() {
|
|
27776
28213
|
const raw = process.env.SYNTAUR_RECORDING_POLL_INTERVAL_MS;
|
|
@@ -27791,13 +28228,13 @@ function sigtermWaitMs() {
|
|
|
27791
28228
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : 1e3;
|
|
27792
28229
|
}
|
|
27793
28230
|
function pidfilePath() {
|
|
27794
|
-
return
|
|
28231
|
+
return resolve70(syntaurRoot(), "recording.pid");
|
|
27795
28232
|
}
|
|
27796
28233
|
function logPath2() {
|
|
27797
|
-
return
|
|
28234
|
+
return resolve70(syntaurRoot(), "recording.log");
|
|
27798
28235
|
}
|
|
27799
28236
|
function sidecarPath() {
|
|
27800
|
-
return
|
|
28237
|
+
return resolve70(syntaurRoot(), "recording.json");
|
|
27801
28238
|
}
|
|
27802
28239
|
function ffmpegArgs(device, fps, mp4Path) {
|
|
27803
28240
|
return [
|
|
@@ -27842,7 +28279,7 @@ async function acquirePidfile(pidfile) {
|
|
|
27842
28279
|
} catch (err2) {
|
|
27843
28280
|
if (err2.code !== "EEXIST") throw err2;
|
|
27844
28281
|
if (attempt === 1) throw err2;
|
|
27845
|
-
const existing = (await
|
|
28282
|
+
const existing = (await readFile47(pidfile, "utf-8").catch(() => "")).trim();
|
|
27846
28283
|
if (existing.startsWith(STARTING_SENTINEL_PREFIX)) {
|
|
27847
28284
|
const parentPidRaw = existing.slice(STARTING_SENTINEL_PREFIX.length);
|
|
27848
28285
|
const parentPid = Number.parseInt(parentPidRaw, 10);
|
|
@@ -27895,8 +28332,8 @@ async function startRecording(input4) {
|
|
|
27895
28332
|
let acquiredPid = null;
|
|
27896
28333
|
try {
|
|
27897
28334
|
logHandle = await open3(log, "w");
|
|
27898
|
-
tmpDir = await mkdtemp4(
|
|
27899
|
-
const mp4Path =
|
|
28335
|
+
tmpDir = await mkdtemp4(join16(tmpdir5(), "syntaur-recording-"));
|
|
28336
|
+
const mp4Path = join16(tmpDir, "recording.mp4");
|
|
27900
28337
|
let child;
|
|
27901
28338
|
try {
|
|
27902
28339
|
child = spawn9("ffmpeg", ffmpegArgs(input4.device, input4.fps, mp4Path), {
|
|
@@ -27944,7 +28381,7 @@ async function startRecording(input4) {
|
|
|
27944
28381
|
logHandle = null;
|
|
27945
28382
|
if (warmupMs > 0) await sleep(warmupMs);
|
|
27946
28383
|
if (!await isProcessAlive(pid)) {
|
|
27947
|
-
const tail = await
|
|
28384
|
+
const tail = await readFile47(log, "utf-8").then((s) => s.split("\n").slice(-20).join("\n")).catch(() => "");
|
|
27948
28385
|
acquiredPid = null;
|
|
27949
28386
|
throw new Error(
|
|
27950
28387
|
`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}
|
|
@@ -28001,7 +28438,7 @@ ${tail}`
|
|
|
28001
28438
|
async function stopRecording() {
|
|
28002
28439
|
const pidfile = pidfilePath();
|
|
28003
28440
|
const sidecar = sidecarPath();
|
|
28004
|
-
const pidRaw = await
|
|
28441
|
+
const pidRaw = await readFile47(pidfile, "utf-8").catch(() => null);
|
|
28005
28442
|
if (pidRaw === null) {
|
|
28006
28443
|
throw new Error(
|
|
28007
28444
|
`No active recording found (no pidfile at ${pidfile}). Did you run --start?`
|
|
@@ -28011,7 +28448,7 @@ async function stopRecording() {
|
|
|
28011
28448
|
if (!Number.isInteger(pid) || pid <= 0) {
|
|
28012
28449
|
throw new Error(`Pidfile at ${pidfile} is corrupt (got "${pidRaw}").`);
|
|
28013
28450
|
}
|
|
28014
|
-
const sidecarRaw = await
|
|
28451
|
+
const sidecarRaw = await readFile47(sidecar, "utf-8").catch(() => null);
|
|
28015
28452
|
if (sidecarRaw === null) {
|
|
28016
28453
|
throw new Error(
|
|
28017
28454
|
`No recording sidecar at ${sidecar}. The recording state is inconsistent \u2014 delete ${pidfile} and re-run --start.`
|
|
@@ -28076,7 +28513,7 @@ async function stopRecording() {
|
|
|
28076
28513
|
// src/db/proof-db.ts
|
|
28077
28514
|
init_paths();
|
|
28078
28515
|
import Database5 from "better-sqlite3";
|
|
28079
|
-
import { resolve as
|
|
28516
|
+
import { resolve as resolve71 } from "path";
|
|
28080
28517
|
var db4 = null;
|
|
28081
28518
|
var PROOF_SCHEMA_VERSION = "1";
|
|
28082
28519
|
var SCHEMA_SQL4 = `
|
|
@@ -28096,7 +28533,7 @@ CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT);
|
|
|
28096
28533
|
`;
|
|
28097
28534
|
function initProofDb(dbPath) {
|
|
28098
28535
|
if (db4) return db4;
|
|
28099
|
-
const finalPath = dbPath ??
|
|
28536
|
+
const finalPath = dbPath ?? resolve71(syntaurRoot(), "syntaur.db");
|
|
28100
28537
|
db4 = new Database5(finalPath);
|
|
28101
28538
|
db4.pragma("journal_mode = WAL");
|
|
28102
28539
|
db4.exec(SCHEMA_SQL4);
|
|
@@ -28144,9 +28581,9 @@ function listArtifactsByAssignment(assignmentId) {
|
|
|
28144
28581
|
|
|
28145
28582
|
// src/utils/transcribers/elevenlabs.ts
|
|
28146
28583
|
import { spawn as spawn10 } from "child_process";
|
|
28147
|
-
import { mkdtemp as mkdtemp5, readFile as
|
|
28584
|
+
import { mkdtemp as mkdtemp5, readFile as readFile48, rm as rm11 } from "fs/promises";
|
|
28148
28585
|
import { tmpdir as tmpdir6 } from "os";
|
|
28149
|
-
import { join as
|
|
28586
|
+
import { join as join17 } from "path";
|
|
28150
28587
|
var SCRIBE_URL = "https://api.elevenlabs.io/v1/speech-to-text";
|
|
28151
28588
|
var NO_AUDIO_MARKERS = [
|
|
28152
28589
|
"Stream map '0:a:0' matches no streams",
|
|
@@ -28208,7 +28645,7 @@ async function extractAudio(videoAbsPath, wavOut) {
|
|
|
28208
28645
|
throw new TranscribeFfmpegError(`ffmpeg failed (exit ${result.code}): ${tail}`);
|
|
28209
28646
|
}
|
|
28210
28647
|
async function callScribe(wavPath, apiKey, opts) {
|
|
28211
|
-
const audio = await
|
|
28648
|
+
const audio = await readFile48(wavPath);
|
|
28212
28649
|
const form = new FormData();
|
|
28213
28650
|
form.set("file", new Blob([new Uint8Array(audio)], { type: "audio/wav" }), "audio.wav");
|
|
28214
28651
|
form.set("model_id", "scribe_v1");
|
|
@@ -28236,8 +28673,8 @@ var elevenLabsScribe = {
|
|
|
28236
28673
|
"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."
|
|
28237
28674
|
);
|
|
28238
28675
|
}
|
|
28239
|
-
const tmp = await mkdtemp5(
|
|
28240
|
-
const wav =
|
|
28676
|
+
const tmp = await mkdtemp5(join17(tmpdir6(), "syntaur-transcribe-"));
|
|
28677
|
+
const wav = join17(tmp, "audio.wav");
|
|
28241
28678
|
try {
|
|
28242
28679
|
await extractAudio(videoAbsPath, wav);
|
|
28243
28680
|
return await callScribe(wav, apiKey, opts);
|
|
@@ -28524,7 +28961,7 @@ async function captureCommand(target, options = {}) {
|
|
|
28524
28961
|
});
|
|
28525
28962
|
}
|
|
28526
28963
|
if (options.file) {
|
|
28527
|
-
const expanded = options.file.startsWith("~/") ?
|
|
28964
|
+
const expanded = options.file.startsWith("~/") ? resolve72(process.env.HOME ?? "", options.file.slice(2)) : resolve72(options.file);
|
|
28528
28965
|
if (!await fileExists(expanded)) {
|
|
28529
28966
|
throw new Error(`--file does not exist: ${options.file}`);
|
|
28530
28967
|
}
|
|
@@ -28565,7 +29002,7 @@ async function captureCommand(target, options = {}) {
|
|
|
28565
29002
|
}
|
|
28566
29003
|
initProofDb();
|
|
28567
29004
|
const subdir = criterionIndex === null ? "untagged" : String(criterionIndex);
|
|
28568
|
-
const destDir =
|
|
29005
|
+
const destDir = resolve72(proofDir(resolved.assignmentDir), subdir);
|
|
28569
29006
|
if (resolvedSource) await mkdir9(destDir, { recursive: true });
|
|
28570
29007
|
const ext = resolvedSource ? extensionForKind(kind) : null;
|
|
28571
29008
|
let id = null;
|
|
@@ -28574,7 +29011,7 @@ async function captureCommand(target, options = {}) {
|
|
|
28574
29011
|
let lastErr = null;
|
|
28575
29012
|
for (let attempt = 0; attempt < MAX_ID_RETRIES; attempt += 1) {
|
|
28576
29013
|
const candidate = generateArtifactId();
|
|
28577
|
-
const candidateAbsPath = resolvedSource && ext ?
|
|
29014
|
+
const candidateAbsPath = resolvedSource && ext ? resolve72(destDir, `${candidate}.${ext}`) : null;
|
|
28578
29015
|
const candidateRel = candidateAbsPath ? relative4(resolved.assignmentDir, candidateAbsPath) : null;
|
|
28579
29016
|
try {
|
|
28580
29017
|
insertArtifact({
|
|
@@ -28618,7 +29055,7 @@ async function captureCommand(target, options = {}) {
|
|
|
28618
29055
|
}
|
|
28619
29056
|
}
|
|
28620
29057
|
if (options.transcribe && kind === "video" && absPath && id) {
|
|
28621
|
-
const sidecarPath2 =
|
|
29058
|
+
const sidecarPath2 = resolve72(destDir, `${id}.transcript.md`);
|
|
28622
29059
|
if (existsSync6(sidecarPath2)) {
|
|
28623
29060
|
console.warn(
|
|
28624
29061
|
`transcript: ${sidecarPath2} already exists, skipping (delete to re-transcribe)`
|
|
@@ -28650,7 +29087,7 @@ async function captureCommand(target, options = {}) {
|
|
|
28650
29087
|
const tagSuffix = criterionIndex === null ? "untagged" : `criterion ${criterionIndex}`;
|
|
28651
29088
|
console.log(`Captured artifact ${id} (${kind}) for ${ref} \u2014 ${tagSuffix}.`);
|
|
28652
29089
|
if (relativeFilePath) {
|
|
28653
|
-
console.log(` file: ${
|
|
29090
|
+
console.log(` file: ${resolve72(resolved.assignmentDir, relativeFilePath)}`);
|
|
28654
29091
|
}
|
|
28655
29092
|
} catch (err2) {
|
|
28656
29093
|
if (options.stop && kind === "video" && shelloutCleanup && resolvedSource) {
|
|
@@ -28673,8 +29110,8 @@ async function captureCommand(target, options = {}) {
|
|
|
28673
29110
|
|
|
28674
29111
|
// src/commands/proof.ts
|
|
28675
29112
|
import { Command as Command6 } from "commander";
|
|
28676
|
-
import { readFile as
|
|
28677
|
-
import { resolve as
|
|
29113
|
+
import { readFile as readFile49, writeFile as writeFile15, rename as rename9, stat as stat9 } from "fs/promises";
|
|
29114
|
+
import { resolve as resolve73, relative as relative5, isAbsolute as isAbsolute11, dirname as dirname21 } from "path";
|
|
28678
29115
|
import { randomBytes as randomBytes4 } from "crypto";
|
|
28679
29116
|
|
|
28680
29117
|
// src/utils/acceptance-criteria-parse.ts
|
|
@@ -28914,11 +29351,11 @@ function renderProofHtml(params2, inlineFiles = /* @__PURE__ */ new Map(), trans
|
|
|
28914
29351
|
|
|
28915
29352
|
// src/commands/proof.ts
|
|
28916
29353
|
async function readAssignmentMeta(assignmentDir) {
|
|
28917
|
-
const path =
|
|
29354
|
+
const path = resolve73(assignmentDir, "assignment.md");
|
|
28918
29355
|
if (!await fileExists(path)) {
|
|
28919
29356
|
return { title: "", body: "" };
|
|
28920
29357
|
}
|
|
28921
|
-
const content = await
|
|
29358
|
+
const content = await readFile49(path, "utf-8");
|
|
28922
29359
|
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
28923
29360
|
let title = "";
|
|
28924
29361
|
if (fmMatch) {
|
|
@@ -28965,7 +29402,7 @@ async function loadInlineFiles(rows, assignmentDir) {
|
|
|
28965
29402
|
for (const r of rows) {
|
|
28966
29403
|
if (!r.file_path) continue;
|
|
28967
29404
|
if (r.kind !== "http" && r.kind !== "text") continue;
|
|
28968
|
-
const abs =
|
|
29405
|
+
const abs = resolve73(assignmentDir, r.file_path);
|
|
28969
29406
|
if (!isWithin(proofRoot, abs)) {
|
|
28970
29407
|
out.set(r.file_path, null);
|
|
28971
29408
|
continue;
|
|
@@ -28980,7 +29417,7 @@ async function loadInlineFiles(rows, assignmentDir) {
|
|
|
28980
29417
|
continue;
|
|
28981
29418
|
}
|
|
28982
29419
|
try {
|
|
28983
|
-
out.set(r.file_path, await
|
|
29420
|
+
out.set(r.file_path, await readFile49(abs, "utf-8"));
|
|
28984
29421
|
} catch {
|
|
28985
29422
|
out.set(r.file_path, null);
|
|
28986
29423
|
}
|
|
@@ -28992,14 +29429,14 @@ async function loadTranscriptSidecars(rows, assignmentDir) {
|
|
|
28992
29429
|
const proofRoot = proofDir(assignmentDir);
|
|
28993
29430
|
for (const r of rows) {
|
|
28994
29431
|
if (r.kind !== "video" || !r.file_path) continue;
|
|
28995
|
-
const videoAbs =
|
|
28996
|
-
const sidecar =
|
|
29432
|
+
const videoAbs = resolve73(assignmentDir, r.file_path);
|
|
29433
|
+
const sidecar = resolve73(dirname21(videoAbs), `${r.id}.transcript.md`);
|
|
28997
29434
|
if (!isWithin(proofRoot, sidecar)) continue;
|
|
28998
29435
|
if (!await fileExists(sidecar)) continue;
|
|
28999
29436
|
const st = await stat9(sidecar);
|
|
29000
29437
|
if (st.size > INLINE_TEXT_LIMIT_BYTES) continue;
|
|
29001
29438
|
try {
|
|
29002
|
-
out.set(r.id, await
|
|
29439
|
+
out.set(r.id, await readFile49(sidecar, "utf-8"));
|
|
29003
29440
|
} catch {
|
|
29004
29441
|
}
|
|
29005
29442
|
}
|
|
@@ -29033,8 +29470,8 @@ async function proofBuildCommand(target, options = {}) {
|
|
|
29033
29470
|
};
|
|
29034
29471
|
const md = renderProofMarkdown(renderParams);
|
|
29035
29472
|
const html = renderProofHtml(renderParams, inlineFiles, transcriptSidecars);
|
|
29036
|
-
const mdPath =
|
|
29037
|
-
const htmlPath =
|
|
29473
|
+
const mdPath = resolve73(resolved.assignmentDir, "proof.md");
|
|
29474
|
+
const htmlPath = resolve73(resolved.assignmentDir, "proof.html");
|
|
29038
29475
|
await atomicWrite(mdPath, md);
|
|
29039
29476
|
await atomicWrite(htmlPath, html);
|
|
29040
29477
|
console.log(`Wrote ${htmlPath}`);
|
|
@@ -29699,7 +30136,7 @@ async function runCcusage(opts = {}) {
|
|
|
29699
30136
|
};
|
|
29700
30137
|
}
|
|
29701
30138
|
function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
|
|
29702
|
-
return new Promise((
|
|
30139
|
+
return new Promise((resolve82) => {
|
|
29703
30140
|
const child = spawn11(binary, args, {
|
|
29704
30141
|
env: env ?? process.env,
|
|
29705
30142
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -29713,7 +30150,7 @@ function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
|
|
|
29713
30150
|
if (settled) return;
|
|
29714
30151
|
settled = true;
|
|
29715
30152
|
clearTimeout(timer2);
|
|
29716
|
-
|
|
30153
|
+
resolve82(result);
|
|
29717
30154
|
};
|
|
29718
30155
|
const timer2 = setTimeout(() => {
|
|
29719
30156
|
timedOut = true;
|
|
@@ -29758,8 +30195,8 @@ function isoToCcusageDate(iso) {
|
|
|
29758
30195
|
// src/usage/cwd-extractor.ts
|
|
29759
30196
|
init_paths();
|
|
29760
30197
|
import { open as open4, readdir as readdir24, stat as stat10 } from "fs/promises";
|
|
29761
|
-
import { join as
|
|
29762
|
-
import { homedir as
|
|
30198
|
+
import { join as join18 } from "path";
|
|
30199
|
+
import { homedir as homedir12 } from "os";
|
|
29763
30200
|
var SCAN_LINE_CAP = 50;
|
|
29764
30201
|
var TAIL_READ_BYTES = 8 * 1024;
|
|
29765
30202
|
var TAIL_READ_BYTES_MAX = 64 * 1024;
|
|
@@ -29833,12 +30270,12 @@ async function* walkClaudeProjects(opts = {}) {
|
|
|
29833
30270
|
const dirs = await listDirSafe(root);
|
|
29834
30271
|
for (const dirent of dirs) {
|
|
29835
30272
|
if (!dirent.isDirectory) continue;
|
|
29836
|
-
const dirPath =
|
|
30273
|
+
const dirPath = join18(root, dirent.name);
|
|
29837
30274
|
const files = await listDirSafe(dirPath);
|
|
29838
30275
|
let cachedCwd = null;
|
|
29839
30276
|
for (const f of files) {
|
|
29840
30277
|
if (!f.isFile || !f.name.endsWith(".jsonl")) continue;
|
|
29841
|
-
const filePath =
|
|
30278
|
+
const filePath = join18(dirPath, f.name);
|
|
29842
30279
|
if (opts.sinceMtimeMs !== void 0) {
|
|
29843
30280
|
const mtime = await mtimeMs(filePath);
|
|
29844
30281
|
if (mtime !== null && mtime < opts.sinceMtimeMs) continue;
|
|
@@ -29875,8 +30312,8 @@ function resolveCodexSessionsRoot(override) {
|
|
|
29875
30312
|
const fromSessionsEnv = process.env.CODEX_SESSIONS_DIR;
|
|
29876
30313
|
if (fromSessionsEnv && fromSessionsEnv.length > 0) return expandHome(fromSessionsEnv);
|
|
29877
30314
|
const fromHomeEnv = process.env.CODEX_HOME;
|
|
29878
|
-
if (fromHomeEnv && fromHomeEnv.length > 0) return
|
|
29879
|
-
return
|
|
30315
|
+
if (fromHomeEnv && fromHomeEnv.length > 0) return join18(expandHome(fromHomeEnv), "sessions");
|
|
30316
|
+
return join18(homedir12(), ".codex", "sessions");
|
|
29880
30317
|
}
|
|
29881
30318
|
async function listDirSafe(path) {
|
|
29882
30319
|
try {
|
|
@@ -29896,7 +30333,7 @@ async function* walkJsonlRecursive(root) {
|
|
|
29896
30333
|
const current = stack.pop();
|
|
29897
30334
|
const entries = await listDirSafe(current);
|
|
29898
30335
|
for (const e of entries) {
|
|
29899
|
-
const full =
|
|
30336
|
+
const full = join18(current, e.name);
|
|
29900
30337
|
if (e.isDirectory) {
|
|
29901
30338
|
stack.push(full);
|
|
29902
30339
|
} else if (e.isFile && e.name.endsWith(".jsonl")) {
|
|
@@ -30235,8 +30672,8 @@ init_slug();
|
|
|
30235
30672
|
init_timestamp();
|
|
30236
30673
|
init_assignment_resolver();
|
|
30237
30674
|
init_assignment_todos();
|
|
30238
|
-
import { resolve as
|
|
30239
|
-
import { readFile as
|
|
30675
|
+
import { resolve as resolve74 } from "path";
|
|
30676
|
+
import { readFile as readFile50 } from "fs/promises";
|
|
30240
30677
|
async function requestCommand(target, text, options = {}) {
|
|
30241
30678
|
if (!text || !text.trim()) {
|
|
30242
30679
|
throw new Error("Request text cannot be empty.");
|
|
@@ -30252,7 +30689,7 @@ async function requestCommand(target, text, options = {}) {
|
|
|
30252
30689
|
if (!isValidSlug(target)) {
|
|
30253
30690
|
throw new Error(`Invalid assignment slug "${target}".`);
|
|
30254
30691
|
}
|
|
30255
|
-
assignmentDir =
|
|
30692
|
+
assignmentDir = resolve74(baseDir, options.project, "assignments", target);
|
|
30256
30693
|
targetRef = target;
|
|
30257
30694
|
} else {
|
|
30258
30695
|
const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
|
|
@@ -30262,12 +30699,12 @@ async function requestCommand(target, text, options = {}) {
|
|
|
30262
30699
|
assignmentDir = resolved.assignmentDir;
|
|
30263
30700
|
targetRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
|
|
30264
30701
|
}
|
|
30265
|
-
const assignmentMdPath2 =
|
|
30702
|
+
const assignmentMdPath2 = resolve74(assignmentDir, "assignment.md");
|
|
30266
30703
|
if (!await fileExists(assignmentMdPath2)) {
|
|
30267
30704
|
throw new Error(`assignment.md not found at ${assignmentMdPath2}`);
|
|
30268
30705
|
}
|
|
30269
30706
|
const source = options.from ?? process.env.SYNTAUR_ASSIGNMENT ?? "unknown";
|
|
30270
|
-
let content = await
|
|
30707
|
+
let content = await readFile50(assignmentMdPath2, "utf-8");
|
|
30271
30708
|
content = appendTodosToAssignmentBody(content, [
|
|
30272
30709
|
{ description: `${text.trim()} (from: ${source})` }
|
|
30273
30710
|
]);
|
|
@@ -30280,13 +30717,13 @@ async function requestCommand(target, text, options = {}) {
|
|
|
30280
30717
|
init_fs();
|
|
30281
30718
|
init_paths();
|
|
30282
30719
|
import { Command as Command9 } from "commander";
|
|
30283
|
-
import { readFile as
|
|
30284
|
-
import { resolve as
|
|
30720
|
+
import { readFile as readFile51, readdir as readdir25 } from "fs/promises";
|
|
30721
|
+
import { resolve as resolve75 } from "path";
|
|
30285
30722
|
async function readContextAssignmentDir(cwd) {
|
|
30286
|
-
const path =
|
|
30723
|
+
const path = resolve75(cwd, ".syntaur", "context.json");
|
|
30287
30724
|
if (!await fileExists(path)) return null;
|
|
30288
30725
|
try {
|
|
30289
|
-
const raw = await
|
|
30726
|
+
const raw = await readFile51(path, "utf-8");
|
|
30290
30727
|
const ctx = JSON.parse(raw);
|
|
30291
30728
|
if (typeof ctx.assignmentDir === "string" && ctx.assignmentDir.length > 0) {
|
|
30292
30729
|
return ctx.assignmentDir;
|
|
@@ -30300,9 +30737,9 @@ async function resolveAssignmentDir(opts) {
|
|
|
30300
30737
|
const cwd = opts.cwd ?? process.cwd();
|
|
30301
30738
|
if (opts.assignment) {
|
|
30302
30739
|
if (opts.project) {
|
|
30303
|
-
return
|
|
30740
|
+
return resolve75(defaultProjectDir(), opts.project, "assignments", opts.assignment);
|
|
30304
30741
|
}
|
|
30305
|
-
return
|
|
30742
|
+
return resolve75(assignmentsDir(), opts.assignment);
|
|
30306
30743
|
}
|
|
30307
30744
|
const fromCtx = await readContextAssignmentDir(cwd);
|
|
30308
30745
|
if (fromCtx) return fromCtx;
|
|
@@ -30445,7 +30882,7 @@ async function runPlanVersion(options) {
|
|
|
30445
30882
|
if (!await fileExists(assignmentDir)) {
|
|
30446
30883
|
throw new Error(`Assignment directory does not exist: ${assignmentDir}`);
|
|
30447
30884
|
}
|
|
30448
|
-
const assignmentMdPath2 =
|
|
30885
|
+
const assignmentMdPath2 = resolve75(assignmentDir, "assignment.md");
|
|
30449
30886
|
if (!await fileExists(assignmentMdPath2)) {
|
|
30450
30887
|
throw new Error(`Missing assignment.md at: ${assignmentMdPath2}`);
|
|
30451
30888
|
}
|
|
@@ -30457,15 +30894,15 @@ async function runPlanVersion(options) {
|
|
|
30457
30894
|
}
|
|
30458
30895
|
const current = planFiles[planFiles.length - 1];
|
|
30459
30896
|
const next = nextPlanFileName(current.version);
|
|
30460
|
-
const newPath =
|
|
30897
|
+
const newPath = resolve75(assignmentDir, next.fileName);
|
|
30461
30898
|
if (await fileExists(newPath) && !options.force) {
|
|
30462
30899
|
throw new Error(`${next.fileName} already exists. Use --force to overwrite.`);
|
|
30463
30900
|
}
|
|
30464
|
-
const assignmentMd = await
|
|
30901
|
+
const assignmentMd = await readFile51(assignmentMdPath2, "utf-8");
|
|
30465
30902
|
const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
|
|
30466
30903
|
const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
|
|
30467
|
-
const oldPlanPath =
|
|
30468
|
-
const oldPlanContent = await
|
|
30904
|
+
const oldPlanPath = resolve75(assignmentDir, current.fileName);
|
|
30905
|
+
const oldPlanContent = await readFile51(oldPlanPath, "utf-8");
|
|
30469
30906
|
const oldBody = oldPlanContent.replace(/^---[\s\S]*?\n---\n?/, "");
|
|
30470
30907
|
const carriedTodos = extractUncheckedTodos(oldBody);
|
|
30471
30908
|
const stub = buildNewPlanStub({
|
|
@@ -30502,26 +30939,26 @@ planCommand.command("version").description(
|
|
|
30502
30939
|
// src/commands/session.ts
|
|
30503
30940
|
init_fs();
|
|
30504
30941
|
import { Command as Command10 } from "commander";
|
|
30505
|
-
import { readFile as
|
|
30506
|
-
import { resolve as
|
|
30942
|
+
import { readFile as readFile52, readdir as readdir26, stat as stat11 } from "fs/promises";
|
|
30943
|
+
import { resolve as resolve76 } from "path";
|
|
30507
30944
|
async function readContext(cwd) {
|
|
30508
|
-
const path =
|
|
30945
|
+
const path = resolve76(cwd, ".syntaur", "context.json");
|
|
30509
30946
|
if (!await fileExists(path)) return null;
|
|
30510
30947
|
try {
|
|
30511
|
-
const raw = await
|
|
30948
|
+
const raw = await readFile52(path, "utf-8");
|
|
30512
30949
|
return JSON.parse(raw);
|
|
30513
30950
|
} catch {
|
|
30514
30951
|
return null;
|
|
30515
30952
|
}
|
|
30516
30953
|
}
|
|
30517
30954
|
async function findLatestSessionSummary(assignmentDir) {
|
|
30518
|
-
const sessionsRoot =
|
|
30955
|
+
const sessionsRoot = resolve76(assignmentDir, "sessions");
|
|
30519
30956
|
if (!await fileExists(sessionsRoot)) return null;
|
|
30520
30957
|
const entries = await readdir26(sessionsRoot, { withFileTypes: true });
|
|
30521
30958
|
let best = null;
|
|
30522
30959
|
for (const entry of entries) {
|
|
30523
30960
|
if (!entry.isDirectory()) continue;
|
|
30524
|
-
const summaryPath =
|
|
30961
|
+
const summaryPath = resolve76(sessionsRoot, entry.name, "summary.md");
|
|
30525
30962
|
if (!await fileExists(summaryPath)) continue;
|
|
30526
30963
|
const st = await stat11(summaryPath);
|
|
30527
30964
|
if (best === null || st.mtime.getTime() > best.mtime.getTime()) {
|
|
@@ -30531,9 +30968,9 @@ async function findLatestSessionSummary(assignmentDir) {
|
|
|
30531
30968
|
return best;
|
|
30532
30969
|
}
|
|
30533
30970
|
async function findOpenHandoff(assignmentDir) {
|
|
30534
|
-
const handoffPath =
|
|
30971
|
+
const handoffPath = resolve76(assignmentDir, "handoff.md");
|
|
30535
30972
|
if (!await fileExists(handoffPath)) return null;
|
|
30536
|
-
const content = await
|
|
30973
|
+
const content = await readFile52(handoffPath, "utf-8");
|
|
30537
30974
|
const body = content.replace(/^---[\s\S]*?\n---\n?/, "").trim();
|
|
30538
30975
|
if (body.length === 0) return null;
|
|
30539
30976
|
if (/^<!--[\s\S]*-->$/.test(body)) return null;
|
|
@@ -30641,13 +31078,13 @@ init_git_worktree();
|
|
|
30641
31078
|
init_fs();
|
|
30642
31079
|
init_paths();
|
|
30643
31080
|
import { Command as Command11 } from "commander";
|
|
30644
|
-
import { readFile as
|
|
30645
|
-
import { resolve as
|
|
31081
|
+
import { readFile as readFile53 } from "fs/promises";
|
|
31082
|
+
import { resolve as resolve77 } from "path";
|
|
30646
31083
|
async function readContext2(cwd) {
|
|
30647
|
-
const path =
|
|
31084
|
+
const path = resolve77(cwd, ".syntaur", "context.json");
|
|
30648
31085
|
if (!await fileExists(path)) return null;
|
|
30649
31086
|
try {
|
|
30650
|
-
return JSON.parse(await
|
|
31087
|
+
return JSON.parse(await readFile53(path, "utf-8"));
|
|
30651
31088
|
} catch {
|
|
30652
31089
|
return null;
|
|
30653
31090
|
}
|
|
@@ -30655,7 +31092,7 @@ async function readContext2(cwd) {
|
|
|
30655
31092
|
async function resolveAssignmentPath2(opts) {
|
|
30656
31093
|
if (opts.assignment) {
|
|
30657
31094
|
if (opts.project) {
|
|
30658
|
-
return
|
|
31095
|
+
return resolve77(
|
|
30659
31096
|
defaultProjectDir(),
|
|
30660
31097
|
opts.project,
|
|
30661
31098
|
"assignments",
|
|
@@ -30663,10 +31100,10 @@ async function resolveAssignmentPath2(opts) {
|
|
|
30663
31100
|
"assignment.md"
|
|
30664
31101
|
);
|
|
30665
31102
|
}
|
|
30666
|
-
return
|
|
31103
|
+
return resolve77(assignmentsDir(), opts.assignment, "assignment.md");
|
|
30667
31104
|
}
|
|
30668
31105
|
const ctx = await readContext2(opts.cwd);
|
|
30669
|
-
if (ctx?.assignmentDir) return
|
|
31106
|
+
if (ctx?.assignmentDir) return resolve77(ctx.assignmentDir, "assignment.md");
|
|
30670
31107
|
throw new Error(
|
|
30671
31108
|
"No active assignment. Pass --assignment <slug> [--project <slug>] or run from a workspace with .syntaur/context.json."
|
|
30672
31109
|
);
|
|
@@ -30677,7 +31114,7 @@ async function runWorktreeCreate(options, cwd = process.cwd()) {
|
|
|
30677
31114
|
}
|
|
30678
31115
|
const repository = options.repository ?? cwd;
|
|
30679
31116
|
const parentBranch = options.parentBranch ?? "main";
|
|
30680
|
-
const worktreePath = options.worktreePath ??
|
|
31117
|
+
const worktreePath = options.worktreePath ?? resolve77(repository, ".worktrees", options.branch);
|
|
30681
31118
|
const assignmentPath = await resolveAssignmentPath2({
|
|
30682
31119
|
assignment: options.assignment,
|
|
30683
31120
|
project: options.project,
|
|
@@ -30714,13 +31151,13 @@ init_paths();
|
|
|
30714
31151
|
init_fs();
|
|
30715
31152
|
init_slug();
|
|
30716
31153
|
import { Command as Command12 } from "commander";
|
|
30717
|
-
import { resolve as
|
|
31154
|
+
import { resolve as resolve79 } from "path";
|
|
30718
31155
|
|
|
30719
31156
|
// src/utils/project-indexes.ts
|
|
30720
31157
|
init_parser();
|
|
30721
31158
|
init_fs();
|
|
30722
|
-
import { readdir as readdir27, readFile as
|
|
30723
|
-
import { resolve as
|
|
31159
|
+
import { readdir as readdir27, readFile as readFile54 } from "fs/promises";
|
|
31160
|
+
import { resolve as resolve78 } from "path";
|
|
30724
31161
|
function nowIso3() {
|
|
30725
31162
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
30726
31163
|
}
|
|
@@ -30739,7 +31176,7 @@ function joinList(items) {
|
|
|
30739
31176
|
return items.length === 0 ? "\u2014" : items.map(escapeCell).join(", ");
|
|
30740
31177
|
}
|
|
30741
31178
|
async function rebuildResourcesIndex(projectDir) {
|
|
30742
|
-
const dir =
|
|
31179
|
+
const dir = resolve78(projectDir, "resources");
|
|
30743
31180
|
await ensureDir(dir);
|
|
30744
31181
|
const files = await listSlugFiles(dir);
|
|
30745
31182
|
const slug = readProjectSlug(projectDir);
|
|
@@ -30755,7 +31192,7 @@ async function rebuildResourcesIndex(projectDir) {
|
|
|
30755
31192
|
lines.push("| Name | Category | Source | Related Assignments | Updated |");
|
|
30756
31193
|
lines.push("|------|----------|--------|---------------------|---------|");
|
|
30757
31194
|
for (const fileName of files) {
|
|
30758
|
-
const content = await
|
|
31195
|
+
const content = await readFile54(resolve78(dir, fileName), "utf-8");
|
|
30759
31196
|
const parsed = parseResource(content);
|
|
30760
31197
|
const slugBase = fileName.replace(/\.md$/, "");
|
|
30761
31198
|
const name = parsed.name || slugBase;
|
|
@@ -30765,12 +31202,12 @@ async function rebuildResourcesIndex(projectDir) {
|
|
|
30765
31202
|
);
|
|
30766
31203
|
}
|
|
30767
31204
|
lines.push("");
|
|
30768
|
-
const indexPath =
|
|
31205
|
+
const indexPath = resolve78(dir, "_index.md");
|
|
30769
31206
|
await writeFileForce(indexPath, lines.join("\n"));
|
|
30770
31207
|
return { total: files.length, path: indexPath };
|
|
30771
31208
|
}
|
|
30772
31209
|
async function rebuildMemoriesIndex(projectDir) {
|
|
30773
|
-
const dir =
|
|
31210
|
+
const dir = resolve78(projectDir, "memories");
|
|
30774
31211
|
await ensureDir(dir);
|
|
30775
31212
|
const files = await listSlugFiles(dir);
|
|
30776
31213
|
const slug = readProjectSlug(projectDir);
|
|
@@ -30786,7 +31223,7 @@ async function rebuildMemoriesIndex(projectDir) {
|
|
|
30786
31223
|
lines.push("| Name | Source | Scope | Source Assignment | Updated |");
|
|
30787
31224
|
lines.push("|------|--------|-------|-------------------|---------|");
|
|
30788
31225
|
for (const fileName of files) {
|
|
30789
|
-
const content = await
|
|
31226
|
+
const content = await readFile54(resolve78(dir, fileName), "utf-8");
|
|
30790
31227
|
const parsed = parseMemory(content);
|
|
30791
31228
|
const slugBase = fileName.replace(/\.md$/, "");
|
|
30792
31229
|
const name = parsed.name || slugBase;
|
|
@@ -30796,7 +31233,7 @@ async function rebuildMemoriesIndex(projectDir) {
|
|
|
30796
31233
|
);
|
|
30797
31234
|
}
|
|
30798
31235
|
lines.push("");
|
|
30799
|
-
const indexPath =
|
|
31236
|
+
const indexPath = resolve78(dir, "_index.md");
|
|
30800
31237
|
await writeFileForce(indexPath, lines.join("\n"));
|
|
30801
31238
|
return { total: files.length, path: indexPath };
|
|
30802
31239
|
}
|
|
@@ -30834,8 +31271,8 @@ async function runResourceAdd(options) {
|
|
|
30834
31271
|
if (!isValidSlug(options.project)) {
|
|
30835
31272
|
throw new Error(`Invalid project slug: "${options.project}".`);
|
|
30836
31273
|
}
|
|
30837
|
-
const projectDir =
|
|
30838
|
-
if (!await fileExists(
|
|
31274
|
+
const projectDir = resolve79(defaultProjectDir(), options.project);
|
|
31275
|
+
if (!await fileExists(resolve79(projectDir, "project.md"))) {
|
|
30839
31276
|
throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
|
|
30840
31277
|
}
|
|
30841
31278
|
if (!options.name) throw new Error("--name is required.");
|
|
@@ -30844,7 +31281,7 @@ async function runResourceAdd(options) {
|
|
|
30844
31281
|
if (!isValidSlug(slug)) {
|
|
30845
31282
|
throw new Error(`Invalid resource slug: "${slug}".`);
|
|
30846
31283
|
}
|
|
30847
|
-
const filePath =
|
|
31284
|
+
const filePath = resolve79(projectDir, "resources", `${slug}.md`);
|
|
30848
31285
|
if (await fileExists(filePath) && !options.force) {
|
|
30849
31286
|
throw new Error(
|
|
30850
31287
|
`Resource "${slug}" already exists at ${filePath}. Use --force to overwrite.`
|
|
@@ -30879,7 +31316,7 @@ init_paths();
|
|
|
30879
31316
|
init_fs();
|
|
30880
31317
|
init_slug();
|
|
30881
31318
|
import { Command as Command13 } from "commander";
|
|
30882
|
-
import { resolve as
|
|
31319
|
+
import { resolve as resolve80 } from "path";
|
|
30883
31320
|
function nowIso5() {
|
|
30884
31321
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
30885
31322
|
}
|
|
@@ -30914,8 +31351,8 @@ async function runMemoryAdd(options) {
|
|
|
30914
31351
|
if (!isValidSlug(options.project)) {
|
|
30915
31352
|
throw new Error(`Invalid project slug: "${options.project}".`);
|
|
30916
31353
|
}
|
|
30917
|
-
const projectDir =
|
|
30918
|
-
if (!await fileExists(
|
|
31354
|
+
const projectDir = resolve80(defaultProjectDir(), options.project);
|
|
31355
|
+
if (!await fileExists(resolve80(projectDir, "project.md"))) {
|
|
30919
31356
|
throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
|
|
30920
31357
|
}
|
|
30921
31358
|
if (!options.name) throw new Error("--name is required.");
|
|
@@ -30924,7 +31361,7 @@ async function runMemoryAdd(options) {
|
|
|
30924
31361
|
if (!isValidSlug(slug)) {
|
|
30925
31362
|
throw new Error(`Invalid memory slug: "${slug}".`);
|
|
30926
31363
|
}
|
|
30927
|
-
const filePath =
|
|
31364
|
+
const filePath = resolve80(projectDir, "memories", `${slug}.md`);
|
|
30928
31365
|
if (await fileExists(filePath) && !options.force) {
|
|
30929
31366
|
throw new Error(
|
|
30930
31367
|
`Memory "${slug}" already exists at ${filePath}. Use --force to overwrite.`
|
|
@@ -30961,8 +31398,8 @@ init_paths();
|
|
|
30961
31398
|
init_fs();
|
|
30962
31399
|
init_frontmatter();
|
|
30963
31400
|
import { Command as Command14 } from "commander";
|
|
30964
|
-
import { readFile as
|
|
30965
|
-
import { resolve as
|
|
31401
|
+
import { readFile as readFile55 } from "fs/promises";
|
|
31402
|
+
import { resolve as resolve81 } from "path";
|
|
30966
31403
|
var AGE_PATTERN = /^(\d+)([dhwm])$/i;
|
|
30967
31404
|
function parseAgeToCutoff(age) {
|
|
30968
31405
|
const match = age.match(AGE_PATTERN);
|
|
@@ -30981,7 +31418,7 @@ function parseAgeToCutoff(age) {
|
|
|
30981
31418
|
}
|
|
30982
31419
|
function assignmentMdPath(item) {
|
|
30983
31420
|
if (item.projectSlug) {
|
|
30984
|
-
return
|
|
31421
|
+
return resolve81(
|
|
30985
31422
|
defaultProjectDir(),
|
|
30986
31423
|
item.projectSlug,
|
|
30987
31424
|
"assignments",
|
|
@@ -30989,13 +31426,13 @@ function assignmentMdPath(item) {
|
|
|
30989
31426
|
"assignment.md"
|
|
30990
31427
|
);
|
|
30991
31428
|
}
|
|
30992
|
-
return
|
|
31429
|
+
return resolve81(assignmentsDir(), item.id, "assignment.md");
|
|
30993
31430
|
}
|
|
30994
31431
|
async function loadTags(item) {
|
|
30995
31432
|
const path = assignmentMdPath(item);
|
|
30996
31433
|
if (!await fileExists(path)) return [];
|
|
30997
31434
|
try {
|
|
30998
|
-
const content = await
|
|
31435
|
+
const content = await readFile55(path, "utf-8");
|
|
30999
31436
|
return parseAssignmentFrontmatter(content).tags;
|
|
31000
31437
|
} catch {
|
|
31001
31438
|
return [];
|
|
@@ -31467,7 +31904,8 @@ function spliceDashDashFromArgv(argv) {
|
|
|
31467
31904
|
// src/index.ts
|
|
31468
31905
|
{
|
|
31469
31906
|
const sub = process.argv[2];
|
|
31470
|
-
|
|
31907
|
+
const isDryRunSetup = sub === "setup" && process.argv.slice(3).includes("--dry-run");
|
|
31908
|
+
if (sub !== "update" && sub !== "upgrade" && !isDryRunSetup) {
|
|
31471
31909
|
await maybePromptInstall(import.meta.url);
|
|
31472
31910
|
await maybeNudgeForNpxInstall(import.meta.url);
|
|
31473
31911
|
}
|
|
@@ -31712,7 +32150,7 @@ program.command("reopen").description("Reopen a completed or failed assignment")
|
|
|
31712
32150
|
process.exit(1);
|
|
31713
32151
|
}
|
|
31714
32152
|
});
|
|
31715
|
-
program.command("setup").description("Initialize Syntaur and optionally install plugins or launch the dashboard").option("--yes", "Skip interactive prompts and perform only the requested flags").option("--claude", "Install the Claude Code plugin").option("--codex", "Install the Codex plugin").option("--claude-dir <path>", "Install the Claude Code plugin at a specific path").option("--codex-dir <path>", "Install the Codex plugin at a specific path").option("--codex-marketplace-path <path>", "Write the Codex marketplace entry to a specific file").option("--dashboard", "Launch the dashboard after setup").action(async (options) => {
|
|
32153
|
+
program.command("setup").description("Initialize Syntaur and optionally install plugins or launch the dashboard").option("--yes", "Skip interactive prompts and perform only the requested flags").option("--claude", "Install the Claude Code plugin").option("--codex", "Install the Codex plugin").option("--claude-dir <path>", "Install the Claude Code plugin at a specific path").option("--codex-dir <path>", "Install the Codex plugin at a specific path").option("--codex-marketplace-path <path>", "Write the Codex marketplace entry to a specific file").option("--dashboard", "Launch the dashboard after setup").option("--target <id>", "Install Syntaur into a cross-agent target (pi, hermes, openclaw, cursor, opencode); comma-separated for several").option("--agent <id>", "Alias for --target; cross-agent target id(s) to install into").option("--force", "Overwrite existing cross-agent protocol files / skills").option("--dry-run", "Print the cross-agent install actions without writing anything").action(async (options) => {
|
|
31716
32154
|
try {
|
|
31717
32155
|
await setupCommand(options);
|
|
31718
32156
|
} catch (error) {
|