syntaur 0.32.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dashboard/dist/assets/{_basePickBy-CV3s3ZBR.js → _basePickBy-BBDt2N1-.js} +1 -1
- package/dashboard/dist/assets/{_baseUniq-BTBb-kpx.js → _baseUniq-CX9QmA6j.js} +1 -1
- package/dashboard/dist/assets/{arc-DroCaru_.js → arc-CQ6470MS.js} +1 -1
- package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-hL5g0oNx.js → architectureDiagram-2XIMDMQ5-q_340vb1.js} +1 -1
- package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-H-mOZOGQ.js → blockDiagram-WCTKOSBZ-DDcJVm3I.js} +1 -1
- package/dashboard/dist/assets/{c4Diagram-IC4MRINW-C7JTywql.js → c4Diagram-IC4MRINW-Bu7rCnPq.js} +1 -1
- package/dashboard/dist/assets/channel-C1JmUAYK.js +1 -0
- package/dashboard/dist/assets/{chunk-4BX2VUAB-C5NgL7Ud.js → chunk-4BX2VUAB-D4mCzHM1.js} +1 -1
- package/dashboard/dist/assets/{chunk-55IACEB6-CpqlZIZp.js → chunk-55IACEB6-qZy5S9aK.js} +1 -1
- package/dashboard/dist/assets/{chunk-FMBD7UC4-DOEJuCgN.js → chunk-FMBD7UC4-CP-aSp5R.js} +1 -1
- package/dashboard/dist/assets/{chunk-JSJVCQXG-DTvwZQeC.js → chunk-JSJVCQXG-Bjd2-Jbp.js} +1 -1
- package/dashboard/dist/assets/{chunk-KX2RTZJC-DtM5R3Ro.js → chunk-KX2RTZJC-BHALK3O8.js} +1 -1
- package/dashboard/dist/assets/{chunk-NQ4KR5QH-BRf7XeyG.js → chunk-NQ4KR5QH-EJgFAbBI.js} +1 -1
- package/dashboard/dist/assets/{chunk-QZHKN3VN-CkRK4_hm.js → chunk-QZHKN3VN-LIJprKdb.js} +1 -1
- package/dashboard/dist/assets/{chunk-WL4C6EOR-D40xff82.js → chunk-WL4C6EOR-Bp9peutH.js} +1 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-CL5uYMtW.js +1 -0
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-CL5uYMtW.js +1 -0
- package/dashboard/dist/assets/clone-BGt3nn5b.js +1 -0
- package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-BzAx8dWI.js → cose-bilkent-S5V4N54A-D2Khnalp.js} +1 -1
- package/dashboard/dist/assets/{dagre-KLK3FWXG-DqBzOGFn.js → dagre-KLK3FWXG-A7FKInZZ.js} +1 -1
- package/dashboard/dist/assets/{diagram-E7M64L7V-BU3Nv4BP.js → diagram-E7M64L7V-CpCC84EE.js} +1 -1
- package/dashboard/dist/assets/{diagram-IFDJBPK2-9173qxjV.js → diagram-IFDJBPK2-UN3agGn6.js} +1 -1
- package/dashboard/dist/assets/{diagram-P4PSJMXO-CDO7XNao.js → diagram-P4PSJMXO-r7USVjRa.js} +1 -1
- package/dashboard/dist/assets/{erDiagram-INFDFZHY-DkO9AjCM.js → erDiagram-INFDFZHY-BqjWbP4d.js} +1 -1
- package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-9Fjhsq_p.js → flowDiagram-PKNHOUZH-D3_hInoz.js} +1 -1
- package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-FL3oGbo9.js → ganttDiagram-A5KZAMGK-Dzf0OcUQ.js} +1 -1
- package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-FS9HpxFJ.js → gitGraphDiagram-K3NZZRJ6-DDVNfYsD.js} +1 -1
- package/dashboard/dist/assets/{graph-COu71lol.js → graph-XQCpDL3e.js} +1 -1
- package/dashboard/dist/assets/index-BlO8cOgL.css +1 -0
- package/dashboard/dist/assets/{index-D1FxzsMS.js → index-DTGG1F6E.js} +130 -125
- package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-Cb7nqRMJ.js → infoDiagram-LFFYTUFH-Bn7xCldX.js} +1 -1
- package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-DU44jQ_t.js → ishikawaDiagram-PHBUUO56-BMaPOOT_.js} +1 -1
- package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-Dvf5wmhX.js → journeyDiagram-4ABVD52K-CfYBwIWr.js} +1 -1
- package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-NNnzIiBX.js → kanban-definition-K7BYSVSG-DQoSgSWy.js} +1 -1
- package/dashboard/dist/assets/{layout-BWL1q6XW.js → layout-CFxopkD1.js} +1 -1
- package/dashboard/dist/assets/{linear-BpjXUE-L.js → linear-q1lde7uY.js} +1 -1
- package/dashboard/dist/assets/{mermaid.core-C1YuKa7V.js → mermaid.core-CclSNuh7.js} +4 -4
- package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-BUS-7SSM.js → mindmap-definition-YRQLILUH-C_XHOwF9.js} +1 -1
- package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-CId0D08y.js → pieDiagram-SKSYHLDU-C8xZgEA3.js} +1 -1
- package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-lrdlvDFz.js → quadrantDiagram-337W2JSQ-JZOm4MlZ.js} +1 -1
- package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-CijOr4BN.js → requirementDiagram-Z7DCOOCP-0o-kjUyz.js} +1 -1
- package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-Bz63rCum.js → sankeyDiagram-WA2Y5GQK-BQVypVuO.js} +1 -1
- package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-0ojwsRXQ.js → sequenceDiagram-2WXFIKYE-eHOgK4bp.js} +1 -1
- package/dashboard/dist/assets/{stateDiagram-RAJIS63D-DvTark-k.js → stateDiagram-RAJIS63D-D08VAF0t.js} +1 -1
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-9uffSM-p.js +1 -0
- package/dashboard/dist/assets/{timeline-definition-YZTLITO2-B4EQprf1.js → timeline-definition-YZTLITO2-BGqUaDJh.js} +1 -1
- package/dashboard/dist/assets/{treemap-KZPCXAKY-ht_xOxVL.js → treemap-KZPCXAKY-DDilTqSL.js} +1 -1
- package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-C4DqZkvq.js → vennDiagram-LZ73GAT5-CGMFf3rB.js} +1 -1
- package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-eoymvv9D.js → xychartDiagram-JWTSCODW-DxpH1jvd.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/dist/dashboard/server.js +9 -1
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.js +772 -452
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/platforms/README.md +38 -7
- package/platforms/hermes/plugins/syntaur/README.md +37 -0
- package/platforms/hermes/plugins/syntaur/__init__.py +151 -0
- package/platforms/hermes/plugins/syntaur/__pycache__/__init__.cpython-312.pyc +0 -0
- package/platforms/hermes/plugins/syntaur/__pycache__/boundary.cpython-312.pyc +0 -0
- package/platforms/hermes/plugins/syntaur/boundary.py +99 -0
- package/platforms/hermes/plugins/syntaur/plugin.yaml +6 -0
- package/platforms/pi/extensions/syntaur/README.md +34 -0
- package/platforms/pi/extensions/syntaur/index.ts +265 -0
- package/dashboard/dist/assets/channel-X6-lrXLw.js +0 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-DfkR91Os.js +0 -1
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-DfkR91Os.js +0 -1
- package/dashboard/dist/assets/clone--OUSRwbL.js +0 -1
- package/dashboard/dist/assets/index-BohN_jjP.css +0 -1
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-CiT1CTy0.js +0 -1
package/dist/index.js
CHANGED
|
@@ -2760,9 +2760,9 @@ function normalizeAgentsFromConfig(agents) {
|
|
|
2760
2760
|
validateAgentList(normalized);
|
|
2761
2761
|
return normalized;
|
|
2762
2762
|
} catch (err2) {
|
|
2763
|
-
const
|
|
2763
|
+
const msg2 = err2 instanceof Error ? err2.message : String(err2);
|
|
2764
2764
|
console.warn(
|
|
2765
|
-
`Warning: ~/.syntaur/config.md agents block is invalid (${
|
|
2765
|
+
`Warning: ~/.syntaur/config.md agents block is invalid (${msg2}) \u2014 using built-in defaults`
|
|
2766
2766
|
);
|
|
2767
2767
|
return null;
|
|
2768
2768
|
}
|
|
@@ -3152,8 +3152,8 @@ async function readConfig() {
|
|
|
3152
3152
|
try {
|
|
3153
3153
|
return parseTerminalConfig(fm["terminal"]);
|
|
3154
3154
|
} catch (err2) {
|
|
3155
|
-
const
|
|
3156
|
-
console.warn(`Warning: ${
|
|
3155
|
+
const msg2 = err2 instanceof TerminalConfigError ? err2.message : String(err2);
|
|
3156
|
+
console.warn(`Warning: ${msg2} \u2014 falling back to default`);
|
|
3157
3157
|
return null;
|
|
3158
3158
|
}
|
|
3159
3159
|
})(),
|
|
@@ -5382,8 +5382,8 @@ async function migrateFromMarkdown(projectsDir2) {
|
|
|
5382
5382
|
return allSessions.length;
|
|
5383
5383
|
}
|
|
5384
5384
|
async function parseMarkdownSessionsIndex(filePath, projectSlug) {
|
|
5385
|
-
const { readFile:
|
|
5386
|
-
const raw2 = await
|
|
5385
|
+
const { readFile: readFile64 } = await import("fs/promises");
|
|
5386
|
+
const raw2 = await readFile64(filePath, "utf-8");
|
|
5387
5387
|
const sessions = [];
|
|
5388
5388
|
const lines = raw2.split("\n");
|
|
5389
5389
|
let inTable = false;
|
|
@@ -5819,8 +5819,8 @@ function scanKey(serversDir2, projectsDir2, assignmentsDir2) {
|
|
|
5819
5819
|
return `${serversDir2}\0${projectsDir2}\0${assignmentsDir2 ?? ""}`;
|
|
5820
5820
|
}
|
|
5821
5821
|
function delay(ms) {
|
|
5822
|
-
return new Promise((
|
|
5823
|
-
const timer2 = setTimeout(
|
|
5822
|
+
return new Promise((resolve87) => {
|
|
5823
|
+
const timer2 = setTimeout(resolve87, ms);
|
|
5824
5824
|
if (typeof timer2.unref === "function") {
|
|
5825
5825
|
timer2.unref();
|
|
5826
5826
|
}
|
|
@@ -8802,7 +8802,7 @@ import {
|
|
|
8802
8802
|
unlinkSync
|
|
8803
8803
|
} from "fs";
|
|
8804
8804
|
import { fileURLToPath as fileURLToPath9, pathToFileURL } from "url";
|
|
8805
|
-
import { dirname as
|
|
8805
|
+
import { dirname as dirname18, resolve as resolve51, join as join10 } from "path";
|
|
8806
8806
|
import { homedir as homedir9, tmpdir as tmpdir2 } from "os";
|
|
8807
8807
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
8808
8808
|
function syntaurRootMjs() {
|
|
@@ -8810,7 +8810,7 @@ function syntaurRootMjs() {
|
|
|
8810
8810
|
if (override && override.length > 0) {
|
|
8811
8811
|
return override;
|
|
8812
8812
|
}
|
|
8813
|
-
return
|
|
8813
|
+
return join10(homedir9(), ".syntaur");
|
|
8814
8814
|
}
|
|
8815
8815
|
async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
8816
8816
|
const { throwOnFailure } = options;
|
|
@@ -8824,38 +8824,38 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
|
8824
8824
|
}
|
|
8825
8825
|
const stateRoot = syntaurRootMjs();
|
|
8826
8826
|
mkdirSync2(stateRoot, { recursive: true });
|
|
8827
|
-
const lockPath =
|
|
8827
|
+
const lockPath = resolve51(stateRoot, "install-url-handler.lock");
|
|
8828
8828
|
let lockFd;
|
|
8829
8829
|
try {
|
|
8830
8830
|
lockFd = openSync(lockPath, "wx");
|
|
8831
8831
|
} catch (err2) {
|
|
8832
8832
|
if (err2 && err2.code === "EEXIST") {
|
|
8833
|
-
const
|
|
8833
|
+
const msg2 = `Another syntaur:// handler registration is in progress (lock at ${lockPath}). Wait for it to finish or remove the stale lock.`;
|
|
8834
8834
|
if (throwOnFailure) {
|
|
8835
|
-
throw new Error(
|
|
8835
|
+
throw new Error(msg2);
|
|
8836
8836
|
}
|
|
8837
|
-
console.warn(`syntaur: skipping macOS URL-handler registration (${
|
|
8837
|
+
console.warn(`syntaur: skipping macOS URL-handler registration (${msg2})`);
|
|
8838
8838
|
return { bundlePath: "" };
|
|
8839
8839
|
}
|
|
8840
8840
|
throw err2;
|
|
8841
8841
|
}
|
|
8842
8842
|
try {
|
|
8843
|
-
const pkgRoot =
|
|
8844
|
-
const cliBin = realpathSync3(
|
|
8843
|
+
const pkgRoot = resolve51(dirname18(fileURLToPath9(import.meta.url)), "..");
|
|
8844
|
+
const cliBin = realpathSync3(resolve51(pkgRoot, "bin/syntaur.js"));
|
|
8845
8845
|
const nodeBin = process.execPath;
|
|
8846
|
-
const bundleParent =
|
|
8846
|
+
const bundleParent = join10(
|
|
8847
8847
|
homedir9(),
|
|
8848
8848
|
"Library",
|
|
8849
8849
|
"Application Support",
|
|
8850
8850
|
"Syntaur"
|
|
8851
8851
|
);
|
|
8852
|
-
const bundlePath =
|
|
8852
|
+
const bundlePath = join10(bundleParent, "syntaur-url.app");
|
|
8853
8853
|
mkdirSync2(bundleParent, { recursive: true });
|
|
8854
8854
|
if (existsSync5(bundlePath)) {
|
|
8855
8855
|
rmSync(bundlePath, { recursive: true, force: true });
|
|
8856
8856
|
}
|
|
8857
8857
|
const installedTerminals = detectInstalledTerminals();
|
|
8858
|
-
const scriptPath =
|
|
8858
|
+
const scriptPath = join10(
|
|
8859
8859
|
tmpdir2(),
|
|
8860
8860
|
`syntaur-url-handler-${process.pid}.applescript`
|
|
8861
8861
|
);
|
|
@@ -8874,7 +8874,7 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
|
8874
8874
|
`osacompile exited with code ${compile.status}: ${compile.stderr || compile.stdout}`
|
|
8875
8875
|
);
|
|
8876
8876
|
}
|
|
8877
|
-
const infoPlistPath =
|
|
8877
|
+
const infoPlistPath = join10(bundlePath, "Contents", "Info.plist");
|
|
8878
8878
|
if (!existsSync5(infoPlistPath)) {
|
|
8879
8879
|
throw new Error(`osacompile did not produce ${infoPlistPath}`);
|
|
8880
8880
|
}
|
|
@@ -8914,23 +8914,23 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
|
8914
8914
|
{ stdio: "pipe", encoding: "utf-8" }
|
|
8915
8915
|
);
|
|
8916
8916
|
if (sign.status !== 0) {
|
|
8917
|
-
const
|
|
8917
|
+
const msg2 = `codesign returned ${sign.status} while re-signing ${bundlePath}: ${sign.stderr || sign.stdout || "(no output)"}`;
|
|
8918
8918
|
if (throwOnFailure) {
|
|
8919
|
-
throw new Error(
|
|
8919
|
+
throw new Error(msg2);
|
|
8920
8920
|
}
|
|
8921
|
-
console.warn(`syntaur: ${
|
|
8921
|
+
console.warn(`syntaur: ${msg2} \u2014 macOS may deny Automation permission.`);
|
|
8922
8922
|
}
|
|
8923
8923
|
const ls = spawnSync7(LSREGISTER, ["-f", bundlePath], {
|
|
8924
8924
|
stdio: "pipe",
|
|
8925
8925
|
encoding: "utf-8"
|
|
8926
8926
|
});
|
|
8927
8927
|
if (ls.status !== 0) {
|
|
8928
|
-
const
|
|
8928
|
+
const msg2 = `lsregister returned ${ls.status} while registering ${bundlePath}: ${ls.stderr || ls.stdout || "(no output)"}`;
|
|
8929
8929
|
if (throwOnFailure) {
|
|
8930
|
-
throw new Error(
|
|
8930
|
+
throw new Error(msg2);
|
|
8931
8931
|
}
|
|
8932
8932
|
console.warn(
|
|
8933
|
-
`syntaur: ${
|
|
8933
|
+
`syntaur: ${msg2} \u2014 \`open syntaur://...\` may not route through the CLI handler until you run \`${LSREGISTER} -f ${bundlePath}\` manually.`
|
|
8934
8934
|
);
|
|
8935
8935
|
}
|
|
8936
8936
|
try {
|
|
@@ -8953,8 +8953,8 @@ async function main() {
|
|
|
8953
8953
|
try {
|
|
8954
8954
|
await registerMacosUrlHandler({ throwOnFailure: false });
|
|
8955
8955
|
} catch (err2) {
|
|
8956
|
-
const
|
|
8957
|
-
console.warn(`syntaur: skipping macOS URL-handler registration (${
|
|
8956
|
+
const msg2 = err2 instanceof Error ? err2.message : String(err2);
|
|
8957
|
+
console.warn(`syntaur: skipping macOS URL-handler registration (${msg2})`);
|
|
8958
8958
|
}
|
|
8959
8959
|
}
|
|
8960
8960
|
function detectInstalledTerminals() {
|
|
@@ -8969,7 +8969,7 @@ function detectInstalledTerminals() {
|
|
|
8969
8969
|
ghostty: "Ghostty.app",
|
|
8970
8970
|
warp: "Warp.app"
|
|
8971
8971
|
};
|
|
8972
|
-
const appDirs = ["/Applications",
|
|
8972
|
+
const appDirs = ["/Applications", join10(homedir9(), "Applications")];
|
|
8973
8973
|
for (const [id, bundleId] of Object.entries(bundleIds)) {
|
|
8974
8974
|
const r = spawnSync7(
|
|
8975
8975
|
"mdfind",
|
|
@@ -8981,7 +8981,7 @@ function detectInstalledTerminals() {
|
|
|
8981
8981
|
continue;
|
|
8982
8982
|
}
|
|
8983
8983
|
const name = bundleNames[id];
|
|
8984
|
-
if (name && appDirs.some((dir) => existsSync5(
|
|
8984
|
+
if (name && appDirs.some((dir) => existsSync5(join10(dir, name)))) {
|
|
8985
8985
|
installed.add(id);
|
|
8986
8986
|
}
|
|
8987
8987
|
}
|
|
@@ -10431,6 +10431,10 @@ var TABLE_COLUMN_IDS = [
|
|
|
10431
10431
|
function isTableColumnId(value) {
|
|
10432
10432
|
return typeof value === "string" && TABLE_COLUMN_IDS.includes(value);
|
|
10433
10433
|
}
|
|
10434
|
+
var WIDGET_SIZES = ["small", "wide", "tall", "large"];
|
|
10435
|
+
function isWidgetSize(value) {
|
|
10436
|
+
return typeof value === "string" && WIDGET_SIZES.includes(value);
|
|
10437
|
+
}
|
|
10434
10438
|
var DEFAULT_FILTERS = {
|
|
10435
10439
|
status: "all",
|
|
10436
10440
|
priority: "all",
|
|
@@ -10523,6 +10527,7 @@ function isDashboardSlot(value) {
|
|
|
10523
10527
|
if (!value || typeof value !== "object") return false;
|
|
10524
10528
|
const obj = value;
|
|
10525
10529
|
if (typeof obj.id !== "string" || obj.id.length === 0) return false;
|
|
10530
|
+
if (obj.size !== void 0 && !isWidgetSize(obj.size)) return false;
|
|
10526
10531
|
if (obj.widget === null) return true;
|
|
10527
10532
|
return isWidgetConfig(obj.widget);
|
|
10528
10533
|
}
|
|
@@ -10753,7 +10758,10 @@ function validateDashboardBody(body) {
|
|
|
10753
10758
|
return { ok: false, error: "slots must be an array" };
|
|
10754
10759
|
}
|
|
10755
10760
|
if (!obj.slots.every(isDashboardSlot)) {
|
|
10756
|
-
return {
|
|
10761
|
+
return {
|
|
10762
|
+
ok: false,
|
|
10763
|
+
error: "every slot must be { id: string, widget: WidgetConfig | null, size?: WidgetSize }"
|
|
10764
|
+
};
|
|
10757
10765
|
}
|
|
10758
10766
|
return { ok: true, value: obj.slots };
|
|
10759
10767
|
}
|
|
@@ -16160,12 +16168,12 @@ function createPlaybooksRouter(playbooksDir3) {
|
|
|
16160
16168
|
const result = await setPlaybookEnabled(playbooksDir3, req.params.slug, true);
|
|
16161
16169
|
res.json({ slug: result.slug, enabled: result.enabled, changed: result.changed });
|
|
16162
16170
|
} catch (error) {
|
|
16163
|
-
const
|
|
16164
|
-
if (
|
|
16165
|
-
res.status(404).json({ error:
|
|
16171
|
+
const msg2 = error instanceof Error ? error.message : "Failed to enable playbook";
|
|
16172
|
+
if (msg2.startsWith("Playbook ")) {
|
|
16173
|
+
res.status(404).json({ error: msg2 });
|
|
16166
16174
|
return;
|
|
16167
16175
|
}
|
|
16168
|
-
res.status(500).json({ error:
|
|
16176
|
+
res.status(500).json({ error: msg2 });
|
|
16169
16177
|
}
|
|
16170
16178
|
});
|
|
16171
16179
|
router.post("/:slug/disable", async (req, res) => {
|
|
@@ -16173,12 +16181,12 @@ function createPlaybooksRouter(playbooksDir3) {
|
|
|
16173
16181
|
const result = await setPlaybookEnabled(playbooksDir3, req.params.slug, false);
|
|
16174
16182
|
res.json({ slug: result.slug, enabled: result.enabled, changed: result.changed });
|
|
16175
16183
|
} catch (error) {
|
|
16176
|
-
const
|
|
16177
|
-
if (
|
|
16178
|
-
res.status(404).json({ error:
|
|
16184
|
+
const msg2 = error instanceof Error ? error.message : "Failed to disable playbook";
|
|
16185
|
+
if (msg2.startsWith("Playbook ")) {
|
|
16186
|
+
res.status(404).json({ error: msg2 });
|
|
16179
16187
|
return;
|
|
16180
16188
|
}
|
|
16181
|
-
res.status(500).json({ error:
|
|
16189
|
+
res.status(500).json({ error: msg2 });
|
|
16182
16190
|
}
|
|
16183
16191
|
});
|
|
16184
16192
|
router.get("/:slug", async (req, res) => {
|
|
@@ -16916,8 +16924,8 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
|
|
|
16916
16924
|
router.post("/:workspace/archive", async (req, res) => {
|
|
16917
16925
|
try {
|
|
16918
16926
|
const { archivePath: archivePath2 } = await Promise.resolve().then(() => (init_parser2(), parser_exports));
|
|
16919
|
-
const { resolve:
|
|
16920
|
-
const { readFile:
|
|
16927
|
+
const { resolve: resolve87 } = await import("path");
|
|
16928
|
+
const { readFile: readFile64 } = await import("fs/promises");
|
|
16921
16929
|
const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
16922
16930
|
const workspace = getWorkspaceParam(req.params.workspace);
|
|
16923
16931
|
const outcome = await wsLock(workspace, async () => {
|
|
@@ -16933,10 +16941,10 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
|
|
|
16933
16941
|
(e) => e.itemIds.every((id) => completedIds.has(id))
|
|
16934
16942
|
);
|
|
16935
16943
|
const archFile = archivePath2(todosDir2, workspace, checklist.archiveInterval);
|
|
16936
|
-
await ensureDir(
|
|
16944
|
+
await ensureDir(resolve87(todosDir2, "archive"));
|
|
16937
16945
|
let archContent = "";
|
|
16938
16946
|
if (await fileExists(archFile)) {
|
|
16939
|
-
archContent = await
|
|
16947
|
+
archContent = await readFile64(archFile, "utf-8");
|
|
16940
16948
|
archContent = archContent.trimEnd() + "\n\n";
|
|
16941
16949
|
} else {
|
|
16942
16950
|
archContent = `---
|
|
@@ -17225,7 +17233,7 @@ workspace: ${workspace}
|
|
|
17225
17233
|
const { readConfig: readConfig3 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
17226
17234
|
const { assignmentsDir: assignmentsDirFn } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
17227
17235
|
const { fileExists: fileExists2, writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
17228
|
-
const { readFile:
|
|
17236
|
+
const { readFile: readFile64 } = await import("fs/promises");
|
|
17229
17237
|
const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
|
|
17230
17238
|
const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
|
|
17231
17239
|
let assignmentRef;
|
|
@@ -17246,7 +17254,7 @@ workspace: ${workspace}
|
|
|
17246
17254
|
}
|
|
17247
17255
|
const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
|
|
17248
17256
|
if (!await fileExists2(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
|
|
17249
|
-
let content = await
|
|
17257
|
+
let content = await readFile64(assignmentMdPath2, "utf-8");
|
|
17250
17258
|
content = appendTodosToAssignmentBody2(
|
|
17251
17259
|
content,
|
|
17252
17260
|
items.map((it) => ({
|
|
@@ -18920,8 +18928,8 @@ async function restoreFromGithub(overrides) {
|
|
|
18920
18928
|
await safeRestoreCategory(localPath, repoSrcPath, isFile);
|
|
18921
18929
|
restored.push(category);
|
|
18922
18930
|
} catch (error) {
|
|
18923
|
-
const
|
|
18924
|
-
console.error(`Failed to restore "${category}": ${
|
|
18931
|
+
const msg2 = error instanceof Error ? error.message : String(error);
|
|
18932
|
+
console.error(`Failed to restore "${category}": ${msg2}`);
|
|
18925
18933
|
failed.push(category);
|
|
18926
18934
|
}
|
|
18927
18935
|
}
|
|
@@ -22083,13 +22091,13 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
|
|
|
22083
22091
|
env: plan.env
|
|
22084
22092
|
});
|
|
22085
22093
|
} catch (err2) {
|
|
22086
|
-
const
|
|
22094
|
+
const msg2 = err2 instanceof Error ? err2.message : String(err2);
|
|
22087
22095
|
throw new TerminalNotFoundError(
|
|
22088
22096
|
plan.terminal,
|
|
22089
|
-
`Spawn failed: ${
|
|
22097
|
+
`Spawn failed: ${msg2}. Verify the terminal is installed and on PATH.`
|
|
22090
22098
|
);
|
|
22091
22099
|
}
|
|
22092
|
-
await new Promise((
|
|
22100
|
+
await new Promise((resolve87, reject) => {
|
|
22093
22101
|
let settled = false;
|
|
22094
22102
|
let stderr = "";
|
|
22095
22103
|
const finishOk = () => {
|
|
@@ -22099,7 +22107,7 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
|
|
|
22099
22107
|
child.unref();
|
|
22100
22108
|
} catch {
|
|
22101
22109
|
}
|
|
22102
|
-
|
|
22110
|
+
resolve87();
|
|
22103
22111
|
};
|
|
22104
22112
|
const finishErr = (remediation) => {
|
|
22105
22113
|
if (settled) return;
|
|
@@ -22270,7 +22278,7 @@ function normalizeSlashes(p) {
|
|
|
22270
22278
|
}
|
|
22271
22279
|
function detectInstallKind(scriptUrl, opts = {}) {
|
|
22272
22280
|
const realpath3 = opts.realpath ?? realpathSync.native;
|
|
22273
|
-
const
|
|
22281
|
+
const readFile64 = opts.readFile ?? ((p) => readFileSync(p, "utf-8"));
|
|
22274
22282
|
const ua = opts.envUserAgent !== void 0 ? opts.envUserAgent : process.env.npm_config_user_agent ?? "";
|
|
22275
22283
|
const resolved = resolveScriptPath(scriptUrl, realpath3);
|
|
22276
22284
|
if (resolved === null) {
|
|
@@ -22291,7 +22299,7 @@ function detectInstallKind(scriptUrl, opts = {}) {
|
|
|
22291
22299
|
const pkgJsonPath = join5(dir, "package.json");
|
|
22292
22300
|
let raw2;
|
|
22293
22301
|
try {
|
|
22294
|
-
raw2 =
|
|
22302
|
+
raw2 = readFile64(pkgJsonPath);
|
|
22295
22303
|
} catch {
|
|
22296
22304
|
const parent2 = dirname12(dir);
|
|
22297
22305
|
if (parent2 === dir) break;
|
|
@@ -23428,36 +23436,267 @@ init_config2();
|
|
|
23428
23436
|
// src/commands/cross-agent-install.ts
|
|
23429
23437
|
init_fs();
|
|
23430
23438
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
23431
|
-
import { resolve as
|
|
23432
|
-
import { readFile as
|
|
23439
|
+
import { dirname as dirname17, join as join9, resolve as resolve48 } from "path";
|
|
23440
|
+
import { cp as cp4, mkdir as mkdir8, readFile as readFile32 } from "fs/promises";
|
|
23433
23441
|
|
|
23434
23442
|
// src/commands/setup-adapter.ts
|
|
23435
23443
|
init_paths();
|
|
23436
23444
|
init_fs();
|
|
23437
23445
|
init_config2();
|
|
23438
23446
|
init_slug();
|
|
23439
|
-
import { resolve as
|
|
23447
|
+
import { resolve as resolve47 } from "path";
|
|
23440
23448
|
|
|
23441
23449
|
// src/targets/registry.ts
|
|
23442
23450
|
init_fs();
|
|
23443
23451
|
import { homedir as homedir8 } from "os";
|
|
23452
|
+
import { resolve as resolve46 } from "path";
|
|
23453
|
+
|
|
23454
|
+
// src/targets/user-descriptors.ts
|
|
23455
|
+
init_fs();
|
|
23456
|
+
init_paths();
|
|
23444
23457
|
import { resolve as resolve45 } from "path";
|
|
23458
|
+
import { readFile as readFile31, readdir as readdir17 } from "fs/promises";
|
|
23459
|
+
|
|
23460
|
+
// src/targets/renderers.ts
|
|
23461
|
+
init_cursor_rules();
|
|
23462
|
+
init_codex_agents();
|
|
23463
|
+
init_opencode_config();
|
|
23464
|
+
init_hermes_soul();
|
|
23465
|
+
var RENDERERS = {
|
|
23466
|
+
codexAgents: (ctx) => renderCodexAgents(ctx),
|
|
23467
|
+
cursorProtocol: () => renderCursorProtocol(),
|
|
23468
|
+
cursorAssignment: (ctx) => renderCursorAssignment(ctx),
|
|
23469
|
+
openCodeConfig: (ctx) => renderOpenCodeConfig({ projectDir: ctx.projectDir }),
|
|
23470
|
+
hermesSoul: (ctx) => renderHermesSoul(ctx)
|
|
23471
|
+
};
|
|
23472
|
+
|
|
23473
|
+
// src/targets/user-descriptors.ts
|
|
23474
|
+
function userTargetsDir() {
|
|
23475
|
+
return resolve45(syntaurRoot(), "targets");
|
|
23476
|
+
}
|
|
23477
|
+
var ID_RE = /^[a-z0-9][a-z0-9_-]*$/;
|
|
23478
|
+
var VALID_RENDERER_KEYS = new Set(Object.keys(RENDERERS));
|
|
23479
|
+
var ALLOWED_TOP_KEYS = /* @__PURE__ */ new Set([
|
|
23480
|
+
"id",
|
|
23481
|
+
"displayName",
|
|
23482
|
+
"skillsShAgentId",
|
|
23483
|
+
"detect",
|
|
23484
|
+
"skillsDir",
|
|
23485
|
+
"instructions"
|
|
23486
|
+
]);
|
|
23487
|
+
function msg(err2) {
|
|
23488
|
+
return err2 instanceof Error ? err2.message : String(err2);
|
|
23489
|
+
}
|
|
23490
|
+
function expandHomeAndEnv(p) {
|
|
23491
|
+
const envExpanded = p.replace(
|
|
23492
|
+
/\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g,
|
|
23493
|
+
(_m, braced, bare) => {
|
|
23494
|
+
const name = braced ?? bare ?? "";
|
|
23495
|
+
const v = process.env[name];
|
|
23496
|
+
return v ?? "";
|
|
23497
|
+
}
|
|
23498
|
+
);
|
|
23499
|
+
return resolve45(expandHome(envExpanded));
|
|
23500
|
+
}
|
|
23501
|
+
function compileDetect(spec) {
|
|
23502
|
+
switch (spec.kind) {
|
|
23503
|
+
case "pathExists": {
|
|
23504
|
+
const p = expandHomeAndEnv(spec.path);
|
|
23505
|
+
return () => fileExists(p);
|
|
23506
|
+
}
|
|
23507
|
+
case "anyPathExists": {
|
|
23508
|
+
const ps = spec.paths.map(expandHomeAndEnv);
|
|
23509
|
+
return async () => {
|
|
23510
|
+
for (const p of ps) {
|
|
23511
|
+
if (await fileExists(p)) return true;
|
|
23512
|
+
}
|
|
23513
|
+
return false;
|
|
23514
|
+
};
|
|
23515
|
+
}
|
|
23516
|
+
case "envSet": {
|
|
23517
|
+
const env = spec.env;
|
|
23518
|
+
return async () => {
|
|
23519
|
+
const v = process.env[env];
|
|
23520
|
+
return typeof v === "string" && v.length > 0;
|
|
23521
|
+
};
|
|
23522
|
+
}
|
|
23523
|
+
}
|
|
23524
|
+
}
|
|
23525
|
+
function isPlainObject(v) {
|
|
23526
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
23527
|
+
}
|
|
23528
|
+
function validateDetect(detect, errors) {
|
|
23529
|
+
if (!isPlainObject(detect)) {
|
|
23530
|
+
errors.push("detect must be an object");
|
|
23531
|
+
return;
|
|
23532
|
+
}
|
|
23533
|
+
switch (detect.kind) {
|
|
23534
|
+
case "pathExists":
|
|
23535
|
+
if (typeof detect.path !== "string" || detect.path.length === 0)
|
|
23536
|
+
errors.push('detect.path must be a non-empty string for kind "pathExists"');
|
|
23537
|
+
break;
|
|
23538
|
+
case "anyPathExists":
|
|
23539
|
+
if (!Array.isArray(detect.paths) || detect.paths.length === 0 || !detect.paths.every((p) => typeof p === "string" && p.length > 0))
|
|
23540
|
+
errors.push('detect.paths must be a non-empty string[] for kind "anyPathExists"');
|
|
23541
|
+
break;
|
|
23542
|
+
case "envSet":
|
|
23543
|
+
if (typeof detect.env !== "string" || detect.env.length === 0)
|
|
23544
|
+
errors.push('detect.env must be a non-empty string for kind "envSet"');
|
|
23545
|
+
break;
|
|
23546
|
+
default:
|
|
23547
|
+
errors.push(
|
|
23548
|
+
`detect.kind must be one of pathExists|anyPathExists|envSet (got ${JSON.stringify(detect.kind)})`
|
|
23549
|
+
);
|
|
23550
|
+
}
|
|
23551
|
+
}
|
|
23552
|
+
function validateInstructions(instructions, errors) {
|
|
23553
|
+
if (!isPlainObject(instructions)) {
|
|
23554
|
+
errors.push("instructions must be an object");
|
|
23555
|
+
return;
|
|
23556
|
+
}
|
|
23557
|
+
if (!Array.isArray(instructions.files) || instructions.files.length === 0) {
|
|
23558
|
+
errors.push("instructions.files must be a non-empty array");
|
|
23559
|
+
return;
|
|
23560
|
+
}
|
|
23561
|
+
instructions.files.forEach((f, i) => {
|
|
23562
|
+
if (!isPlainObject(f)) {
|
|
23563
|
+
errors.push(`instructions.files[${i}] must be an object`);
|
|
23564
|
+
return;
|
|
23565
|
+
}
|
|
23566
|
+
if (typeof f.path !== "string" || f.path.length === 0)
|
|
23567
|
+
errors.push(`instructions.files[${i}].path must be a non-empty string`);
|
|
23568
|
+
if (typeof f.renderer !== "string" || !VALID_RENDERER_KEYS.has(f.renderer))
|
|
23569
|
+
errors.push(
|
|
23570
|
+
`instructions.files[${i}].renderer ${JSON.stringify(f.renderer)} is not a known renderer (valid: ${[...VALID_RENDERER_KEYS].join(", ")})`
|
|
23571
|
+
);
|
|
23572
|
+
});
|
|
23573
|
+
}
|
|
23574
|
+
function validateUserDescriptor(data, builtinIds) {
|
|
23575
|
+
const errors = [];
|
|
23576
|
+
if (!isPlainObject(data)) {
|
|
23577
|
+
return { ok: false, errors: ["descriptor must be a JSON object"] };
|
|
23578
|
+
}
|
|
23579
|
+
for (const k of Object.keys(data)) {
|
|
23580
|
+
if (!ALLOWED_TOP_KEYS.has(k)) errors.push(`unknown field "${k}"`);
|
|
23581
|
+
}
|
|
23582
|
+
if (typeof data.id !== "string" || data.id.length === 0) {
|
|
23583
|
+
errors.push("id is required and must be a non-empty string");
|
|
23584
|
+
} else if (!ID_RE.test(data.id)) {
|
|
23585
|
+
errors.push(`id "${data.id}" must match ${ID_RE.source}`);
|
|
23586
|
+
} else if (builtinIds.has(data.id)) {
|
|
23587
|
+
errors.push(
|
|
23588
|
+
`id "${data.id}" collides with a built-in agent (built-ins cannot be overridden)`
|
|
23589
|
+
);
|
|
23590
|
+
}
|
|
23591
|
+
if (typeof data.displayName !== "string" || data.displayName.trim().length === 0) {
|
|
23592
|
+
errors.push("displayName is required and must be a non-empty string");
|
|
23593
|
+
}
|
|
23594
|
+
if (data.skillsShAgentId !== void 0 && (typeof data.skillsShAgentId !== "string" || data.skillsShAgentId.length === 0)) {
|
|
23595
|
+
errors.push("skillsShAgentId must be a non-empty string when present");
|
|
23596
|
+
}
|
|
23597
|
+
if (data.detect === void 0) {
|
|
23598
|
+
errors.push("detect is required");
|
|
23599
|
+
} else {
|
|
23600
|
+
validateDetect(data.detect, errors);
|
|
23601
|
+
}
|
|
23602
|
+
if (data.skillsDir !== void 0) {
|
|
23603
|
+
if (!isPlainObject(data.skillsDir)) {
|
|
23604
|
+
errors.push("skillsDir must be an object");
|
|
23605
|
+
} else {
|
|
23606
|
+
for (const k of Object.keys(data.skillsDir)) {
|
|
23607
|
+
if (k !== "project" && k !== "global") errors.push(`skillsDir.${k} is not a valid key`);
|
|
23608
|
+
}
|
|
23609
|
+
if (data.skillsDir.project !== void 0 && typeof data.skillsDir.project !== "string")
|
|
23610
|
+
errors.push("skillsDir.project must be a string");
|
|
23611
|
+
if (data.skillsDir.global !== void 0 && typeof data.skillsDir.global !== "string")
|
|
23612
|
+
errors.push("skillsDir.global must be a string");
|
|
23613
|
+
}
|
|
23614
|
+
}
|
|
23615
|
+
if (data.instructions !== void 0) {
|
|
23616
|
+
validateInstructions(data.instructions, errors);
|
|
23617
|
+
}
|
|
23618
|
+
if (errors.length > 0) return { ok: false, errors };
|
|
23619
|
+
return { ok: true, value: data };
|
|
23620
|
+
}
|
|
23621
|
+
function compileDescriptor(desc) {
|
|
23622
|
+
const target = {
|
|
23623
|
+
id: desc.id,
|
|
23624
|
+
displayName: desc.displayName,
|
|
23625
|
+
detect: compileDetect(desc.detect)
|
|
23626
|
+
};
|
|
23627
|
+
if (desc.skillsShAgentId) target.skillsShAgentId = desc.skillsShAgentId;
|
|
23628
|
+
if (desc.skillsDir) {
|
|
23629
|
+
const skillsDir = {};
|
|
23630
|
+
if (desc.skillsDir.global) skillsDir.global = expandHomeAndEnv(desc.skillsDir.global);
|
|
23631
|
+
if (desc.skillsDir.project) skillsDir.project = desc.skillsDir.project;
|
|
23632
|
+
target.skillsDir = skillsDir;
|
|
23633
|
+
}
|
|
23634
|
+
if (desc.instructions) target.instructions = desc.instructions;
|
|
23635
|
+
return target;
|
|
23636
|
+
}
|
|
23637
|
+
async function loadUserDescriptors(opts = {}) {
|
|
23638
|
+
const dir = opts.dir ?? userTargetsDir();
|
|
23639
|
+
const builtinIds = opts.builtinIds ?? /* @__PURE__ */ new Set();
|
|
23640
|
+
const warnings = [];
|
|
23641
|
+
if (!await fileExists(dir)) return { targets: [], warnings };
|
|
23642
|
+
let files;
|
|
23643
|
+
try {
|
|
23644
|
+
files = (await readdir17(dir)).filter((f) => f.endsWith(".json")).sort();
|
|
23645
|
+
} catch (err2) {
|
|
23646
|
+
return { targets: [], warnings: [`could not read ${dir}: ${msg(err2)}`] };
|
|
23647
|
+
}
|
|
23648
|
+
const targets = [];
|
|
23649
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23650
|
+
for (const file of files) {
|
|
23651
|
+
const full = resolve45(dir, file);
|
|
23652
|
+
let raw2;
|
|
23653
|
+
try {
|
|
23654
|
+
raw2 = await readFile31(full, "utf-8");
|
|
23655
|
+
} catch (err2) {
|
|
23656
|
+
warnings.push(`skipped ${file}: ${msg(err2)}`);
|
|
23657
|
+
continue;
|
|
23658
|
+
}
|
|
23659
|
+
let parsed;
|
|
23660
|
+
try {
|
|
23661
|
+
parsed = JSON.parse(raw2);
|
|
23662
|
+
} catch (err2) {
|
|
23663
|
+
warnings.push(`skipped ${file}: invalid JSON: ${msg(err2)}`);
|
|
23664
|
+
continue;
|
|
23665
|
+
}
|
|
23666
|
+
const result = validateUserDescriptor(parsed, builtinIds);
|
|
23667
|
+
if (!result.ok) {
|
|
23668
|
+
warnings.push(`skipped ${file}: ${result.errors.join("; ")}`);
|
|
23669
|
+
continue;
|
|
23670
|
+
}
|
|
23671
|
+
if (seen.has(result.value.id)) {
|
|
23672
|
+
warnings.push(
|
|
23673
|
+
`skipped ${file}: duplicate id "${result.value.id}" (already loaded from an earlier file)`
|
|
23674
|
+
);
|
|
23675
|
+
continue;
|
|
23676
|
+
}
|
|
23677
|
+
seen.add(result.value.id);
|
|
23678
|
+
targets.push(compileDescriptor(result.value));
|
|
23679
|
+
}
|
|
23680
|
+
return { targets, warnings };
|
|
23681
|
+
}
|
|
23682
|
+
|
|
23683
|
+
// src/targets/registry.ts
|
|
23445
23684
|
function home(...segments) {
|
|
23446
|
-
return
|
|
23685
|
+
return resolve46(homedir8(), ...segments);
|
|
23447
23686
|
}
|
|
23448
23687
|
function hermesHome() {
|
|
23449
23688
|
const env = process.env.HERMES_HOME;
|
|
23450
|
-
return env && env.length > 0 ?
|
|
23689
|
+
return env && env.length > 0 ? resolve46(env) : home(".hermes");
|
|
23451
23690
|
}
|
|
23452
23691
|
function hermesSkillsDir() {
|
|
23453
|
-
return
|
|
23692
|
+
return resolve46(hermesHome(), "skills");
|
|
23454
23693
|
}
|
|
23455
23694
|
function isHermesHomeCustom() {
|
|
23456
23695
|
return hermesHome() !== home(".hermes");
|
|
23457
23696
|
}
|
|
23458
23697
|
function codexHome() {
|
|
23459
23698
|
const env = process.env.CODEX_HOME;
|
|
23460
|
-
return env && env.length > 0 ?
|
|
23699
|
+
return env && env.length > 0 ? resolve46(env) : home(".codex");
|
|
23461
23700
|
}
|
|
23462
23701
|
var detectDir = (dir) => () => fileExists(dir);
|
|
23463
23702
|
var AGENT_TARGETS = [
|
|
@@ -23481,7 +23720,7 @@ var AGENT_TARGETS = [
|
|
|
23481
23720
|
skillsShAgentId: "codex",
|
|
23482
23721
|
nativePlugin: "codex",
|
|
23483
23722
|
detect: detectDir(codexHome()),
|
|
23484
|
-
skillsDir: { global:
|
|
23723
|
+
skillsDir: { global: resolve46(codexHome(), "skills") },
|
|
23485
23724
|
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] }
|
|
23486
23725
|
},
|
|
23487
23726
|
{
|
|
@@ -23513,7 +23752,13 @@ var AGENT_TARGETS = [
|
|
|
23513
23752
|
skillsShAgentId: "pi",
|
|
23514
23753
|
detect: detectDir(home(".pi")),
|
|
23515
23754
|
skillsDir: { global: home(".pi", "agent", "skills") },
|
|
23516
|
-
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] }
|
|
23755
|
+
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] },
|
|
23756
|
+
tier3: {
|
|
23757
|
+
kind: "pi-extension",
|
|
23758
|
+
source: "platforms/pi/extensions/syntaur",
|
|
23759
|
+
installDir: () => home(".pi", "agent", "extensions", "syntaur"),
|
|
23760
|
+
entry: "index.ts"
|
|
23761
|
+
}
|
|
23517
23762
|
},
|
|
23518
23763
|
{
|
|
23519
23764
|
id: "openclaw",
|
|
@@ -23521,7 +23766,15 @@ var AGENT_TARGETS = [
|
|
|
23521
23766
|
skillsShAgentId: "openclaw",
|
|
23522
23767
|
detect: detectDir(home(".openclaw")),
|
|
23523
23768
|
skillsDir: { global: home(".openclaw", "skills") },
|
|
23524
|
-
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] }
|
|
23769
|
+
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] },
|
|
23770
|
+
// OpenClaw runs on pi-coding-agent (design memo), so it reuses the pi
|
|
23771
|
+
// extension SOURCE; only the install dir differs.
|
|
23772
|
+
tier3: {
|
|
23773
|
+
kind: "pi-extension",
|
|
23774
|
+
source: "platforms/pi/extensions/syntaur",
|
|
23775
|
+
installDir: () => home(".openclaw", "extensions", "syntaur"),
|
|
23776
|
+
entry: "index.ts"
|
|
23777
|
+
}
|
|
23525
23778
|
},
|
|
23526
23779
|
{
|
|
23527
23780
|
id: "hermes",
|
|
@@ -23529,42 +23782,34 @@ var AGENT_TARGETS = [
|
|
|
23529
23782
|
skillsShAgentId: "hermes-agent",
|
|
23530
23783
|
detect: () => fileExists(hermesHome()),
|
|
23531
23784
|
skillsDir: { global: hermesSkillsDir() },
|
|
23532
|
-
instructions: { files: [{ path: "SOUL.md", renderer: "hermesSoul" }] }
|
|
23785
|
+
instructions: { files: [{ path: "SOUL.md", renderer: "hermesSoul" }] },
|
|
23786
|
+
tier3: {
|
|
23787
|
+
kind: "hermes-plugin",
|
|
23788
|
+
source: "platforms/hermes/plugins/syntaur",
|
|
23789
|
+
installDir: () => resolve46(hermesHome(), "plugins", "syntaur"),
|
|
23790
|
+
entry: "plugin.yaml"
|
|
23791
|
+
}
|
|
23533
23792
|
}
|
|
23534
23793
|
];
|
|
23535
23794
|
var AGENT_TARGETS_BY_ID = Object.fromEntries(
|
|
23536
23795
|
AGENT_TARGETS.map((t) => [t.id, t])
|
|
23537
23796
|
);
|
|
23538
|
-
function
|
|
23539
|
-
|
|
23540
|
-
|
|
23541
|
-
|
|
23542
|
-
return AGENT_TARGETS
|
|
23543
|
-
}
|
|
23544
|
-
function adapterTargets() {
|
|
23545
|
-
return AGENT_TARGETS.filter((t) => t.instructions !== void 0);
|
|
23797
|
+
async function resolveAgentTargets() {
|
|
23798
|
+
const { targets: user, warnings } = await loadUserDescriptors({
|
|
23799
|
+
builtinIds: new Set(AGENT_TARGETS.map((t) => t.id))
|
|
23800
|
+
});
|
|
23801
|
+
return { targets: [...AGENT_TARGETS, ...user], warnings };
|
|
23546
23802
|
}
|
|
23547
23803
|
|
|
23548
|
-
// src/targets/renderers.ts
|
|
23549
|
-
init_cursor_rules();
|
|
23550
|
-
init_codex_agents();
|
|
23551
|
-
init_opencode_config();
|
|
23552
|
-
init_hermes_soul();
|
|
23553
|
-
var RENDERERS = {
|
|
23554
|
-
codexAgents: (ctx) => renderCodexAgents(ctx),
|
|
23555
|
-
cursorProtocol: () => renderCursorProtocol(),
|
|
23556
|
-
cursorAssignment: (ctx) => renderCursorAssignment(ctx),
|
|
23557
|
-
openCodeConfig: (ctx) => renderOpenCodeConfig({ projectDir: ctx.projectDir }),
|
|
23558
|
-
hermesSoul: (ctx) => renderHermesSoul(ctx)
|
|
23559
|
-
};
|
|
23560
|
-
|
|
23561
23804
|
// src/commands/setup-adapter.ts
|
|
23562
23805
|
async function setupAdapterCommand(framework, options) {
|
|
23563
|
-
const
|
|
23806
|
+
const { targets: known, warnings } = await resolveAgentTargets();
|
|
23807
|
+
const target = known.find((t) => t.id === framework);
|
|
23564
23808
|
if (!target || !target.instructions) {
|
|
23565
|
-
const supported =
|
|
23809
|
+
const supported = known.filter((t) => t.instructions !== void 0).map((t) => t.id).join(", ");
|
|
23810
|
+
const warn2 = warnings.length ? ` (descriptor warnings: ${warnings.join("; ")})` : "";
|
|
23566
23811
|
throw new Error(
|
|
23567
|
-
`Unsupported framework "${framework}". Supported: ${supported}`
|
|
23812
|
+
`Unsupported framework "${framework}". Supported: ${supported}.${warn2}`
|
|
23568
23813
|
);
|
|
23569
23814
|
}
|
|
23570
23815
|
if (!options.project) {
|
|
@@ -23585,13 +23830,13 @@ async function setupAdapterCommand(framework, options) {
|
|
|
23585
23830
|
}
|
|
23586
23831
|
const config = await readConfig();
|
|
23587
23832
|
const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
|
|
23588
|
-
const projectDir =
|
|
23589
|
-
const assignmentDir =
|
|
23590
|
-
const projectMdPath =
|
|
23833
|
+
const projectDir = resolve47(baseDir, options.project);
|
|
23834
|
+
const assignmentDir = resolve47(projectDir, "assignments", options.assignment);
|
|
23835
|
+
const projectMdPath = resolve47(projectDir, "project.md");
|
|
23591
23836
|
if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
|
|
23592
23837
|
throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
|
|
23593
23838
|
}
|
|
23594
|
-
const assignmentMdPath2 =
|
|
23839
|
+
const assignmentMdPath2 = resolve47(assignmentDir, "assignment.md");
|
|
23595
23840
|
if (!await fileExists(assignmentDir) || !await fileExists(assignmentMdPath2)) {
|
|
23596
23841
|
throw new Error(
|
|
23597
23842
|
`Assignment "${options.assignment}" not found at ${assignmentDir}.`
|
|
@@ -23608,7 +23853,7 @@ async function setupAdapterCommand(framework, options) {
|
|
|
23608
23853
|
const upToDateFiles = [];
|
|
23609
23854
|
const skippedFiles = [];
|
|
23610
23855
|
for (const file of target.instructions.files) {
|
|
23611
|
-
const filePath =
|
|
23856
|
+
const filePath = resolve47(cwd, file.path);
|
|
23612
23857
|
const content = RENDERERS[file.renderer](rendererParams);
|
|
23613
23858
|
const status = await writeFileReport(filePath, content, {
|
|
23614
23859
|
force: options.force
|
|
@@ -23647,6 +23892,33 @@ async function setupAdapterCommand(framework, options) {
|
|
|
23647
23892
|
// src/commands/cross-agent-install.ts
|
|
23648
23893
|
init_config2();
|
|
23649
23894
|
var DEFAULT_SKILLS_SOURCE = "prong-horn/syntaur";
|
|
23895
|
+
async function installTier3Plugin(t, opts = {}) {
|
|
23896
|
+
if (!t.tier3) return "none";
|
|
23897
|
+
const plugin = t.tier3;
|
|
23898
|
+
const installDir = plugin.installDir();
|
|
23899
|
+
const prefix = opts.prefix ?? "";
|
|
23900
|
+
if (opts.dryRun) {
|
|
23901
|
+
console.log(`${prefix}Tier 3 (${t.id}): ${plugin.source} -> ${installDir}`);
|
|
23902
|
+
return "dry-run";
|
|
23903
|
+
}
|
|
23904
|
+
if (await fileExists(join9(installDir, plugin.entry)) && !opts.force) {
|
|
23905
|
+
console.log(
|
|
23906
|
+
`Tier 3 (${t.id}): already installed at ${installDir} (use --force to overwrite).`
|
|
23907
|
+
);
|
|
23908
|
+
return "already-present";
|
|
23909
|
+
}
|
|
23910
|
+
try {
|
|
23911
|
+
const sourceDir = resolve48(await findPackageRoot(plugin.source), plugin.source);
|
|
23912
|
+
await mkdir8(dirname17(installDir), { recursive: true });
|
|
23913
|
+
await cp4(sourceDir, installDir, { recursive: true, force: true });
|
|
23914
|
+
console.log(`Tier 3 (${t.id}): installed ${plugin.kind} -> ${installDir}`);
|
|
23915
|
+
return "installed";
|
|
23916
|
+
} catch (err2) {
|
|
23917
|
+
const msg2 = err2 instanceof Error ? err2.message : String(err2);
|
|
23918
|
+
console.log(`Tier 3 for ${t.id} FAILED: ${msg2}`);
|
|
23919
|
+
return "failed";
|
|
23920
|
+
}
|
|
23921
|
+
}
|
|
23650
23922
|
function parseTargetIds(options) {
|
|
23651
23923
|
const raw2 = [options.target, options.agent].filter(Boolean).join(",");
|
|
23652
23924
|
const ids = raw2.split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -23661,10 +23933,10 @@ function isNpxAvailable() {
|
|
|
23661
23933
|
}
|
|
23662
23934
|
}
|
|
23663
23935
|
async function readAssignmentContext() {
|
|
23664
|
-
const p =
|
|
23936
|
+
const p = resolve48(process.cwd(), ".syntaur", "context.json");
|
|
23665
23937
|
if (!await fileExists(p)) return null;
|
|
23666
23938
|
try {
|
|
23667
|
-
return JSON.parse(await
|
|
23939
|
+
return JSON.parse(await readFile32(p, "utf-8"));
|
|
23668
23940
|
} catch {
|
|
23669
23941
|
return null;
|
|
23670
23942
|
}
|
|
@@ -23674,12 +23946,15 @@ async function crossAgentInstallCommand(options) {
|
|
|
23674
23946
|
if (ids.length === 0) {
|
|
23675
23947
|
throw new Error("No agents specified. Use --target <id> or --agent <id>.");
|
|
23676
23948
|
}
|
|
23949
|
+
const { targets: known, warnings } = await resolveAgentTargets();
|
|
23950
|
+
for (const w of warnings) console.log(`Warning (user target): ${w}`);
|
|
23951
|
+
const byId = new Map(known.map((t) => [t.id, t]));
|
|
23677
23952
|
const targets = [];
|
|
23678
23953
|
for (const id of ids) {
|
|
23679
|
-
const t =
|
|
23954
|
+
const t = byId.get(id);
|
|
23680
23955
|
if (!t) {
|
|
23681
23956
|
throw new Error(
|
|
23682
|
-
`Unknown agent "${id}". Known agents: ${
|
|
23957
|
+
`Unknown agent "${id}". Known agents: ${known.map((k) => k.id).join(", ")}`
|
|
23683
23958
|
);
|
|
23684
23959
|
}
|
|
23685
23960
|
if (t.nativePlugin) {
|
|
@@ -23713,8 +23988,15 @@ async function crossAgentInstallCommand(options) {
|
|
|
23713
23988
|
}
|
|
23714
23989
|
for (const t of targets) {
|
|
23715
23990
|
const globalDir = t.id === "hermes" ? hermesSkillsDir() : t.skillsDir?.global;
|
|
23716
|
-
if (!globalDir) continue;
|
|
23717
23991
|
const offlineNeeded = !tier1Done;
|
|
23992
|
+
if (!globalDir) {
|
|
23993
|
+
if (offlineNeeded && !dryRun) {
|
|
23994
|
+
console.log(
|
|
23995
|
+
`Warning: skills NOT installed for ${t.displayName} \u2014 Tier-1 (npx skills add) was unavailable/failed and the descriptor has no skillsDir.global for an offline copy.`
|
|
23996
|
+
);
|
|
23997
|
+
}
|
|
23998
|
+
continue;
|
|
23999
|
+
}
|
|
23718
24000
|
const hermesCustom = t.id === "hermes" && isHermesHomeCustom();
|
|
23719
24001
|
if (!offlineNeeded && !hermesCustom) continue;
|
|
23720
24002
|
if (dryRun) {
|
|
@@ -23726,15 +24008,15 @@ async function crossAgentInstallCommand(options) {
|
|
|
23726
24008
|
await installSkillsToDir({ targetDir: globalDir, force });
|
|
23727
24009
|
console.log(`Copied skills -> ${globalDir}${reason}`);
|
|
23728
24010
|
}
|
|
23729
|
-
const
|
|
23730
|
-
if (
|
|
24011
|
+
const adapterTargets = targets.filter((t) => t.instructions);
|
|
24012
|
+
if (adapterTargets.length > 0) {
|
|
23731
24013
|
const ctx = await readAssignmentContext();
|
|
23732
24014
|
const haveCtx = Boolean(ctx?.projectSlug && ctx?.assignmentSlug);
|
|
23733
|
-
for (const t of
|
|
24015
|
+
for (const t of adapterTargets) {
|
|
23734
24016
|
if (dryRun) {
|
|
23735
24017
|
for (const f of t.instructions.files) {
|
|
23736
24018
|
console.log(
|
|
23737
|
-
`${prefix}Tier 2 (${t.id}): ${
|
|
24019
|
+
`${prefix}Tier 2 (${t.id}): ${resolve48(process.cwd(), f.path)}`
|
|
23738
24020
|
);
|
|
23739
24021
|
}
|
|
23740
24022
|
continue;
|
|
@@ -23752,11 +24034,21 @@ async function crossAgentInstallCommand(options) {
|
|
|
23752
24034
|
force
|
|
23753
24035
|
});
|
|
23754
24036
|
} catch (err2) {
|
|
23755
|
-
const
|
|
23756
|
-
console.log(`Tier 2 for ${t.id} skipped: ${
|
|
24037
|
+
const msg2 = err2 instanceof Error ? err2.message : String(err2);
|
|
24038
|
+
console.log(`Tier 2 for ${t.id} skipped: ${msg2}`);
|
|
23757
24039
|
}
|
|
23758
24040
|
}
|
|
23759
24041
|
}
|
|
24042
|
+
const tier3Failures = [];
|
|
24043
|
+
for (const t of targets.filter((x) => x.tier3)) {
|
|
24044
|
+
const result = await installTier3Plugin(t, { dryRun, force, prefix });
|
|
24045
|
+
if (result === "failed") tier3Failures.push(t.displayName);
|
|
24046
|
+
}
|
|
24047
|
+
if (tier3Failures.length > 0) {
|
|
24048
|
+
throw new Error(
|
|
24049
|
+
`Tier-3 enforcement plugin failed to install for: ${tier3Failures.join(", ")}. Enforcement is NOT active for ${tier3Failures.length > 1 ? "those agents" : "that agent"} \u2014 check permissions and re-run \`syntaur setup --target <id> --force\`.`
|
|
24050
|
+
);
|
|
24051
|
+
}
|
|
23760
24052
|
if (!dryRun) {
|
|
23761
24053
|
const current = (await readConfig()).integrations.installedAgents ?? {};
|
|
23762
24054
|
const next = { ...current };
|
|
@@ -23881,7 +24173,7 @@ async function setupCommand(options) {
|
|
|
23881
24173
|
}
|
|
23882
24174
|
|
|
23883
24175
|
// src/commands/uninstall.ts
|
|
23884
|
-
import { resolve as
|
|
24176
|
+
import { resolve as resolve49 } from "path";
|
|
23885
24177
|
init_paths();
|
|
23886
24178
|
function expandTargets(options) {
|
|
23887
24179
|
if (options.all) {
|
|
@@ -23961,7 +24253,7 @@ async function uninstallCommand(options) {
|
|
|
23961
24253
|
const configuredProjectDir = await getConfiguredProjectDir();
|
|
23962
24254
|
await removeSyntaurData();
|
|
23963
24255
|
console.log(`Removed ${syntaurRoot()}`);
|
|
23964
|
-
if (configuredProjectDir &&
|
|
24256
|
+
if (configuredProjectDir && resolve49(configuredProjectDir) !== resolve49(syntaurRoot(), "projects")) {
|
|
23965
24257
|
console.warn(
|
|
23966
24258
|
`Warning: config.md pointed to an external project directory (${configuredProjectDir}). That directory was not removed automatically.`
|
|
23967
24259
|
);
|
|
@@ -23976,7 +24268,7 @@ async function uninstallCommand(options) {
|
|
|
23976
24268
|
init_paths();
|
|
23977
24269
|
init_fs();
|
|
23978
24270
|
init_config2();
|
|
23979
|
-
import { resolve as
|
|
24271
|
+
import { resolve as resolve50 } from "path";
|
|
23980
24272
|
init_git_worktree();
|
|
23981
24273
|
init_cwd();
|
|
23982
24274
|
init_session_db();
|
|
@@ -23993,7 +24285,7 @@ async function trackSessionCommand(options) {
|
|
|
23993
24285
|
if (options.project) {
|
|
23994
24286
|
const config = await readConfig();
|
|
23995
24287
|
const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
|
|
23996
|
-
const projectDir =
|
|
24288
|
+
const projectDir = resolve50(baseDir, options.project);
|
|
23997
24289
|
if (!await fileExists(projectDir)) {
|
|
23998
24290
|
throw new Error(
|
|
23999
24291
|
`Project "${options.project}" not found at ${projectDir}.`
|
|
@@ -24127,8 +24419,8 @@ function formatInstallUrlHandlerError(err2) {
|
|
|
24127
24419
|
init_config2();
|
|
24128
24420
|
init_paths();
|
|
24129
24421
|
init_fs();
|
|
24130
|
-
import { resolve as
|
|
24131
|
-
import { readFile as
|
|
24422
|
+
import { resolve as resolve52, isAbsolute as isAbsolute8 } from "path";
|
|
24423
|
+
import { readFile as readFile33 } from "fs/promises";
|
|
24132
24424
|
import { select, confirm as confirm2, input as input3 } from "@inquirer/prompts";
|
|
24133
24425
|
async function browseCommand(options) {
|
|
24134
24426
|
const config = await readConfig();
|
|
@@ -24197,7 +24489,7 @@ async function pickAgent2(agents) {
|
|
|
24197
24489
|
return picked;
|
|
24198
24490
|
}
|
|
24199
24491
|
async function ensureWorktree(opts) {
|
|
24200
|
-
const assignmentPath =
|
|
24492
|
+
const assignmentPath = resolve52(
|
|
24201
24493
|
opts.projectsDir,
|
|
24202
24494
|
opts.projectSlug,
|
|
24203
24495
|
"assignments",
|
|
@@ -24207,7 +24499,7 @@ async function ensureWorktree(opts) {
|
|
|
24207
24499
|
if (!await fileExists(assignmentPath)) {
|
|
24208
24500
|
return void 0;
|
|
24209
24501
|
}
|
|
24210
|
-
const content = await
|
|
24502
|
+
const content = await readFile33(assignmentPath, "utf-8");
|
|
24211
24503
|
const { parseAssignmentFrontmatter: parseAssignmentFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
|
|
24212
24504
|
const fm = parseAssignmentFrontmatter2(content);
|
|
24213
24505
|
const { workspace } = fm;
|
|
@@ -24277,7 +24569,7 @@ async function ensureWorktree(opts) {
|
|
|
24277
24569
|
async function runCreate(opts) {
|
|
24278
24570
|
const { createWorktreeAndRecord: createWorktreeAndRecord2, GitWorktreeError: GitWorktreeError2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
24279
24571
|
const expandedWorktree = expandHome(opts.worktreePath);
|
|
24280
|
-
const absWorktree = isAbsolute8(expandedWorktree) ? expandedWorktree :
|
|
24572
|
+
const absWorktree = isAbsolute8(expandedWorktree) ? expandedWorktree : resolve52(expandedWorktree);
|
|
24281
24573
|
try {
|
|
24282
24574
|
await createWorktreeAndRecord2({
|
|
24283
24575
|
assignmentPath: opts.assignmentPath,
|
|
@@ -24289,11 +24581,11 @@ async function runCreate(opts) {
|
|
|
24289
24581
|
console.log(`syntaur: created worktree at ${absWorktree} on branch ${opts.branch}`);
|
|
24290
24582
|
return absWorktree;
|
|
24291
24583
|
} catch (err2) {
|
|
24292
|
-
const
|
|
24584
|
+
const msg2 = err2 instanceof Error ? err2.message : String(err2);
|
|
24293
24585
|
if (err2 instanceof GitWorktreeError2) {
|
|
24294
|
-
console.error(`syntaur: ${
|
|
24586
|
+
console.error(`syntaur: ${msg2}`);
|
|
24295
24587
|
} else {
|
|
24296
|
-
console.error(`syntaur: ${
|
|
24588
|
+
console.error(`syntaur: ${msg2}`);
|
|
24297
24589
|
}
|
|
24298
24590
|
process.exit(1);
|
|
24299
24591
|
}
|
|
@@ -24306,7 +24598,7 @@ init_paths();
|
|
|
24306
24598
|
init_fs();
|
|
24307
24599
|
init_playbook();
|
|
24308
24600
|
init_playbooks();
|
|
24309
|
-
import { resolve as
|
|
24601
|
+
import { resolve as resolve53 } from "path";
|
|
24310
24602
|
async function createPlaybookCommand(name, options) {
|
|
24311
24603
|
if (!name.trim()) {
|
|
24312
24604
|
throw new Error("Playbook name cannot be empty.");
|
|
@@ -24319,7 +24611,7 @@ async function createPlaybookCommand(name, options) {
|
|
|
24319
24611
|
}
|
|
24320
24612
|
const dir = playbooksDir();
|
|
24321
24613
|
await ensureDir(dir);
|
|
24322
|
-
const filePath =
|
|
24614
|
+
const filePath = resolve53(dir, `${slug}.md`);
|
|
24323
24615
|
if (await fileExists(filePath)) {
|
|
24324
24616
|
throw new Error(
|
|
24325
24617
|
`Playbook "${slug}" already exists at ${filePath}
|
|
@@ -24341,8 +24633,8 @@ init_paths();
|
|
|
24341
24633
|
init_fs();
|
|
24342
24634
|
init_parser();
|
|
24343
24635
|
init_config2();
|
|
24344
|
-
import { readdir as
|
|
24345
|
-
import { resolve as
|
|
24636
|
+
import { readdir as readdir18, readFile as readFile34 } from "fs/promises";
|
|
24637
|
+
import { resolve as resolve54 } from "path";
|
|
24346
24638
|
async function listPlaybooksCommand(options = {}) {
|
|
24347
24639
|
const dir = playbooksDir();
|
|
24348
24640
|
if (!await fileExists(dir)) {
|
|
@@ -24351,14 +24643,14 @@ async function listPlaybooksCommand(options = {}) {
|
|
|
24351
24643
|
}
|
|
24352
24644
|
const config = await readConfig();
|
|
24353
24645
|
const disabledSet = new Set(config.playbooks.disabled);
|
|
24354
|
-
const entries = await
|
|
24646
|
+
const entries = await readdir18(dir, { withFileTypes: true });
|
|
24355
24647
|
const mdFiles = entries.filter(
|
|
24356
24648
|
(e) => e.isFile() && e.name.endsWith(".md") && !e.name.startsWith("_") && e.name !== "manifest.md"
|
|
24357
24649
|
);
|
|
24358
24650
|
const rows = [];
|
|
24359
24651
|
for (const entry of mdFiles) {
|
|
24360
|
-
const filePath =
|
|
24361
|
-
const raw2 = await
|
|
24652
|
+
const filePath = resolve54(dir, entry.name);
|
|
24653
|
+
const raw2 = await readFile34(filePath, "utf-8");
|
|
24362
24654
|
const parsed = parsePlaybook(raw2);
|
|
24363
24655
|
const slug = parsed.slug || entry.name.replace(/\.md$/, "");
|
|
24364
24656
|
const disabled = disabledSet.has(slug);
|
|
@@ -24481,14 +24773,14 @@ init_fs();
|
|
|
24481
24773
|
init_config2();
|
|
24482
24774
|
init_slug();
|
|
24483
24775
|
import { Command as Command2 } from "commander";
|
|
24484
|
-
import { readFile as
|
|
24485
|
-
import { resolve as
|
|
24776
|
+
import { readFile as readFile36 } from "fs/promises";
|
|
24777
|
+
import { resolve as resolve56 } from "path";
|
|
24486
24778
|
|
|
24487
24779
|
// src/commands/bundle.ts
|
|
24488
24780
|
init_paths();
|
|
24489
24781
|
import { Command } from "commander";
|
|
24490
|
-
import { mkdir as
|
|
24491
|
-
import { resolve as
|
|
24782
|
+
import { mkdir as mkdir9, readFile as readFile35, readdir as readdir19, rm as rm8, writeFile as writeFile13 } from "fs/promises";
|
|
24783
|
+
import { resolve as resolve55 } from "path";
|
|
24492
24784
|
init_parser2();
|
|
24493
24785
|
init_fs();
|
|
24494
24786
|
init_config2();
|
|
@@ -24506,7 +24798,7 @@ async function resolveBundleScope(options) {
|
|
|
24506
24798
|
throw new Error(`Invalid project slug: "${options.project}".`);
|
|
24507
24799
|
}
|
|
24508
24800
|
const config = await readConfig();
|
|
24509
|
-
const projectMd =
|
|
24801
|
+
const projectMd = resolve55(config.defaultProjectDir, options.project, "project.md");
|
|
24510
24802
|
if (!await fileExists(projectMd)) {
|
|
24511
24803
|
throw new Error(`Project "${options.project}" not found.`);
|
|
24512
24804
|
}
|
|
@@ -24576,10 +24868,10 @@ function pickNextPlanFile(planDir, existingFiles) {
|
|
|
24576
24868
|
const m = f.match(/^plan-v(\d+)\.md$/);
|
|
24577
24869
|
if (m) versions.add(parseInt(m[1], 10));
|
|
24578
24870
|
}
|
|
24579
|
-
if (versions.size === 0) return { target:
|
|
24871
|
+
if (versions.size === 0) return { target: resolve55(planDir, "plan.md"), version: 1 };
|
|
24580
24872
|
let n = 2;
|
|
24581
24873
|
while (versions.has(n)) n++;
|
|
24582
|
-
return { target:
|
|
24874
|
+
return { target: resolve55(planDir, `plan-v${n}.md`), version: n };
|
|
24583
24875
|
}
|
|
24584
24876
|
function dedupePreserveOrder(ids) {
|
|
24585
24877
|
const out = [];
|
|
@@ -24663,7 +24955,7 @@ bundleCommand.command("new").description("Create a new bundle from 2+ existing t
|
|
|
24663
24955
|
if (options.plan) {
|
|
24664
24956
|
const planDir = bundlePlanDir(sc.todosPath, sc.scopeId, id);
|
|
24665
24957
|
await ensureDir(planDir);
|
|
24666
|
-
const target =
|
|
24958
|
+
const target = resolve55(planDir, "plan.md");
|
|
24667
24959
|
const memberLines = items.map((it) => `- ${it.description} [t:${it.id}]`).join("\n");
|
|
24668
24960
|
const stub = [
|
|
24669
24961
|
"---",
|
|
@@ -24780,7 +25072,7 @@ bundleCommand.command("plan").description("Create or open the bundle's shared pl
|
|
|
24780
25072
|
}
|
|
24781
25073
|
const planDir = bundlePlanDir(sc.todosPath, sc.scopeId, id);
|
|
24782
25074
|
await ensureDir(planDir);
|
|
24783
|
-
const existing = (await
|
|
25075
|
+
const existing = (await readdir19(planDir).catch(() => [])).filter((f) => /^plan(?:-v\d+)?\.md$/.test(f));
|
|
24784
25076
|
const { target } = pickNextPlanFile(planDir, existing);
|
|
24785
25077
|
const checklist = await readChecklist(sc.todosPath, sc.checklistKey);
|
|
24786
25078
|
if (!await fileExists(target)) {
|
|
@@ -24839,7 +25131,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
24839
25131
|
}
|
|
24840
25132
|
const repository = options.repository ?? process.cwd();
|
|
24841
25133
|
const parentBranch = options.parentBranch ?? "main";
|
|
24842
|
-
const worktreePath = options.worktreePath ??
|
|
25134
|
+
const worktreePath = options.worktreePath ?? resolve55(repository, ".worktrees", options.branch);
|
|
24843
25135
|
const checklist = await readChecklist(sc.todosPath, sc.checklistKey);
|
|
24844
25136
|
for (const memberId of bundle.todoIds) {
|
|
24845
25137
|
const item = checklist.items.find((i) => i.id === memberId);
|
|
@@ -24849,8 +25141,8 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
24849
25141
|
}
|
|
24850
25142
|
const bundlesFilePath = bundlesPath(sc.todosPath);
|
|
24851
25143
|
const checklistFilePath = checklistPath(sc.todosPath, sc.checklistKey);
|
|
24852
|
-
const bundlesSnapshot = await fileExists(bundlesFilePath) ? await
|
|
24853
|
-
const checklistSnapshot = await fileExists(checklistFilePath) ? await
|
|
25144
|
+
const bundlesSnapshot = await fileExists(bundlesFilePath) ? await readFile35(bundlesFilePath, "utf-8") : null;
|
|
25145
|
+
const checklistSnapshot = await fileExists(checklistFilePath) ? await readFile35(checklistFilePath, "utf-8") : null;
|
|
24854
25146
|
const record = async () => {
|
|
24855
25147
|
bundle.branch = options.branch;
|
|
24856
25148
|
bundle.worktreePath = worktreePath;
|
|
@@ -24866,8 +25158,8 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
24866
25158
|
try {
|
|
24867
25159
|
await writeBundles(sc.todosPath, bundles);
|
|
24868
25160
|
await writeChecklist(sc.todosPath, checklist);
|
|
24869
|
-
const ctxDir =
|
|
24870
|
-
await
|
|
25161
|
+
const ctxDir = resolve55(worktreePath, ".syntaur");
|
|
25162
|
+
await mkdir9(ctxDir, { recursive: true });
|
|
24871
25163
|
const payload = {
|
|
24872
25164
|
bundleId: bundle.id,
|
|
24873
25165
|
bundleSlug: bundle.slug,
|
|
@@ -24880,7 +25172,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
24880
25172
|
repository,
|
|
24881
25173
|
boundAt: nowISO()
|
|
24882
25174
|
};
|
|
24883
|
-
await writeFile13(
|
|
25175
|
+
await writeFile13(resolve55(ctxDir, "context.json"), JSON.stringify(payload, null, 2) + "\n");
|
|
24884
25176
|
} catch (err2) {
|
|
24885
25177
|
try {
|
|
24886
25178
|
if (bundlesSnapshot === null) {
|
|
@@ -25070,7 +25362,7 @@ async function resolveScope(options) {
|
|
|
25070
25362
|
throw new Error(`Invalid project slug: "${options.project}".`);
|
|
25071
25363
|
}
|
|
25072
25364
|
const config = await readConfig();
|
|
25073
|
-
const projectMd =
|
|
25365
|
+
const projectMd = resolve56(config.defaultProjectDir, options.project, "project.md");
|
|
25074
25366
|
if (!await fileExists(projectMd)) {
|
|
25075
25367
|
throw new Error(`Project "${options.project}" not found.`);
|
|
25076
25368
|
}
|
|
@@ -25393,10 +25685,10 @@ todoCommand.command("archive").description("Archive completed todos and their lo
|
|
|
25393
25685
|
(e) => e.itemIds.every((id) => completedIds.has(id))
|
|
25394
25686
|
);
|
|
25395
25687
|
const archFile = archivePath(todosPath, workspace, checklist.archiveInterval);
|
|
25396
|
-
await ensureDir(
|
|
25688
|
+
await ensureDir(resolve56(todosPath, "archive"));
|
|
25397
25689
|
let archContent = "";
|
|
25398
25690
|
if (await fileExists(archFile)) {
|
|
25399
|
-
archContent = await
|
|
25691
|
+
archContent = await readFile36(archFile, "utf-8");
|
|
25400
25692
|
archContent = archContent.trimEnd() + "\n\n";
|
|
25401
25693
|
} else {
|
|
25402
25694
|
archContent = `---
|
|
@@ -25573,12 +25865,12 @@ function describeScope(scope) {
|
|
|
25573
25865
|
}
|
|
25574
25866
|
async function injectPromotedTodos(assignmentDir, todos, scopeLabel) {
|
|
25575
25867
|
const { resolve: resolvePath2 } = await import("path");
|
|
25576
|
-
const { readFile:
|
|
25868
|
+
const { readFile: readFile64 } = await import("fs/promises");
|
|
25577
25869
|
const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
25578
25870
|
const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
|
|
25579
25871
|
const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
|
|
25580
25872
|
const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
|
|
25581
|
-
let content = await
|
|
25873
|
+
let content = await readFile64(assignmentMdPath2, "utf-8");
|
|
25582
25874
|
content = appendTodosToAssignmentBody2(
|
|
25583
25875
|
content,
|
|
25584
25876
|
todos.map((t) => ({
|
|
@@ -25623,13 +25915,13 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
|
|
|
25623
25915
|
}
|
|
25624
25916
|
const planDir = todoPlanDir(todosPath, workspace, id);
|
|
25625
25917
|
await ensureDir(planDir);
|
|
25626
|
-
const { readdir:
|
|
25627
|
-
const existingFiles = (await
|
|
25918
|
+
const { readdir: readdir33 } = await import("fs/promises");
|
|
25919
|
+
const existingFiles = (await readdir33(planDir).catch(() => [])).filter(
|
|
25628
25920
|
(f) => /^plan(?:-v\d+)?\.md$/.test(f)
|
|
25629
25921
|
);
|
|
25630
25922
|
let target;
|
|
25631
25923
|
if (existingFiles.length === 0) {
|
|
25632
|
-
target =
|
|
25924
|
+
target = resolve56(planDir, "plan.md");
|
|
25633
25925
|
} else {
|
|
25634
25926
|
const versions = /* @__PURE__ */ new Set();
|
|
25635
25927
|
for (const f of existingFiles) {
|
|
@@ -25639,7 +25931,7 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
|
|
|
25639
25931
|
}
|
|
25640
25932
|
let n = 2;
|
|
25641
25933
|
while (versions.has(n)) n++;
|
|
25642
|
-
target =
|
|
25934
|
+
target = resolve56(planDir, `plan-v${n}.md`);
|
|
25643
25935
|
}
|
|
25644
25936
|
if (!await fileExists(target)) {
|
|
25645
25937
|
const stub = `---
|
|
@@ -25709,9 +26001,9 @@ async function moveTodo(id, options) {
|
|
|
25709
26001
|
if (await fileExists(newPlanDir)) {
|
|
25710
26002
|
throw new Error(`Plan directory already exists at target: ${newPlanDir}; refusing to move.`);
|
|
25711
26003
|
}
|
|
25712
|
-
const { rename: rename11, mkdir:
|
|
25713
|
-
const { dirname:
|
|
25714
|
-
await
|
|
26004
|
+
const { rename: rename11, mkdir: mkdir12 } = await import("fs/promises");
|
|
26005
|
+
const { dirname: dirname24 } = await import("path");
|
|
26006
|
+
await mkdir12(dirname24(newPlanDir), { recursive: true });
|
|
25715
26007
|
await rename11(item.planDir, newPlanDir);
|
|
25716
26008
|
item.planDir = newPlanDir;
|
|
25717
26009
|
}
|
|
@@ -25828,24 +26120,24 @@ backupCommand.command("config").description("Show or update backup configuration
|
|
|
25828
26120
|
|
|
25829
26121
|
// src/commands/doctor.ts
|
|
25830
26122
|
import { Command as Command4 } from "commander";
|
|
25831
|
-
import { readFile as
|
|
25832
|
-
import { isAbsolute as isAbsolute11, resolve as
|
|
26123
|
+
import { readFile as readFile46 } from "fs/promises";
|
|
26124
|
+
import { isAbsolute as isAbsolute11, resolve as resolve69 } from "path";
|
|
25833
26125
|
|
|
25834
26126
|
// src/utils/doctor/index.ts
|
|
25835
26127
|
import { fileURLToPath as fileURLToPath11 } from "url";
|
|
25836
|
-
import { readFile as
|
|
25837
|
-
import { dirname as
|
|
26128
|
+
import { readFile as readFile45 } from "fs/promises";
|
|
26129
|
+
import { dirname as dirname21, join as join14 } from "path";
|
|
25838
26130
|
|
|
25839
26131
|
// src/utils/doctor/context.ts
|
|
25840
26132
|
init_config2();
|
|
25841
26133
|
init_paths();
|
|
25842
26134
|
init_fs();
|
|
25843
26135
|
import Database4 from "better-sqlite3";
|
|
25844
|
-
import { resolve as
|
|
26136
|
+
import { resolve as resolve57 } from "path";
|
|
25845
26137
|
async function buildCheckContext(cwd = process.cwd()) {
|
|
25846
26138
|
const config = await readConfig();
|
|
25847
26139
|
const root = syntaurRoot();
|
|
25848
|
-
const dbPath =
|
|
26140
|
+
const dbPath = resolve57(root, "syntaur.db");
|
|
25849
26141
|
let db5 = null;
|
|
25850
26142
|
let dbError = null;
|
|
25851
26143
|
if (await fileExists(dbPath)) {
|
|
@@ -25879,10 +26171,10 @@ function closeCheckContext(ctx) {
|
|
|
25879
26171
|
// src/utils/doctor/checks/env.ts
|
|
25880
26172
|
init_fs();
|
|
25881
26173
|
init_paths();
|
|
25882
|
-
import { resolve as
|
|
25883
|
-
import { readFile as
|
|
26174
|
+
import { resolve as resolve58, isAbsolute as isAbsolute9 } from "path";
|
|
26175
|
+
import { readFile as readFile37, stat as stat4 } from "fs/promises";
|
|
25884
26176
|
import { fileURLToPath as fileURLToPath10 } from "url";
|
|
25885
|
-
import { dirname as
|
|
26177
|
+
import { dirname as dirname19, join as join11 } from "path";
|
|
25886
26178
|
var CATEGORY = "env";
|
|
25887
26179
|
var syntaurRootExists = {
|
|
25888
26180
|
id: "env.syntaur-root-exists",
|
|
@@ -25920,7 +26212,7 @@ var configValid = {
|
|
|
25920
26212
|
category: CATEGORY,
|
|
25921
26213
|
title: "~/.syntaur/config.md is valid",
|
|
25922
26214
|
async run(ctx) {
|
|
25923
|
-
const configPath2 =
|
|
26215
|
+
const configPath2 = resolve58(ctx.syntaurRoot, "config.md");
|
|
25924
26216
|
if (!await fileExists(configPath2)) {
|
|
25925
26217
|
return {
|
|
25926
26218
|
id: this.id,
|
|
@@ -25937,7 +26229,7 @@ var configValid = {
|
|
|
25937
26229
|
autoFixable: false
|
|
25938
26230
|
};
|
|
25939
26231
|
}
|
|
25940
|
-
const content = await
|
|
26232
|
+
const content = await readFile37(configPath2, "utf-8");
|
|
25941
26233
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
25942
26234
|
if (!fmMatch || fmMatch[1].trim() === "") {
|
|
25943
26235
|
return {
|
|
@@ -26213,14 +26505,14 @@ async function readLocalVersion() {
|
|
|
26213
26505
|
async function readLocalPkg() {
|
|
26214
26506
|
try {
|
|
26215
26507
|
const here = fileURLToPath10(import.meta.url);
|
|
26216
|
-
let dir =
|
|
26508
|
+
let dir = dirname19(here);
|
|
26217
26509
|
for (let i = 0; i < 6; i++) {
|
|
26218
|
-
const candidate =
|
|
26510
|
+
const candidate = join11(dir, "package.json");
|
|
26219
26511
|
try {
|
|
26220
|
-
const text = await
|
|
26512
|
+
const text = await readFile37(candidate, "utf-8");
|
|
26221
26513
|
return JSON.parse(text);
|
|
26222
26514
|
} catch {
|
|
26223
|
-
dir =
|
|
26515
|
+
dir = dirname19(dir);
|
|
26224
26516
|
}
|
|
26225
26517
|
}
|
|
26226
26518
|
return null;
|
|
@@ -26269,8 +26561,8 @@ function versionGte(a, b) {
|
|
|
26269
26561
|
|
|
26270
26562
|
// src/utils/doctor/checks/structure.ts
|
|
26271
26563
|
init_fs();
|
|
26272
|
-
import { resolve as
|
|
26273
|
-
import { readdir as
|
|
26564
|
+
import { resolve as resolve59 } from "path";
|
|
26565
|
+
import { readdir as readdir20, stat as stat5 } from "fs/promises";
|
|
26274
26566
|
var CATEGORY2 = "structure";
|
|
26275
26567
|
var KNOWN_TOP_LEVEL = /* @__PURE__ */ new Set([
|
|
26276
26568
|
"projects",
|
|
@@ -26289,7 +26581,7 @@ var projectsDir = {
|
|
|
26289
26581
|
category: CATEGORY2,
|
|
26290
26582
|
title: "projects/ directory exists",
|
|
26291
26583
|
async run(ctx) {
|
|
26292
|
-
const p =
|
|
26584
|
+
const p = resolve59(ctx.syntaurRoot, "projects");
|
|
26293
26585
|
if (!await fileExists(p)) {
|
|
26294
26586
|
return {
|
|
26295
26587
|
id: this.id,
|
|
@@ -26314,7 +26606,7 @@ var playbooksDir2 = {
|
|
|
26314
26606
|
category: CATEGORY2,
|
|
26315
26607
|
title: "playbooks/ directory exists",
|
|
26316
26608
|
async run(ctx) {
|
|
26317
|
-
const p =
|
|
26609
|
+
const p = resolve59(ctx.syntaurRoot, "playbooks");
|
|
26318
26610
|
if (!await fileExists(p)) {
|
|
26319
26611
|
return {
|
|
26320
26612
|
id: this.id,
|
|
@@ -26339,7 +26631,7 @@ var todosDirValid = {
|
|
|
26339
26631
|
category: CATEGORY2,
|
|
26340
26632
|
title: "todos/ directory is readable (if present)",
|
|
26341
26633
|
async run(ctx) {
|
|
26342
|
-
const p =
|
|
26634
|
+
const p = resolve59(ctx.syntaurRoot, "todos");
|
|
26343
26635
|
if (!await fileExists(p)) {
|
|
26344
26636
|
return {
|
|
26345
26637
|
id: this.id,
|
|
@@ -26370,7 +26662,7 @@ var serversDirValid = {
|
|
|
26370
26662
|
category: CATEGORY2,
|
|
26371
26663
|
title: "servers/ directory is readable (if present)",
|
|
26372
26664
|
async run(ctx) {
|
|
26373
|
-
const p =
|
|
26665
|
+
const p = resolve59(ctx.syntaurRoot, "servers");
|
|
26374
26666
|
if (!await fileExists(p)) {
|
|
26375
26667
|
return {
|
|
26376
26668
|
id: this.id,
|
|
@@ -26401,7 +26693,7 @@ var knownFilesRecognized = {
|
|
|
26401
26693
|
category: CATEGORY2,
|
|
26402
26694
|
title: "No unexpected top-level entries under ~/.syntaur/",
|
|
26403
26695
|
async run(ctx) {
|
|
26404
|
-
const entries = await
|
|
26696
|
+
const entries = await readdir20(ctx.syntaurRoot, { withFileTypes: true });
|
|
26405
26697
|
const unexpected = [];
|
|
26406
26698
|
for (const e of entries) {
|
|
26407
26699
|
if (e.name.startsWith(".")) continue;
|
|
@@ -26415,7 +26707,7 @@ var knownFilesRecognized = {
|
|
|
26415
26707
|
title: this.title,
|
|
26416
26708
|
status: "warn",
|
|
26417
26709
|
detail: `unexpected top-level entries: ${unexpected.join(", ")}`,
|
|
26418
|
-
affected: unexpected.map((n) =>
|
|
26710
|
+
affected: unexpected.map((n) => resolve59(ctx.syntaurRoot, n)),
|
|
26419
26711
|
remediation: {
|
|
26420
26712
|
kind: "manual",
|
|
26421
26713
|
suggestion: "Review these entries \u2014 they may be leftover state from older versions",
|
|
@@ -26444,8 +26736,8 @@ function pass2(check) {
|
|
|
26444
26736
|
|
|
26445
26737
|
// src/utils/doctor/checks/project.ts
|
|
26446
26738
|
init_fs();
|
|
26447
|
-
import { resolve as
|
|
26448
|
-
import { readdir as
|
|
26739
|
+
import { resolve as resolve60 } from "path";
|
|
26740
|
+
import { readdir as readdir21, stat as stat6 } from "fs/promises";
|
|
26449
26741
|
var CATEGORY3 = "project";
|
|
26450
26742
|
var REQUIRED_PROJECT_FILES = [
|
|
26451
26743
|
"project.md",
|
|
@@ -26469,15 +26761,15 @@ var PROJECT_MARKERS = ["project.md", "manifest.md", "assignments"];
|
|
|
26469
26761
|
async function listProjects2(ctx) {
|
|
26470
26762
|
const dir = ctx.config.defaultProjectDir;
|
|
26471
26763
|
if (!await fileExists(dir)) return [];
|
|
26472
|
-
const entries = await
|
|
26764
|
+
const entries = await readdir21(dir, { withFileTypes: true });
|
|
26473
26765
|
const result = [];
|
|
26474
26766
|
for (const e of entries) {
|
|
26475
26767
|
if (!e.isDirectory()) continue;
|
|
26476
26768
|
if (e.name.startsWith(".") || e.name.startsWith("_")) continue;
|
|
26477
|
-
const projectDir =
|
|
26769
|
+
const projectDir = resolve60(dir, e.name);
|
|
26478
26770
|
let looksLikeProject = false;
|
|
26479
26771
|
for (const marker of PROJECT_MARKERS) {
|
|
26480
|
-
if (await fileExists(
|
|
26772
|
+
if (await fileExists(resolve60(projectDir, marker))) {
|
|
26481
26773
|
looksLikeProject = true;
|
|
26482
26774
|
break;
|
|
26483
26775
|
}
|
|
@@ -26496,7 +26788,7 @@ var requiredFiles = {
|
|
|
26496
26788
|
for (const projectDir of projects) {
|
|
26497
26789
|
const missing = [];
|
|
26498
26790
|
for (const rel of REQUIRED_PROJECT_FILES) {
|
|
26499
|
-
const p =
|
|
26791
|
+
const p = resolve60(projectDir, rel);
|
|
26500
26792
|
if (!await fileExists(p)) missing.push(rel);
|
|
26501
26793
|
}
|
|
26502
26794
|
if (missing.length === 0) continue;
|
|
@@ -26506,7 +26798,7 @@ var requiredFiles = {
|
|
|
26506
26798
|
title: this.title,
|
|
26507
26799
|
status: "error",
|
|
26508
26800
|
detail: `project at ${projectDir} is missing: ${missing.join(", ")}`,
|
|
26509
|
-
affected: missing.map((m) =>
|
|
26801
|
+
affected: missing.map((m) => resolve60(projectDir, m)),
|
|
26510
26802
|
remediation: {
|
|
26511
26803
|
kind: "manual",
|
|
26512
26804
|
suggestion: "Recreate the missing scaffold files from templates",
|
|
@@ -26529,7 +26821,7 @@ var manifestStale = {
|
|
|
26529
26821
|
const projects = await listProjects2(ctx);
|
|
26530
26822
|
const results = [];
|
|
26531
26823
|
for (const projectDir of projects) {
|
|
26532
|
-
const manifestPath =
|
|
26824
|
+
const manifestPath = resolve60(projectDir, "manifest.md");
|
|
26533
26825
|
if (!await fileExists(manifestPath)) continue;
|
|
26534
26826
|
const manifestMtime = (await stat6(manifestPath)).mtimeMs;
|
|
26535
26827
|
const newestAssignment = await newestAssignmentMtime(projectDir);
|
|
@@ -26563,7 +26855,7 @@ var orphanFiles = {
|
|
|
26563
26855
|
const projects = await listProjects2(ctx);
|
|
26564
26856
|
const results = [];
|
|
26565
26857
|
for (const projectDir of projects) {
|
|
26566
|
-
const entries = await
|
|
26858
|
+
const entries = await readdir21(projectDir, { withFileTypes: true });
|
|
26567
26859
|
const orphans = [];
|
|
26568
26860
|
for (const e of entries) {
|
|
26569
26861
|
if (e.name.startsWith(".")) continue;
|
|
@@ -26578,7 +26870,7 @@ var orphanFiles = {
|
|
|
26578
26870
|
title: this.title,
|
|
26579
26871
|
status: "warn",
|
|
26580
26872
|
detail: `project at ${projectDir} has unexpected entries: ${orphans.join(", ")}`,
|
|
26581
|
-
affected: orphans.map((o) =>
|
|
26873
|
+
affected: orphans.map((o) => resolve60(projectDir, o)),
|
|
26582
26874
|
autoFixable: false
|
|
26583
26875
|
});
|
|
26584
26876
|
}
|
|
@@ -26588,18 +26880,18 @@ var orphanFiles = {
|
|
|
26588
26880
|
};
|
|
26589
26881
|
var projectChecks = [requiredFiles, manifestStale, orphanFiles];
|
|
26590
26882
|
async function newestAssignmentMtime(projectDir) {
|
|
26591
|
-
const assignmentsRoot =
|
|
26883
|
+
const assignmentsRoot = resolve60(projectDir, "assignments");
|
|
26592
26884
|
if (!await fileExists(assignmentsRoot)) return 0;
|
|
26593
26885
|
let newest = 0;
|
|
26594
26886
|
let entries;
|
|
26595
26887
|
try {
|
|
26596
|
-
entries = await
|
|
26888
|
+
entries = await readdir21(assignmentsRoot, { withFileTypes: true });
|
|
26597
26889
|
} catch {
|
|
26598
26890
|
return 0;
|
|
26599
26891
|
}
|
|
26600
26892
|
for (const e of entries) {
|
|
26601
26893
|
if (!e.isDirectory()) continue;
|
|
26602
|
-
const assignmentMd =
|
|
26894
|
+
const assignmentMd = resolve60(assignmentsRoot, e.name, "assignment.md");
|
|
26603
26895
|
try {
|
|
26604
26896
|
const s = await stat6(assignmentMd);
|
|
26605
26897
|
if (s.mtimeMs > newest) newest = s.mtimeMs;
|
|
@@ -26623,8 +26915,8 @@ init_fs();
|
|
|
26623
26915
|
init_parser();
|
|
26624
26916
|
init_types();
|
|
26625
26917
|
init_paths();
|
|
26626
|
-
import { resolve as
|
|
26627
|
-
import { readFile as
|
|
26918
|
+
import { resolve as resolve61 } from "path";
|
|
26919
|
+
import { readFile as readFile38, readdir as readdir22 } from "fs/promises";
|
|
26628
26920
|
var CATEGORY4 = "assignment";
|
|
26629
26921
|
var STATUSES_REQUIRING_HANDOFF = /* @__PURE__ */ new Set(["review", "completed"]);
|
|
26630
26922
|
var PRE_WORKSPACE_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -26718,7 +27010,7 @@ var invalidStatus = {
|
|
|
26718
27010
|
const allowed = configuredStatuses(ctx);
|
|
26719
27011
|
const results = [];
|
|
26720
27012
|
for (const a of withAssignmentMd) {
|
|
26721
|
-
const path =
|
|
27013
|
+
const path = resolve61(a.assignmentDir, "assignment.md");
|
|
26722
27014
|
const parsed = await parseSafe2(path);
|
|
26723
27015
|
if (!parsed) continue;
|
|
26724
27016
|
if (!allowed.has(parsed.status)) {
|
|
@@ -26751,7 +27043,7 @@ var workspaceMissing = {
|
|
|
26751
27043
|
const terminal = terminalStatuses(ctx);
|
|
26752
27044
|
const results = [];
|
|
26753
27045
|
for (const a of withAssignmentMd) {
|
|
26754
|
-
const path =
|
|
27046
|
+
const path = resolve61(a.assignmentDir, "assignment.md");
|
|
26755
27047
|
const parsed = await parseSafe2(path);
|
|
26756
27048
|
if (!parsed) continue;
|
|
26757
27049
|
if (terminal.has(parsed.status)) continue;
|
|
@@ -26798,12 +27090,12 @@ var requiredFilesByStatus = {
|
|
|
26798
27090
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
26799
27091
|
const results = [];
|
|
26800
27092
|
for (const a of withAssignmentMd) {
|
|
26801
|
-
const assignmentPath =
|
|
27093
|
+
const assignmentPath = resolve61(a.assignmentDir, "assignment.md");
|
|
26802
27094
|
const parsed = await parseSafe2(assignmentPath);
|
|
26803
27095
|
if (!parsed) continue;
|
|
26804
27096
|
const missing = [];
|
|
26805
27097
|
if (STATUSES_REQUIRING_HANDOFF.has(parsed.status)) {
|
|
26806
|
-
const handoffPath =
|
|
27098
|
+
const handoffPath = resolve61(a.assignmentDir, "handoff.md");
|
|
26807
27099
|
if (!await fileExists(handoffPath)) missing.push("handoff.md");
|
|
26808
27100
|
}
|
|
26809
27101
|
if (missing.length === 0) continue;
|
|
@@ -26813,7 +27105,7 @@ var requiredFilesByStatus = {
|
|
|
26813
27105
|
title: this.title,
|
|
26814
27106
|
status: "warn",
|
|
26815
27107
|
detail: `${a.projectSlug}/${a.assignmentSlug} (status: ${parsed.status}) is missing ${missing.join(", ")}`,
|
|
26816
|
-
affected: missing.map((m) =>
|
|
27108
|
+
affected: missing.map((m) => resolve61(a.assignmentDir, m)),
|
|
26817
27109
|
remediation: {
|
|
26818
27110
|
kind: "manual",
|
|
26819
27111
|
suggestion: `Create the missing ${missing.join(" and ")} files for this assignment`,
|
|
@@ -26836,7 +27128,7 @@ var companionFilesScaffolded = {
|
|
|
26836
27128
|
for (const a of withAssignmentMd) {
|
|
26837
27129
|
const missing = [];
|
|
26838
27130
|
for (const filename of ["progress.md", "comments.md"]) {
|
|
26839
|
-
if (!await fileExists(
|
|
27131
|
+
if (!await fileExists(resolve61(a.assignmentDir, filename))) {
|
|
26840
27132
|
missing.push(filename);
|
|
26841
27133
|
}
|
|
26842
27134
|
}
|
|
@@ -26848,7 +27140,7 @@ var companionFilesScaffolded = {
|
|
|
26848
27140
|
title: this.title,
|
|
26849
27141
|
status: "warn",
|
|
26850
27142
|
detail: `${label} is missing ${missing.join(" and ")} (pre-v2.0 assignment \u2014 not required, but scaffolding them keeps the dashboard and CLIs consistent)`,
|
|
26851
|
-
affected: missing.map((m) =>
|
|
27143
|
+
affected: missing.map((m) => resolve61(a.assignmentDir, m)),
|
|
26852
27144
|
remediation: {
|
|
26853
27145
|
kind: "manual",
|
|
26854
27146
|
suggestion: `Create ${missing.join(" and ")} with the renderProgress/renderComments templates, or re-scaffold via the CLI`,
|
|
@@ -26881,7 +27173,7 @@ var typeDefinition = {
|
|
|
26881
27173
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
26882
27174
|
const results = [];
|
|
26883
27175
|
for (const a of withAssignmentMd) {
|
|
26884
|
-
const path =
|
|
27176
|
+
const path = resolve61(a.assignmentDir, "assignment.md");
|
|
26885
27177
|
const parsed = await parseSafe2(path);
|
|
26886
27178
|
if (!parsed) continue;
|
|
26887
27179
|
if (!parsed.type) continue;
|
|
@@ -26915,7 +27207,7 @@ var projectFrontmatterMatchesContainer = {
|
|
|
26915
27207
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
26916
27208
|
const results = [];
|
|
26917
27209
|
for (const a of withAssignmentMd) {
|
|
26918
|
-
const path =
|
|
27210
|
+
const path = resolve61(a.assignmentDir, "assignment.md");
|
|
26919
27211
|
const parsed = await parseSafe2(path);
|
|
26920
27212
|
if (!parsed) continue;
|
|
26921
27213
|
if (a.standalone) {
|
|
@@ -26966,13 +27258,13 @@ var draftMissingObjective = {
|
|
|
26966
27258
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
26967
27259
|
const results = [];
|
|
26968
27260
|
for (const a of withAssignmentMd) {
|
|
26969
|
-
const path =
|
|
27261
|
+
const path = resolve61(a.assignmentDir, "assignment.md");
|
|
26970
27262
|
const parsed = await parseSafe2(path);
|
|
26971
27263
|
if (!parsed) continue;
|
|
26972
27264
|
if (parsed.status !== "draft") continue;
|
|
26973
27265
|
let raw2;
|
|
26974
27266
|
try {
|
|
26975
|
-
raw2 = await
|
|
27267
|
+
raw2 = await readFile38(path, "utf-8");
|
|
26976
27268
|
} catch {
|
|
26977
27269
|
continue;
|
|
26978
27270
|
}
|
|
@@ -27005,16 +27297,16 @@ var readyToImplementMissingPlan = {
|
|
|
27005
27297
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
27006
27298
|
const results = [];
|
|
27007
27299
|
for (const a of withAssignmentMd) {
|
|
27008
|
-
const path =
|
|
27300
|
+
const path = resolve61(a.assignmentDir, "assignment.md");
|
|
27009
27301
|
const parsed = await parseSafe2(path);
|
|
27010
27302
|
if (!parsed) continue;
|
|
27011
27303
|
if (parsed.status !== "ready_to_implement") continue;
|
|
27012
|
-
const entries = await
|
|
27304
|
+
const entries = await readdir22(a.assignmentDir).catch(() => []);
|
|
27013
27305
|
const planFiles = entries.filter((f) => /^plan(?:-v\d+)?\.md$/i.test(f));
|
|
27014
27306
|
let hasPlanContent = false;
|
|
27015
27307
|
for (const f of planFiles) {
|
|
27016
27308
|
try {
|
|
27017
|
-
const c2 = await
|
|
27309
|
+
const c2 = await readFile38(resolve61(a.assignmentDir, f), "utf-8");
|
|
27018
27310
|
if (c2.trim().length > 0) {
|
|
27019
27311
|
hasPlanContent = true;
|
|
27020
27312
|
break;
|
|
@@ -27030,7 +27322,7 @@ var readyToImplementMissingPlan = {
|
|
|
27030
27322
|
title: this.title,
|
|
27031
27323
|
status: "warn",
|
|
27032
27324
|
detail: `${label} (status: ready_to_implement) has no plan.md or plan-v<N>.md`,
|
|
27033
|
-
affected: [
|
|
27325
|
+
affected: [resolve61(a.assignmentDir, "plan.md")],
|
|
27034
27326
|
remediation: {
|
|
27035
27327
|
kind: "manual",
|
|
27036
27328
|
suggestion: `Write a plan with '/plan-assignment' (or 'syntaur plan'), then re-mark ready_to_implement`,
|
|
@@ -27057,7 +27349,7 @@ var assignmentChecks = [
|
|
|
27057
27349
|
];
|
|
27058
27350
|
async function parseSafe2(path) {
|
|
27059
27351
|
try {
|
|
27060
|
-
const content = await
|
|
27352
|
+
const content = await readFile38(path, "utf-8");
|
|
27061
27353
|
return parseAssignmentFull(content);
|
|
27062
27354
|
} catch {
|
|
27063
27355
|
return null;
|
|
@@ -27076,7 +27368,7 @@ function pass4(check, detail) {
|
|
|
27076
27368
|
|
|
27077
27369
|
// src/utils/doctor/checks/dashboard.ts
|
|
27078
27370
|
init_fs();
|
|
27079
|
-
import { resolve as
|
|
27371
|
+
import { resolve as resolve62 } from "path";
|
|
27080
27372
|
var CATEGORY5 = "dashboard";
|
|
27081
27373
|
var dbReachable = {
|
|
27082
27374
|
id: "dashboard.db-reachable",
|
|
@@ -27090,7 +27382,7 @@ var dbReachable = {
|
|
|
27090
27382
|
title: this.title,
|
|
27091
27383
|
status: "error",
|
|
27092
27384
|
detail: `could not open syntaur.db: ${ctx.dbError ?? "unknown error"}`,
|
|
27093
|
-
affected: [
|
|
27385
|
+
affected: [resolve62(ctx.syntaurRoot, "syntaur.db")],
|
|
27094
27386
|
remediation: {
|
|
27095
27387
|
kind: "manual",
|
|
27096
27388
|
suggestion: "Start the dashboard once (`syntaur dashboard`) to initialize the DB, or restore it from backup",
|
|
@@ -27108,7 +27400,7 @@ var dbReachable = {
|
|
|
27108
27400
|
title: this.title,
|
|
27109
27401
|
status: "error",
|
|
27110
27402
|
detail: 'syntaur.db is missing the expected "sessions" table',
|
|
27111
|
-
affected: [
|
|
27403
|
+
affected: [resolve62(ctx.syntaurRoot, "syntaur.db")],
|
|
27112
27404
|
autoFixable: false
|
|
27113
27405
|
};
|
|
27114
27406
|
}
|
|
@@ -27120,7 +27412,7 @@ var dbReachable = {
|
|
|
27120
27412
|
title: this.title,
|
|
27121
27413
|
status: "error",
|
|
27122
27414
|
detail: `syntaur.db query failed: ${err2 instanceof Error ? err2.message : String(err2)}`,
|
|
27123
|
-
affected: [
|
|
27415
|
+
affected: [resolve62(ctx.syntaurRoot, "syntaur.db")],
|
|
27124
27416
|
autoFixable: false
|
|
27125
27417
|
};
|
|
27126
27418
|
}
|
|
@@ -27146,7 +27438,7 @@ var ghostSessions = {
|
|
|
27146
27438
|
const results = [];
|
|
27147
27439
|
for (const row of rows) {
|
|
27148
27440
|
if (!row.project_slug) continue;
|
|
27149
|
-
const projectPath =
|
|
27441
|
+
const projectPath = resolve62(projectsDir2, row.project_slug, "project.md");
|
|
27150
27442
|
if (!await fileExists(projectPath)) {
|
|
27151
27443
|
results.push({
|
|
27152
27444
|
id: this.id,
|
|
@@ -27165,7 +27457,7 @@ var ghostSessions = {
|
|
|
27165
27457
|
continue;
|
|
27166
27458
|
}
|
|
27167
27459
|
if (row.assignment_slug) {
|
|
27168
|
-
const assignmentPath =
|
|
27460
|
+
const assignmentPath = resolve62(
|
|
27169
27461
|
projectsDir2,
|
|
27170
27462
|
row.project_slug,
|
|
27171
27463
|
"assignments",
|
|
@@ -27217,8 +27509,8 @@ function skipped(check, reason) {
|
|
|
27217
27509
|
|
|
27218
27510
|
// src/utils/doctor/checks/integrations.ts
|
|
27219
27511
|
init_fs();
|
|
27220
|
-
import { resolve as
|
|
27221
|
-
import { readdir as
|
|
27512
|
+
import { resolve as resolve63, dirname as dirname20, basename as basename6 } from "path";
|
|
27513
|
+
import { readdir as readdir23, readFile as readFile39 } from "fs/promises";
|
|
27222
27514
|
import { homedir as homedir10 } from "os";
|
|
27223
27515
|
var CATEGORY6 = "integrations";
|
|
27224
27516
|
var claudePluginLinked = {
|
|
@@ -27281,7 +27573,7 @@ var backupConfigured = {
|
|
|
27281
27573
|
if (ctx.config.backup?.repo) return pass6(this);
|
|
27282
27574
|
const projectsDir2 = ctx.config.defaultProjectDir;
|
|
27283
27575
|
if (!await fileExists(projectsDir2)) return skipped2(this, "no projects dir");
|
|
27284
|
-
const entries = await
|
|
27576
|
+
const entries = await readdir23(projectsDir2, { withFileTypes: true });
|
|
27285
27577
|
const hasProjects = entries.some((e) => e.isDirectory() && !e.name.startsWith(".") && !e.name.startsWith("_"));
|
|
27286
27578
|
if (!hasProjects) return skipped2(this, "no projects yet");
|
|
27287
27579
|
return {
|
|
@@ -27300,10 +27592,10 @@ var backupConfigured = {
|
|
|
27300
27592
|
}
|
|
27301
27593
|
};
|
|
27302
27594
|
async function readKnownMarketplaces() {
|
|
27303
|
-
const path =
|
|
27595
|
+
const path = resolve63(homedir10(), ".claude", "plugins", "known_marketplaces.json");
|
|
27304
27596
|
if (!await fileExists(path)) return {};
|
|
27305
27597
|
try {
|
|
27306
|
-
const raw2 = await
|
|
27598
|
+
const raw2 = await readFile39(path, "utf-8");
|
|
27307
27599
|
return JSON.parse(raw2);
|
|
27308
27600
|
} catch {
|
|
27309
27601
|
return {};
|
|
@@ -27319,7 +27611,7 @@ var claudeMarketplaceRegistered = {
|
|
|
27319
27611
|
if (!await fileExists(dir)) {
|
|
27320
27612
|
return skipped2(this, "claudePluginDir does not exist (run install-plugin)");
|
|
27321
27613
|
}
|
|
27322
|
-
const pluginsParent =
|
|
27614
|
+
const pluginsParent = dirname20(dir);
|
|
27323
27615
|
if (basename6(pluginsParent) !== "plugins") {
|
|
27324
27616
|
return {
|
|
27325
27617
|
id: this.id,
|
|
@@ -27336,8 +27628,8 @@ var claudeMarketplaceRegistered = {
|
|
|
27336
27628
|
autoFixable: false
|
|
27337
27629
|
};
|
|
27338
27630
|
}
|
|
27339
|
-
const marketplaceRoot =
|
|
27340
|
-
const marketplaceManifest =
|
|
27631
|
+
const marketplaceRoot = dirname20(pluginsParent);
|
|
27632
|
+
const marketplaceManifest = resolve63(marketplaceRoot, ".claude-plugin", "marketplace.json");
|
|
27341
27633
|
if (!await fileExists(marketplaceManifest)) {
|
|
27342
27634
|
return {
|
|
27343
27635
|
id: this.id,
|
|
@@ -27356,7 +27648,7 @@ var claudeMarketplaceRegistered = {
|
|
|
27356
27648
|
}
|
|
27357
27649
|
let parsed = {};
|
|
27358
27650
|
try {
|
|
27359
|
-
parsed = JSON.parse(await
|
|
27651
|
+
parsed = JSON.parse(await readFile39(marketplaceManifest, "utf-8"));
|
|
27360
27652
|
} catch {
|
|
27361
27653
|
return {
|
|
27362
27654
|
id: this.id,
|
|
@@ -27388,7 +27680,7 @@ var claudeMarketplaceRegistered = {
|
|
|
27388
27680
|
title: this.title,
|
|
27389
27681
|
status: "error",
|
|
27390
27682
|
detail: issues.join("; "),
|
|
27391
|
-
affected: [marketplaceManifest,
|
|
27683
|
+
affected: [marketplaceManifest, resolve63(homedir10(), ".claude", "plugins", "known_marketplaces.json")],
|
|
27392
27684
|
remediation: {
|
|
27393
27685
|
kind: "manual",
|
|
27394
27686
|
suggestion: "Re-run install-plugin to ensure both files are in sync.",
|
|
@@ -27428,8 +27720,8 @@ function skipped2(check, reason) {
|
|
|
27428
27720
|
init_fs();
|
|
27429
27721
|
init_parser();
|
|
27430
27722
|
init_types();
|
|
27431
|
-
import { resolve as
|
|
27432
|
-
import { readFile as
|
|
27723
|
+
import { resolve as resolve64 } from "path";
|
|
27724
|
+
import { readFile as readFile40 } from "fs/promises";
|
|
27433
27725
|
var CATEGORY7 = "workspace";
|
|
27434
27726
|
var ASSIGNMENT_FIELDS = ["projectSlug", "assignmentSlug", "projectDir", "assignmentDir"];
|
|
27435
27727
|
var BUNDLE_FIELDS = ["bundleId", "bundleScope", "bundleScopeId"];
|
|
@@ -27450,12 +27742,12 @@ function isStandaloneSession(ctx) {
|
|
|
27450
27742
|
return !hasAnyAssignmentField(ctx) && !hasAnyBundleField(ctx) && typeof ctx.sessionId === "string" && ctx.sessionId.length > 0;
|
|
27451
27743
|
}
|
|
27452
27744
|
async function loadContext(ctx) {
|
|
27453
|
-
const path =
|
|
27745
|
+
const path = resolve64(ctx.cwd, ".syntaur", "context.json");
|
|
27454
27746
|
if (!await fileExists(path)) {
|
|
27455
27747
|
return { data: null, path, exists: false, parseError: null };
|
|
27456
27748
|
}
|
|
27457
27749
|
try {
|
|
27458
|
-
const raw2 = await
|
|
27750
|
+
const raw2 = await readFile40(path, "utf-8");
|
|
27459
27751
|
return { data: JSON.parse(raw2), path, exists: true, parseError: null };
|
|
27460
27752
|
} catch (err2) {
|
|
27461
27753
|
return {
|
|
@@ -27549,7 +27841,7 @@ var contextAssignmentResolves = {
|
|
|
27549
27841
|
if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to resolve");
|
|
27550
27842
|
if (isBundleContext(data)) return skipped3(this, "bundle context \u2014 no assignment to resolve");
|
|
27551
27843
|
if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
|
|
27552
|
-
const assignmentMd =
|
|
27844
|
+
const assignmentMd = resolve64(data.assignmentDir, "assignment.md");
|
|
27553
27845
|
if (!await fileExists(assignmentMd)) {
|
|
27554
27846
|
return {
|
|
27555
27847
|
id: this.id,
|
|
@@ -27579,10 +27871,10 @@ var contextTerminal = {
|
|
|
27579
27871
|
if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to check");
|
|
27580
27872
|
if (isBundleContext(data)) return skipped3(this, "bundle context \u2014 no assignment to check");
|
|
27581
27873
|
if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
|
|
27582
|
-
const assignmentMd =
|
|
27874
|
+
const assignmentMd = resolve64(data.assignmentDir, "assignment.md");
|
|
27583
27875
|
if (!await fileExists(assignmentMd)) return skipped3(this, "assignment file missing");
|
|
27584
27876
|
try {
|
|
27585
|
-
const content = await
|
|
27877
|
+
const content = await readFile40(assignmentMd, "utf-8");
|
|
27586
27878
|
const parsed = parseAssignmentFull(content);
|
|
27587
27879
|
const terminal = terminalStatuses2(ctx);
|
|
27588
27880
|
if (terminal.has(parsed.status)) {
|
|
@@ -27728,15 +28020,15 @@ var agentChecks = [agentsResolvable];
|
|
|
27728
28020
|
// src/utils/doctor/checks/terminal.ts
|
|
27729
28021
|
init_config2();
|
|
27730
28022
|
import { spawnSync as spawnSync9 } from "child_process";
|
|
27731
|
-
import { readFile as
|
|
27732
|
-
import { resolve as
|
|
28023
|
+
import { readFile as readFile41 } from "fs/promises";
|
|
28024
|
+
import { resolve as resolve65 } from "path";
|
|
27733
28025
|
init_paths();
|
|
27734
28026
|
init_fs();
|
|
27735
28027
|
var CATEGORY9 = "terminal";
|
|
27736
28028
|
async function readRawTerminalKey() {
|
|
27737
|
-
const configPath2 =
|
|
28029
|
+
const configPath2 = resolve65(syntaurRoot(), "config.md");
|
|
27738
28030
|
if (!await fileExists(configPath2)) return null;
|
|
27739
|
-
const content = await
|
|
28031
|
+
const content = await readFile41(configPath2, "utf-8");
|
|
27740
28032
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
27741
28033
|
if (!fmMatch) return null;
|
|
27742
28034
|
const line = fmMatch[1].split("\n").find((l) => /^terminal:\s*/.test(l));
|
|
@@ -27886,13 +28178,13 @@ var terminalChecks = [
|
|
|
27886
28178
|
|
|
27887
28179
|
// src/utils/doctor/checks/skills.ts
|
|
27888
28180
|
init_fs();
|
|
27889
|
-
import { resolve as
|
|
27890
|
-
import { readdir as
|
|
28181
|
+
import { resolve as resolve66, join as join12 } from "path";
|
|
28182
|
+
import { readdir as readdir24, readFile as readFile42, lstat as lstat4 } from "fs/promises";
|
|
27891
28183
|
import { homedir as homedir11 } from "os";
|
|
27892
28184
|
var CATEGORY10 = "skills";
|
|
27893
28185
|
var skillTargets = [
|
|
27894
|
-
{ agent: "claude", dir:
|
|
27895
|
-
{ agent: "codex", dir:
|
|
28186
|
+
{ agent: "claude", dir: resolve66(homedir11(), ".claude", "skills"), label: "~/.claude/skills" },
|
|
28187
|
+
{ agent: "codex", dir: resolve66(homedir11(), ".codex", "skills"), label: "~/.codex/skills" }
|
|
27896
28188
|
];
|
|
27897
28189
|
var skillsDedupCheck = {
|
|
27898
28190
|
id: "skills.dedup",
|
|
@@ -27907,21 +28199,21 @@ var skillsDedupCheck = {
|
|
|
27907
28199
|
const present = [];
|
|
27908
28200
|
let entries;
|
|
27909
28201
|
try {
|
|
27910
|
-
entries = await
|
|
28202
|
+
entries = await readdir24(dir, { withFileTypes: true });
|
|
27911
28203
|
} catch {
|
|
27912
28204
|
continue;
|
|
27913
28205
|
}
|
|
27914
28206
|
for (const entry of entries) {
|
|
27915
28207
|
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
|
|
27916
28208
|
if (!KNOWN_SKILLS.includes(entry.name)) continue;
|
|
27917
|
-
const skillMd =
|
|
28209
|
+
const skillMd = join12(dir, entry.name, "SKILL.md");
|
|
27918
28210
|
if (!await fileExists(skillMd)) continue;
|
|
27919
|
-
const content = await
|
|
28211
|
+
const content = await readFile42(skillMd, "utf-8").catch(() => "");
|
|
27920
28212
|
const match = content.match(/^name:\s*(\S+)\s*$/m);
|
|
27921
28213
|
if (!match || match[1] !== entry.name) continue;
|
|
27922
28214
|
let isSymlink2 = false;
|
|
27923
28215
|
try {
|
|
27924
|
-
isSymlink2 = (await lstat4(
|
|
28216
|
+
isSymlink2 = (await lstat4(join12(dir, entry.name))).isSymbolicLink();
|
|
27925
28217
|
} catch {
|
|
27926
28218
|
}
|
|
27927
28219
|
present.push({ name: entry.name, isSymlink: isSymlink2 });
|
|
@@ -27933,7 +28225,7 @@ var skillsDedupCheck = {
|
|
|
27933
28225
|
findings.push(
|
|
27934
28226
|
`${label}: ${nonSymlink.length} syntaur skill(s) installed globally while the syntaur plugin is enabled (${agent}) \u2014 duplicate registrations`
|
|
27935
28227
|
);
|
|
27936
|
-
for (const p of nonSymlink) affected.push(
|
|
28228
|
+
for (const p of nonSymlink) affected.push(join12(dir, p.name));
|
|
27937
28229
|
}
|
|
27938
28230
|
}
|
|
27939
28231
|
}
|
|
@@ -27966,12 +28258,12 @@ var skillsChecks = [skillsDedupCheck];
|
|
|
27966
28258
|
|
|
27967
28259
|
// src/utils/doctor/checks/cross-agent.ts
|
|
27968
28260
|
init_fs();
|
|
27969
|
-
import { join as
|
|
27970
|
-
import { readFile as
|
|
28261
|
+
import { join as join13, resolve as resolve67 } from "path";
|
|
28262
|
+
import { readFile as readFile44 } from "fs/promises";
|
|
27971
28263
|
|
|
27972
28264
|
// src/utils/skill-frontmatter.ts
|
|
27973
28265
|
import { createHash } from "crypto";
|
|
27974
|
-
import { readFile as
|
|
28266
|
+
import { readFile as readFile43 } from "fs/promises";
|
|
27975
28267
|
function stripQuotes(raw2) {
|
|
27976
28268
|
const t = raw2.trim();
|
|
27977
28269
|
if (t.length >= 2 && (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'"))) {
|
|
@@ -28015,7 +28307,7 @@ function readSkillIdentity(skillMdText) {
|
|
|
28015
28307
|
return { name, hasDescription };
|
|
28016
28308
|
}
|
|
28017
28309
|
async function sha256File(path) {
|
|
28018
|
-
return createHash("sha256").update(await
|
|
28310
|
+
return createHash("sha256").update(await readFile43(path)).digest("hex");
|
|
28019
28311
|
}
|
|
28020
28312
|
|
|
28021
28313
|
// src/utils/doctor/checks/cross-agent.ts
|
|
@@ -28024,14 +28316,14 @@ async function checkTargetSkillsIntegrity(installedDir, canonicalSkillsDir, know
|
|
|
28024
28316
|
const problems = [];
|
|
28025
28317
|
let valid = 0;
|
|
28026
28318
|
for (const skill of knownSkills) {
|
|
28027
|
-
const installedPath =
|
|
28319
|
+
const installedPath = join13(installedDir, skill, "SKILL.md");
|
|
28028
28320
|
if (!await fileExists(installedPath)) {
|
|
28029
28321
|
problems.push({ skill, kind: "missing" });
|
|
28030
28322
|
continue;
|
|
28031
28323
|
}
|
|
28032
28324
|
let text;
|
|
28033
28325
|
try {
|
|
28034
|
-
text = await
|
|
28326
|
+
text = await readFile44(installedPath, "utf-8");
|
|
28035
28327
|
} catch {
|
|
28036
28328
|
problems.push({ skill, kind: "invalid-frontmatter" });
|
|
28037
28329
|
continue;
|
|
@@ -28042,7 +28334,7 @@ async function checkTargetSkillsIntegrity(installedDir, canonicalSkillsDir, know
|
|
|
28042
28334
|
continue;
|
|
28043
28335
|
}
|
|
28044
28336
|
valid++;
|
|
28045
|
-
const canonicalPath =
|
|
28337
|
+
const canonicalPath = join13(canonicalSkillsDir, skill, "SKILL.md");
|
|
28046
28338
|
if (await fileExists(canonicalPath)) {
|
|
28047
28339
|
const [installedHash, canonicalHash] = await Promise.all([
|
|
28048
28340
|
sha256File(installedPath),
|
|
@@ -28075,6 +28367,7 @@ var crossAgentSkillsCheck = {
|
|
|
28075
28367
|
title: "Cross-agent targets have Syntaur skills + protocol files",
|
|
28076
28368
|
async run(ctx) {
|
|
28077
28369
|
const installed = ctx.config.integrations.installedAgents ?? {};
|
|
28370
|
+
const { targets: resolvedTargets, warnings: descriptorWarnings } = await resolveAgentTargets();
|
|
28078
28371
|
const canonicalSkillsDir = await getSkillsDir();
|
|
28079
28372
|
let knownSkills;
|
|
28080
28373
|
try {
|
|
@@ -28088,7 +28381,7 @@ var crossAgentSkillsCheck = {
|
|
|
28088
28381
|
const problems = [];
|
|
28089
28382
|
const affected = [];
|
|
28090
28383
|
let considered = 0;
|
|
28091
|
-
for (const t of
|
|
28384
|
+
for (const t of resolvedTargets) {
|
|
28092
28385
|
if (t.nativePlugin) continue;
|
|
28093
28386
|
const dir = t.skillsDir?.global;
|
|
28094
28387
|
if (!dir) continue;
|
|
@@ -28107,15 +28400,41 @@ var crossAgentSkillsCheck = {
|
|
|
28107
28400
|
}
|
|
28108
28401
|
if (recorded && t.instructions) {
|
|
28109
28402
|
for (const f of t.instructions.files) {
|
|
28110
|
-
const p =
|
|
28403
|
+
const p = resolve67(ctx.cwd, f.path);
|
|
28111
28404
|
if (!await fileExists(p)) {
|
|
28112
28405
|
problems.push(`${t.displayName}: missing protocol file ${f.path} in cwd`);
|
|
28113
28406
|
affected.push(p);
|
|
28114
28407
|
}
|
|
28115
28408
|
}
|
|
28116
28409
|
}
|
|
28410
|
+
if (t.tier3) {
|
|
28411
|
+
const installDir = t.tier3.installDir();
|
|
28412
|
+
const installed2 = await fileExists(join13(installDir, t.tier3.entry));
|
|
28413
|
+
lines.push(
|
|
28414
|
+
`${t.displayName}: Tier-3 ${t.tier3.kind} ${installed2 ? "installed" : "absent"} (${installDir})`
|
|
28415
|
+
);
|
|
28416
|
+
if (recorded && !installed2) {
|
|
28417
|
+
problems.push(`${t.displayName}: Tier-3 ${t.tier3.kind} not installed`);
|
|
28418
|
+
affected.push(installDir);
|
|
28419
|
+
}
|
|
28420
|
+
}
|
|
28117
28421
|
}
|
|
28118
28422
|
if (considered === 0) {
|
|
28423
|
+
if (descriptorWarnings.length > 0) {
|
|
28424
|
+
return {
|
|
28425
|
+
id: this.id,
|
|
28426
|
+
category: this.category,
|
|
28427
|
+
title: this.title,
|
|
28428
|
+
status: "warn",
|
|
28429
|
+
detail: `User target descriptor issues: ${descriptorWarnings.join("; ")}`,
|
|
28430
|
+
remediation: {
|
|
28431
|
+
kind: "manual",
|
|
28432
|
+
suggestion: `Fix or remove the offending file(s) in ~/.syntaur/targets/ (see references/user-targets.md).`,
|
|
28433
|
+
command: null
|
|
28434
|
+
},
|
|
28435
|
+
autoFixable: false
|
|
28436
|
+
};
|
|
28437
|
+
}
|
|
28119
28438
|
return {
|
|
28120
28439
|
id: this.id,
|
|
28121
28440
|
category: this.category,
|
|
@@ -28125,6 +28444,7 @@ var crossAgentSkillsCheck = {
|
|
|
28125
28444
|
autoFixable: false
|
|
28126
28445
|
};
|
|
28127
28446
|
}
|
|
28447
|
+
for (const w of descriptorWarnings) problems.push(`user target descriptor: ${w}`);
|
|
28128
28448
|
if (problems.length > 0) {
|
|
28129
28449
|
return {
|
|
28130
28450
|
id: this.id,
|
|
@@ -28156,8 +28476,8 @@ var crossAgentChecks = [crossAgentSkillsCheck];
|
|
|
28156
28476
|
// src/utils/doctor/checks/bundles.ts
|
|
28157
28477
|
init_fs();
|
|
28158
28478
|
init_paths();
|
|
28159
|
-
import { resolve as
|
|
28160
|
-
import { readdir as
|
|
28479
|
+
import { resolve as resolve68 } from "path";
|
|
28480
|
+
import { readdir as readdir25 } from "fs/promises";
|
|
28161
28481
|
import { spawnSync as spawnSync10 } from "child_process";
|
|
28162
28482
|
init_parser2();
|
|
28163
28483
|
var CATEGORY12 = "bundles";
|
|
@@ -28165,7 +28485,7 @@ async function listScopes(ctx) {
|
|
|
28165
28485
|
const out = [];
|
|
28166
28486
|
const td = todosDir();
|
|
28167
28487
|
if (await fileExists(td)) {
|
|
28168
|
-
const entries = await
|
|
28488
|
+
const entries = await readdir25(td).catch(() => []);
|
|
28169
28489
|
for (const f of entries) {
|
|
28170
28490
|
if (typeof f !== "string") continue;
|
|
28171
28491
|
if (!f.endsWith(".md") || f.endsWith("-log.md")) continue;
|
|
@@ -28181,12 +28501,12 @@ async function listScopes(ctx) {
|
|
|
28181
28501
|
}
|
|
28182
28502
|
}
|
|
28183
28503
|
if (await fileExists(ctx.config.defaultProjectDir)) {
|
|
28184
|
-
const projectEntries = await
|
|
28504
|
+
const projectEntries = await readdir25(ctx.config.defaultProjectDir, { withFileTypes: true }).catch(() => []);
|
|
28185
28505
|
for (const e of projectEntries) {
|
|
28186
28506
|
if (!e.isDirectory()) continue;
|
|
28187
28507
|
const slug = e.name;
|
|
28188
28508
|
if (typeof slug !== "string" || slug.startsWith(".")) continue;
|
|
28189
|
-
const projectMd =
|
|
28509
|
+
const projectMd = resolve68(ctx.config.defaultProjectDir, slug, "project.md");
|
|
28190
28510
|
if (!await fileExists(projectMd)) continue;
|
|
28191
28511
|
out.push({
|
|
28192
28512
|
scopeLabel: `project:${slug}`,
|
|
@@ -28475,14 +28795,14 @@ async function finalize(checks) {
|
|
|
28475
28795
|
async function readVersion() {
|
|
28476
28796
|
try {
|
|
28477
28797
|
const here = fileURLToPath11(import.meta.url);
|
|
28478
|
-
let dir =
|
|
28798
|
+
let dir = dirname21(here);
|
|
28479
28799
|
for (let i = 0; i < 6; i++) {
|
|
28480
28800
|
try {
|
|
28481
|
-
const raw2 = await
|
|
28801
|
+
const raw2 = await readFile45(join14(dir, "package.json"), "utf-8");
|
|
28482
28802
|
const parsed = JSON.parse(raw2);
|
|
28483
28803
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
28484
28804
|
} catch {
|
|
28485
|
-
dir =
|
|
28805
|
+
dir = dirname21(dir);
|
|
28486
28806
|
}
|
|
28487
28807
|
}
|
|
28488
28808
|
return null;
|
|
@@ -28575,7 +28895,7 @@ var REQUIRED_WORKSPACE_FIELDS = [
|
|
|
28575
28895
|
];
|
|
28576
28896
|
var ISO_DATE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
|
|
28577
28897
|
async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
|
|
28578
|
-
const absolute = isAbsolute11(inputPath) ? inputPath :
|
|
28898
|
+
const absolute = isAbsolute11(inputPath) ? inputPath : resolve69(cwd, inputPath);
|
|
28579
28899
|
const errors = [];
|
|
28580
28900
|
const warnings = [];
|
|
28581
28901
|
if (!await fileExists(absolute)) {
|
|
@@ -28588,7 +28908,7 @@ async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
|
|
|
28588
28908
|
}
|
|
28589
28909
|
let content;
|
|
28590
28910
|
try {
|
|
28591
|
-
content = await
|
|
28911
|
+
content = await readFile46(absolute, "utf-8");
|
|
28592
28912
|
} catch (err2) {
|
|
28593
28913
|
return {
|
|
28594
28914
|
ok: false,
|
|
@@ -28654,20 +28974,20 @@ var doctorCommand = new Command4("doctor").description("Diagnose Syntaur state a
|
|
|
28654
28974
|
process.exit(result.ok ? 0 : 1);
|
|
28655
28975
|
}
|
|
28656
28976
|
if (!await fileExists(syntaurRoot())) {
|
|
28657
|
-
const
|
|
28977
|
+
const msg2 = "~/.syntaur/ does not exist. Run `syntaur init` first.";
|
|
28658
28978
|
if (options.json) {
|
|
28659
28979
|
process.stdout.write(
|
|
28660
28980
|
JSON.stringify(
|
|
28661
28981
|
{
|
|
28662
28982
|
version: "1.0",
|
|
28663
|
-
error:
|
|
28983
|
+
error: msg2
|
|
28664
28984
|
},
|
|
28665
28985
|
null,
|
|
28666
28986
|
2
|
|
28667
28987
|
) + "\n"
|
|
28668
28988
|
);
|
|
28669
28989
|
} else {
|
|
28670
|
-
process.stderr.write(
|
|
28990
|
+
process.stderr.write(msg2 + "\n");
|
|
28671
28991
|
}
|
|
28672
28992
|
process.exit(2);
|
|
28673
28993
|
}
|
|
@@ -28686,11 +29006,11 @@ var doctorCommand = new Command4("doctor").description("Diagnose Syntaur state a
|
|
|
28686
29006
|
const hasError = report.summary.error > 0;
|
|
28687
29007
|
process.exit(hasError ? 1 : 0);
|
|
28688
29008
|
} catch (err2) {
|
|
28689
|
-
const
|
|
29009
|
+
const msg2 = err2 instanceof Error ? err2.message : String(err2);
|
|
28690
29010
|
if (options.json) {
|
|
28691
|
-
process.stdout.write(JSON.stringify({ version: "1.0", error:
|
|
29011
|
+
process.stdout.write(JSON.stringify({ version: "1.0", error: msg2 }, null, 2) + "\n");
|
|
28692
29012
|
} else {
|
|
28693
|
-
process.stderr.write(`doctor itself failed: ${
|
|
29013
|
+
process.stderr.write(`doctor itself failed: ${msg2}
|
|
28694
29014
|
`);
|
|
28695
29015
|
}
|
|
28696
29016
|
process.exit(2);
|
|
@@ -28912,8 +29232,8 @@ init_uuid();
|
|
|
28912
29232
|
init_timestamp();
|
|
28913
29233
|
init_assignment_resolver();
|
|
28914
29234
|
init_templates();
|
|
28915
|
-
import { resolve as
|
|
28916
|
-
import { readFile as
|
|
29235
|
+
import { resolve as resolve70 } from "path";
|
|
29236
|
+
import { readFile as readFile47 } from "fs/promises";
|
|
28917
29237
|
function shortId() {
|
|
28918
29238
|
return generateId().split("-")[0];
|
|
28919
29239
|
}
|
|
@@ -28943,7 +29263,7 @@ async function commentCommand(target, text, options = {}) {
|
|
|
28943
29263
|
if (!isValidSlug(target)) {
|
|
28944
29264
|
throw new Error(`Invalid assignment slug "${target}".`);
|
|
28945
29265
|
}
|
|
28946
|
-
assignmentDir =
|
|
29266
|
+
assignmentDir = resolve70(baseDir, options.project, "assignments", target);
|
|
28947
29267
|
assignmentRef = target;
|
|
28948
29268
|
} else {
|
|
28949
29269
|
const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
|
|
@@ -28953,13 +29273,13 @@ async function commentCommand(target, text, options = {}) {
|
|
|
28953
29273
|
assignmentDir = resolved.assignmentDir;
|
|
28954
29274
|
assignmentRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
|
|
28955
29275
|
}
|
|
28956
|
-
const commentsPath =
|
|
29276
|
+
const commentsPath = resolve70(assignmentDir, "comments.md");
|
|
28957
29277
|
const timestamp = nowTimestamp();
|
|
28958
29278
|
const author = options.author ?? process.env.USER ?? "unknown";
|
|
28959
29279
|
let currentContent;
|
|
28960
29280
|
let currentCount = 0;
|
|
28961
29281
|
if (await fileExists(commentsPath)) {
|
|
28962
|
-
currentContent = await
|
|
29282
|
+
currentContent = await readFile47(commentsPath, "utf-8");
|
|
28963
29283
|
const countMatch = currentContent.match(/^entryCount:\s*(\d+)/m);
|
|
28964
29284
|
if (countMatch) currentCount = parseInt(countMatch[1], 10);
|
|
28965
29285
|
} else {
|
|
@@ -28993,8 +29313,8 @@ ${entry}`;
|
|
|
28993
29313
|
}
|
|
28994
29314
|
|
|
28995
29315
|
// src/commands/capture.ts
|
|
28996
|
-
import { resolve as
|
|
28997
|
-
import { copyFile as copyFile3, mkdir as
|
|
29316
|
+
import { resolve as resolve74, relative as relative4, dirname as dirname22 } from "path";
|
|
29317
|
+
import { copyFile as copyFile3, mkdir as mkdir11, realpath as realpath2, rm as rm13, stat as stat9, writeFile as writeFile15 } from "fs/promises";
|
|
28998
29318
|
import { existsSync as existsSync6 } from "fs";
|
|
28999
29319
|
|
|
29000
29320
|
// src/utils/assignment-target.ts
|
|
@@ -29004,8 +29324,8 @@ init_config2();
|
|
|
29004
29324
|
init_slug();
|
|
29005
29325
|
init_assignment_resolver();
|
|
29006
29326
|
init_parser();
|
|
29007
|
-
import { resolve as
|
|
29008
|
-
import { readFile as
|
|
29327
|
+
import { resolve as resolve71 } from "path";
|
|
29328
|
+
import { readFile as readFile48 } from "fs/promises";
|
|
29009
29329
|
var AssignmentTargetError = class extends Error {
|
|
29010
29330
|
};
|
|
29011
29331
|
function classifyContext(ctx) {
|
|
@@ -29017,10 +29337,10 @@ function classifyContext(ctx) {
|
|
|
29017
29337
|
return "empty";
|
|
29018
29338
|
}
|
|
29019
29339
|
async function readAssignmentFrontmatterId(assignmentDir) {
|
|
29020
|
-
const path =
|
|
29340
|
+
const path = resolve71(assignmentDir, "assignment.md");
|
|
29021
29341
|
if (!await fileExists(path)) return null;
|
|
29022
29342
|
try {
|
|
29023
|
-
const content = await
|
|
29343
|
+
const content = await readFile48(path, "utf-8");
|
|
29024
29344
|
const [fm] = extractFrontmatter(content);
|
|
29025
29345
|
return getField(fm, "id");
|
|
29026
29346
|
} catch {
|
|
@@ -29028,10 +29348,10 @@ async function readAssignmentFrontmatterId(assignmentDir) {
|
|
|
29028
29348
|
}
|
|
29029
29349
|
}
|
|
29030
29350
|
async function readContextJson(cwd) {
|
|
29031
|
-
const path =
|
|
29351
|
+
const path = resolve71(cwd, ".syntaur", "context.json");
|
|
29032
29352
|
if (!await fileExists(path)) return null;
|
|
29033
29353
|
try {
|
|
29034
|
-
const raw2 = await
|
|
29354
|
+
const raw2 = await readFile48(path, "utf-8");
|
|
29035
29355
|
return JSON.parse(raw2);
|
|
29036
29356
|
} catch {
|
|
29037
29357
|
return null;
|
|
@@ -29052,15 +29372,15 @@ async function resolveAssignmentTarget(input4, opts = {}) {
|
|
|
29052
29372
|
if (!isValidSlug(input4)) {
|
|
29053
29373
|
throw new AssignmentTargetError(`Invalid assignment slug "${input4}".`);
|
|
29054
29374
|
}
|
|
29055
|
-
const projectDir =
|
|
29056
|
-
const projectMdPath =
|
|
29375
|
+
const projectDir = resolve71(baseDir, opts.project);
|
|
29376
|
+
const projectMdPath = resolve71(projectDir, "project.md");
|
|
29057
29377
|
if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
|
|
29058
29378
|
throw new AssignmentTargetError(
|
|
29059
29379
|
`Project "${opts.project}" not found at ${projectDir}.`
|
|
29060
29380
|
);
|
|
29061
29381
|
}
|
|
29062
|
-
const assignmentDir =
|
|
29063
|
-
const assignmentMdPath2 =
|
|
29382
|
+
const assignmentDir = resolve71(projectDir, "assignments", input4);
|
|
29383
|
+
const assignmentMdPath2 = resolve71(assignmentDir, "assignment.md");
|
|
29064
29384
|
if (!await fileExists(assignmentMdPath2)) {
|
|
29065
29385
|
throw new AssignmentTargetError(
|
|
29066
29386
|
`Assignment "${input4}" not found in project "${opts.project}".`
|
|
@@ -29099,7 +29419,7 @@ async function resolveAssignmentTarget(input4, opts = {}) {
|
|
|
29099
29419
|
}
|
|
29100
29420
|
if (ctx.assignmentDir) {
|
|
29101
29421
|
const dir = expandHome(ctx.assignmentDir);
|
|
29102
|
-
const assignmentMdPath2 =
|
|
29422
|
+
const assignmentMdPath2 = resolve71(dir, "assignment.md");
|
|
29103
29423
|
if (!await fileExists(assignmentMdPath2)) {
|
|
29104
29424
|
throw new AssignmentTargetError(
|
|
29105
29425
|
`.syntaur/context.json points to a missing assignment dir: ${dir}.`
|
|
@@ -29128,8 +29448,8 @@ async function resolveAssignmentTarget(input4, opts = {}) {
|
|
|
29128
29448
|
`.syntaur/context.json contains invalid slugs: project="${ctx.projectSlug}" assignment="${ctx.assignmentSlug}".`
|
|
29129
29449
|
);
|
|
29130
29450
|
}
|
|
29131
|
-
const assignmentDir =
|
|
29132
|
-
const assignmentMdPath2 =
|
|
29451
|
+
const assignmentDir = resolve71(baseDir, ctx.projectSlug, "assignments", ctx.assignmentSlug);
|
|
29452
|
+
const assignmentMdPath2 = resolve71(assignmentDir, "assignment.md");
|
|
29133
29453
|
if (!await fileExists(assignmentMdPath2)) {
|
|
29134
29454
|
throw new AssignmentTargetError(
|
|
29135
29455
|
`.syntaur/context.json points to a missing assignment: ${assignmentDir}.`
|
|
@@ -29158,7 +29478,7 @@ init_fs();
|
|
|
29158
29478
|
import { spawn as spawn7 } from "child_process";
|
|
29159
29479
|
import { mkdtemp as mkdtemp2, rm as rm9, stat as stat7 } from "fs/promises";
|
|
29160
29480
|
import { tmpdir as tmpdir3 } from "os";
|
|
29161
|
-
import { join as
|
|
29481
|
+
import { join as join15 } from "path";
|
|
29162
29482
|
function argsFor(mode, pngPath) {
|
|
29163
29483
|
switch (mode) {
|
|
29164
29484
|
case "interactive":
|
|
@@ -29191,8 +29511,8 @@ async function captureScreenshot(mode) {
|
|
|
29191
29511
|
"screencapture is only available on macOS. Use --file <path> to attach an existing image."
|
|
29192
29512
|
);
|
|
29193
29513
|
}
|
|
29194
|
-
const tmpDir = await mkdtemp2(
|
|
29195
|
-
const pngPath =
|
|
29514
|
+
const tmpDir = await mkdtemp2(join15(tmpdir3(), "syntaur-screenshot-"));
|
|
29515
|
+
const pngPath = join15(tmpDir, "shot.png");
|
|
29196
29516
|
const cleanup = async () => {
|
|
29197
29517
|
await rm9(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
29198
29518
|
});
|
|
@@ -29230,9 +29550,9 @@ async function captureScreenshot(mode) {
|
|
|
29230
29550
|
|
|
29231
29551
|
// src/utils/asciinema.ts
|
|
29232
29552
|
import { spawn as spawn8 } from "child_process";
|
|
29233
|
-
import { mkdtemp as mkdtemp3, readFile as
|
|
29553
|
+
import { mkdtemp as mkdtemp3, readFile as readFile49, rm as rm10 } from "fs/promises";
|
|
29234
29554
|
import { tmpdir as tmpdir4 } from "os";
|
|
29235
|
-
import { join as
|
|
29555
|
+
import { join as join16 } from "path";
|
|
29236
29556
|
var SAFE_RE = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
29237
29557
|
function shellQuote2(s) {
|
|
29238
29558
|
if (s.length === 0) return `''`;
|
|
@@ -29269,8 +29589,8 @@ function runAsciinema(args, stdio) {
|
|
|
29269
29589
|
});
|
|
29270
29590
|
}
|
|
29271
29591
|
async function captureAsciinema(opts) {
|
|
29272
|
-
const tmpDir = await mkdtemp3(
|
|
29273
|
-
const castPath =
|
|
29592
|
+
const tmpDir = await mkdtemp3(join16(tmpdir4(), "syntaur-asciinema-"));
|
|
29593
|
+
const castPath = join16(tmpDir, "session.cast");
|
|
29274
29594
|
const cleanup = async () => {
|
|
29275
29595
|
await rm10(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
29276
29596
|
});
|
|
@@ -29293,7 +29613,7 @@ async function captureAsciinema(opts) {
|
|
|
29293
29613
|
}
|
|
29294
29614
|
throw err2;
|
|
29295
29615
|
}
|
|
29296
|
-
const text = await
|
|
29616
|
+
const text = await readFile49(castPath, "utf8").catch(() => null);
|
|
29297
29617
|
if (text === null) {
|
|
29298
29618
|
throw new Error(
|
|
29299
29619
|
`asciinema produced no cast file at ${castPath} (exit ${exitCode}). Try running 'asciinema rec ${castPath}' directly to diagnose.`
|
|
@@ -29321,9 +29641,9 @@ async function captureAsciinema(opts) {
|
|
|
29321
29641
|
// src/utils/recording.ts
|
|
29322
29642
|
init_paths();
|
|
29323
29643
|
import { spawn as spawn9 } from "child_process";
|
|
29324
|
-
import { mkdir as
|
|
29644
|
+
import { mkdir as mkdir10, mkdtemp as mkdtemp4, open as open3, readFile as readFile50, rm as rm11, stat as stat8, unlink as unlink10, writeFile as writeFile14 } from "fs/promises";
|
|
29325
29645
|
import { tmpdir as tmpdir5 } from "os";
|
|
29326
|
-
import { join as
|
|
29646
|
+
import { join as join17, resolve as resolve72 } from "path";
|
|
29327
29647
|
import { setTimeout as sleep } from "timers/promises";
|
|
29328
29648
|
function sigintPollIntervalMs() {
|
|
29329
29649
|
const raw2 = process.env.SYNTAUR_RECORDING_POLL_INTERVAL_MS;
|
|
@@ -29344,13 +29664,13 @@ function sigtermWaitMs() {
|
|
|
29344
29664
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : 1e3;
|
|
29345
29665
|
}
|
|
29346
29666
|
function pidfilePath() {
|
|
29347
|
-
return
|
|
29667
|
+
return resolve72(syntaurRoot(), "recording.pid");
|
|
29348
29668
|
}
|
|
29349
29669
|
function logPath2() {
|
|
29350
|
-
return
|
|
29670
|
+
return resolve72(syntaurRoot(), "recording.log");
|
|
29351
29671
|
}
|
|
29352
29672
|
function sidecarPath() {
|
|
29353
|
-
return
|
|
29673
|
+
return resolve72(syntaurRoot(), "recording.json");
|
|
29354
29674
|
}
|
|
29355
29675
|
function ffmpegArgs(device, fps, mp4Path) {
|
|
29356
29676
|
return [
|
|
@@ -29395,7 +29715,7 @@ async function acquirePidfile(pidfile) {
|
|
|
29395
29715
|
} catch (err2) {
|
|
29396
29716
|
if (err2.code !== "EEXIST") throw err2;
|
|
29397
29717
|
if (attempt === 1) throw err2;
|
|
29398
|
-
const existing = (await
|
|
29718
|
+
const existing = (await readFile50(pidfile, "utf-8").catch(() => "")).trim();
|
|
29399
29719
|
if (existing.startsWith(STARTING_SENTINEL_PREFIX)) {
|
|
29400
29720
|
const parentPidRaw = existing.slice(STARTING_SENTINEL_PREFIX.length);
|
|
29401
29721
|
const parentPid = Number.parseInt(parentPidRaw, 10);
|
|
@@ -29437,7 +29757,7 @@ async function startRecording(input4) {
|
|
|
29437
29757
|
);
|
|
29438
29758
|
}
|
|
29439
29759
|
const root = syntaurRoot();
|
|
29440
|
-
await
|
|
29760
|
+
await mkdir10(root, { recursive: true });
|
|
29441
29761
|
const pidfile = pidfilePath();
|
|
29442
29762
|
const log = logPath2();
|
|
29443
29763
|
const sidecar = sidecarPath();
|
|
@@ -29448,8 +29768,8 @@ async function startRecording(input4) {
|
|
|
29448
29768
|
let acquiredPid = null;
|
|
29449
29769
|
try {
|
|
29450
29770
|
logHandle = await open3(log, "w");
|
|
29451
|
-
tmpDir = await mkdtemp4(
|
|
29452
|
-
const mp4Path =
|
|
29771
|
+
tmpDir = await mkdtemp4(join17(tmpdir5(), "syntaur-recording-"));
|
|
29772
|
+
const mp4Path = join17(tmpDir, "recording.mp4");
|
|
29453
29773
|
let child;
|
|
29454
29774
|
try {
|
|
29455
29775
|
child = spawn9("ffmpeg", ffmpegArgs(input4.device, input4.fps, mp4Path), {
|
|
@@ -29497,7 +29817,7 @@ async function startRecording(input4) {
|
|
|
29497
29817
|
logHandle = null;
|
|
29498
29818
|
if (warmupMs > 0) await sleep(warmupMs);
|
|
29499
29819
|
if (!await isProcessAlive(pid)) {
|
|
29500
|
-
const tail = await
|
|
29820
|
+
const tail = await readFile50(log, "utf-8").then((s) => s.split("\n").slice(-20).join("\n")).catch(() => "");
|
|
29501
29821
|
acquiredPid = null;
|
|
29502
29822
|
throw new Error(
|
|
29503
29823
|
`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}
|
|
@@ -29554,7 +29874,7 @@ ${tail}`
|
|
|
29554
29874
|
async function stopRecording() {
|
|
29555
29875
|
const pidfile = pidfilePath();
|
|
29556
29876
|
const sidecar = sidecarPath();
|
|
29557
|
-
const pidRaw = await
|
|
29877
|
+
const pidRaw = await readFile50(pidfile, "utf-8").catch(() => null);
|
|
29558
29878
|
if (pidRaw === null) {
|
|
29559
29879
|
throw new Error(
|
|
29560
29880
|
`No active recording found (no pidfile at ${pidfile}). Did you run --start?`
|
|
@@ -29564,7 +29884,7 @@ async function stopRecording() {
|
|
|
29564
29884
|
if (!Number.isInteger(pid) || pid <= 0) {
|
|
29565
29885
|
throw new Error(`Pidfile at ${pidfile} is corrupt (got "${pidRaw}").`);
|
|
29566
29886
|
}
|
|
29567
|
-
const sidecarRaw = await
|
|
29887
|
+
const sidecarRaw = await readFile50(sidecar, "utf-8").catch(() => null);
|
|
29568
29888
|
if (sidecarRaw === null) {
|
|
29569
29889
|
throw new Error(
|
|
29570
29890
|
`No recording sidecar at ${sidecar}. The recording state is inconsistent \u2014 delete ${pidfile} and re-run --start.`
|
|
@@ -29629,7 +29949,7 @@ async function stopRecording() {
|
|
|
29629
29949
|
// src/db/proof-db.ts
|
|
29630
29950
|
init_paths();
|
|
29631
29951
|
import Database5 from "better-sqlite3";
|
|
29632
|
-
import { resolve as
|
|
29952
|
+
import { resolve as resolve73 } from "path";
|
|
29633
29953
|
var db4 = null;
|
|
29634
29954
|
var PROOF_SCHEMA_VERSION = "1";
|
|
29635
29955
|
var SCHEMA_SQL4 = `
|
|
@@ -29649,7 +29969,7 @@ CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT);
|
|
|
29649
29969
|
`;
|
|
29650
29970
|
function initProofDb(dbPath) {
|
|
29651
29971
|
if (db4) return db4;
|
|
29652
|
-
const finalPath = dbPath ??
|
|
29972
|
+
const finalPath = dbPath ?? resolve73(syntaurRoot(), "syntaur.db");
|
|
29653
29973
|
db4 = new Database5(finalPath);
|
|
29654
29974
|
db4.pragma("journal_mode = WAL");
|
|
29655
29975
|
db4.exec(SCHEMA_SQL4);
|
|
@@ -29697,9 +30017,9 @@ function listArtifactsByAssignment(assignmentId) {
|
|
|
29697
30017
|
|
|
29698
30018
|
// src/utils/transcribers/elevenlabs.ts
|
|
29699
30019
|
import { spawn as spawn10 } from "child_process";
|
|
29700
|
-
import { mkdtemp as mkdtemp5, readFile as
|
|
30020
|
+
import { mkdtemp as mkdtemp5, readFile as readFile51, rm as rm12 } from "fs/promises";
|
|
29701
30021
|
import { tmpdir as tmpdir6 } from "os";
|
|
29702
|
-
import { join as
|
|
30022
|
+
import { join as join18 } from "path";
|
|
29703
30023
|
var SCRIBE_URL = "https://api.elevenlabs.io/v1/speech-to-text";
|
|
29704
30024
|
var NO_AUDIO_MARKERS = [
|
|
29705
30025
|
"Stream map '0:a:0' matches no streams",
|
|
@@ -29761,7 +30081,7 @@ async function extractAudio(videoAbsPath, wavOut) {
|
|
|
29761
30081
|
throw new TranscribeFfmpegError(`ffmpeg failed (exit ${result.code}): ${tail}`);
|
|
29762
30082
|
}
|
|
29763
30083
|
async function callScribe(wavPath, apiKey, opts) {
|
|
29764
|
-
const audio = await
|
|
30084
|
+
const audio = await readFile51(wavPath);
|
|
29765
30085
|
const form = new FormData();
|
|
29766
30086
|
form.set("file", new Blob([new Uint8Array(audio)], { type: "audio/wav" }), "audio.wav");
|
|
29767
30087
|
form.set("model_id", "scribe_v1");
|
|
@@ -29789,8 +30109,8 @@ var elevenLabsScribe = {
|
|
|
29789
30109
|
"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."
|
|
29790
30110
|
);
|
|
29791
30111
|
}
|
|
29792
|
-
const tmp = await mkdtemp5(
|
|
29793
|
-
const wav =
|
|
30112
|
+
const tmp = await mkdtemp5(join18(tmpdir6(), "syntaur-transcribe-"));
|
|
30113
|
+
const wav = join18(tmp, "audio.wav");
|
|
29794
30114
|
try {
|
|
29795
30115
|
await extractAudio(videoAbsPath, wav);
|
|
29796
30116
|
return await callScribe(wav, apiKey, opts);
|
|
@@ -30064,7 +30384,7 @@ async function captureCommand(target, options = {}) {
|
|
|
30064
30384
|
criterionIndex = sidecar.criterionIndex;
|
|
30065
30385
|
stopNote = sidecar.note;
|
|
30066
30386
|
resolvedSource = mp4Path;
|
|
30067
|
-
const mp4TmpDir =
|
|
30387
|
+
const mp4TmpDir = dirname22(mp4Path);
|
|
30068
30388
|
shelloutCleanup = async () => {
|
|
30069
30389
|
await rm13(mp4TmpDir, { recursive: true, force: true }).catch(() => {
|
|
30070
30390
|
});
|
|
@@ -30077,7 +30397,7 @@ async function captureCommand(target, options = {}) {
|
|
|
30077
30397
|
});
|
|
30078
30398
|
}
|
|
30079
30399
|
if (options.file) {
|
|
30080
|
-
const expanded = options.file.startsWith("~/") ?
|
|
30400
|
+
const expanded = options.file.startsWith("~/") ? resolve74(process.env.HOME ?? "", options.file.slice(2)) : resolve74(options.file);
|
|
30081
30401
|
if (!await fileExists(expanded)) {
|
|
30082
30402
|
throw new Error(`--file does not exist: ${options.file}`);
|
|
30083
30403
|
}
|
|
@@ -30118,8 +30438,8 @@ async function captureCommand(target, options = {}) {
|
|
|
30118
30438
|
}
|
|
30119
30439
|
initProofDb();
|
|
30120
30440
|
const subdir = criterionIndex === null ? "untagged" : String(criterionIndex);
|
|
30121
|
-
const destDir =
|
|
30122
|
-
if (resolvedSource) await
|
|
30441
|
+
const destDir = resolve74(proofDir(resolved.assignmentDir), subdir);
|
|
30442
|
+
if (resolvedSource) await mkdir11(destDir, { recursive: true });
|
|
30123
30443
|
const ext = resolvedSource ? extensionForKind(kind) : null;
|
|
30124
30444
|
let id = null;
|
|
30125
30445
|
let relativeFilePath = null;
|
|
@@ -30127,7 +30447,7 @@ async function captureCommand(target, options = {}) {
|
|
|
30127
30447
|
let lastErr = null;
|
|
30128
30448
|
for (let attempt = 0; attempt < MAX_ID_RETRIES; attempt += 1) {
|
|
30129
30449
|
const candidate = generateArtifactId();
|
|
30130
|
-
const candidateAbsPath = resolvedSource && ext ?
|
|
30450
|
+
const candidateAbsPath = resolvedSource && ext ? resolve74(destDir, `${candidate}.${ext}`) : null;
|
|
30131
30451
|
const candidateRel = candidateAbsPath ? relative4(resolved.assignmentDir, candidateAbsPath) : null;
|
|
30132
30452
|
try {
|
|
30133
30453
|
insertArtifact({
|
|
@@ -30171,7 +30491,7 @@ async function captureCommand(target, options = {}) {
|
|
|
30171
30491
|
}
|
|
30172
30492
|
}
|
|
30173
30493
|
if (options.transcribe && kind === "video" && absPath && id) {
|
|
30174
|
-
const sidecarPath2 =
|
|
30494
|
+
const sidecarPath2 = resolve74(destDir, `${id}.transcript.md`);
|
|
30175
30495
|
if (existsSync6(sidecarPath2)) {
|
|
30176
30496
|
console.warn(
|
|
30177
30497
|
`transcript: ${sidecarPath2} already exists, skipping (delete to re-transcribe)`
|
|
@@ -30203,7 +30523,7 @@ async function captureCommand(target, options = {}) {
|
|
|
30203
30523
|
const tagSuffix = criterionIndex === null ? "untagged" : `criterion ${criterionIndex}`;
|
|
30204
30524
|
console.log(`Captured artifact ${id} (${kind}) for ${ref} \u2014 ${tagSuffix}.`);
|
|
30205
30525
|
if (relativeFilePath) {
|
|
30206
|
-
console.log(` file: ${
|
|
30526
|
+
console.log(` file: ${resolve74(resolved.assignmentDir, relativeFilePath)}`);
|
|
30207
30527
|
}
|
|
30208
30528
|
} catch (err2) {
|
|
30209
30529
|
if (options.stop && kind === "video" && shelloutCleanup && resolvedSource) {
|
|
@@ -30226,8 +30546,8 @@ async function captureCommand(target, options = {}) {
|
|
|
30226
30546
|
|
|
30227
30547
|
// src/commands/proof.ts
|
|
30228
30548
|
import { Command as Command6 } from "commander";
|
|
30229
|
-
import { readFile as
|
|
30230
|
-
import { resolve as
|
|
30549
|
+
import { readFile as readFile52, writeFile as writeFile16, rename as rename10, stat as stat10 } from "fs/promises";
|
|
30550
|
+
import { resolve as resolve75, relative as relative5, isAbsolute as isAbsolute12, dirname as dirname23 } from "path";
|
|
30231
30551
|
import { randomBytes as randomBytes4 } from "crypto";
|
|
30232
30552
|
|
|
30233
30553
|
// src/utils/acceptance-criteria-parse.ts
|
|
@@ -30467,11 +30787,11 @@ function renderProofHtml(params2, inlineFiles = /* @__PURE__ */ new Map(), trans
|
|
|
30467
30787
|
|
|
30468
30788
|
// src/commands/proof.ts
|
|
30469
30789
|
async function readAssignmentMeta(assignmentDir) {
|
|
30470
|
-
const path =
|
|
30790
|
+
const path = resolve75(assignmentDir, "assignment.md");
|
|
30471
30791
|
if (!await fileExists(path)) {
|
|
30472
30792
|
return { title: "", body: "" };
|
|
30473
30793
|
}
|
|
30474
|
-
const content = await
|
|
30794
|
+
const content = await readFile52(path, "utf-8");
|
|
30475
30795
|
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
30476
30796
|
let title = "";
|
|
30477
30797
|
if (fmMatch) {
|
|
@@ -30518,7 +30838,7 @@ async function loadInlineFiles(rows, assignmentDir) {
|
|
|
30518
30838
|
for (const r of rows) {
|
|
30519
30839
|
if (!r.file_path) continue;
|
|
30520
30840
|
if (r.kind !== "http" && r.kind !== "text") continue;
|
|
30521
|
-
const abs =
|
|
30841
|
+
const abs = resolve75(assignmentDir, r.file_path);
|
|
30522
30842
|
if (!isWithin(proofRoot, abs)) {
|
|
30523
30843
|
out.set(r.file_path, null);
|
|
30524
30844
|
continue;
|
|
@@ -30533,7 +30853,7 @@ async function loadInlineFiles(rows, assignmentDir) {
|
|
|
30533
30853
|
continue;
|
|
30534
30854
|
}
|
|
30535
30855
|
try {
|
|
30536
|
-
out.set(r.file_path, await
|
|
30856
|
+
out.set(r.file_path, await readFile52(abs, "utf-8"));
|
|
30537
30857
|
} catch {
|
|
30538
30858
|
out.set(r.file_path, null);
|
|
30539
30859
|
}
|
|
@@ -30545,14 +30865,14 @@ async function loadTranscriptSidecars(rows, assignmentDir) {
|
|
|
30545
30865
|
const proofRoot = proofDir(assignmentDir);
|
|
30546
30866
|
for (const r of rows) {
|
|
30547
30867
|
if (r.kind !== "video" || !r.file_path) continue;
|
|
30548
|
-
const videoAbs =
|
|
30549
|
-
const sidecar =
|
|
30868
|
+
const videoAbs = resolve75(assignmentDir, r.file_path);
|
|
30869
|
+
const sidecar = resolve75(dirname23(videoAbs), `${r.id}.transcript.md`);
|
|
30550
30870
|
if (!isWithin(proofRoot, sidecar)) continue;
|
|
30551
30871
|
if (!await fileExists(sidecar)) continue;
|
|
30552
30872
|
const st = await stat10(sidecar);
|
|
30553
30873
|
if (st.size > INLINE_TEXT_LIMIT_BYTES) continue;
|
|
30554
30874
|
try {
|
|
30555
|
-
out.set(r.id, await
|
|
30875
|
+
out.set(r.id, await readFile52(sidecar, "utf-8"));
|
|
30556
30876
|
} catch {
|
|
30557
30877
|
}
|
|
30558
30878
|
}
|
|
@@ -30586,8 +30906,8 @@ async function proofBuildCommand(target, options = {}) {
|
|
|
30586
30906
|
};
|
|
30587
30907
|
const md = renderProofMarkdown(renderParams);
|
|
30588
30908
|
const html = renderProofHtml(renderParams, inlineFiles, transcriptSidecars);
|
|
30589
|
-
const mdPath =
|
|
30590
|
-
const htmlPath =
|
|
30909
|
+
const mdPath = resolve75(resolved.assignmentDir, "proof.md");
|
|
30910
|
+
const htmlPath = resolve75(resolved.assignmentDir, "proof.html");
|
|
30591
30911
|
await atomicWrite(mdPath, md);
|
|
30592
30912
|
await atomicWrite(htmlPath, html);
|
|
30593
30913
|
console.log(`Wrote ${htmlPath}`);
|
|
@@ -31252,7 +31572,7 @@ async function runCcusage(opts = {}) {
|
|
|
31252
31572
|
};
|
|
31253
31573
|
}
|
|
31254
31574
|
function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
|
|
31255
|
-
return new Promise((
|
|
31575
|
+
return new Promise((resolve87) => {
|
|
31256
31576
|
const child = spawn11(binary, args, {
|
|
31257
31577
|
env: env ?? process.env,
|
|
31258
31578
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -31266,7 +31586,7 @@ function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
|
|
|
31266
31586
|
if (settled) return;
|
|
31267
31587
|
settled = true;
|
|
31268
31588
|
clearTimeout(timer2);
|
|
31269
|
-
|
|
31589
|
+
resolve87(result);
|
|
31270
31590
|
};
|
|
31271
31591
|
const timer2 = setTimeout(() => {
|
|
31272
31592
|
timedOut = true;
|
|
@@ -31310,8 +31630,8 @@ function isoToCcusageDate(iso) {
|
|
|
31310
31630
|
|
|
31311
31631
|
// src/usage/cwd-extractor.ts
|
|
31312
31632
|
init_paths();
|
|
31313
|
-
import { open as open4, readdir as
|
|
31314
|
-
import { join as
|
|
31633
|
+
import { open as open4, readdir as readdir26, stat as stat11 } from "fs/promises";
|
|
31634
|
+
import { join as join19 } from "path";
|
|
31315
31635
|
import { homedir as homedir12 } from "os";
|
|
31316
31636
|
var SCAN_LINE_CAP = 50;
|
|
31317
31637
|
var TAIL_READ_BYTES = 8 * 1024;
|
|
@@ -31386,12 +31706,12 @@ async function* walkClaudeProjects(opts = {}) {
|
|
|
31386
31706
|
const dirs = await listDirSafe(root);
|
|
31387
31707
|
for (const dirent of dirs) {
|
|
31388
31708
|
if (!dirent.isDirectory) continue;
|
|
31389
|
-
const dirPath =
|
|
31709
|
+
const dirPath = join19(root, dirent.name);
|
|
31390
31710
|
const files = await listDirSafe(dirPath);
|
|
31391
31711
|
let cachedCwd = null;
|
|
31392
31712
|
for (const f of files) {
|
|
31393
31713
|
if (!f.isFile || !f.name.endsWith(".jsonl")) continue;
|
|
31394
|
-
const filePath =
|
|
31714
|
+
const filePath = join19(dirPath, f.name);
|
|
31395
31715
|
if (opts.sinceMtimeMs !== void 0) {
|
|
31396
31716
|
const mtime = await mtimeMs(filePath);
|
|
31397
31717
|
if (mtime !== null && mtime < opts.sinceMtimeMs) continue;
|
|
@@ -31428,12 +31748,12 @@ function resolveCodexSessionsRoot(override) {
|
|
|
31428
31748
|
const fromSessionsEnv = process.env.CODEX_SESSIONS_DIR;
|
|
31429
31749
|
if (fromSessionsEnv && fromSessionsEnv.length > 0) return expandHome(fromSessionsEnv);
|
|
31430
31750
|
const fromHomeEnv = process.env.CODEX_HOME;
|
|
31431
|
-
if (fromHomeEnv && fromHomeEnv.length > 0) return
|
|
31432
|
-
return
|
|
31751
|
+
if (fromHomeEnv && fromHomeEnv.length > 0) return join19(expandHome(fromHomeEnv), "sessions");
|
|
31752
|
+
return join19(homedir12(), ".codex", "sessions");
|
|
31433
31753
|
}
|
|
31434
31754
|
async function listDirSafe(path) {
|
|
31435
31755
|
try {
|
|
31436
|
-
const entries = await
|
|
31756
|
+
const entries = await readdir26(path, { withFileTypes: true });
|
|
31437
31757
|
return entries.map((e) => ({
|
|
31438
31758
|
name: e.name,
|
|
31439
31759
|
isFile: e.isFile(),
|
|
@@ -31449,7 +31769,7 @@ async function* walkJsonlRecursive(root) {
|
|
|
31449
31769
|
const current = stack.pop();
|
|
31450
31770
|
const entries = await listDirSafe(current);
|
|
31451
31771
|
for (const e of entries) {
|
|
31452
|
-
const full =
|
|
31772
|
+
const full = join19(current, e.name);
|
|
31453
31773
|
if (e.isDirectory) {
|
|
31454
31774
|
stack.push(full);
|
|
31455
31775
|
} else if (e.isFile && e.name.endsWith(".jsonl")) {
|
|
@@ -31788,8 +32108,8 @@ init_slug();
|
|
|
31788
32108
|
init_timestamp();
|
|
31789
32109
|
init_assignment_resolver();
|
|
31790
32110
|
init_assignment_todos();
|
|
31791
|
-
import { resolve as
|
|
31792
|
-
import { readFile as
|
|
32111
|
+
import { resolve as resolve76 } from "path";
|
|
32112
|
+
import { readFile as readFile53 } from "fs/promises";
|
|
31793
32113
|
async function requestCommand(target, text, options = {}) {
|
|
31794
32114
|
if (!text || !text.trim()) {
|
|
31795
32115
|
throw new Error("Request text cannot be empty.");
|
|
@@ -31805,7 +32125,7 @@ async function requestCommand(target, text, options = {}) {
|
|
|
31805
32125
|
if (!isValidSlug(target)) {
|
|
31806
32126
|
throw new Error(`Invalid assignment slug "${target}".`);
|
|
31807
32127
|
}
|
|
31808
|
-
assignmentDir =
|
|
32128
|
+
assignmentDir = resolve76(baseDir, options.project, "assignments", target);
|
|
31809
32129
|
targetRef = target;
|
|
31810
32130
|
} else {
|
|
31811
32131
|
const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
|
|
@@ -31815,12 +32135,12 @@ async function requestCommand(target, text, options = {}) {
|
|
|
31815
32135
|
assignmentDir = resolved.assignmentDir;
|
|
31816
32136
|
targetRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
|
|
31817
32137
|
}
|
|
31818
|
-
const assignmentMdPath2 =
|
|
32138
|
+
const assignmentMdPath2 = resolve76(assignmentDir, "assignment.md");
|
|
31819
32139
|
if (!await fileExists(assignmentMdPath2)) {
|
|
31820
32140
|
throw new Error(`assignment.md not found at ${assignmentMdPath2}`);
|
|
31821
32141
|
}
|
|
31822
32142
|
const source = options.from ?? process.env.SYNTAUR_ASSIGNMENT ?? "unknown";
|
|
31823
|
-
let content = await
|
|
32143
|
+
let content = await readFile53(assignmentMdPath2, "utf-8");
|
|
31824
32144
|
content = appendTodosToAssignmentBody(content, [
|
|
31825
32145
|
{ description: `${text.trim()} (from: ${source})` }
|
|
31826
32146
|
]);
|
|
@@ -31834,13 +32154,13 @@ init_fs();
|
|
|
31834
32154
|
init_paths();
|
|
31835
32155
|
init_config2();
|
|
31836
32156
|
import { Command as Command9 } from "commander";
|
|
31837
|
-
import { readFile as
|
|
31838
|
-
import { resolve as
|
|
32157
|
+
import { readFile as readFile54, readdir as readdir27 } from "fs/promises";
|
|
32158
|
+
import { resolve as resolve77 } from "path";
|
|
31839
32159
|
async function readContextAssignmentDir(cwd) {
|
|
31840
|
-
const path =
|
|
32160
|
+
const path = resolve77(cwd, ".syntaur", "context.json");
|
|
31841
32161
|
if (!await fileExists(path)) return null;
|
|
31842
32162
|
try {
|
|
31843
|
-
const raw2 = await
|
|
32163
|
+
const raw2 = await readFile54(path, "utf-8");
|
|
31844
32164
|
const ctx = JSON.parse(raw2);
|
|
31845
32165
|
if (typeof ctx.assignmentDir === "string" && ctx.assignmentDir.length > 0) {
|
|
31846
32166
|
return ctx.assignmentDir;
|
|
@@ -31854,9 +32174,9 @@ async function resolveAssignmentDir(opts) {
|
|
|
31854
32174
|
const cwd = opts.cwd ?? process.cwd();
|
|
31855
32175
|
if (opts.assignment) {
|
|
31856
32176
|
if (opts.project) {
|
|
31857
|
-
return
|
|
32177
|
+
return resolve77((await readConfig()).defaultProjectDir, opts.project, "assignments", opts.assignment);
|
|
31858
32178
|
}
|
|
31859
|
-
return
|
|
32179
|
+
return resolve77(assignmentsDir(), opts.assignment);
|
|
31860
32180
|
}
|
|
31861
32181
|
const fromCtx = await readContextAssignmentDir(cwd);
|
|
31862
32182
|
if (fromCtx) return fromCtx;
|
|
@@ -31867,7 +32187,7 @@ async function resolveAssignmentDir(opts) {
|
|
|
31867
32187
|
var PLAN_PATTERN = /^plan(?:-v(\d+))?\.md$/;
|
|
31868
32188
|
async function listPlanFiles(assignmentDir) {
|
|
31869
32189
|
if (!await fileExists(assignmentDir)) return [];
|
|
31870
|
-
const entries = await
|
|
32190
|
+
const entries = await readdir27(assignmentDir, { withFileTypes: true });
|
|
31871
32191
|
const out = [];
|
|
31872
32192
|
for (const e of entries) {
|
|
31873
32193
|
if (!e.isFile()) continue;
|
|
@@ -32052,17 +32372,17 @@ async function runPlanCreate(options) {
|
|
|
32052
32372
|
if (!await fileExists(assignmentDir)) {
|
|
32053
32373
|
throw new Error(`Assignment directory does not exist: ${assignmentDir}`);
|
|
32054
32374
|
}
|
|
32055
|
-
const assignmentMdPath2 =
|
|
32375
|
+
const assignmentMdPath2 = resolve77(assignmentDir, "assignment.md");
|
|
32056
32376
|
if (!await fileExists(assignmentMdPath2)) {
|
|
32057
32377
|
throw new Error(`Missing assignment.md at: ${assignmentMdPath2}`);
|
|
32058
32378
|
}
|
|
32059
|
-
const planPath =
|
|
32379
|
+
const planPath = resolve77(assignmentDir, "plan.md");
|
|
32060
32380
|
if (await fileExists(planPath) && !options.force) {
|
|
32061
32381
|
throw new Error(
|
|
32062
32382
|
"plan.md already exists. Use --force to overwrite, or `syntaur plan version` to create the next version."
|
|
32063
32383
|
);
|
|
32064
32384
|
}
|
|
32065
|
-
const assignmentMd = await
|
|
32385
|
+
const assignmentMd = await readFile54(assignmentMdPath2, "utf-8");
|
|
32066
32386
|
const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
|
|
32067
32387
|
const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
|
|
32068
32388
|
await writeFileForce(planPath, buildInitialPlanStub(slug));
|
|
@@ -32082,7 +32402,7 @@ async function runPlanVersion(options) {
|
|
|
32082
32402
|
if (!await fileExists(assignmentDir)) {
|
|
32083
32403
|
throw new Error(`Assignment directory does not exist: ${assignmentDir}`);
|
|
32084
32404
|
}
|
|
32085
|
-
const assignmentMdPath2 =
|
|
32405
|
+
const assignmentMdPath2 = resolve77(assignmentDir, "assignment.md");
|
|
32086
32406
|
if (!await fileExists(assignmentMdPath2)) {
|
|
32087
32407
|
throw new Error(`Missing assignment.md at: ${assignmentMdPath2}`);
|
|
32088
32408
|
}
|
|
@@ -32094,15 +32414,15 @@ async function runPlanVersion(options) {
|
|
|
32094
32414
|
}
|
|
32095
32415
|
const current = planFiles[planFiles.length - 1];
|
|
32096
32416
|
const next = nextPlanFileName(current.version);
|
|
32097
|
-
const newPath =
|
|
32417
|
+
const newPath = resolve77(assignmentDir, next.fileName);
|
|
32098
32418
|
if (await fileExists(newPath) && !options.force) {
|
|
32099
32419
|
throw new Error(`${next.fileName} already exists. Use --force to overwrite.`);
|
|
32100
32420
|
}
|
|
32101
|
-
const assignmentMd = await
|
|
32421
|
+
const assignmentMd = await readFile54(assignmentMdPath2, "utf-8");
|
|
32102
32422
|
const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
|
|
32103
32423
|
const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
|
|
32104
|
-
const oldPlanPath =
|
|
32105
|
-
const oldPlanContent = await
|
|
32424
|
+
const oldPlanPath = resolve77(assignmentDir, current.fileName);
|
|
32425
|
+
const oldPlanContent = await readFile54(oldPlanPath, "utf-8");
|
|
32106
32426
|
const oldBody = oldPlanContent.replace(/^---[\s\S]*?\n---\n?/, "");
|
|
32107
32427
|
const carriedTodos = extractUncheckedTodos(oldBody);
|
|
32108
32428
|
const stub = buildNewPlanStub({
|
|
@@ -32150,26 +32470,26 @@ init_paths();
|
|
|
32150
32470
|
init_config2();
|
|
32151
32471
|
init_timestamp();
|
|
32152
32472
|
import { Command as Command10 } from "commander";
|
|
32153
|
-
import { readFile as
|
|
32154
|
-
import { resolve as
|
|
32473
|
+
import { readFile as readFile55, readdir as readdir28, stat as stat12 } from "fs/promises";
|
|
32474
|
+
import { resolve as resolve78 } from "path";
|
|
32155
32475
|
async function readContext(cwd) {
|
|
32156
|
-
const path =
|
|
32476
|
+
const path = resolve78(cwd, ".syntaur", "context.json");
|
|
32157
32477
|
if (!await fileExists(path)) return null;
|
|
32158
32478
|
try {
|
|
32159
|
-
const raw2 = await
|
|
32479
|
+
const raw2 = await readFile55(path, "utf-8");
|
|
32160
32480
|
return JSON.parse(raw2);
|
|
32161
32481
|
} catch {
|
|
32162
32482
|
return null;
|
|
32163
32483
|
}
|
|
32164
32484
|
}
|
|
32165
32485
|
async function findLatestSessionSummary(assignmentDir) {
|
|
32166
|
-
const sessionsRoot =
|
|
32486
|
+
const sessionsRoot = resolve78(assignmentDir, "sessions");
|
|
32167
32487
|
if (!await fileExists(sessionsRoot)) return null;
|
|
32168
|
-
const entries = await
|
|
32488
|
+
const entries = await readdir28(sessionsRoot, { withFileTypes: true });
|
|
32169
32489
|
let best = null;
|
|
32170
32490
|
for (const entry of entries) {
|
|
32171
32491
|
if (!entry.isDirectory()) continue;
|
|
32172
|
-
const summaryPath =
|
|
32492
|
+
const summaryPath = resolve78(sessionsRoot, entry.name, "summary.md");
|
|
32173
32493
|
if (!await fileExists(summaryPath)) continue;
|
|
32174
32494
|
const st = await stat12(summaryPath);
|
|
32175
32495
|
if (best === null || st.mtime.getTime() > best.mtime.getTime()) {
|
|
@@ -32179,9 +32499,9 @@ async function findLatestSessionSummary(assignmentDir) {
|
|
|
32179
32499
|
return best;
|
|
32180
32500
|
}
|
|
32181
32501
|
async function findOpenHandoff(assignmentDir) {
|
|
32182
|
-
const handoffPath =
|
|
32502
|
+
const handoffPath = resolve78(assignmentDir, "handoff.md");
|
|
32183
32503
|
if (!await fileExists(handoffPath)) return null;
|
|
32184
|
-
const content = await
|
|
32504
|
+
const content = await readFile55(handoffPath, "utf-8");
|
|
32185
32505
|
const body = content.replace(/^---[\s\S]*?\n---\n?/, "").trim();
|
|
32186
32506
|
if (body.length === 0) return null;
|
|
32187
32507
|
if (/^<!--[\s\S]*-->$/.test(body)) return null;
|
|
@@ -32276,7 +32596,7 @@ async function resolveSaveTarget(options, cwd) {
|
|
|
32276
32596
|
let slug;
|
|
32277
32597
|
const ctx = await readContext(cwd);
|
|
32278
32598
|
if (options.assignment) {
|
|
32279
|
-
assignmentDir = options.project ?
|
|
32599
|
+
assignmentDir = options.project ? resolve78((await readConfig()).defaultProjectDir, options.project, "assignments", options.assignment) : resolve78(assignmentsDir(), options.assignment);
|
|
32280
32600
|
slug = options.assignment;
|
|
32281
32601
|
} else {
|
|
32282
32602
|
if (!ctx?.assignmentDir) {
|
|
@@ -32329,21 +32649,21 @@ function extractCreated(content) {
|
|
|
32329
32649
|
}
|
|
32330
32650
|
async function runSessionSave(options, cwd = process.cwd(), body) {
|
|
32331
32651
|
const { assignmentDir, slug, sessionId } = await resolveSaveTarget(options, cwd);
|
|
32332
|
-
if (!await fileExists(
|
|
32652
|
+
if (!await fileExists(resolve78(assignmentDir, "assignment.md"))) {
|
|
32333
32653
|
throw new Error(`No assignment found at ${assignmentDir} (missing assignment.md).`);
|
|
32334
32654
|
}
|
|
32335
|
-
const sessionDir =
|
|
32336
|
-
const summaryPath =
|
|
32655
|
+
const sessionDir = resolve78(assignmentDir, "sessions", sessionId);
|
|
32656
|
+
const summaryPath = resolve78(sessionDir, "summary.md");
|
|
32337
32657
|
const now = nowTimestamp();
|
|
32338
32658
|
let created = now;
|
|
32339
32659
|
if (await fileExists(summaryPath)) {
|
|
32340
|
-
const existing = await
|
|
32660
|
+
const existing = await readFile55(summaryPath, "utf-8");
|
|
32341
32661
|
created = extractCreated(existing) ?? now;
|
|
32342
32662
|
}
|
|
32343
32663
|
let sectionBody = body;
|
|
32344
32664
|
if (sectionBody === void 0) {
|
|
32345
32665
|
if (options.fromFile) {
|
|
32346
|
-
sectionBody = await
|
|
32666
|
+
sectionBody = await readFile55(resolve78(cwd, options.fromFile), "utf-8");
|
|
32347
32667
|
} else {
|
|
32348
32668
|
sectionBody = await readStdin();
|
|
32349
32669
|
}
|
|
@@ -32391,13 +32711,13 @@ init_config2();
|
|
|
32391
32711
|
init_timestamp();
|
|
32392
32712
|
init_frontmatter();
|
|
32393
32713
|
import { Command as Command11 } from "commander";
|
|
32394
|
-
import { readFile as
|
|
32395
|
-
import { resolve as
|
|
32714
|
+
import { readFile as readFile56 } from "fs/promises";
|
|
32715
|
+
import { resolve as resolve79 } from "path";
|
|
32396
32716
|
async function readContext2(cwd) {
|
|
32397
|
-
const path =
|
|
32717
|
+
const path = resolve79(cwd, ".syntaur", "context.json");
|
|
32398
32718
|
if (!await fileExists(path)) return null;
|
|
32399
32719
|
try {
|
|
32400
|
-
return JSON.parse(await
|
|
32720
|
+
return JSON.parse(await readFile56(path, "utf-8"));
|
|
32401
32721
|
} catch {
|
|
32402
32722
|
return null;
|
|
32403
32723
|
}
|
|
@@ -32406,12 +32726,12 @@ async function resolveAssignmentPath2(opts) {
|
|
|
32406
32726
|
if (opts.assignment) {
|
|
32407
32727
|
if (opts.project) {
|
|
32408
32728
|
const projectsDir2 = (await readConfig()).defaultProjectDir;
|
|
32409
|
-
return
|
|
32729
|
+
return resolve79(projectsDir2, opts.project, "assignments", opts.assignment, "assignment.md");
|
|
32410
32730
|
}
|
|
32411
|
-
return
|
|
32731
|
+
return resolve79(assignmentsDir(), opts.assignment, "assignment.md");
|
|
32412
32732
|
}
|
|
32413
32733
|
const ctx = await readContext2(opts.cwd);
|
|
32414
|
-
if (ctx?.assignmentDir) return
|
|
32734
|
+
if (ctx?.assignmentDir) return resolve79(ctx.assignmentDir, "assignment.md");
|
|
32415
32735
|
throw new Error(
|
|
32416
32736
|
"No active assignment. Pass --assignment <slug> [--project <slug>] or run from a workspace with .syntaur/context.json."
|
|
32417
32737
|
);
|
|
@@ -32422,7 +32742,7 @@ async function runWorktreeCreate(options, cwd = process.cwd()) {
|
|
|
32422
32742
|
}
|
|
32423
32743
|
const repository = options.repository ?? cwd;
|
|
32424
32744
|
const parentBranch = options.parentBranch ?? "main";
|
|
32425
|
-
const worktreePath = options.worktreePath ??
|
|
32745
|
+
const worktreePath = options.worktreePath ?? resolve79(repository, ".worktrees", options.branch);
|
|
32426
32746
|
const assignmentPath = await resolveAssignmentPath2({
|
|
32427
32747
|
assignment: options.assignment,
|
|
32428
32748
|
project: options.project,
|
|
@@ -32452,7 +32772,7 @@ async function runWorktreeRemove(options, cwd = process.cwd()) {
|
|
|
32452
32772
|
if (!await fileExists(assignmentPath)) {
|
|
32453
32773
|
throw new Error(`Assignment file not found: ${assignmentPath}`);
|
|
32454
32774
|
}
|
|
32455
|
-
const original = await
|
|
32775
|
+
const original = await readFile56(assignmentPath, "utf-8");
|
|
32456
32776
|
const fm = parseAssignmentFrontmatter(original);
|
|
32457
32777
|
const repository = options.repository ?? fm.workspace.repository ?? void 0;
|
|
32458
32778
|
const worktreePath = fm.workspace.worktreePath ?? void 0;
|
|
@@ -32551,14 +32871,14 @@ init_config2();
|
|
|
32551
32871
|
init_fs();
|
|
32552
32872
|
init_slug();
|
|
32553
32873
|
import { Command as Command12 } from "commander";
|
|
32554
|
-
import { resolve as
|
|
32555
|
-
import { readFile as
|
|
32874
|
+
import { resolve as resolve81 } from "path";
|
|
32875
|
+
import { readFile as readFile58, readdir as readdir30, rm as rm14 } from "fs/promises";
|
|
32556
32876
|
|
|
32557
32877
|
// src/utils/project-indexes.ts
|
|
32558
32878
|
init_parser();
|
|
32559
32879
|
init_fs();
|
|
32560
|
-
import { readdir as
|
|
32561
|
-
import { resolve as
|
|
32880
|
+
import { readdir as readdir29, readFile as readFile57 } from "fs/promises";
|
|
32881
|
+
import { resolve as resolve80 } from "path";
|
|
32562
32882
|
function nowIso3() {
|
|
32563
32883
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
32564
32884
|
}
|
|
@@ -32567,7 +32887,7 @@ function readProjectSlug(projectDir) {
|
|
|
32567
32887
|
}
|
|
32568
32888
|
async function listSlugFiles(dir) {
|
|
32569
32889
|
if (!await fileExists(dir)) return [];
|
|
32570
|
-
const entries = await
|
|
32890
|
+
const entries = await readdir29(dir, { withFileTypes: true });
|
|
32571
32891
|
return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && !e.name.startsWith("_")).map((e) => e.name).sort();
|
|
32572
32892
|
}
|
|
32573
32893
|
function escapeCell(value) {
|
|
@@ -32577,7 +32897,7 @@ function joinList(items) {
|
|
|
32577
32897
|
return items.length === 0 ? "\u2014" : items.map(escapeCell).join(", ");
|
|
32578
32898
|
}
|
|
32579
32899
|
async function rebuildResourcesIndex(projectDir) {
|
|
32580
|
-
const dir =
|
|
32900
|
+
const dir = resolve80(projectDir, "resources");
|
|
32581
32901
|
await ensureDir(dir);
|
|
32582
32902
|
const files = await listSlugFiles(dir);
|
|
32583
32903
|
const slug = readProjectSlug(projectDir);
|
|
@@ -32593,7 +32913,7 @@ async function rebuildResourcesIndex(projectDir) {
|
|
|
32593
32913
|
lines.push("| Name | Category | Source | Related Assignments | Updated |");
|
|
32594
32914
|
lines.push("|------|----------|--------|---------------------|---------|");
|
|
32595
32915
|
for (const fileName of files) {
|
|
32596
|
-
const content = await
|
|
32916
|
+
const content = await readFile57(resolve80(dir, fileName), "utf-8");
|
|
32597
32917
|
const parsed = parseResource(content);
|
|
32598
32918
|
const slugBase = fileName.replace(/\.md$/, "");
|
|
32599
32919
|
const name = parsed.name || slugBase;
|
|
@@ -32603,12 +32923,12 @@ async function rebuildResourcesIndex(projectDir) {
|
|
|
32603
32923
|
);
|
|
32604
32924
|
}
|
|
32605
32925
|
lines.push("");
|
|
32606
|
-
const indexPath =
|
|
32926
|
+
const indexPath = resolve80(dir, "_index.md");
|
|
32607
32927
|
await writeFileForce(indexPath, lines.join("\n"));
|
|
32608
32928
|
return { total: files.length, path: indexPath };
|
|
32609
32929
|
}
|
|
32610
32930
|
async function rebuildMemoriesIndex(projectDir) {
|
|
32611
|
-
const dir =
|
|
32931
|
+
const dir = resolve80(projectDir, "memories");
|
|
32612
32932
|
await ensureDir(dir);
|
|
32613
32933
|
const files = await listSlugFiles(dir);
|
|
32614
32934
|
const slug = readProjectSlug(projectDir);
|
|
@@ -32624,7 +32944,7 @@ async function rebuildMemoriesIndex(projectDir) {
|
|
|
32624
32944
|
lines.push("| Name | Source | Scope | Source Assignment | Updated |");
|
|
32625
32945
|
lines.push("|------|--------|-------|-------------------|---------|");
|
|
32626
32946
|
for (const fileName of files) {
|
|
32627
|
-
const content = await
|
|
32947
|
+
const content = await readFile57(resolve80(dir, fileName), "utf-8");
|
|
32628
32948
|
const parsed = parseMemory(content);
|
|
32629
32949
|
const slugBase = fileName.replace(/\.md$/, "");
|
|
32630
32950
|
const name = parsed.name || slugBase;
|
|
@@ -32634,7 +32954,7 @@ async function rebuildMemoriesIndex(projectDir) {
|
|
|
32634
32954
|
);
|
|
32635
32955
|
}
|
|
32636
32956
|
lines.push("");
|
|
32637
|
-
const indexPath =
|
|
32957
|
+
const indexPath = resolve80(dir, "_index.md");
|
|
32638
32958
|
await writeFileForce(indexPath, lines.join("\n"));
|
|
32639
32959
|
return { total: files.length, path: indexPath };
|
|
32640
32960
|
}
|
|
@@ -32698,8 +33018,8 @@ ${opts.body ?? "<!-- Add notes about this resource here. -->"}
|
|
|
32698
33018
|
}
|
|
32699
33019
|
async function resolveProjectDir(project) {
|
|
32700
33020
|
if (!isValidSlug(project)) throw new Error(`Invalid project slug: "${project}".`);
|
|
32701
|
-
const projectDir =
|
|
32702
|
-
if (!await fileExists(
|
|
33021
|
+
const projectDir = resolve81((await readConfig()).defaultProjectDir, project);
|
|
33022
|
+
if (!await fileExists(resolve81(projectDir, "project.md"))) {
|
|
32703
33023
|
throw new Error(`Project "${project}" not found at ${projectDir}.`);
|
|
32704
33024
|
}
|
|
32705
33025
|
return projectDir;
|
|
@@ -32712,7 +33032,7 @@ async function runResourceAdd(options) {
|
|
|
32712
33032
|
if (!isValidSlug(slug)) {
|
|
32713
33033
|
throw new Error(`Invalid resource slug: "${slug}".`);
|
|
32714
33034
|
}
|
|
32715
|
-
const filePath =
|
|
33035
|
+
const filePath = resolve81(projectDir, "resources", `${slug}.md`);
|
|
32716
33036
|
if (await fileExists(filePath) && !options.force) {
|
|
32717
33037
|
throw new Error(
|
|
32718
33038
|
`Resource "${slug}" already exists at ${filePath}. Use --force to overwrite.`
|
|
@@ -32729,9 +33049,9 @@ async function runResourceAdd(options) {
|
|
|
32729
33049
|
return { filePath, indexPath, total };
|
|
32730
33050
|
}
|
|
32731
33051
|
async function listResourceSlugs(projectDir) {
|
|
32732
|
-
const dir =
|
|
33052
|
+
const dir = resolve81(projectDir, "resources");
|
|
32733
33053
|
if (!await fileExists(dir)) return [];
|
|
32734
|
-
const entries = await
|
|
33054
|
+
const entries = await readdir30(dir, { withFileTypes: true });
|
|
32735
33055
|
return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_index.md").map((e) => e.name.slice(0, -3)).sort();
|
|
32736
33056
|
}
|
|
32737
33057
|
async function runResourceList(project) {
|
|
@@ -32739,16 +33059,16 @@ async function runResourceList(project) {
|
|
|
32739
33059
|
const slugs = await listResourceSlugs(projectDir);
|
|
32740
33060
|
const out = [];
|
|
32741
33061
|
for (const slug of slugs) {
|
|
32742
|
-
const parsed = parseResource(await
|
|
33062
|
+
const parsed = parseResource(await readFile58(resolve81(projectDir, "resources", `${slug}.md`), "utf-8"));
|
|
32743
33063
|
out.push({ slug, name: parsed.name, category: parsed.category, source: parsed.source, updated: parsed.updated });
|
|
32744
33064
|
}
|
|
32745
33065
|
return out;
|
|
32746
33066
|
}
|
|
32747
33067
|
async function runResourceShow(project, slug) {
|
|
32748
33068
|
const projectDir = await resolveProjectDir(project);
|
|
32749
|
-
const filePath =
|
|
33069
|
+
const filePath = resolve81(projectDir, "resources", `${slug}.md`);
|
|
32750
33070
|
if (!await fileExists(filePath)) throw new Error(`Resource "${slug}" not found in project "${project}".`);
|
|
32751
|
-
const parsed = parseResource(await
|
|
33071
|
+
const parsed = parseResource(await readFile58(filePath, "utf-8"));
|
|
32752
33072
|
return {
|
|
32753
33073
|
slug,
|
|
32754
33074
|
name: parsed.name,
|
|
@@ -32762,14 +33082,14 @@ async function runResourceShow(project, slug) {
|
|
|
32762
33082
|
}
|
|
32763
33083
|
async function runResourceUpdate(slug, options) {
|
|
32764
33084
|
const projectDir = await resolveProjectDir(options.project);
|
|
32765
|
-
const filePath =
|
|
33085
|
+
const filePath = resolve81(projectDir, "resources", `${slug}.md`);
|
|
32766
33086
|
if (!await fileExists(filePath)) {
|
|
32767
33087
|
throw new Error(`Resource "${slug}" not found in project "${options.project}".`);
|
|
32768
33088
|
}
|
|
32769
33089
|
if (options.name === void 0 && options.source === void 0 && options.category === void 0 && options.relatedAssignments === void 0) {
|
|
32770
33090
|
throw new Error("Provide at least one of --name, --source, --category, --related-assignments.");
|
|
32771
33091
|
}
|
|
32772
|
-
const original = await
|
|
33092
|
+
const original = await readFile58(filePath, "utf-8");
|
|
32773
33093
|
const content = editResourceFrontmatter(original, {
|
|
32774
33094
|
name: options.name,
|
|
32775
33095
|
category: options.category,
|
|
@@ -32782,7 +33102,7 @@ async function runResourceUpdate(slug, options) {
|
|
|
32782
33102
|
}
|
|
32783
33103
|
async function runResourceRemove(slug, options) {
|
|
32784
33104
|
const projectDir = await resolveProjectDir(options.project);
|
|
32785
|
-
const filePath =
|
|
33105
|
+
const filePath = resolve81(projectDir, "resources", `${slug}.md`);
|
|
32786
33106
|
if (!await fileExists(filePath)) {
|
|
32787
33107
|
throw new Error(`Resource "${slug}" not found in project "${options.project}".`);
|
|
32788
33108
|
}
|
|
@@ -32865,8 +33185,8 @@ init_config2();
|
|
|
32865
33185
|
init_fs();
|
|
32866
33186
|
init_slug();
|
|
32867
33187
|
import { Command as Command13 } from "commander";
|
|
32868
|
-
import { resolve as
|
|
32869
|
-
import { readFile as
|
|
33188
|
+
import { resolve as resolve82 } from "path";
|
|
33189
|
+
import { readFile as readFile59, readdir as readdir31, rm as rm15 } from "fs/promises";
|
|
32870
33190
|
init_parser();
|
|
32871
33191
|
function nowIso5() {
|
|
32872
33192
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
@@ -32930,8 +33250,8 @@ ${opts.body ?? "<!-- Capture the load-bearing context for this memory here. -->"
|
|
|
32930
33250
|
}
|
|
32931
33251
|
async function resolveProjectDir2(project) {
|
|
32932
33252
|
if (!isValidSlug(project)) throw new Error(`Invalid project slug: "${project}".`);
|
|
32933
|
-
const projectDir =
|
|
32934
|
-
if (!await fileExists(
|
|
33253
|
+
const projectDir = resolve82((await readConfig()).defaultProjectDir, project);
|
|
33254
|
+
if (!await fileExists(resolve82(projectDir, "project.md"))) {
|
|
32935
33255
|
throw new Error(`Project "${project}" not found at ${projectDir}.`);
|
|
32936
33256
|
}
|
|
32937
33257
|
return projectDir;
|
|
@@ -32944,7 +33264,7 @@ async function runMemoryAdd(options) {
|
|
|
32944
33264
|
if (!isValidSlug(slug)) {
|
|
32945
33265
|
throw new Error(`Invalid memory slug: "${slug}".`);
|
|
32946
33266
|
}
|
|
32947
|
-
const filePath =
|
|
33267
|
+
const filePath = resolve82(projectDir, "memories", `${slug}.md`);
|
|
32948
33268
|
if (await fileExists(filePath) && !options.force) {
|
|
32949
33269
|
throw new Error(
|
|
32950
33270
|
`Memory "${slug}" already exists at ${filePath}. Use --force to overwrite.`
|
|
@@ -32962,9 +33282,9 @@ async function runMemoryAdd(options) {
|
|
|
32962
33282
|
return { filePath, indexPath, total };
|
|
32963
33283
|
}
|
|
32964
33284
|
async function listMemorySlugs(projectDir) {
|
|
32965
|
-
const dir =
|
|
33285
|
+
const dir = resolve82(projectDir, "memories");
|
|
32966
33286
|
if (!await fileExists(dir)) return [];
|
|
32967
|
-
const entries = await
|
|
33287
|
+
const entries = await readdir31(dir, { withFileTypes: true });
|
|
32968
33288
|
return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_index.md").map((e) => e.name.slice(0, -3)).sort();
|
|
32969
33289
|
}
|
|
32970
33290
|
async function runMemoryList(project) {
|
|
@@ -32972,16 +33292,16 @@ async function runMemoryList(project) {
|
|
|
32972
33292
|
const slugs = await listMemorySlugs(projectDir);
|
|
32973
33293
|
const out = [];
|
|
32974
33294
|
for (const slug of slugs) {
|
|
32975
|
-
const parsed = parseMemory(await
|
|
33295
|
+
const parsed = parseMemory(await readFile59(resolve82(projectDir, "memories", `${slug}.md`), "utf-8"));
|
|
32976
33296
|
out.push({ slug, name: parsed.name, scope: parsed.scope, source: parsed.source, updated: parsed.updated });
|
|
32977
33297
|
}
|
|
32978
33298
|
return out;
|
|
32979
33299
|
}
|
|
32980
33300
|
async function runMemoryShow(project, slug) {
|
|
32981
33301
|
const projectDir = await resolveProjectDir2(project);
|
|
32982
|
-
const filePath =
|
|
33302
|
+
const filePath = resolve82(projectDir, "memories", `${slug}.md`);
|
|
32983
33303
|
if (!await fileExists(filePath)) throw new Error(`Memory "${slug}" not found in project "${project}".`);
|
|
32984
|
-
const parsed = parseMemory(await
|
|
33304
|
+
const parsed = parseMemory(await readFile59(filePath, "utf-8"));
|
|
32985
33305
|
return {
|
|
32986
33306
|
slug,
|
|
32987
33307
|
name: parsed.name,
|
|
@@ -32996,7 +33316,7 @@ async function runMemoryShow(project, slug) {
|
|
|
32996
33316
|
}
|
|
32997
33317
|
async function runMemoryUpdate(slug, options) {
|
|
32998
33318
|
const projectDir = await resolveProjectDir2(options.project);
|
|
32999
|
-
const filePath =
|
|
33319
|
+
const filePath = resolve82(projectDir, "memories", `${slug}.md`);
|
|
33000
33320
|
if (!await fileExists(filePath)) {
|
|
33001
33321
|
throw new Error(`Memory "${slug}" not found in project "${options.project}".`);
|
|
33002
33322
|
}
|
|
@@ -33005,7 +33325,7 @@ async function runMemoryUpdate(slug, options) {
|
|
|
33005
33325
|
"Provide at least one of --name, --source, --scope, --source-assignment, --related-assignments."
|
|
33006
33326
|
);
|
|
33007
33327
|
}
|
|
33008
|
-
const original = await
|
|
33328
|
+
const original = await readFile59(filePath, "utf-8");
|
|
33009
33329
|
const content = editMemoryFrontmatter(original, {
|
|
33010
33330
|
name: options.name,
|
|
33011
33331
|
source: options.source,
|
|
@@ -33019,7 +33339,7 @@ async function runMemoryUpdate(slug, options) {
|
|
|
33019
33339
|
}
|
|
33020
33340
|
async function runMemoryRemove(slug, options) {
|
|
33021
33341
|
const projectDir = await resolveProjectDir2(options.project);
|
|
33022
|
-
const filePath =
|
|
33342
|
+
const filePath = resolve82(projectDir, "memories", `${slug}.md`);
|
|
33023
33343
|
if (!await fileExists(filePath)) {
|
|
33024
33344
|
throw new Error(`Memory "${slug}" not found in project "${options.project}".`);
|
|
33025
33345
|
}
|
|
@@ -33104,8 +33424,8 @@ init_paths();
|
|
|
33104
33424
|
init_fs();
|
|
33105
33425
|
init_frontmatter();
|
|
33106
33426
|
import { Command as Command14 } from "commander";
|
|
33107
|
-
import { readFile as
|
|
33108
|
-
import { resolve as
|
|
33427
|
+
import { readFile as readFile60 } from "fs/promises";
|
|
33428
|
+
import { resolve as resolve83 } from "path";
|
|
33109
33429
|
var AGE_PATTERN = /^(\d+)([dhwm])$/i;
|
|
33110
33430
|
function parseAgeToCutoff(age) {
|
|
33111
33431
|
const match = age.match(AGE_PATTERN);
|
|
@@ -33124,7 +33444,7 @@ function parseAgeToCutoff(age) {
|
|
|
33124
33444
|
}
|
|
33125
33445
|
function assignmentMdPath(item) {
|
|
33126
33446
|
if (item.projectSlug) {
|
|
33127
|
-
return
|
|
33447
|
+
return resolve83(
|
|
33128
33448
|
defaultProjectDir(),
|
|
33129
33449
|
item.projectSlug,
|
|
33130
33450
|
"assignments",
|
|
@@ -33132,13 +33452,13 @@ function assignmentMdPath(item) {
|
|
|
33132
33452
|
"assignment.md"
|
|
33133
33453
|
);
|
|
33134
33454
|
}
|
|
33135
|
-
return
|
|
33455
|
+
return resolve83(assignmentsDir(), item.id, "assignment.md");
|
|
33136
33456
|
}
|
|
33137
33457
|
async function loadTags(item) {
|
|
33138
33458
|
const path = assignmentMdPath(item);
|
|
33139
33459
|
if (!await fileExists(path)) return [];
|
|
33140
33460
|
try {
|
|
33141
|
-
const content = await
|
|
33461
|
+
const content = await readFile60(path, "utf-8");
|
|
33142
33462
|
return parseAssignmentFrontmatter(content).tags;
|
|
33143
33463
|
} catch {
|
|
33144
33464
|
return [];
|
|
@@ -33567,8 +33887,8 @@ init_fs();
|
|
|
33567
33887
|
init_timestamp();
|
|
33568
33888
|
init_frontmatter();
|
|
33569
33889
|
import { Command as Command16 } from "commander";
|
|
33570
|
-
import { readFile as
|
|
33571
|
-
import { resolve as
|
|
33890
|
+
import { readFile as readFile61 } from "fs/promises";
|
|
33891
|
+
import { resolve as resolve84 } from "path";
|
|
33572
33892
|
async function scanDirs() {
|
|
33573
33893
|
const config = await readConfig();
|
|
33574
33894
|
return { projectsDir: config.defaultProjectDir, standaloneDir: assignmentsDir() };
|
|
@@ -33578,12 +33898,12 @@ function fail3(error) {
|
|
|
33578
33898
|
process.exit(1);
|
|
33579
33899
|
}
|
|
33580
33900
|
function configPath() {
|
|
33581
|
-
return
|
|
33901
|
+
return resolve84(syntaurRoot(), "config.md");
|
|
33582
33902
|
}
|
|
33583
33903
|
async function readStatusBlock() {
|
|
33584
33904
|
const p = configPath();
|
|
33585
33905
|
if (!await fileExists(p)) return null;
|
|
33586
|
-
const content = await
|
|
33906
|
+
const content = await readFile61(p, "utf-8");
|
|
33587
33907
|
return parseStatusConfig(content);
|
|
33588
33908
|
}
|
|
33589
33909
|
async function requireStatusBlock() {
|
|
@@ -33832,7 +34152,7 @@ async function runStatusRename(id, opts) {
|
|
|
33832
34152
|
printBlockDiff(before, after);
|
|
33833
34153
|
const now2 = nowTimestamp();
|
|
33834
34154
|
for (const a of affected) {
|
|
33835
|
-
const original = await
|
|
34155
|
+
const original = await readFile61(a.path, "utf-8");
|
|
33836
34156
|
const rewritten = updateAssignmentFile(original, { status: newId, updated: now2 });
|
|
33837
34157
|
console.log(`
|
|
33838
34158
|
--- ${a.display}/assignment.md`);
|
|
@@ -33843,9 +34163,9 @@ async function runStatusRename(id, opts) {
|
|
|
33843
34163
|
}
|
|
33844
34164
|
const cfgPath = configPath();
|
|
33845
34165
|
const buffers = /* @__PURE__ */ new Map();
|
|
33846
|
-
buffers.set(cfgPath, await fileExists(cfgPath) ? await
|
|
34166
|
+
buffers.set(cfgPath, await fileExists(cfgPath) ? await readFile61(cfgPath, "utf-8") : "");
|
|
33847
34167
|
for (const a of affected) {
|
|
33848
|
-
buffers.set(a.path, await
|
|
34168
|
+
buffers.set(a.path, await readFile61(a.path, "utf-8"));
|
|
33849
34169
|
}
|
|
33850
34170
|
const now = nowTimestamp();
|
|
33851
34171
|
try {
|
|
@@ -34025,13 +34345,13 @@ init_config2();
|
|
|
34025
34345
|
init_timestamp();
|
|
34026
34346
|
init_frontmatter();
|
|
34027
34347
|
import { Command as Command17 } from "commander";
|
|
34028
|
-
import { readFile as
|
|
34029
|
-
import { resolve as
|
|
34348
|
+
import { readFile as readFile62 } from "fs/promises";
|
|
34349
|
+
import { resolve as resolve85 } from "path";
|
|
34030
34350
|
async function readContext3(cwd) {
|
|
34031
|
-
const path =
|
|
34351
|
+
const path = resolve85(cwd, ".syntaur", "context.json");
|
|
34032
34352
|
if (!await fileExists(path)) return null;
|
|
34033
34353
|
try {
|
|
34034
|
-
return JSON.parse(await
|
|
34354
|
+
return JSON.parse(await readFile62(path, "utf-8"));
|
|
34035
34355
|
} catch {
|
|
34036
34356
|
return null;
|
|
34037
34357
|
}
|
|
@@ -34040,12 +34360,12 @@ async function resolveAssignmentPath3(opts) {
|
|
|
34040
34360
|
if (opts.assignment) {
|
|
34041
34361
|
if (opts.project) {
|
|
34042
34362
|
const projectsDir2 = (await readConfig()).defaultProjectDir;
|
|
34043
|
-
return
|
|
34363
|
+
return resolve85(projectsDir2, opts.project, "assignments", opts.assignment, "assignment.md");
|
|
34044
34364
|
}
|
|
34045
|
-
return
|
|
34365
|
+
return resolve85(assignmentsDir(), opts.assignment, "assignment.md");
|
|
34046
34366
|
}
|
|
34047
34367
|
const ctx = await readContext3(opts.cwd);
|
|
34048
|
-
if (ctx?.assignmentDir) return
|
|
34368
|
+
if (ctx?.assignmentDir) return resolve85(ctx.assignmentDir, "assignment.md");
|
|
34049
34369
|
throw new Error(
|
|
34050
34370
|
"No active assignment. Pass --assignment <slug> [--project <slug>] or run from a workspace with .syntaur/context.json."
|
|
34051
34371
|
);
|
|
@@ -34082,7 +34402,7 @@ async function runWorkspaceSet(options, cwd = process.cwd()) {
|
|
|
34082
34402
|
${pre.errors.map((e) => ` - ${e}`).join("\n")}`
|
|
34083
34403
|
);
|
|
34084
34404
|
}
|
|
34085
|
-
const original = await
|
|
34405
|
+
const original = await readFile62(path, "utf-8");
|
|
34086
34406
|
let next = updateAssignmentWorkspace(original, partial);
|
|
34087
34407
|
next = updateAssignmentFile(next, { updated: nowTimestamp() });
|
|
34088
34408
|
await writeFileForce(path, next);
|
|
@@ -34119,13 +34439,13 @@ init_config2();
|
|
|
34119
34439
|
init_timestamp();
|
|
34120
34440
|
init_templates();
|
|
34121
34441
|
import { Command as Command18 } from "commander";
|
|
34122
|
-
import { readFile as
|
|
34123
|
-
import { resolve as
|
|
34442
|
+
import { readFile as readFile63 } from "fs/promises";
|
|
34443
|
+
import { resolve as resolve86 } from "path";
|
|
34124
34444
|
async function readContext4(cwd) {
|
|
34125
|
-
const path =
|
|
34445
|
+
const path = resolve86(cwd, ".syntaur", "context.json");
|
|
34126
34446
|
if (!await fileExists(path)) return null;
|
|
34127
34447
|
try {
|
|
34128
|
-
return JSON.parse(await
|
|
34448
|
+
return JSON.parse(await readFile63(path, "utf-8"));
|
|
34129
34449
|
} catch {
|
|
34130
34450
|
return null;
|
|
34131
34451
|
}
|
|
@@ -34135,11 +34455,11 @@ async function resolveAssignmentDir2(opts) {
|
|
|
34135
34455
|
if (opts.project) {
|
|
34136
34456
|
const projectsDir2 = (await readConfig()).defaultProjectDir;
|
|
34137
34457
|
return {
|
|
34138
|
-
dir:
|
|
34458
|
+
dir: resolve86(projectsDir2, opts.project, "assignments", opts.assignment),
|
|
34139
34459
|
slug: opts.assignment
|
|
34140
34460
|
};
|
|
34141
34461
|
}
|
|
34142
|
-
return { dir:
|
|
34462
|
+
return { dir: resolve86(assignmentsDir(), opts.assignment), slug: opts.assignment };
|
|
34143
34463
|
}
|
|
34144
34464
|
const ctx = await readContext4(opts.cwd);
|
|
34145
34465
|
if (ctx?.assignmentDir) {
|
|
@@ -34201,12 +34521,12 @@ async function runProgressLog(text, options, cwd = process.cwd()) {
|
|
|
34201
34521
|
project: options.project,
|
|
34202
34522
|
cwd
|
|
34203
34523
|
});
|
|
34204
|
-
if (!await fileExists(
|
|
34524
|
+
if (!await fileExists(resolve86(dir, "assignment.md"))) {
|
|
34205
34525
|
throw new Error(`No assignment found at ${dir} (missing assignment.md).`);
|
|
34206
34526
|
}
|
|
34207
|
-
const path =
|
|
34527
|
+
const path = resolve86(dir, "progress.md");
|
|
34208
34528
|
const now = nowTimestamp();
|
|
34209
|
-
const content = await fileExists(path) ? await
|
|
34529
|
+
const content = await fileExists(path) ? await readFile63(path, "utf-8") : renderProgress({ assignment: slug, timestamp: now });
|
|
34210
34530
|
const next = appendProgressEntry(content, text, now);
|
|
34211
34531
|
await writeFileForce(path, next);
|
|
34212
34532
|
return path;
|
|
@@ -34226,10 +34546,10 @@ progressCommand.command("log").description("Append a timestamped entry to the as
|
|
|
34226
34546
|
|
|
34227
34547
|
// src/cli-default-command.ts
|
|
34228
34548
|
init_config2();
|
|
34229
|
-
import { readdir as
|
|
34549
|
+
import { readdir as readdir32 } from "fs/promises";
|
|
34230
34550
|
async function hasAnyProjectContent(projectsDir2) {
|
|
34231
34551
|
try {
|
|
34232
|
-
const entries = await
|
|
34552
|
+
const entries = await readdir32(projectsDir2, { withFileTypes: true });
|
|
34233
34553
|
return entries.some((entry) => entry.isDirectory());
|
|
34234
34554
|
} catch {
|
|
34235
34555
|
return false;
|
|
@@ -34531,7 +34851,7 @@ program.command("reopen").description("Reopen a completed or failed assignment")
|
|
|
34531
34851
|
process.exit(1);
|
|
34532
34852
|
}
|
|
34533
34853
|
});
|
|
34534
|
-
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
|
|
34854
|
+
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. Built-in ids: pi, hermes, openclaw, cursor, opencode (plus any user descriptors in ~/.syntaur/targets/). 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) => {
|
|
34535
34855
|
try {
|
|
34536
34856
|
await setupCommand(options);
|
|
34537
34857
|
} catch (error) {
|
|
@@ -34640,7 +34960,7 @@ program.command("uninstall").description("Remove Syntaur integrations and option
|
|
|
34640
34960
|
process.exit(1);
|
|
34641
34961
|
}
|
|
34642
34962
|
});
|
|
34643
|
-
program.command("setup-adapter").description("Generate adapter instruction files for a framework in the current directory").argument("<framework>", "Target framework
|
|
34963
|
+
program.command("setup-adapter").description("Generate adapter instruction files for a framework in the current directory").argument("<framework>", "Target framework: built-in ids cursor, codex, opencode, pi, openclaw, hermes (plus any user descriptor with an instructions adapter in ~/.syntaur/targets/)").option("--project <slug>", "Target project slug (required)").option("--assignment <slug>", "Target assignment slug (required)").option("--force", "Overwrite existing adapter files").option("--dir <path>", "Override default project directory").action(async (framework, options) => {
|
|
34644
34964
|
try {
|
|
34645
34965
|
await setupAdapterCommand(framework, options);
|
|
34646
34966
|
} catch (error) {
|