syntaur 0.62.0 → 0.65.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +20 -0
- package/dashboard/dist/assets/{_basePickBy-C0DmX-Lf.js → _basePickBy-CrrGp7iQ.js} +1 -1
- package/dashboard/dist/assets/{_baseUniq-B656N5Fp.js → _baseUniq-CR-L9Z4l.js} +1 -1
- package/dashboard/dist/assets/{arc-DWrED_i3.js → arc-Bplhanol.js} +1 -1
- package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-B7gQ_B6F.js → architectureDiagram-2XIMDMQ5-hcuAyqPz.js} +1 -1
- package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-CrqgprVY.js → blockDiagram-WCTKOSBZ-BkGOQX1p.js} +1 -1
- package/dashboard/dist/assets/{c4Diagram-IC4MRINW-B6JBjUpY.js → c4Diagram-IC4MRINW-CyhVhe9Z.js} +1 -1
- package/dashboard/dist/assets/channel-DKDXpYJX.js +1 -0
- package/dashboard/dist/assets/{chunk-4BX2VUAB-Co4Kcyxc.js → chunk-4BX2VUAB-DWT4Kb7h.js} +1 -1
- package/dashboard/dist/assets/{chunk-55IACEB6-D9r_hMAn.js → chunk-55IACEB6-DabzdGiV.js} +1 -1
- package/dashboard/dist/assets/{chunk-FMBD7UC4-Dxxe9AQy.js → chunk-FMBD7UC4-9u9EbTn2.js} +1 -1
- package/dashboard/dist/assets/{chunk-JSJVCQXG-CXn2IalW.js → chunk-JSJVCQXG-qNUjUgoq.js} +1 -1
- package/dashboard/dist/assets/{chunk-KX2RTZJC-C0lpRUjK.js → chunk-KX2RTZJC-Iw8btz_i.js} +1 -1
- package/dashboard/dist/assets/{chunk-NQ4KR5QH-CE2rv8cX.js → chunk-NQ4KR5QH-DuWW63Ax.js} +1 -1
- package/dashboard/dist/assets/{chunk-QZHKN3VN-Drs_1Xrc.js → chunk-QZHKN3VN-CquL_I3V.js} +1 -1
- package/dashboard/dist/assets/{chunk-WL4C6EOR-IlTQx43D.js → chunk-WL4C6EOR-CmAQtVO_.js} +1 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-U7OD7LGq.js +1 -0
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-U7OD7LGq.js +1 -0
- package/dashboard/dist/assets/clone-CZUxWIoY.js +1 -0
- package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-C4Xv3sEQ.js → cose-bilkent-S5V4N54A-D_vWs01G.js} +1 -1
- package/dashboard/dist/assets/{dagre-KLK3FWXG-BzfEk7Lk.js → dagre-KLK3FWXG-DRSd99h1.js} +1 -1
- package/dashboard/dist/assets/{diagram-E7M64L7V-CPwBFGGc.js → diagram-E7M64L7V-CYIlPZb0.js} +1 -1
- package/dashboard/dist/assets/{diagram-IFDJBPK2-DSbGA26W.js → diagram-IFDJBPK2-D1Mk78S1.js} +1 -1
- package/dashboard/dist/assets/{diagram-P4PSJMXO-XGhn9Qv-.js → diagram-P4PSJMXO-cK1mot2F.js} +1 -1
- package/dashboard/dist/assets/{erDiagram-INFDFZHY-XeTWZkc6.js → erDiagram-INFDFZHY-CKAce3P6.js} +1 -1
- package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-7vHLCNpk.js → flowDiagram-PKNHOUZH-B8UyrAbG.js} +1 -1
- package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-C9ifnMpV.js → ganttDiagram-A5KZAMGK-DFlWro9k.js} +1 -1
- package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-2o_Myer6.js → gitGraphDiagram-K3NZZRJ6-CfvsGSZk.js} +1 -1
- package/dashboard/dist/assets/{graph-D9VPbOXW.js → graph-DTnszQr1.js} +1 -1
- package/dashboard/dist/assets/index-BukhcQ51.js +659 -0
- package/dashboard/dist/assets/{index-BLRRdPLK.css → index-DlUgV5eO.css} +1 -1
- package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-BlCEEtf8.js → infoDiagram-LFFYTUFH-B4CQ1F6_.js} +1 -1
- package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-BGYOHhaE.js → ishikawaDiagram-PHBUUO56-BJf9J-fu.js} +1 -1
- package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-Cn3nH440.js → journeyDiagram-4ABVD52K-CDt3Ieap.js} +1 -1
- package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-Beagbum1.js → kanban-definition-K7BYSVSG-DvenMiPw.js} +1 -1
- package/dashboard/dist/assets/{layout-DXJOlege.js → layout-B_3cS6Wx.js} +1 -1
- package/dashboard/dist/assets/{linear-gb5BSwpC.js → linear-VVB-1jRr.js} +1 -1
- package/dashboard/dist/assets/{mermaid.core-leU3TCkv.js → mermaid.core-BR4E6mM3.js} +4 -4
- package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-DFGnCvnf.js → mindmap-definition-YRQLILUH-BSMVANTC.js} +1 -1
- package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-HmtQWxMR.js → pieDiagram-SKSYHLDU-Bc1KLLbU.js} +1 -1
- package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-BTDN-lUs.js → quadrantDiagram-337W2JSQ-DCxPDJLj.js} +1 -1
- package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-Da0Yc9Cc.js → requirementDiagram-Z7DCOOCP-CIR7dfaq.js} +1 -1
- package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-DgfucBhp.js → sankeyDiagram-WA2Y5GQK-BSmLrby0.js} +1 -1
- package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-CFIS7rpy.js → sequenceDiagram-2WXFIKYE-D8SKlaHf.js} +1 -1
- package/dashboard/dist/assets/{stateDiagram-RAJIS63D-CYPPhI5Y.js → stateDiagram-RAJIS63D-P-weHmzQ.js} +1 -1
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-DgvK3I0Y.js +1 -0
- package/dashboard/dist/assets/{timeline-definition-YZTLITO2-BidLs2_X.js → timeline-definition-YZTLITO2-AWMvjwea.js} +1 -1
- package/dashboard/dist/assets/{treemap-KZPCXAKY-cEHQHmiX.js → treemap-KZPCXAKY-ByTswXsP.js} +1 -1
- package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-B78ndeUP.js → vennDiagram-LZ73GAT5-FhcL4LCg.js} +1 -1
- package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-DhNlfMcT.js → xychartDiagram-JWTSCODW-Aql6py8q.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/dist/dashboard/server.js +441 -100
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.js +1011 -561
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/platforms/claude-code/.claude-plugin/plugin.json +1 -1
- package/platforms/codex/.codex-plugin/plugin.json +1 -1
- package/platforms/hermes/plugins/syntaur/__pycache__/__init__.cpython-312.pyc +0 -0
- package/platforms/hermes/plugins/syntaur/__pycache__/boundary.cpython-312.pyc +0 -0
- package/dashboard/dist/assets/channel-CDkiQtSs.js +0 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-C8nQGnrI.js +0 -1
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-C8nQGnrI.js +0 -1
- package/dashboard/dist/assets/clone-BYliW2bC.js +0 -1
- package/dashboard/dist/assets/index-n4_qf3_i.js +0 -644
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-DC2NHdS4.js +0 -1
package/dist/index.js
CHANGED
|
@@ -7599,7 +7599,7 @@ async function computeFactsDetailed(input4) {
|
|
|
7599
7599
|
const ac = countRealAcceptanceCriteria(body);
|
|
7600
7600
|
const needsPlanDigest = frontmatter.planApproval !== null || declarations.some((d) => d.type === "attestation" && d.binds === "plan");
|
|
7601
7601
|
const planFile = await latestPlanFile(assignmentDir);
|
|
7602
|
-
const [planFileContent,
|
|
7602
|
+
const [planFileContent, unresolvedQuestions2, depsSatisfied] = await Promise.all([
|
|
7603
7603
|
needsPlanDigest && planFile ? readFile10(resolve13(assignmentDir, planFile), "utf-8").catch(() => null) : Promise.resolve(null),
|
|
7604
7604
|
countUnresolvedQuestions(assignmentDir),
|
|
7605
7605
|
areDependenciesSatisfied(projectDir, frontmatter.dependsOn, terminalStatuses3)
|
|
@@ -7617,7 +7617,7 @@ async function computeFactsDetailed(input4) {
|
|
|
7617
7617
|
workspaceSet: frontmatter.workspace.repository !== null && frontmatter.workspace.branch !== null,
|
|
7618
7618
|
implementationStarted: frontmatter.implementationStarted,
|
|
7619
7619
|
depsSatisfied,
|
|
7620
|
-
unresolvedQuestions,
|
|
7620
|
+
unresolvedQuestions: unresolvedQuestions2,
|
|
7621
7621
|
blocked: frontmatter.blockedReason !== null,
|
|
7622
7622
|
parked: frontmatter.parked,
|
|
7623
7623
|
reviewRequested: frontmatter.reviewRequested,
|
|
@@ -8878,8 +8878,8 @@ async function migrateFromMarkdown(projectsDir2) {
|
|
|
8878
8878
|
return allSessions.length;
|
|
8879
8879
|
}
|
|
8880
8880
|
async function parseMarkdownSessionsIndex(filePath, projectSlug) {
|
|
8881
|
-
const { readFile:
|
|
8882
|
-
const raw2 = await
|
|
8881
|
+
const { readFile: readFile81 } = await import("fs/promises");
|
|
8882
|
+
const raw2 = await readFile81(filePath, "utf-8");
|
|
8883
8883
|
const sessions = [];
|
|
8884
8884
|
const lines = raw2.split("\n");
|
|
8885
8885
|
let inTable = false;
|
|
@@ -9338,8 +9338,8 @@ function scanKey(serversDir2, projectsDir2, assignmentsDir2) {
|
|
|
9338
9338
|
return `${serversDir2}\0${projectsDir2}\0${assignmentsDir2 ?? ""}`;
|
|
9339
9339
|
}
|
|
9340
9340
|
function delay(ms) {
|
|
9341
|
-
return new Promise((
|
|
9342
|
-
const timer3 = setTimeout(
|
|
9341
|
+
return new Promise((resolve110) => {
|
|
9342
|
+
const timer3 = setTimeout(resolve110, ms);
|
|
9343
9343
|
if (typeof timer3.unref === "function") {
|
|
9344
9344
|
timer3.unref();
|
|
9345
9345
|
}
|
|
@@ -13083,10 +13083,10 @@ var init_renderers = __esm({
|
|
|
13083
13083
|
});
|
|
13084
13084
|
|
|
13085
13085
|
// src/targets/user-descriptors.ts
|
|
13086
|
-
import { resolve as
|
|
13087
|
-
import { readFile as
|
|
13086
|
+
import { resolve as resolve45 } from "path";
|
|
13087
|
+
import { readFile as readFile31, readdir as readdir19 } from "fs/promises";
|
|
13088
13088
|
function userTargetsDir() {
|
|
13089
|
-
return
|
|
13089
|
+
return resolve45(syntaurRoot(), "targets");
|
|
13090
13090
|
}
|
|
13091
13091
|
function msg(err2) {
|
|
13092
13092
|
return err2 instanceof Error ? err2.message : String(err2);
|
|
@@ -13100,7 +13100,7 @@ function expandHomeAndEnv(p) {
|
|
|
13100
13100
|
return v ?? "";
|
|
13101
13101
|
}
|
|
13102
13102
|
);
|
|
13103
|
-
return
|
|
13103
|
+
return resolve45(expandHome(envExpanded));
|
|
13104
13104
|
}
|
|
13105
13105
|
function compileDetect(spec) {
|
|
13106
13106
|
switch (spec.kind) {
|
|
@@ -13252,10 +13252,10 @@ async function loadUserDescriptors(opts = {}) {
|
|
|
13252
13252
|
const targets = [];
|
|
13253
13253
|
const seen = /* @__PURE__ */ new Set();
|
|
13254
13254
|
for (const file of files) {
|
|
13255
|
-
const full =
|
|
13255
|
+
const full = resolve45(dir, file);
|
|
13256
13256
|
let raw2;
|
|
13257
13257
|
try {
|
|
13258
|
-
raw2 = await
|
|
13258
|
+
raw2 = await readFile31(full, "utf-8");
|
|
13259
13259
|
} catch (err2) {
|
|
13260
13260
|
warnings.push(`skipped ${file}: ${msg(err2)}`);
|
|
13261
13261
|
continue;
|
|
@@ -13305,23 +13305,23 @@ var init_user_descriptors = __esm({
|
|
|
13305
13305
|
|
|
13306
13306
|
// src/targets/registry.ts
|
|
13307
13307
|
import { homedir as homedir7 } from "os";
|
|
13308
|
-
import { join as join10, resolve as
|
|
13308
|
+
import { join as join10, resolve as resolve46 } from "path";
|
|
13309
13309
|
function home(...segments) {
|
|
13310
|
-
return
|
|
13310
|
+
return resolve46(homedir7(), ...segments);
|
|
13311
13311
|
}
|
|
13312
13312
|
function hermesHome() {
|
|
13313
13313
|
const env = process.env.HERMES_HOME;
|
|
13314
|
-
return env && env.length > 0 ?
|
|
13314
|
+
return env && env.length > 0 ? resolve46(env) : home(".hermes");
|
|
13315
13315
|
}
|
|
13316
13316
|
function hermesSkillsDir() {
|
|
13317
|
-
return
|
|
13317
|
+
return resolve46(hermesHome(), "skills");
|
|
13318
13318
|
}
|
|
13319
13319
|
function isHermesHomeCustom() {
|
|
13320
13320
|
return hermesHome() !== home(".hermes");
|
|
13321
13321
|
}
|
|
13322
13322
|
function codexHome() {
|
|
13323
13323
|
const env = process.env.CODEX_HOME;
|
|
13324
|
-
return env && env.length > 0 ?
|
|
13324
|
+
return env && env.length > 0 ? resolve46(env) : home(".codex");
|
|
13325
13325
|
}
|
|
13326
13326
|
function toDiscovered(meta) {
|
|
13327
13327
|
if (!meta) return null;
|
|
@@ -13388,7 +13388,7 @@ var init_registry = __esm({
|
|
|
13388
13388
|
skillsShAgentId: "codex",
|
|
13389
13389
|
nativePlugin: "codex",
|
|
13390
13390
|
detect: detectDir(codexHome()),
|
|
13391
|
-
skillsDir: { global:
|
|
13391
|
+
skillsDir: { global: resolve46(codexHome(), "skills") },
|
|
13392
13392
|
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] },
|
|
13393
13393
|
sessions: codexSessions
|
|
13394
13394
|
},
|
|
@@ -13456,7 +13456,7 @@ var init_registry = __esm({
|
|
|
13456
13456
|
tier3: {
|
|
13457
13457
|
kind: "hermes-plugin",
|
|
13458
13458
|
source: "platforms/hermes/plugins/syntaur",
|
|
13459
|
-
installDir: () =>
|
|
13459
|
+
installDir: () => resolve46(hermesHome(), "plugins", "syntaur"),
|
|
13460
13460
|
entry: "plugin.yaml"
|
|
13461
13461
|
}
|
|
13462
13462
|
}
|
|
@@ -13475,8 +13475,8 @@ __export(scanner_exports2, {
|
|
|
13475
13475
|
import { execFile as execFile3, execFileSync as execFileSync4 } from "child_process";
|
|
13476
13476
|
import { promisify as promisify3 } from "util";
|
|
13477
13477
|
import { statSync as statSync4 } from "fs";
|
|
13478
|
-
import { readFile as
|
|
13479
|
-
import { resolve as
|
|
13478
|
+
import { readFile as readFile32 } from "fs/promises";
|
|
13479
|
+
import { resolve as resolve47 } from "path";
|
|
13480
13480
|
function emptySummary() {
|
|
13481
13481
|
return { discovered: 0, inserted: 0, revived: 0, swept: 0, skipped: 0, changed: false };
|
|
13482
13482
|
}
|
|
@@ -13532,10 +13532,10 @@ async function defaultOpenFiles(files) {
|
|
|
13532
13532
|
async function readContextLink(cwd, cache3) {
|
|
13533
13533
|
if (cache3.has(cwd)) return cache3.get(cwd);
|
|
13534
13534
|
let link = null;
|
|
13535
|
-
const path =
|
|
13535
|
+
const path = resolve47(cwd, ".syntaur", "context.json");
|
|
13536
13536
|
if (await fileExists(path)) {
|
|
13537
13537
|
try {
|
|
13538
|
-
const parsed = JSON.parse(await
|
|
13538
|
+
const parsed = JSON.parse(await readFile32(path, "utf-8"));
|
|
13539
13539
|
link = {
|
|
13540
13540
|
projectSlug: typeof parsed.projectSlug === "string" ? parsed.projectSlug : null,
|
|
13541
13541
|
assignmentSlug: typeof parsed.assignmentSlug === "string" ? parsed.assignmentSlug : null
|
|
@@ -13709,7 +13709,7 @@ import {
|
|
|
13709
13709
|
unlinkSync
|
|
13710
13710
|
} from "fs";
|
|
13711
13711
|
import { fileURLToPath as fileURLToPath9, pathToFileURL } from "url";
|
|
13712
|
-
import { dirname as dirname21, resolve as
|
|
13712
|
+
import { dirname as dirname21, resolve as resolve71, join as join16 } from "path";
|
|
13713
13713
|
import { homedir as homedir13, tmpdir as tmpdir2 } from "os";
|
|
13714
13714
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
13715
13715
|
function syntaurRootMjs() {
|
|
@@ -13731,7 +13731,7 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
|
13731
13731
|
}
|
|
13732
13732
|
const stateRoot = syntaurRootMjs();
|
|
13733
13733
|
mkdirSync3(stateRoot, { recursive: true });
|
|
13734
|
-
const lockPath =
|
|
13734
|
+
const lockPath = resolve71(stateRoot, "install-url-handler.lock");
|
|
13735
13735
|
let lockFd;
|
|
13736
13736
|
try {
|
|
13737
13737
|
lockFd = openSync(lockPath, "wx");
|
|
@@ -13747,8 +13747,8 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
|
13747
13747
|
throw err2;
|
|
13748
13748
|
}
|
|
13749
13749
|
try {
|
|
13750
|
-
const pkgRoot =
|
|
13751
|
-
const cliBin = realpathSync3(
|
|
13750
|
+
const pkgRoot = resolve71(dirname21(fileURLToPath9(import.meta.url)), "..");
|
|
13751
|
+
const cliBin = realpathSync3(resolve71(pkgRoot, "bin/syntaur.js"));
|
|
13752
13752
|
const nodeBin = process.execPath;
|
|
13753
13753
|
const bundleParent = join16(
|
|
13754
13754
|
homedir13(),
|
|
@@ -14598,7 +14598,7 @@ var init_App = __esm({
|
|
|
14598
14598
|
});
|
|
14599
14599
|
|
|
14600
14600
|
// src/index.ts
|
|
14601
|
-
import { Command as
|
|
14601
|
+
import { Command as Command24, InvalidArgumentError } from "commander";
|
|
14602
14602
|
|
|
14603
14603
|
// src/commands/init.ts
|
|
14604
14604
|
init_paths();
|
|
@@ -14756,7 +14756,7 @@ init_create_assignment();
|
|
|
14756
14756
|
init_config2();
|
|
14757
14757
|
import { spawn as spawn5 } from "child_process";
|
|
14758
14758
|
import { createServer as createNetServer } from "net";
|
|
14759
|
-
import { resolve as
|
|
14759
|
+
import { resolve as resolve49, dirname as dirname13 } from "path";
|
|
14760
14760
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
14761
14761
|
|
|
14762
14762
|
// src/dashboard/server.ts
|
|
@@ -14766,7 +14766,7 @@ init_assignment_resolver();
|
|
|
14766
14766
|
init_agent_sessions();
|
|
14767
14767
|
import express from "express";
|
|
14768
14768
|
import { createServer } from "http";
|
|
14769
|
-
import { resolve as
|
|
14769
|
+
import { resolve as resolve48 } from "path";
|
|
14770
14770
|
import { writeFile as writeFile8, unlink as unlink9 } from "fs/promises";
|
|
14771
14771
|
import { WebSocketServer, WebSocket } from "ws";
|
|
14772
14772
|
|
|
@@ -20192,7 +20192,7 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
|
|
|
20192
20192
|
`Spawn failed: ${msg2}. Verify the terminal is installed and on PATH.`
|
|
20193
20193
|
);
|
|
20194
20194
|
}
|
|
20195
|
-
await new Promise((
|
|
20195
|
+
await new Promise((resolve110, reject) => {
|
|
20196
20196
|
let settled = false;
|
|
20197
20197
|
let stderr = "";
|
|
20198
20198
|
const finishOk = () => {
|
|
@@ -20202,7 +20202,7 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
|
|
|
20202
20202
|
child.unref();
|
|
20203
20203
|
} catch {
|
|
20204
20204
|
}
|
|
20205
|
-
|
|
20205
|
+
resolve110();
|
|
20206
20206
|
};
|
|
20207
20207
|
const finishErr = (remediation) => {
|
|
20208
20208
|
if (settled) return;
|
|
@@ -20468,7 +20468,7 @@ function normalizeSlashes(p) {
|
|
|
20468
20468
|
}
|
|
20469
20469
|
function detectInstallKind(scriptUrl, opts = {}) {
|
|
20470
20470
|
const realpath3 = opts.realpath ?? realpathSync.native;
|
|
20471
|
-
const
|
|
20471
|
+
const readFile81 = opts.readFile ?? ((p) => readFileSync2(p, "utf-8"));
|
|
20472
20472
|
const ua = opts.envUserAgent !== void 0 ? opts.envUserAgent : process.env.npm_config_user_agent ?? "";
|
|
20473
20473
|
const resolved = resolveScriptPath(scriptUrl, realpath3);
|
|
20474
20474
|
if (resolved === null) {
|
|
@@ -20489,7 +20489,7 @@ function detectInstallKind(scriptUrl, opts = {}) {
|
|
|
20489
20489
|
const pkgJsonPath = join7(dir, "package.json");
|
|
20490
20490
|
let raw2;
|
|
20491
20491
|
try {
|
|
20492
|
-
raw2 =
|
|
20492
|
+
raw2 = readFile81(pkgJsonPath);
|
|
20493
20493
|
} catch {
|
|
20494
20494
|
const parent2 = dirname7(dir);
|
|
20495
20495
|
if (parent2 === dir) break;
|
|
@@ -23877,6 +23877,346 @@ function parseFilters(query) {
|
|
|
23877
23877
|
return out;
|
|
23878
23878
|
}
|
|
23879
23879
|
|
|
23880
|
+
// src/dashboard/api-inbox.ts
|
|
23881
|
+
import { Router as Router16 } from "express";
|
|
23882
|
+
|
|
23883
|
+
// src/inbox/index.ts
|
|
23884
|
+
init_fs();
|
|
23885
|
+
init_assignment_walk();
|
|
23886
|
+
init_parser();
|
|
23887
|
+
init_facts();
|
|
23888
|
+
init_state_machine();
|
|
23889
|
+
import { resolve as resolve39 } from "path";
|
|
23890
|
+
import { readFile as readFile26 } from "fs/promises";
|
|
23891
|
+
|
|
23892
|
+
// src/inbox/types.ts
|
|
23893
|
+
var INBOX_CATEGORIES = [
|
|
23894
|
+
"review",
|
|
23895
|
+
"blocked",
|
|
23896
|
+
"question",
|
|
23897
|
+
"plan-approval"
|
|
23898
|
+
];
|
|
23899
|
+
|
|
23900
|
+
// src/inbox/index.ts
|
|
23901
|
+
function isReview(a) {
|
|
23902
|
+
return a.status === "review";
|
|
23903
|
+
}
|
|
23904
|
+
function isBlocked(a) {
|
|
23905
|
+
return a.status === "blocked";
|
|
23906
|
+
}
|
|
23907
|
+
function isUnresolvedQuestion(c2) {
|
|
23908
|
+
return c2.type === "question" && c2.resolved !== true;
|
|
23909
|
+
}
|
|
23910
|
+
function unresolvedQuestions(comments) {
|
|
23911
|
+
return comments.filter(isUnresolvedQuestion);
|
|
23912
|
+
}
|
|
23913
|
+
async function isPlanAwaitingApproval(a, assignmentDir) {
|
|
23914
|
+
if (a.status !== "ready_for_planning") return false;
|
|
23915
|
+
const latest = await latestPlanFile(assignmentDir);
|
|
23916
|
+
if (latest === null) return false;
|
|
23917
|
+
const approved = await isPlanApproved(assignmentDir, { planApproval: a.planApproval });
|
|
23918
|
+
return !approved;
|
|
23919
|
+
}
|
|
23920
|
+
function canonicalRfc3339(ms) {
|
|
23921
|
+
return new Date(ms).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
23922
|
+
}
|
|
23923
|
+
function validTimestamp(value) {
|
|
23924
|
+
if (typeof value !== "string") return null;
|
|
23925
|
+
const t = value.trim();
|
|
23926
|
+
if (t.length === 0) return null;
|
|
23927
|
+
const ms = Date.parse(t);
|
|
23928
|
+
return Number.isNaN(ms) ? null : canonicalRfc3339(ms);
|
|
23929
|
+
}
|
|
23930
|
+
function latestStatusHistoryAt(a) {
|
|
23931
|
+
let best = null;
|
|
23932
|
+
for (const e of a.statusHistory) {
|
|
23933
|
+
const at = validTimestamp(e.at);
|
|
23934
|
+
if (at === null) continue;
|
|
23935
|
+
const ms = Date.parse(at);
|
|
23936
|
+
if (best === null || ms >= best.ms) best = { at, ms };
|
|
23937
|
+
}
|
|
23938
|
+
return best?.at ?? null;
|
|
23939
|
+
}
|
|
23940
|
+
function latestStatusHistoryAtWhere(a, pred) {
|
|
23941
|
+
let best = null;
|
|
23942
|
+
for (const e of a.statusHistory) {
|
|
23943
|
+
if (!pred(e)) continue;
|
|
23944
|
+
const at = validTimestamp(e.at);
|
|
23945
|
+
if (at === null) continue;
|
|
23946
|
+
const ms = Date.parse(at);
|
|
23947
|
+
if (best === null || ms >= best.ms) best = { at, ms };
|
|
23948
|
+
}
|
|
23949
|
+
return best?.at ?? null;
|
|
23950
|
+
}
|
|
23951
|
+
function resolveSince(category, a, now, comment) {
|
|
23952
|
+
let primary = null;
|
|
23953
|
+
switch (category) {
|
|
23954
|
+
case "review":
|
|
23955
|
+
primary = latestStatusHistoryAtWhere(a, (e) => e.to === "review");
|
|
23956
|
+
break;
|
|
23957
|
+
case "blocked":
|
|
23958
|
+
primary = latestStatusHistoryAtWhere(a, (e) => e.dispositionTo === "blocked");
|
|
23959
|
+
break;
|
|
23960
|
+
case "question":
|
|
23961
|
+
primary = validTimestamp(comment?.timestamp);
|
|
23962
|
+
break;
|
|
23963
|
+
case "plan-approval":
|
|
23964
|
+
primary = latestStatusHistoryAt(a);
|
|
23965
|
+
break;
|
|
23966
|
+
}
|
|
23967
|
+
return primary ?? latestStatusHistoryAt(a) ?? validTimestamp(a.updated) ?? validTimestamp(a.created) ?? canonicalRfc3339(now);
|
|
23968
|
+
}
|
|
23969
|
+
function computeAgeMs(since, now) {
|
|
23970
|
+
const ms = Date.parse(since);
|
|
23971
|
+
if (Number.isNaN(ms)) return 0;
|
|
23972
|
+
return Math.max(0, now - ms);
|
|
23973
|
+
}
|
|
23974
|
+
var KNOWN_TRANSITION_CLI_VERBS = /* @__PURE__ */ new Set([
|
|
23975
|
+
"start",
|
|
23976
|
+
"complete",
|
|
23977
|
+
"fail",
|
|
23978
|
+
"reopen",
|
|
23979
|
+
"block",
|
|
23980
|
+
"unblock",
|
|
23981
|
+
"review"
|
|
23982
|
+
]);
|
|
23983
|
+
function deriveReviewVerbs(config) {
|
|
23984
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
23985
|
+
for (const t of config.transitions) {
|
|
23986
|
+
if (t.from === "review") candidates.add(t.command);
|
|
23987
|
+
}
|
|
23988
|
+
for (const key of config.transitionTable.keys()) {
|
|
23989
|
+
if (key.startsWith("review:")) candidates.add(key.slice("review:".length));
|
|
23990
|
+
}
|
|
23991
|
+
const blockedParked = config.blockedParkedStatuses ?? /* @__PURE__ */ new Set();
|
|
23992
|
+
const terminalAccept = [];
|
|
23993
|
+
const activeReopen = [];
|
|
23994
|
+
for (const command of candidates) {
|
|
23995
|
+
const target = getTargetStatus("review", command, config.transitionTable);
|
|
23996
|
+
if (target === null) continue;
|
|
23997
|
+
const isTerminal = config.terminalStatuses.has(target);
|
|
23998
|
+
if (isTerminal && command !== "fail" && KNOWN_TRANSITION_CLI_VERBS.has(command)) {
|
|
23999
|
+
terminalAccept.push(command);
|
|
24000
|
+
}
|
|
24001
|
+
if (!isTerminal && !blockedParked.has(target) && (command === "start" || command === "reopen")) {
|
|
24002
|
+
activeReopen.push(command);
|
|
24003
|
+
}
|
|
24004
|
+
}
|
|
24005
|
+
const accept = terminalAccept.find((c2) => c2 === "complete") ?? terminalAccept[0] ?? null;
|
|
24006
|
+
const reopen = activeReopen.find((c2) => c2 === "start") ?? activeReopen.find((c2) => c2 === "reopen") ?? null;
|
|
24007
|
+
return { accept, reopen };
|
|
24008
|
+
}
|
|
24009
|
+
function targetAndProject(item) {
|
|
24010
|
+
if (item.project === null) {
|
|
24011
|
+
return { target: item.assignmentId, projectFlag: "" };
|
|
24012
|
+
}
|
|
24013
|
+
return { target: item.assignmentSlug, projectFlag: ` --project ${item.project}` };
|
|
24014
|
+
}
|
|
24015
|
+
function buildAction(category, item, ctx) {
|
|
24016
|
+
const { target, projectFlag } = targetAndProject(item);
|
|
24017
|
+
switch (category) {
|
|
24018
|
+
case "review":
|
|
24019
|
+
if (ctx.acceptCommand) {
|
|
24020
|
+
return {
|
|
24021
|
+
verb: "Accept",
|
|
24022
|
+
command: `syntaur ${ctx.acceptCommand} ${target}${projectFlag}`
|
|
24023
|
+
};
|
|
24024
|
+
}
|
|
24025
|
+
if (ctx.reopenCommand) {
|
|
24026
|
+
return {
|
|
24027
|
+
verb: "Reopen",
|
|
24028
|
+
command: `syntaur ${ctx.reopenCommand} ${target}${projectFlag}`
|
|
24029
|
+
};
|
|
24030
|
+
}
|
|
24031
|
+
return {
|
|
24032
|
+
verb: "Review",
|
|
24033
|
+
command: `syntaur timeline ${target}${projectFlag}`
|
|
24034
|
+
};
|
|
24035
|
+
case "blocked":
|
|
24036
|
+
return {
|
|
24037
|
+
verb: "Unblock",
|
|
24038
|
+
command: `syntaur unblock ${target}${projectFlag}`
|
|
24039
|
+
};
|
|
24040
|
+
case "question":
|
|
24041
|
+
return {
|
|
24042
|
+
verb: "Answer",
|
|
24043
|
+
command: `syntaur comment ${target} "<answer>" --reply-to ${ctx.commentId ?? ""}${projectFlag}`
|
|
24044
|
+
};
|
|
24045
|
+
case "plan-approval":
|
|
24046
|
+
return {
|
|
24047
|
+
verb: "Approve plan",
|
|
24048
|
+
command: `syntaur plan approve ${target}${projectFlag}`
|
|
24049
|
+
};
|
|
24050
|
+
}
|
|
24051
|
+
}
|
|
24052
|
+
function orderByUrgency(items) {
|
|
24053
|
+
return [...items].sort((x, y) => y.ageMs - x.ageMs);
|
|
24054
|
+
}
|
|
24055
|
+
function summarizeQuestion(c2) {
|
|
24056
|
+
const body = c2.body.replace(/\s+/g, " ").trim();
|
|
24057
|
+
const clipped = body.length > 140 ? `${body.slice(0, 137)}...` : body;
|
|
24058
|
+
return clipped.length > 0 ? clipped : "(empty question)";
|
|
24059
|
+
}
|
|
24060
|
+
async function computeInbox(opts) {
|
|
24061
|
+
const now = opts.now ?? Date.now();
|
|
24062
|
+
const typeFilter = opts.types && opts.types.length > 0 ? new Set(opts.types) : null;
|
|
24063
|
+
const reviewVerbs = deriveReviewVerbs(opts.statusConfig);
|
|
24064
|
+
const walk = await listAssignmentsByProject(opts.projectsDir, opts.assignmentsDir);
|
|
24065
|
+
const matched = [];
|
|
24066
|
+
for (const entry of walk.withAssignmentMd) {
|
|
24067
|
+
if (opts.project !== void 0 && entry.projectSlug !== opts.project) continue;
|
|
24068
|
+
let parsed;
|
|
24069
|
+
try {
|
|
24070
|
+
const content = await readFile26(resolve39(entry.assignmentDir, "assignment.md"), "utf-8");
|
|
24071
|
+
parsed = parseAssignmentFull(content);
|
|
24072
|
+
} catch {
|
|
24073
|
+
continue;
|
|
24074
|
+
}
|
|
24075
|
+
if (parsed.archived) continue;
|
|
24076
|
+
if (parsed.disposition === "parked" || parsed.disposition === "terminal") continue;
|
|
24077
|
+
if (opts.statusConfig.terminalStatuses.has(parsed.status)) continue;
|
|
24078
|
+
const project = entry.projectSlug;
|
|
24079
|
+
const assignmentSlug = entry.assignmentSlug;
|
|
24080
|
+
const assignmentId = parsed.id;
|
|
24081
|
+
const title = parsed.title;
|
|
24082
|
+
const baseItem = { project, assignmentSlug, assignmentId };
|
|
24083
|
+
if ((!typeFilter || typeFilter.has("review")) && isReview(parsed)) {
|
|
24084
|
+
const since = resolveSince("review", parsed, now);
|
|
24085
|
+
matched.push({
|
|
24086
|
+
...baseItem,
|
|
24087
|
+
title,
|
|
24088
|
+
category: "review",
|
|
24089
|
+
since,
|
|
24090
|
+
ageMs: computeAgeMs(since, now),
|
|
24091
|
+
summary: parsed.reviewRequested ? "Review requested \u2014 awaiting accept or reopen." : "Awaiting review \u2014 accept or reopen.",
|
|
24092
|
+
acceptCommand: reviewVerbs.accept,
|
|
24093
|
+
reopenCommand: reviewVerbs.reopen,
|
|
24094
|
+
action: buildAction("review", baseItem, {
|
|
24095
|
+
acceptCommand: reviewVerbs.accept,
|
|
24096
|
+
reopenCommand: reviewVerbs.reopen
|
|
24097
|
+
})
|
|
24098
|
+
});
|
|
24099
|
+
}
|
|
24100
|
+
if ((!typeFilter || typeFilter.has("blocked")) && isBlocked(parsed)) {
|
|
24101
|
+
const since = resolveSince("blocked", parsed, now);
|
|
24102
|
+
matched.push({
|
|
24103
|
+
...baseItem,
|
|
24104
|
+
title,
|
|
24105
|
+
category: "blocked",
|
|
24106
|
+
since,
|
|
24107
|
+
ageMs: computeAgeMs(since, now),
|
|
24108
|
+
summary: parsed.blockedReason ? `Blocked: ${parsed.blockedReason}` : "Blocked \u2014 awaiting unblock.",
|
|
24109
|
+
action: buildAction("blocked", baseItem, {})
|
|
24110
|
+
});
|
|
24111
|
+
}
|
|
24112
|
+
if (!typeFilter || typeFilter.has("question")) {
|
|
24113
|
+
const commentsPath = resolve39(entry.assignmentDir, "comments.md");
|
|
24114
|
+
if (await fileExists(commentsPath)) {
|
|
24115
|
+
try {
|
|
24116
|
+
const content = await readFile26(commentsPath, "utf-8");
|
|
24117
|
+
const parsedComments = parseComments(content);
|
|
24118
|
+
for (const c2 of unresolvedQuestions(parsedComments.entries)) {
|
|
24119
|
+
const since = resolveSince("question", parsed, now, c2);
|
|
24120
|
+
matched.push({
|
|
24121
|
+
...baseItem,
|
|
24122
|
+
title,
|
|
24123
|
+
category: "question",
|
|
24124
|
+
since,
|
|
24125
|
+
ageMs: computeAgeMs(since, now),
|
|
24126
|
+
summary: summarizeQuestion(c2),
|
|
24127
|
+
commentId: c2.id,
|
|
24128
|
+
action: buildAction("question", baseItem, {
|
|
24129
|
+
commentId: c2.id
|
|
24130
|
+
})
|
|
24131
|
+
});
|
|
24132
|
+
}
|
|
24133
|
+
} catch {
|
|
24134
|
+
}
|
|
24135
|
+
}
|
|
24136
|
+
}
|
|
24137
|
+
if (!typeFilter || typeFilter.has("plan-approval")) {
|
|
24138
|
+
if (await isPlanAwaitingApproval(parsed, entry.assignmentDir)) {
|
|
24139
|
+
const since = resolveSince("plan-approval", parsed, now);
|
|
24140
|
+
matched.push({
|
|
24141
|
+
...baseItem,
|
|
24142
|
+
title,
|
|
24143
|
+
category: "plan-approval",
|
|
24144
|
+
since,
|
|
24145
|
+
ageMs: computeAgeMs(since, now),
|
|
24146
|
+
summary: "Plan awaiting approval.",
|
|
24147
|
+
action: buildAction("plan-approval", baseItem, {})
|
|
24148
|
+
});
|
|
24149
|
+
}
|
|
24150
|
+
}
|
|
24151
|
+
}
|
|
24152
|
+
const counts = {
|
|
24153
|
+
review: 0,
|
|
24154
|
+
blocked: 0,
|
|
24155
|
+
question: 0,
|
|
24156
|
+
"plan-approval": 0
|
|
24157
|
+
};
|
|
24158
|
+
for (const item of matched) counts[item.category]++;
|
|
24159
|
+
const total = matched.length;
|
|
24160
|
+
const ordered = [];
|
|
24161
|
+
for (const category of INBOX_CATEGORIES) {
|
|
24162
|
+
ordered.push(...orderByUrgency(matched.filter((i) => i.category === category)));
|
|
24163
|
+
}
|
|
24164
|
+
const items = opts.limit !== void 0 && opts.limit >= 0 ? ordered.slice(0, opts.limit) : ordered;
|
|
24165
|
+
return { items, counts, total };
|
|
24166
|
+
}
|
|
24167
|
+
|
|
24168
|
+
// src/dashboard/api-inbox.ts
|
|
24169
|
+
init_api();
|
|
24170
|
+
init_config2();
|
|
24171
|
+
function createInboxRouter(projectsDir2, assignmentsDir2) {
|
|
24172
|
+
const router = Router16();
|
|
24173
|
+
router.get("/inbox", async (req2, res) => {
|
|
24174
|
+
try {
|
|
24175
|
+
const project = typeof req2.query.project === "string" && req2.query.project.length > 0 ? req2.query.project : void 0;
|
|
24176
|
+
let types;
|
|
24177
|
+
if (typeof req2.query.type === "string" && req2.query.type.length > 0) {
|
|
24178
|
+
const raw2 = req2.query.type.split(",").map((t) => t.trim()).filter(Boolean);
|
|
24179
|
+
const unknown = raw2.filter((t) => !INBOX_CATEGORIES.includes(t));
|
|
24180
|
+
if (unknown.length > 0) {
|
|
24181
|
+
res.status(400).json({
|
|
24182
|
+
error: `Unknown inbox type(s): ${unknown.map((u) => JSON.stringify(u)).join(", ")}. Valid types: ${INBOX_CATEGORIES.join(", ")}.`
|
|
24183
|
+
});
|
|
24184
|
+
return;
|
|
24185
|
+
}
|
|
24186
|
+
types = raw2;
|
|
24187
|
+
}
|
|
24188
|
+
let limit;
|
|
24189
|
+
if (typeof req2.query.limit === "string") {
|
|
24190
|
+
const n = Number(req2.query.limit);
|
|
24191
|
+
if (Number.isInteger(n) && n > 0) limit = n;
|
|
24192
|
+
}
|
|
24193
|
+
const resolved = await getStatusConfig();
|
|
24194
|
+
const headline = (resolved.derive ?? DEFAULT_DERIVE_CONFIG).headline;
|
|
24195
|
+
const blockedParkedStatuses = new Set(
|
|
24196
|
+
[headline.blocked, headline.parked].filter(Boolean)
|
|
24197
|
+
);
|
|
24198
|
+
const statusConfig = { ...resolved, blockedParkedStatuses };
|
|
24199
|
+
const result = await computeInbox({
|
|
24200
|
+
projectsDir: projectsDir2,
|
|
24201
|
+
assignmentsDir: assignmentsDir2,
|
|
24202
|
+
project,
|
|
24203
|
+
types,
|
|
24204
|
+
limit,
|
|
24205
|
+
statusConfig
|
|
24206
|
+
});
|
|
24207
|
+
res.json(result);
|
|
24208
|
+
} catch (error) {
|
|
24209
|
+
console.warn("[inbox] failed to compute inbox:", error);
|
|
24210
|
+
res.json({
|
|
24211
|
+
items: [],
|
|
24212
|
+
counts: { review: 0, blocked: 0, question: 0, "plan-approval": 0 },
|
|
24213
|
+
total: 0
|
|
24214
|
+
});
|
|
24215
|
+
}
|
|
24216
|
+
});
|
|
24217
|
+
return router;
|
|
24218
|
+
}
|
|
24219
|
+
|
|
23880
24220
|
// src/dashboard/api-playbooks.ts
|
|
23881
24221
|
init_api();
|
|
23882
24222
|
init_parser();
|
|
@@ -23885,9 +24225,9 @@ init_timestamp();
|
|
|
23885
24225
|
init_fs();
|
|
23886
24226
|
init_playbook();
|
|
23887
24227
|
init_playbooks();
|
|
23888
|
-
import { Router as
|
|
23889
|
-
import { resolve as
|
|
23890
|
-
import { readFile as
|
|
24228
|
+
import { Router as Router17 } from "express";
|
|
24229
|
+
import { resolve as resolve40 } from "path";
|
|
24230
|
+
import { readFile as readFile27 } from "fs/promises";
|
|
23891
24231
|
function statusForPlaybookError(code) {
|
|
23892
24232
|
switch (code) {
|
|
23893
24233
|
case "manifest":
|
|
@@ -23901,7 +24241,7 @@ function statusForPlaybookError(code) {
|
|
|
23901
24241
|
}
|
|
23902
24242
|
}
|
|
23903
24243
|
function createPlaybooksRouter(playbooksDir3) {
|
|
23904
|
-
const router =
|
|
24244
|
+
const router = Router17();
|
|
23905
24245
|
router.get("/", async (_req, res) => {
|
|
23906
24246
|
try {
|
|
23907
24247
|
const playbooks = await listPlaybooks(playbooksDir3);
|
|
@@ -23968,8 +24308,8 @@ function createPlaybooksRouter(playbooksDir3) {
|
|
|
23968
24308
|
res.status(404).json({ error: `Playbook "${req2.params.slug}" not found` });
|
|
23969
24309
|
return;
|
|
23970
24310
|
}
|
|
23971
|
-
const filePath =
|
|
23972
|
-
const content = await
|
|
24311
|
+
const filePath = resolve40(playbooksDir3, resolved.filename);
|
|
24312
|
+
const content = await readFile27(filePath, "utf-8");
|
|
23973
24313
|
res.json({
|
|
23974
24314
|
documentType: "playbook",
|
|
23975
24315
|
title: `Edit Playbook: ${resolved.slug}`,
|
|
@@ -23994,7 +24334,7 @@ function createPlaybooksRouter(playbooksDir3) {
|
|
|
23994
24334
|
return;
|
|
23995
24335
|
}
|
|
23996
24336
|
await ensureDir(playbooksDir3);
|
|
23997
|
-
const filePath =
|
|
24337
|
+
const filePath = resolve40(playbooksDir3, `${slug}.md`);
|
|
23998
24338
|
if (await fileExists(filePath)) {
|
|
23999
24339
|
res.status(409).json({ error: `Playbook "${slug}" already exists` });
|
|
24000
24340
|
return;
|
|
@@ -24018,7 +24358,7 @@ function createPlaybooksRouter(playbooksDir3) {
|
|
|
24018
24358
|
res.status(404).json({ error: `Playbook "${req2.params.slug}" not found` });
|
|
24019
24359
|
return;
|
|
24020
24360
|
}
|
|
24021
|
-
const filePath =
|
|
24361
|
+
const filePath = resolve40(playbooksDir3, resolved.filename);
|
|
24022
24362
|
await writeFileForce(filePath, content);
|
|
24023
24363
|
await rebuildPlaybookManifest(playbooksDir3);
|
|
24024
24364
|
res.json({ slug: resolved.slug, path: filePath });
|
|
@@ -24065,7 +24405,7 @@ init_fs_migration();
|
|
|
24065
24405
|
init_parser2();
|
|
24066
24406
|
init_fs();
|
|
24067
24407
|
init_paths();
|
|
24068
|
-
import { Router as
|
|
24408
|
+
import { Router as Router19 } from "express";
|
|
24069
24409
|
import { readdir as readdir17 } from "fs/promises";
|
|
24070
24410
|
import { resolve as resolvePath, dirname as dirname11 } from "path";
|
|
24071
24411
|
import { rename as rename6, mkdir as mkdir5 } from "fs/promises";
|
|
@@ -24078,7 +24418,7 @@ import { raw } from "express";
|
|
|
24078
24418
|
|
|
24079
24419
|
// src/todos/attachments.ts
|
|
24080
24420
|
import { mkdir as mkdir4, readdir as readdir16, stat as stat5, rename as rename5, rm as rm4, unlink as unlink7, writeFile as writeFile6, cp } from "fs/promises";
|
|
24081
|
-
import { resolve as
|
|
24421
|
+
import { resolve as resolve41, basename as basename5, dirname as dirname10, extname } from "path";
|
|
24082
24422
|
|
|
24083
24423
|
// src/utils/proof-artifact-id.ts
|
|
24084
24424
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
@@ -24189,12 +24529,12 @@ function sanitizeAttachmentName(name) {
|
|
|
24189
24529
|
return n;
|
|
24190
24530
|
}
|
|
24191
24531
|
function attachmentsRootDir(todosDir2) {
|
|
24192
|
-
return
|
|
24532
|
+
return resolve41(todosDir2, "attachments");
|
|
24193
24533
|
}
|
|
24194
24534
|
function attachmentDirFor(todosDir2, scopeId, todoId) {
|
|
24195
24535
|
assertScope(scopeId);
|
|
24196
24536
|
assertTodoId(todoId);
|
|
24197
|
-
return
|
|
24537
|
+
return resolve41(attachmentsRootDir(todosDir2), scopeId, todoId);
|
|
24198
24538
|
}
|
|
24199
24539
|
async function dirExists(p) {
|
|
24200
24540
|
try {
|
|
@@ -24208,7 +24548,7 @@ async function writeAttachment(todosDir2, scopeId, todoId, originalName, bytes)
|
|
|
24208
24548
|
await mkdir4(dir, { recursive: true });
|
|
24209
24549
|
const id = generateArtifactId();
|
|
24210
24550
|
const filename = sanitizeAttachmentName(originalName);
|
|
24211
|
-
await writeFile6(
|
|
24551
|
+
await writeFile6(resolve41(dir, `${id}__${filename}`), bytes);
|
|
24212
24552
|
return {
|
|
24213
24553
|
id,
|
|
24214
24554
|
filename,
|
|
@@ -24233,7 +24573,7 @@ async function listAttachments(todosDir2, scopeId, todoId) {
|
|
|
24233
24573
|
if (!ATTACHMENT_ID_RE.test(id)) continue;
|
|
24234
24574
|
const filename = stored.slice(sep2 + 2);
|
|
24235
24575
|
try {
|
|
24236
|
-
const st = await stat5(
|
|
24576
|
+
const st = await stat5(resolve41(dir, stored));
|
|
24237
24577
|
if (!st.isFile()) continue;
|
|
24238
24578
|
out.push({ id, filename, mime: mimeForName(filename), size: st.size, createdAt: st.mtime.toISOString() });
|
|
24239
24579
|
} catch {
|
|
@@ -24244,7 +24584,7 @@ async function listAttachments(todosDir2, scopeId, todoId) {
|
|
|
24244
24584
|
}
|
|
24245
24585
|
async function readScopeAttachments(todosDir2, scopeId) {
|
|
24246
24586
|
assertScope(scopeId);
|
|
24247
|
-
const scopeDir =
|
|
24587
|
+
const scopeDir = resolve41(attachmentsRootDir(todosDir2), scopeId);
|
|
24248
24588
|
let todoIds;
|
|
24249
24589
|
try {
|
|
24250
24590
|
todoIds = await readdir16(scopeDir);
|
|
@@ -24272,7 +24612,7 @@ async function resolveAttachmentFile(todosDir2, scopeId, todoId, attachmentId) {
|
|
|
24272
24612
|
const stored = names.find((n) => n.startsWith(prefix));
|
|
24273
24613
|
if (!stored) return null;
|
|
24274
24614
|
const filename = stored.slice(prefix.length);
|
|
24275
|
-
return { path:
|
|
24615
|
+
return { path: resolve41(dir, stored), filename, mime: mimeForName(filename) };
|
|
24276
24616
|
}
|
|
24277
24617
|
async function deleteAttachment(todosDir2, scopeId, todoId, attachmentId) {
|
|
24278
24618
|
const resolved = await resolveAttachmentFile(todosDir2, scopeId, todoId, attachmentId);
|
|
@@ -24434,7 +24774,7 @@ function touchItem3(item) {
|
|
|
24434
24774
|
item.updatedAt = now;
|
|
24435
24775
|
}
|
|
24436
24776
|
function createTodosRouter(todosDir2, broadcast, projectsDir2) {
|
|
24437
|
-
const router =
|
|
24777
|
+
const router = Router19();
|
|
24438
24778
|
installRecordsInvalidation(router);
|
|
24439
24779
|
function broadcastUpdate() {
|
|
24440
24780
|
broadcast({ type: "todos-updated", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
@@ -24684,8 +25024,8 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
|
|
|
24684
25024
|
router.post("/:workspace/archive", async (req2, res) => {
|
|
24685
25025
|
try {
|
|
24686
25026
|
const { archivePath: archivePath2 } = await Promise.resolve().then(() => (init_parser2(), parser_exports));
|
|
24687
|
-
const { resolve:
|
|
24688
|
-
const { readFile:
|
|
25027
|
+
const { resolve: resolve110 } = await import("path");
|
|
25028
|
+
const { readFile: readFile81 } = await import("fs/promises");
|
|
24689
25029
|
const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
24690
25030
|
const workspace = getWorkspaceParam(req2.params.workspace);
|
|
24691
25031
|
const outcome = await wsLock(workspace, async () => {
|
|
@@ -24701,10 +25041,10 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
|
|
|
24701
25041
|
(e) => e.itemIds.every((id) => completedIds.has(id))
|
|
24702
25042
|
);
|
|
24703
25043
|
const archFile = archivePath2(todosDir2, workspace, checklist.archiveInterval);
|
|
24704
|
-
await ensureDir(
|
|
25044
|
+
await ensureDir(resolve110(todosDir2, "archive"));
|
|
24705
25045
|
let archContent = "";
|
|
24706
25046
|
if (await fileExists(archFile)) {
|
|
24707
|
-
archContent = await
|
|
25047
|
+
archContent = await readFile81(archFile, "utf-8");
|
|
24708
25048
|
archContent = archContent.trimEnd() + "\n\n";
|
|
24709
25049
|
} else {
|
|
24710
25050
|
archContent = `---
|
|
@@ -24996,7 +25336,7 @@ workspace: ${workspace}
|
|
|
24996
25336
|
const { readConfig: readConfig3 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
24997
25337
|
const { assignmentsDir: assignmentsDirFn } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
24998
25338
|
const { fileExists: fileExists2, writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
24999
|
-
const { readFile:
|
|
25339
|
+
const { readFile: readFile81 } = await import("fs/promises");
|
|
25000
25340
|
const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
|
|
25001
25341
|
const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
|
|
25002
25342
|
let assignmentRef;
|
|
@@ -25017,7 +25357,7 @@ workspace: ${workspace}
|
|
|
25017
25357
|
}
|
|
25018
25358
|
const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
|
|
25019
25359
|
if (!await fileExists2(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
|
|
25020
|
-
let content = await
|
|
25360
|
+
let content = await readFile81(assignmentMdPath2, "utf-8");
|
|
25021
25361
|
content = appendTodosToAssignmentBody2(
|
|
25022
25362
|
content,
|
|
25023
25363
|
items.map((it) => ({
|
|
@@ -25211,9 +25551,9 @@ init_parser2();
|
|
|
25211
25551
|
init_fs();
|
|
25212
25552
|
init_paths();
|
|
25213
25553
|
init_slug();
|
|
25214
|
-
import { Router as
|
|
25215
|
-
import { mkdir as mkdir6, readFile as
|
|
25216
|
-
import { resolve as
|
|
25554
|
+
import { Router as Router20 } from "express";
|
|
25555
|
+
import { mkdir as mkdir6, readFile as readFile28, rename as rename7 } from "fs/promises";
|
|
25556
|
+
import { resolve as resolve42, dirname as dirname12 } from "path";
|
|
25217
25557
|
init_promote_todos();
|
|
25218
25558
|
init_api();
|
|
25219
25559
|
var WORKSPACE_REGEX2 = /^[a-z0-9_][a-z0-9-]*$/;
|
|
@@ -25230,7 +25570,7 @@ function params(req2) {
|
|
|
25230
25570
|
return req2.params;
|
|
25231
25571
|
}
|
|
25232
25572
|
async function projectExists(projectsDir2, slug) {
|
|
25233
|
-
return fileExists(
|
|
25573
|
+
return fileExists(resolve42(projectsDir2, slug, "project.md"));
|
|
25234
25574
|
}
|
|
25235
25575
|
async function ensureProjectTodosDir(projectsDir2, slug) {
|
|
25236
25576
|
const todosDir2 = projectTodosDir(projectsDir2, slug);
|
|
@@ -25247,7 +25587,7 @@ async function ensureProjectTodosDir(projectsDir2, slug) {
|
|
|
25247
25587
|
throw err2;
|
|
25248
25588
|
}
|
|
25249
25589
|
try {
|
|
25250
|
-
await mkdir6(
|
|
25590
|
+
await mkdir6(resolve42(todosDir2, "archive"), { recursive: false });
|
|
25251
25591
|
} catch (err2) {
|
|
25252
25592
|
const code = err2.code;
|
|
25253
25593
|
if (code === "EEXIST") return;
|
|
@@ -25263,7 +25603,7 @@ function notFound(res, slug) {
|
|
|
25263
25603
|
res.status(404).json({ error: `Project "${slug}" not found` });
|
|
25264
25604
|
}
|
|
25265
25605
|
function createProjectTodosRouter(projectsDir2, broadcast, workspaceTodosDir) {
|
|
25266
|
-
const router =
|
|
25606
|
+
const router = Router20({ mergeParams: true });
|
|
25267
25607
|
installRecordsInvalidation(router);
|
|
25268
25608
|
function broadcastUpdate(projectSlug) {
|
|
25269
25609
|
broadcast({ type: "todos-updated", projectSlug, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
@@ -25451,7 +25791,7 @@ function createProjectTodosRouter(projectsDir2, broadcast, workspaceTodosDir) {
|
|
|
25451
25791
|
const archFile = archivePath(todosDir2, slug, checklist.archiveInterval);
|
|
25452
25792
|
let archContent = "";
|
|
25453
25793
|
if (await fileExists(archFile)) {
|
|
25454
|
-
archContent = await
|
|
25794
|
+
archContent = await readFile28(archFile, "utf-8");
|
|
25455
25795
|
archContent = archContent.trimEnd() + "\n\n";
|
|
25456
25796
|
} else {
|
|
25457
25797
|
archContent = `---
|
|
@@ -25913,17 +26253,17 @@ workspace: ${slug}
|
|
|
25913
26253
|
if (tg.includes("/")) {
|
|
25914
26254
|
const parts = tg.split("/");
|
|
25915
26255
|
if (parts.length !== 2) return { error: `Invalid target.assignment "${tg}"` };
|
|
25916
|
-
assignmentDir =
|
|
26256
|
+
assignmentDir = resolve42(projectsDir2, parts[0], "assignments", parts[1]);
|
|
25917
26257
|
assignmentRef = `${parts[0]}/${parts[1]}`;
|
|
25918
26258
|
} else if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(tg)) {
|
|
25919
|
-
assignmentDir =
|
|
26259
|
+
assignmentDir = resolve42(assignmentsDirFn(), tg);
|
|
25920
26260
|
assignmentRef = tg;
|
|
25921
26261
|
} else {
|
|
25922
26262
|
return { error: `Invalid target.assignment "${tg}"` };
|
|
25923
26263
|
}
|
|
25924
|
-
const assignmentMdPath2 =
|
|
26264
|
+
const assignmentMdPath2 = resolve42(assignmentDir, "assignment.md");
|
|
25925
26265
|
if (!await fileExists(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
|
|
25926
|
-
let content = await
|
|
26266
|
+
let content = await readFile28(assignmentMdPath2, "utf-8");
|
|
25927
26267
|
content = appendTodosToAssignmentBody2(
|
|
25928
26268
|
content,
|
|
25929
26269
|
items.map((it) => ({
|
|
@@ -26125,7 +26465,7 @@ workspace: ${slug}
|
|
|
26125
26465
|
}
|
|
26126
26466
|
|
|
26127
26467
|
// src/dashboard/api-bundles.ts
|
|
26128
|
-
import { Router as
|
|
26468
|
+
import { Router as Router21 } from "express";
|
|
26129
26469
|
import { readdir as readdir18 } from "fs/promises";
|
|
26130
26470
|
|
|
26131
26471
|
// src/todos/bundle-parser.ts
|
|
@@ -26134,7 +26474,7 @@ init_fs();
|
|
|
26134
26474
|
init_paths();
|
|
26135
26475
|
init_parser2();
|
|
26136
26476
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
26137
|
-
import { readFile as
|
|
26477
|
+
import { readFile as readFile29 } from "fs/promises";
|
|
26138
26478
|
var BUNDLE_ID_REGEX = /^[a-f0-9]{4}$/;
|
|
26139
26479
|
var SCOPE_VALUES = /* @__PURE__ */ new Set(["workspace", "project", "global"]);
|
|
26140
26480
|
var SCOPE_ID_REGEX = /^[a-z0-9_][a-z0-9_-]*$/;
|
|
@@ -26237,7 +26577,7 @@ ${lines}
|
|
|
26237
26577
|
async function readBundles(todosDir2) {
|
|
26238
26578
|
const path = bundlesPath(todosDir2);
|
|
26239
26579
|
if (!await fileExists(path)) return [];
|
|
26240
|
-
const content = await
|
|
26580
|
+
const content = await readFile29(path, "utf-8");
|
|
26241
26581
|
return parseBundles(content).bundles;
|
|
26242
26582
|
}
|
|
26243
26583
|
async function writeBundles(todosDir2, bundles) {
|
|
@@ -26276,7 +26616,7 @@ function annotate(bundle, items) {
|
|
|
26276
26616
|
}
|
|
26277
26617
|
function createBundlesRouter(todosDir2, broadcast) {
|
|
26278
26618
|
void broadcast;
|
|
26279
|
-
const router =
|
|
26619
|
+
const router = Router21();
|
|
26280
26620
|
function validateWorkspace(req2, res, next) {
|
|
26281
26621
|
const workspace = getWorkspaceParam2(req2.params.workspace);
|
|
26282
26622
|
if (workspace && !WORKSPACE_REGEX3.test(workspace)) {
|
|
@@ -26342,8 +26682,8 @@ function createBundlesRouter(todosDir2, broadcast) {
|
|
|
26342
26682
|
init_fs();
|
|
26343
26683
|
init_paths();
|
|
26344
26684
|
init_slug();
|
|
26345
|
-
import { Router as
|
|
26346
|
-
import { resolve as
|
|
26685
|
+
import { Router as Router22 } from "express";
|
|
26686
|
+
import { resolve as resolve43 } from "path";
|
|
26347
26687
|
init_parser2();
|
|
26348
26688
|
function deriveStatus2(bundle, items) {
|
|
26349
26689
|
const members = bundle.todoIds.map((id) => items.find((i) => i.id === id)).filter((i) => i !== void 0);
|
|
@@ -26372,7 +26712,7 @@ function notFound2(res, slug) {
|
|
|
26372
26712
|
}
|
|
26373
26713
|
function createProjectBundlesRouter(projectsDir2, broadcast) {
|
|
26374
26714
|
void broadcast;
|
|
26375
|
-
const router =
|
|
26715
|
+
const router = Router22({ mergeParams: true });
|
|
26376
26716
|
function validateProjectId(req2, res, next) {
|
|
26377
26717
|
const slug = getProjectIdParam2(req2.params.projectId);
|
|
26378
26718
|
if (!slug || !isValidSlug(slug)) {
|
|
@@ -26385,7 +26725,7 @@ function createProjectBundlesRouter(projectsDir2, broadcast) {
|
|
|
26385
26725
|
router.get("/", async (req2, res) => {
|
|
26386
26726
|
try {
|
|
26387
26727
|
const slug = getProjectIdParam2(req2.params.projectId);
|
|
26388
|
-
const projectMd =
|
|
26728
|
+
const projectMd = resolve43(projectsDir2, slug, "project.md");
|
|
26389
26729
|
if (!await fileExists(projectMd)) {
|
|
26390
26730
|
notFound2(res, slug);
|
|
26391
26731
|
return;
|
|
@@ -26406,7 +26746,7 @@ function createProjectBundlesRouter(projectsDir2, broadcast) {
|
|
|
26406
26746
|
init_config2();
|
|
26407
26747
|
init_api();
|
|
26408
26748
|
init_scanner();
|
|
26409
|
-
import { Router as
|
|
26749
|
+
import { Router as Router23 } from "express";
|
|
26410
26750
|
|
|
26411
26751
|
// src/utils/github-backup.ts
|
|
26412
26752
|
init_paths();
|
|
@@ -26414,8 +26754,8 @@ init_fs();
|
|
|
26414
26754
|
init_config2();
|
|
26415
26755
|
import { execFile as execFile2 } from "child_process";
|
|
26416
26756
|
import { promisify as promisify2 } from "util";
|
|
26417
|
-
import { cp as cp2, mkdtemp, rm as rm5, readFile as
|
|
26418
|
-
import { resolve as
|
|
26757
|
+
import { cp as cp2, mkdtemp, rm as rm5, readFile as readFile30, writeFile as writeFile7, unlink as unlink8, stat as stat6, open as open5, rename as rename8 } from "fs/promises";
|
|
26758
|
+
import { resolve as resolve44, join as join9 } from "path";
|
|
26419
26759
|
import { tmpdir } from "os";
|
|
26420
26760
|
var exec2 = promisify2(execFile2);
|
|
26421
26761
|
var VALID_CATEGORIES = ["projects", "playbooks", "todos", "servers", "config"];
|
|
@@ -26455,7 +26795,7 @@ async function resolveCategoryPath(category) {
|
|
|
26455
26795
|
case "servers":
|
|
26456
26796
|
return { sourcePath: serversDir(), repoPath: "servers", isFile: false };
|
|
26457
26797
|
case "config":
|
|
26458
|
-
return { sourcePath:
|
|
26798
|
+
return { sourcePath: resolve44(syntaurRoot(), "config.md"), repoPath: "config.md", isFile: true };
|
|
26459
26799
|
}
|
|
26460
26800
|
}
|
|
26461
26801
|
async function checkGitInstalled() {
|
|
@@ -26466,7 +26806,7 @@ async function checkGitInstalled() {
|
|
|
26466
26806
|
}
|
|
26467
26807
|
}
|
|
26468
26808
|
async function acquireLock2() {
|
|
26469
|
-
const lockPath =
|
|
26809
|
+
const lockPath = resolve44(syntaurRoot(), LOCK_FILE_NAME);
|
|
26470
26810
|
await ensureDir(syntaurRoot());
|
|
26471
26811
|
try {
|
|
26472
26812
|
const handle = await open5(lockPath, "wx");
|
|
@@ -26475,7 +26815,7 @@ async function acquireLock2() {
|
|
|
26475
26815
|
return lockPath;
|
|
26476
26816
|
} catch (err2) {
|
|
26477
26817
|
if (err2.code === "EEXIST") {
|
|
26478
|
-
const pid = await
|
|
26818
|
+
const pid = await readFile30(lockPath, "utf-8").catch(() => "");
|
|
26479
26819
|
throw new Error(
|
|
26480
26820
|
`Backup operation already in progress (lock file at ${lockPath}, pid ${pid.trim() || "unknown"}). If stale, delete the file and retry.`
|
|
26481
26821
|
);
|
|
@@ -26513,7 +26853,7 @@ async function copyRecursive(src, dest) {
|
|
|
26513
26853
|
await ensureDir(dest);
|
|
26514
26854
|
await cp2(src, dest, { recursive: true, force: true });
|
|
26515
26855
|
} else {
|
|
26516
|
-
await ensureDir(
|
|
26856
|
+
await ensureDir(resolve44(dest, ".."));
|
|
26517
26857
|
await cp2(src, dest, { force: true });
|
|
26518
26858
|
}
|
|
26519
26859
|
}
|
|
@@ -26522,7 +26862,7 @@ function resolveCategoriesStrict(csv) {
|
|
|
26522
26862
|
return parseCategoriesStrict(parts);
|
|
26523
26863
|
}
|
|
26524
26864
|
async function readSanitizedConfig(configPath2) {
|
|
26525
|
-
const content = await
|
|
26865
|
+
const content = await readFile30(configPath2, "utf-8");
|
|
26526
26866
|
return content.replace(/^(\s*lastBackup:\s*).*$/m, "$1null").replace(/^(\s*lastRestore:\s*).*$/m, "$1null");
|
|
26527
26867
|
}
|
|
26528
26868
|
async function backupToGithub(overrides) {
|
|
@@ -26561,7 +26901,7 @@ async function backupToGithub(overrides) {
|
|
|
26561
26901
|
}
|
|
26562
26902
|
if (category === "config") {
|
|
26563
26903
|
const sanitized = await readSanitizedConfig(sourcePath);
|
|
26564
|
-
await ensureDir(
|
|
26904
|
+
await ensureDir(resolve44(destPath, ".."));
|
|
26565
26905
|
await writeFile7(destPath, sanitized, "utf-8");
|
|
26566
26906
|
} else {
|
|
26567
26907
|
await copyRecursive(sourcePath, destPath);
|
|
@@ -26615,7 +26955,7 @@ async function backupToGithub(overrides) {
|
|
|
26615
26955
|
}
|
|
26616
26956
|
async function safeRestoreCategory(localPath, repoSrcPath, isFile) {
|
|
26617
26957
|
if (isFile) {
|
|
26618
|
-
await ensureDir(
|
|
26958
|
+
await ensureDir(resolve44(localPath, ".."));
|
|
26619
26959
|
await cp2(repoSrcPath, localPath, { force: true });
|
|
26620
26960
|
return;
|
|
26621
26961
|
}
|
|
@@ -26716,7 +27056,7 @@ async function restoreFromGithub(overrides) {
|
|
|
26716
27056
|
}
|
|
26717
27057
|
async function getBackupStatus() {
|
|
26718
27058
|
const config = await readConfig();
|
|
26719
|
-
const lockPath =
|
|
27059
|
+
const lockPath = resolve44(syntaurRoot(), LOCK_FILE_NAME);
|
|
26720
27060
|
const locked = await fileExists(lockPath);
|
|
26721
27061
|
return {
|
|
26722
27062
|
repo: config.backup?.repo ?? null,
|
|
@@ -26729,7 +27069,7 @@ async function getBackupStatus() {
|
|
|
26729
27069
|
|
|
26730
27070
|
// src/dashboard/api-backup.ts
|
|
26731
27071
|
function createBackupRouter() {
|
|
26732
|
-
const router =
|
|
27072
|
+
const router = Router23();
|
|
26733
27073
|
router.get("/", async (_req, res) => {
|
|
26734
27074
|
try {
|
|
26735
27075
|
const status = await getBackupStatus();
|
|
@@ -27199,7 +27539,7 @@ async function runCcusage(opts = {}) {
|
|
|
27199
27539
|
};
|
|
27200
27540
|
}
|
|
27201
27541
|
function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
|
|
27202
|
-
return new Promise((
|
|
27542
|
+
return new Promise((resolve110) => {
|
|
27203
27543
|
const child = spawn4(binary, args, {
|
|
27204
27544
|
env: env ?? process.env,
|
|
27205
27545
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -27213,7 +27553,7 @@ function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
|
|
|
27213
27553
|
if (settled) return;
|
|
27214
27554
|
settled = true;
|
|
27215
27555
|
clearTimeout(timer3);
|
|
27216
|
-
|
|
27556
|
+
resolve110(result);
|
|
27217
27557
|
};
|
|
27218
27558
|
const timer3 = setTimeout(() => {
|
|
27219
27559
|
timedOut = true;
|
|
@@ -27512,7 +27852,7 @@ function createDashboardServer(options) {
|
|
|
27512
27852
|
(async () => {
|
|
27513
27853
|
try {
|
|
27514
27854
|
const configResult = await migrateLegacyConfig(
|
|
27515
|
-
|
|
27855
|
+
resolve48(syntaurRoot(), "config.md")
|
|
27516
27856
|
);
|
|
27517
27857
|
const projectResult = await migrateLegacyProjectFiles(projectsDir2);
|
|
27518
27858
|
const summary = summarizeMigration(projectResult, configResult);
|
|
@@ -28002,6 +28342,7 @@ function createDashboardServer(options) {
|
|
|
28002
28342
|
app.use("/api/schedules", createSchedulesRouter(broadcast));
|
|
28003
28343
|
app.use("/api/usage", createUsageRouter(projectsDir2, assignmentsDir2));
|
|
28004
28344
|
app.use("/api", createEventsRouter(projectsDir2, assignmentsDir2));
|
|
28345
|
+
app.use("/api", createInboxRouter(projectsDir2, assignmentsDir2));
|
|
28005
28346
|
app.use("/api/agent-sessions", createAgentSessionsRouter(projectsDir2, broadcast, assignmentsDir2));
|
|
28006
28347
|
app.use("/api/config/agents", createAgentsRouter());
|
|
28007
28348
|
app.use(
|
|
@@ -28034,14 +28375,14 @@ function createDashboardServer(options) {
|
|
|
28034
28375
|
app.use("/api/backup", createBackupRouter());
|
|
28035
28376
|
if (serveStaticUi && dashboardDistPath) {
|
|
28036
28377
|
const sendOpts = { dotfiles: "allow" };
|
|
28037
|
-
app.use("/assets", express.static(
|
|
28378
|
+
app.use("/assets", express.static(resolve48(dashboardDistPath, "assets"), sendOpts));
|
|
28038
28379
|
app.use(express.static(dashboardDistPath, { ...sendOpts, index: false, fallthrough: true }));
|
|
28039
28380
|
app.get("{*path}", async (req2, res) => {
|
|
28040
28381
|
if (req2.path.startsWith("/api") || req2.path === "/ws" || req2.path.startsWith("/assets")) {
|
|
28041
28382
|
res.status(404).json({ error: "Not Found" });
|
|
28042
28383
|
return;
|
|
28043
28384
|
}
|
|
28044
|
-
const indexPath =
|
|
28385
|
+
const indexPath = resolve48(dashboardDistPath, "index.html");
|
|
28045
28386
|
if (!await fileExists(indexPath)) {
|
|
28046
28387
|
res.status(503).send(
|
|
28047
28388
|
'Dashboard not built. Run "npm run build:dashboard" first.'
|
|
@@ -28075,8 +28416,8 @@ function createDashboardServer(options) {
|
|
|
28075
28416
|
if (!await migrationGate()) return;
|
|
28076
28417
|
try {
|
|
28077
28418
|
const context = await resolveDeriveContext2();
|
|
28078
|
-
const projectDir = projectSlug ?
|
|
28079
|
-
const path = projectDir ?
|
|
28419
|
+
const projectDir = projectSlug ? resolve48(projectsDir2, projectSlug) : null;
|
|
28420
|
+
const path = projectDir ? resolve48(projectDir, "assignments", assignmentSlug, "assignment.md") : resolve48(assignmentsDir2, assignmentSlug, "assignment.md");
|
|
28080
28421
|
if (!await fileExists(path)) return;
|
|
28081
28422
|
const result = await recomputeAndWrite2(path, {
|
|
28082
28423
|
cause: "derive",
|
|
@@ -28129,8 +28470,8 @@ function createDashboardServer(options) {
|
|
|
28129
28470
|
serversDir: serversDir2,
|
|
28130
28471
|
playbooksDir: playbooksDir3,
|
|
28131
28472
|
todosDir: todosDir2,
|
|
28132
|
-
dbPath:
|
|
28133
|
-
configPath:
|
|
28473
|
+
dbPath: resolve48(syntaurRoot(), "syntaur.db"),
|
|
28474
|
+
configPath: resolve48(syntaurRoot(), "config.md"),
|
|
28134
28475
|
onMessage: broadcast,
|
|
28135
28476
|
onAssignmentChanged: (projectSlug, assignmentSlug) => {
|
|
28136
28477
|
void recomputeOne(projectSlug, assignmentSlug);
|
|
@@ -28166,7 +28507,7 @@ function createDashboardServer(options) {
|
|
|
28166
28507
|
}
|
|
28167
28508
|
});
|
|
28168
28509
|
server.listen(port, () => {
|
|
28169
|
-
const portFile =
|
|
28510
|
+
const portFile = resolve48(syntaurRoot(), "dashboard-port");
|
|
28170
28511
|
writeFile8(portFile, String(port), "utf-8").catch(() => {
|
|
28171
28512
|
});
|
|
28172
28513
|
resolvePromise();
|
|
@@ -28186,7 +28527,7 @@ function createDashboardServer(options) {
|
|
|
28186
28527
|
client.terminate();
|
|
28187
28528
|
}
|
|
28188
28529
|
clients.clear();
|
|
28189
|
-
const portFile =
|
|
28530
|
+
const portFile = resolve48(syntaurRoot(), "dashboard-port");
|
|
28190
28531
|
await unlink9(portFile).catch(() => {
|
|
28191
28532
|
});
|
|
28192
28533
|
server.closeAllConnections?.();
|
|
@@ -28314,8 +28655,8 @@ async function dashboardCommand(options) {
|
|
|
28314
28655
|
port = availablePort;
|
|
28315
28656
|
}
|
|
28316
28657
|
const thisFile = fileURLToPath3(import.meta.url);
|
|
28317
|
-
const packageRoot =
|
|
28318
|
-
const dashboardDist =
|
|
28658
|
+
const packageRoot = resolve49(dirname13(thisFile), "..");
|
|
28659
|
+
const dashboardDist = resolve49(packageRoot, "dashboard", "dist");
|
|
28319
28660
|
const server = createDashboardServer({
|
|
28320
28661
|
port,
|
|
28321
28662
|
projectsDir: projectsDir2,
|
|
@@ -28339,8 +28680,8 @@ async function dashboardCommand(options) {
|
|
|
28339
28680
|
}
|
|
28340
28681
|
let viteProcess = null;
|
|
28341
28682
|
if (mode === "dev") {
|
|
28342
|
-
const dashboardDir =
|
|
28343
|
-
const viteBin =
|
|
28683
|
+
const dashboardDir = resolve49(packageRoot, "dashboard");
|
|
28684
|
+
const viteBin = resolve49(dashboardDir, "node_modules", ".bin", "vite");
|
|
28344
28685
|
if (!await fileExists(viteBin)) {
|
|
28345
28686
|
console.error(
|
|
28346
28687
|
'Vite not found. Run "npm ci --prefix dashboard" first, or use the default bundled dashboard mode.'
|
|
@@ -28415,7 +28756,7 @@ init_config2();
|
|
|
28415
28756
|
init_slug();
|
|
28416
28757
|
init_lifecycle();
|
|
28417
28758
|
init_assignment_resolver();
|
|
28418
|
-
import { resolve as
|
|
28759
|
+
import { resolve as resolve50 } from "path";
|
|
28419
28760
|
function resolveLinkedTodosLookup(projectsDir2) {
|
|
28420
28761
|
return { todosDir: todosDir(), projectsDir: projectsDir2 };
|
|
28421
28762
|
}
|
|
@@ -28429,8 +28770,8 @@ async function runTransition(assignment, command, options = {}) {
|
|
|
28429
28770
|
if (!isValidSlug(assignment)) {
|
|
28430
28771
|
throw new Error(`Invalid assignment slug "${assignment}".`);
|
|
28431
28772
|
}
|
|
28432
|
-
const projectDir =
|
|
28433
|
-
const projectMdPath =
|
|
28773
|
+
const projectDir = resolve50(baseDir, options.project);
|
|
28774
|
+
const projectMdPath = resolve50(projectDir, "project.md");
|
|
28434
28775
|
if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
|
|
28435
28776
|
throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
|
|
28436
28777
|
}
|
|
@@ -28463,8 +28804,8 @@ async function runAssign(assignment, agent, options = {}) {
|
|
|
28463
28804
|
if (!isValidSlug(assignment)) {
|
|
28464
28805
|
throw new Error(`Invalid assignment slug "${assignment}".`);
|
|
28465
28806
|
}
|
|
28466
|
-
const projectDir =
|
|
28467
|
-
const projectMdPath =
|
|
28807
|
+
const projectDir = resolve50(baseDir, options.project);
|
|
28808
|
+
const projectMdPath = resolve50(projectDir, "project.md");
|
|
28468
28809
|
if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
|
|
28469
28810
|
throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
|
|
28470
28811
|
}
|
|
@@ -28488,8 +28829,8 @@ async function runUnassign(assignment, options = {}) {
|
|
|
28488
28829
|
if (!isValidSlug(assignment)) {
|
|
28489
28830
|
throw new Error(`Invalid assignment slug "${assignment}".`);
|
|
28490
28831
|
}
|
|
28491
|
-
const projectDir =
|
|
28492
|
-
const projectMdPath =
|
|
28832
|
+
const projectDir = resolve50(baseDir, options.project);
|
|
28833
|
+
const projectMdPath = resolve50(projectDir, "project.md");
|
|
28493
28834
|
if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
|
|
28494
28835
|
throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
|
|
28495
28836
|
}
|
|
@@ -28540,17 +28881,17 @@ init_facts();
|
|
|
28540
28881
|
init_git_worktree();
|
|
28541
28882
|
init_recompute();
|
|
28542
28883
|
init_event_emit();
|
|
28543
|
-
import { readFile as
|
|
28544
|
-
import { resolve as
|
|
28884
|
+
import { readFile as readFile33 } from "fs/promises";
|
|
28885
|
+
import { resolve as resolve51, basename as basename6 } from "path";
|
|
28545
28886
|
async function resolveTarget(assignment, options) {
|
|
28546
28887
|
const config = await readConfig();
|
|
28547
28888
|
const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
|
|
28548
28889
|
if (options.project) {
|
|
28549
28890
|
if (!isValidSlug(options.project)) throw new Error(`Invalid project slug "${options.project}".`);
|
|
28550
28891
|
if (!isValidSlug(assignment)) throw new Error(`Invalid assignment slug "${assignment}".`);
|
|
28551
|
-
const projectDir =
|
|
28552
|
-
const assignmentDir =
|
|
28553
|
-
const assignmentPath =
|
|
28892
|
+
const projectDir = resolve51(baseDir, options.project);
|
|
28893
|
+
const assignmentDir = resolve51(projectDir, "assignments", assignment);
|
|
28894
|
+
const assignmentPath = resolve51(assignmentDir, "assignment.md");
|
|
28554
28895
|
if (!await fileExists(assignmentPath)) {
|
|
28555
28896
|
throw new Error(`Assignment "${assignment}" not found at ${assignmentPath}.`);
|
|
28556
28897
|
}
|
|
@@ -28562,14 +28903,14 @@ async function resolveTarget(assignment, options) {
|
|
|
28562
28903
|
}
|
|
28563
28904
|
return {
|
|
28564
28905
|
assignmentDir: resolved.assignmentDir,
|
|
28565
|
-
assignmentPath:
|
|
28566
|
-
projectDir: resolved.standalone ? null :
|
|
28906
|
+
assignmentPath: resolve51(resolved.assignmentDir, "assignment.md"),
|
|
28907
|
+
projectDir: resolved.standalone ? null : resolve51(resolved.assignmentDir, "..", "..")
|
|
28567
28908
|
};
|
|
28568
28909
|
}
|
|
28569
28910
|
async function inferActor(options) {
|
|
28570
28911
|
if (options.agent) return `agent:${options.agent}`;
|
|
28571
28912
|
try {
|
|
28572
|
-
const raw2 = await
|
|
28913
|
+
const raw2 = await readFile33(resolve51(process.cwd(), ".syntaur", "context.json"), "utf-8");
|
|
28573
28914
|
const ctx = JSON.parse(raw2);
|
|
28574
28915
|
if (ctx.sessionId) return `agent:${ctx.sessionId.slice(0, 8)}`;
|
|
28575
28916
|
} catch {
|
|
@@ -28578,7 +28919,7 @@ async function inferActor(options) {
|
|
|
28578
28919
|
}
|
|
28579
28920
|
async function emitDeriveEvent(target, type, actor, details) {
|
|
28580
28921
|
try {
|
|
28581
|
-
const fm = parseAssignmentFrontmatter(await
|
|
28922
|
+
const fm = parseAssignmentFrontmatter(await readFile33(target.assignmentPath, "utf-8"));
|
|
28582
28923
|
emitEvent({
|
|
28583
28924
|
assignmentId: fm.id,
|
|
28584
28925
|
projectSlug: target.projectDir ? basename6(target.projectDir) : null,
|
|
@@ -28639,7 +28980,7 @@ async function planApproveCommand(assignment, options) {
|
|
|
28639
28980
|
throw new Error("No plan file found (plan.md / plan-v*.md). Write a plan before approving.");
|
|
28640
28981
|
}
|
|
28641
28982
|
approvedFile = planFile;
|
|
28642
|
-
const planContent = await
|
|
28983
|
+
const planContent = await readFile33(resolve51(target2.assignmentDir, planFile), "utf-8");
|
|
28643
28984
|
return updatePlanApproval(content, {
|
|
28644
28985
|
file: planFile,
|
|
28645
28986
|
digest: planDigest(planContent),
|
|
@@ -28712,7 +29053,7 @@ async function attestCommand(assignment, fact, options) {
|
|
|
28712
29053
|
"No plan file found (plan.md / plan-v*.md). Write a plan before attesting a binds:plan fact."
|
|
28713
29054
|
);
|
|
28714
29055
|
}
|
|
28715
|
-
const planContent = await
|
|
29056
|
+
const planContent = await readFile33(resolve51(target2.assignmentDir, planFile), "utf-8");
|
|
28716
29057
|
record.file = planFile;
|
|
28717
29058
|
record.digest = planDigest(planContent);
|
|
28718
29059
|
} else if (binds === "commit") {
|
|
@@ -28864,8 +29205,8 @@ init_frontmatter();
|
|
|
28864
29205
|
init_timestamp();
|
|
28865
29206
|
init_assignment_resolver();
|
|
28866
29207
|
init_event_emit();
|
|
28867
|
-
import { resolve as
|
|
28868
|
-
import { readFile as
|
|
29208
|
+
import { resolve as resolve52 } from "path";
|
|
29209
|
+
import { readFile as readFile34, writeFile as writeFile9 } from "fs/promises";
|
|
28869
29210
|
async function resolveTarget2(target, options) {
|
|
28870
29211
|
const config = await readConfig();
|
|
28871
29212
|
const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
|
|
@@ -28876,7 +29217,7 @@ async function resolveTarget2(target, options) {
|
|
|
28876
29217
|
if (!isValidSlug(target)) {
|
|
28877
29218
|
throw new Error(`Invalid assignment slug "${target}".`);
|
|
28878
29219
|
}
|
|
28879
|
-
const assignmentMd =
|
|
29220
|
+
const assignmentMd = resolve52(baseDir, options.project, "assignments", target, "assignment.md");
|
|
28880
29221
|
if (!await fileExists(assignmentMd)) {
|
|
28881
29222
|
throw new Error(`Assignment "${target}" not found in project "${options.project}".`);
|
|
28882
29223
|
}
|
|
@@ -28886,18 +29227,18 @@ async function resolveTarget2(target, options) {
|
|
|
28886
29227
|
if (resolved) {
|
|
28887
29228
|
return {
|
|
28888
29229
|
kind: "assignment",
|
|
28889
|
-
filePath:
|
|
29230
|
+
filePath: resolve52(resolved.assignmentDir, "assignment.md"),
|
|
28890
29231
|
label: resolved.projectSlug ? `assignment "${resolved.projectSlug}/${resolved.assignmentSlug}"` : `assignment "${target}"`
|
|
28891
29232
|
};
|
|
28892
29233
|
}
|
|
28893
|
-
const projectMd =
|
|
29234
|
+
const projectMd = resolve52(baseDir, target, "project.md");
|
|
28894
29235
|
if (await fileExists(projectMd)) {
|
|
28895
29236
|
return { kind: "project", filePath: projectMd, label: `project "${target}"` };
|
|
28896
29237
|
}
|
|
28897
29238
|
return null;
|
|
28898
29239
|
}
|
|
28899
29240
|
async function writeArchiveState(filePath, archived, reason) {
|
|
28900
|
-
const content = await
|
|
29241
|
+
const content = await readFile34(filePath, "utf-8");
|
|
28901
29242
|
const updated = updateAssignmentFile(content, {
|
|
28902
29243
|
archived,
|
|
28903
29244
|
archivedAt: archived ? nowTimestamp() : null,
|
|
@@ -28909,7 +29250,7 @@ async function writeArchiveState(filePath, archived, reason) {
|
|
|
28909
29250
|
async function emitArchiveEvent(resolved, type, reason) {
|
|
28910
29251
|
if (resolved.kind !== "assignment") return;
|
|
28911
29252
|
try {
|
|
28912
|
-
const fm = parseAssignmentFrontmatter(await
|
|
29253
|
+
const fm = parseAssignmentFrontmatter(await readFile34(resolved.filePath, "utf-8"));
|
|
28913
29254
|
emitEvent({
|
|
28914
29255
|
assignmentId: fm.id,
|
|
28915
29256
|
projectSlug: fm.project,
|
|
@@ -28979,8 +29320,8 @@ init_config2();
|
|
|
28979
29320
|
init_frontmatter();
|
|
28980
29321
|
init_timestamp();
|
|
28981
29322
|
init_event_emit();
|
|
28982
|
-
import { resolve as
|
|
28983
|
-
import { readdir as readdir20, readFile as
|
|
29323
|
+
import { resolve as resolve53 } from "path";
|
|
29324
|
+
import { readdir as readdir20, readFile as readFile35 } from "fs/promises";
|
|
28984
29325
|
var PROMOTABLE_STATUSES = /* @__PURE__ */ new Set(["pending"]);
|
|
28985
29326
|
function objectiveIsFleshedOut(content) {
|
|
28986
29327
|
const match = content.match(/##\s+Objective\s*\n([\s\S]*?)(?=\n##\s+|$)/);
|
|
@@ -29002,11 +29343,11 @@ async function collectCandidates(baseDirs) {
|
|
|
29002
29343
|
for (const m of projects) {
|
|
29003
29344
|
if (!m.isDirectory()) continue;
|
|
29004
29345
|
if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
|
|
29005
|
-
const directAssignmentMd =
|
|
29346
|
+
const directAssignmentMd = resolve53(baseDir, m.name, "assignment.md");
|
|
29006
29347
|
if (await fileExists(directAssignmentMd)) {
|
|
29007
29348
|
const fm = await parseSafe(directAssignmentMd);
|
|
29008
29349
|
if (fm && PROMOTABLE_STATUSES.has(fm.status)) {
|
|
29009
|
-
const content = await
|
|
29350
|
+
const content = await readFile35(directAssignmentMd, "utf-8");
|
|
29010
29351
|
if (objectiveIsFleshedOut(content) && hasAcceptanceCriteria(content)) {
|
|
29011
29352
|
candidates.push({
|
|
29012
29353
|
projectSlug: null,
|
|
@@ -29019,17 +29360,17 @@ async function collectCandidates(baseDirs) {
|
|
|
29019
29360
|
}
|
|
29020
29361
|
continue;
|
|
29021
29362
|
}
|
|
29022
|
-
const assignmentsDir2 =
|
|
29363
|
+
const assignmentsDir2 = resolve53(baseDir, m.name, "assignments");
|
|
29023
29364
|
if (!await fileExists(assignmentsDir2)) continue;
|
|
29024
29365
|
const entries = await readdir20(assignmentsDir2, { withFileTypes: true });
|
|
29025
29366
|
for (const a of entries) {
|
|
29026
29367
|
if (!a.isDirectory()) continue;
|
|
29027
29368
|
if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
|
|
29028
|
-
const assignmentMd =
|
|
29369
|
+
const assignmentMd = resolve53(assignmentsDir2, a.name, "assignment.md");
|
|
29029
29370
|
if (!await fileExists(assignmentMd)) continue;
|
|
29030
29371
|
const fm = await parseSafe(assignmentMd);
|
|
29031
29372
|
if (!fm || !PROMOTABLE_STATUSES.has(fm.status)) continue;
|
|
29032
|
-
const content = await
|
|
29373
|
+
const content = await readFile35(assignmentMd, "utf-8");
|
|
29033
29374
|
if (!objectiveIsFleshedOut(content)) continue;
|
|
29034
29375
|
if (!hasAcceptanceCriteria(content)) continue;
|
|
29035
29376
|
candidates.push({
|
|
@@ -29046,7 +29387,7 @@ async function collectCandidates(baseDirs) {
|
|
|
29046
29387
|
}
|
|
29047
29388
|
async function parseSafe(path) {
|
|
29048
29389
|
try {
|
|
29049
|
-
const content = await
|
|
29390
|
+
const content = await readFile35(path, "utf-8");
|
|
29050
29391
|
return parseAssignmentFrontmatter(content);
|
|
29051
29392
|
} catch {
|
|
29052
29393
|
return null;
|
|
@@ -29076,7 +29417,7 @@ async function migrateStatusesCommand(options) {
|
|
|
29076
29417
|
let migrated = 0;
|
|
29077
29418
|
await withSuppressedEvents(async () => {
|
|
29078
29419
|
for (const c2 of candidates) {
|
|
29079
|
-
const content = await
|
|
29420
|
+
const content = await readFile35(c2.assignmentMd, "utf-8");
|
|
29080
29421
|
const updated = appendStatusHistoryEntry(
|
|
29081
29422
|
updateAssignmentFile(content, {
|
|
29082
29423
|
status: c2.toStatus,
|
|
@@ -29098,11 +29439,11 @@ init_config2();
|
|
|
29098
29439
|
init_frontmatter();
|
|
29099
29440
|
init_event_emit();
|
|
29100
29441
|
init_types();
|
|
29101
|
-
import { resolve as
|
|
29102
|
-
import { readdir as readdir21, readFile as
|
|
29442
|
+
import { resolve as resolve54 } from "path";
|
|
29443
|
+
import { readdir as readdir21, readFile as readFile36 } from "fs/promises";
|
|
29103
29444
|
async function parseSafe2(path) {
|
|
29104
29445
|
try {
|
|
29105
|
-
return parseAssignmentFrontmatter(await
|
|
29446
|
+
return parseAssignmentFrontmatter(await readFile36(path, "utf-8"));
|
|
29106
29447
|
} catch {
|
|
29107
29448
|
return null;
|
|
29108
29449
|
}
|
|
@@ -29129,7 +29470,7 @@ async function collectTargets(baseDirs, terminalStatuses3) {
|
|
|
29129
29470
|
for (const m of entries) {
|
|
29130
29471
|
if (!m.isDirectory()) continue;
|
|
29131
29472
|
if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
|
|
29132
|
-
const directAssignmentMd =
|
|
29473
|
+
const directAssignmentMd = resolve54(baseDir, m.name, "assignment.md");
|
|
29133
29474
|
if (await fileExists(directAssignmentMd)) {
|
|
29134
29475
|
if (seen.has(directAssignmentMd)) continue;
|
|
29135
29476
|
const fm = await parseSafe2(directAssignmentMd);
|
|
@@ -29144,13 +29485,13 @@ async function collectTargets(baseDirs, terminalStatuses3) {
|
|
|
29144
29485
|
}
|
|
29145
29486
|
continue;
|
|
29146
29487
|
}
|
|
29147
|
-
const assignmentsBase =
|
|
29488
|
+
const assignmentsBase = resolve54(baseDir, m.name, "assignments");
|
|
29148
29489
|
if (!await fileExists(assignmentsBase)) continue;
|
|
29149
29490
|
const slugs = await readdir21(assignmentsBase, { withFileTypes: true });
|
|
29150
29491
|
for (const a of slugs) {
|
|
29151
29492
|
if (!a.isDirectory()) continue;
|
|
29152
29493
|
if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
|
|
29153
|
-
const assignmentMd =
|
|
29494
|
+
const assignmentMd = resolve54(assignmentsBase, a.name, "assignment.md");
|
|
29154
29495
|
if (!await fileExists(assignmentMd)) continue;
|
|
29155
29496
|
if (seen.has(assignmentMd)) continue;
|
|
29156
29497
|
const fm = await parseSafe2(assignmentMd);
|
|
@@ -29194,7 +29535,7 @@ async function migrateStatusHistoryCommand(options) {
|
|
|
29194
29535
|
await withSuppressedEvents(async () => {
|
|
29195
29536
|
for (const t of targets) {
|
|
29196
29537
|
try {
|
|
29197
|
-
const content = await
|
|
29538
|
+
const content = await readFile36(t.assignmentMd, "utf-8");
|
|
29198
29539
|
if (parseAssignmentFrontmatter(content).statusHistory.length > 0) continue;
|
|
29199
29540
|
const seededContent = appendStatusHistoryEntry(content, {
|
|
29200
29541
|
at: t.seedAt,
|
|
@@ -29222,11 +29563,11 @@ init_fs();
|
|
|
29222
29563
|
init_config2();
|
|
29223
29564
|
init_parser();
|
|
29224
29565
|
init_events_db();
|
|
29225
|
-
import { resolve as
|
|
29226
|
-
import { readdir as readdir22, readFile as
|
|
29566
|
+
import { resolve as resolve55 } from "path";
|
|
29567
|
+
import { readdir as readdir22, readFile as readFile37 } from "fs/promises";
|
|
29227
29568
|
async function parseSafe3(path) {
|
|
29228
29569
|
try {
|
|
29229
|
-
return parseAssignmentFull(await
|
|
29570
|
+
return parseAssignmentFull(await readFile37(path, "utf-8"));
|
|
29230
29571
|
} catch {
|
|
29231
29572
|
return null;
|
|
29232
29573
|
}
|
|
@@ -29263,7 +29604,7 @@ async function collectTargets2(baseDirs) {
|
|
|
29263
29604
|
for (const m of entries) {
|
|
29264
29605
|
if (!m.isDirectory()) continue;
|
|
29265
29606
|
if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
|
|
29266
|
-
const directAssignmentMd =
|
|
29607
|
+
const directAssignmentMd = resolve55(baseDir, m.name, "assignment.md");
|
|
29267
29608
|
if (await fileExists(directAssignmentMd)) {
|
|
29268
29609
|
if (seen.has(directAssignmentMd)) continue;
|
|
29269
29610
|
seen.add(directAssignmentMd);
|
|
@@ -29281,13 +29622,13 @@ async function collectTargets2(baseDirs) {
|
|
|
29281
29622
|
}
|
|
29282
29623
|
continue;
|
|
29283
29624
|
}
|
|
29284
|
-
const assignmentsBase =
|
|
29625
|
+
const assignmentsBase = resolve55(baseDir, m.name, "assignments");
|
|
29285
29626
|
if (!await fileExists(assignmentsBase)) continue;
|
|
29286
29627
|
const slugs = await readdir22(assignmentsBase, { withFileTypes: true });
|
|
29287
29628
|
for (const a of slugs) {
|
|
29288
29629
|
if (!a.isDirectory()) continue;
|
|
29289
29630
|
if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
|
|
29290
|
-
const assignmentMd =
|
|
29631
|
+
const assignmentMd = resolve55(assignmentsBase, a.name, "assignment.md");
|
|
29291
29632
|
if (!await fileExists(assignmentMd)) continue;
|
|
29292
29633
|
if (seen.has(assignmentMd)) continue;
|
|
29293
29634
|
seen.add(assignmentMd);
|
|
@@ -29368,8 +29709,8 @@ init_frontmatter();
|
|
|
29368
29709
|
init_facts();
|
|
29369
29710
|
init_derive();
|
|
29370
29711
|
init_recompute();
|
|
29371
|
-
import { readdir as readdir23, readFile as
|
|
29372
|
-
import { resolve as
|
|
29712
|
+
import { readdir as readdir23, readFile as readFile38 } from "fs/promises";
|
|
29713
|
+
import { resolve as resolve56 } from "path";
|
|
29373
29714
|
var IMPLEMENTATION_STATUSES = /* @__PURE__ */ new Set(["in_progress", "review", "code_review"]);
|
|
29374
29715
|
var REVIEW_STATUSES = /* @__PURE__ */ new Set(["review", "code_review"]);
|
|
29375
29716
|
async function listTargets(projectsDir2, standaloneDir) {
|
|
@@ -29380,15 +29721,15 @@ async function listTargets(projectsDir2, standaloneDir) {
|
|
|
29380
29721
|
} catch {
|
|
29381
29722
|
}
|
|
29382
29723
|
for (const project of projects) {
|
|
29383
|
-
const projectDir =
|
|
29724
|
+
const projectDir = resolve56(projectsDir2, project);
|
|
29384
29725
|
let slugs = [];
|
|
29385
29726
|
try {
|
|
29386
|
-
slugs = await readdir23(
|
|
29727
|
+
slugs = await readdir23(resolve56(projectDir, "assignments"));
|
|
29387
29728
|
} catch {
|
|
29388
29729
|
continue;
|
|
29389
29730
|
}
|
|
29390
29731
|
for (const slug of slugs) {
|
|
29391
|
-
const path =
|
|
29732
|
+
const path = resolve56(projectDir, "assignments", slug, "assignment.md");
|
|
29392
29733
|
if (await fileExists(path)) targets.push({ path, projectDir, ref: `${project}/${slug}` });
|
|
29393
29734
|
}
|
|
29394
29735
|
}
|
|
@@ -29398,7 +29739,7 @@ async function listTargets(projectsDir2, standaloneDir) {
|
|
|
29398
29739
|
} catch {
|
|
29399
29740
|
}
|
|
29400
29741
|
for (const id of ids) {
|
|
29401
|
-
const path =
|
|
29742
|
+
const path = resolve56(standaloneDir, id, "assignment.md");
|
|
29402
29743
|
if (await fileExists(path)) targets.push({ path, projectDir: null, ref: id });
|
|
29403
29744
|
}
|
|
29404
29745
|
return targets;
|
|
@@ -29453,7 +29794,7 @@ async function migrateDeriveCommand(options) {
|
|
|
29453
29794
|
for (const target of targets) {
|
|
29454
29795
|
let content;
|
|
29455
29796
|
try {
|
|
29456
|
-
content = await
|
|
29797
|
+
content = await readFile38(target.path, "utf-8");
|
|
29457
29798
|
} catch {
|
|
29458
29799
|
continue;
|
|
29459
29800
|
}
|
|
@@ -29468,7 +29809,7 @@ async function migrateDeriveCommand(options) {
|
|
|
29468
29809
|
const seededFm = parseAssignmentFrontmatter(seededContent);
|
|
29469
29810
|
const body = seededContent.replace(/^---\n[\s\S]*?\n---/, "");
|
|
29470
29811
|
const facts = await computeFacts({
|
|
29471
|
-
assignmentDir:
|
|
29812
|
+
assignmentDir: resolve56(target.path, ".."),
|
|
29472
29813
|
frontmatter: seededFm,
|
|
29473
29814
|
body,
|
|
29474
29815
|
projectDir: target.projectDir,
|
|
@@ -29528,7 +29869,7 @@ async function migrateDeriveCommand(options) {
|
|
|
29528
29869
|
}
|
|
29529
29870
|
|
|
29530
29871
|
// src/commands/complete.ts
|
|
29531
|
-
import { resolve as
|
|
29872
|
+
import { resolve as resolve57 } from "path";
|
|
29532
29873
|
init_config2();
|
|
29533
29874
|
init_paths();
|
|
29534
29875
|
init_assignment_resolver();
|
|
@@ -29542,12 +29883,12 @@ async function completeCommand(assignment, options) {
|
|
|
29542
29883
|
let projectDir;
|
|
29543
29884
|
let changedSlug;
|
|
29544
29885
|
if (options.project) {
|
|
29545
|
-
projectDir =
|
|
29886
|
+
projectDir = resolve57(baseDir, options.project);
|
|
29546
29887
|
changedSlug = assignment;
|
|
29547
29888
|
} else {
|
|
29548
29889
|
const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), assignment);
|
|
29549
29890
|
if (!resolved) return;
|
|
29550
|
-
projectDir = resolved.standalone ? null :
|
|
29891
|
+
projectDir = resolved.standalone ? null : resolve57(resolved.assignmentDir, "..", "..");
|
|
29551
29892
|
changedSlug = resolved.assignmentSlug;
|
|
29552
29893
|
}
|
|
29553
29894
|
if (projectDir) {
|
|
@@ -29578,7 +29919,7 @@ async function reviewCommand(assignment, options) {
|
|
|
29578
29919
|
}
|
|
29579
29920
|
|
|
29580
29921
|
// src/commands/fail.ts
|
|
29581
|
-
import { resolve as
|
|
29922
|
+
import { resolve as resolve58 } from "path";
|
|
29582
29923
|
init_config2();
|
|
29583
29924
|
init_paths();
|
|
29584
29925
|
init_assignment_resolver();
|
|
@@ -29592,12 +29933,12 @@ async function failCommand(assignment, options) {
|
|
|
29592
29933
|
let projectDir;
|
|
29593
29934
|
let changedSlug;
|
|
29594
29935
|
if (options.project) {
|
|
29595
|
-
projectDir =
|
|
29936
|
+
projectDir = resolve58(baseDir, options.project);
|
|
29596
29937
|
changedSlug = assignment;
|
|
29597
29938
|
} else {
|
|
29598
29939
|
const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), assignment);
|
|
29599
29940
|
if (!resolved) return;
|
|
29600
|
-
projectDir = resolved.standalone ? null :
|
|
29941
|
+
projectDir = resolved.standalone ? null : resolve58(resolved.assignmentDir, "..", "..");
|
|
29601
29942
|
changedSlug = resolved.assignmentSlug;
|
|
29602
29943
|
}
|
|
29603
29944
|
if (projectDir) {
|
|
@@ -29613,7 +29954,7 @@ async function failCommand(assignment, options) {
|
|
|
29613
29954
|
}
|
|
29614
29955
|
|
|
29615
29956
|
// src/commands/reopen.ts
|
|
29616
|
-
import { resolve as
|
|
29957
|
+
import { resolve as resolve59 } from "path";
|
|
29617
29958
|
init_config2();
|
|
29618
29959
|
init_paths();
|
|
29619
29960
|
init_assignment_resolver();
|
|
@@ -29629,14 +29970,14 @@ async function reopenCommand(assignment, options) {
|
|
|
29629
29970
|
let projectDir;
|
|
29630
29971
|
let changedSlug;
|
|
29631
29972
|
if (options.project) {
|
|
29632
|
-
projectDir =
|
|
29633
|
-
assignmentPath =
|
|
29973
|
+
projectDir = resolve59(baseDir, options.project);
|
|
29974
|
+
assignmentPath = resolve59(projectDir, "assignments", assignment, "assignment.md");
|
|
29634
29975
|
changedSlug = assignment;
|
|
29635
29976
|
} else {
|
|
29636
29977
|
const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), assignment);
|
|
29637
29978
|
if (!resolved) return;
|
|
29638
|
-
assignmentPath =
|
|
29639
|
-
projectDir = resolved.standalone ? null :
|
|
29979
|
+
assignmentPath = resolve59(resolved.assignmentDir, "assignment.md");
|
|
29980
|
+
projectDir = resolved.standalone ? null : resolve59(resolved.assignmentDir, "..", "..");
|
|
29640
29981
|
changedSlug = resolved.assignmentSlug;
|
|
29641
29982
|
}
|
|
29642
29983
|
const derived = await recomputeAndWrite(assignmentPath, {
|
|
@@ -29670,7 +30011,7 @@ import {
|
|
|
29670
30011
|
readdir as readdir24,
|
|
29671
30012
|
symlink,
|
|
29672
30013
|
lstat,
|
|
29673
|
-
readFile as
|
|
30014
|
+
readFile as readFile39,
|
|
29674
30015
|
readlink,
|
|
29675
30016
|
rename as rename9,
|
|
29676
30017
|
rm as rm6,
|
|
@@ -29679,20 +30020,20 @@ import {
|
|
|
29679
30020
|
} from "fs/promises";
|
|
29680
30021
|
import { existsSync as existsSync4 } from "fs";
|
|
29681
30022
|
import { homedir as homedir8 } from "os";
|
|
29682
|
-
import { basename as basename7, dirname as dirname15, isAbsolute as isAbsolute7, relative as relative2, resolve as
|
|
30023
|
+
import { basename as basename7, dirname as dirname15, isAbsolute as isAbsolute7, relative as relative2, resolve as resolve61 } from "path";
|
|
29683
30024
|
|
|
29684
30025
|
// src/utils/package-root.ts
|
|
29685
30026
|
init_fs();
|
|
29686
|
-
import { dirname as dirname14, resolve as
|
|
30027
|
+
import { dirname as dirname14, resolve as resolve60 } from "path";
|
|
29687
30028
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
29688
30029
|
async function findPackageRoot(expectedRelativePath) {
|
|
29689
30030
|
let currentDir = dirname14(fileURLToPath4(import.meta.url));
|
|
29690
30031
|
while (true) {
|
|
29691
|
-
const candidate =
|
|
30032
|
+
const candidate = resolve60(currentDir, expectedRelativePath);
|
|
29692
30033
|
if (await fileExists(candidate)) {
|
|
29693
30034
|
return currentDir;
|
|
29694
30035
|
}
|
|
29695
|
-
const parentDir =
|
|
30036
|
+
const parentDir = resolve60(currentDir, "..");
|
|
29696
30037
|
if (parentDir === currentDir) {
|
|
29697
30038
|
throw new Error(
|
|
29698
30039
|
`Could not locate package root containing ${expectedRelativePath}.`
|
|
@@ -29713,25 +30054,25 @@ function getPluginManifestRelativePath(pluginKind) {
|
|
|
29713
30054
|
}
|
|
29714
30055
|
function getDefaultPluginTargetDir(pluginKind) {
|
|
29715
30056
|
const home2 = homedir8();
|
|
29716
|
-
return pluginKind === "claude" ?
|
|
30057
|
+
return pluginKind === "claude" ? resolve61(home2, ".claude", "plugins", "syntaur") : resolve61(home2, "plugins", "syntaur");
|
|
29717
30058
|
}
|
|
29718
30059
|
function getDefaultMarketplacePath() {
|
|
29719
|
-
return
|
|
30060
|
+
return resolve61(homedir8(), ".agents", "plugins", "marketplace.json");
|
|
29720
30061
|
}
|
|
29721
30062
|
function getClaudeMarketplacesRoot() {
|
|
29722
|
-
return
|
|
30063
|
+
return resolve61(homedir8(), ".claude", "plugins", "marketplaces");
|
|
29723
30064
|
}
|
|
29724
30065
|
function getClaudeKnownMarketplacesPath() {
|
|
29725
|
-
return
|
|
30066
|
+
return resolve61(homedir8(), ".claude", "plugins", "known_marketplaces.json");
|
|
29726
30067
|
}
|
|
29727
30068
|
function getClaudeInstalledPluginsPath() {
|
|
29728
|
-
return
|
|
30069
|
+
return resolve61(homedir8(), ".claude", "plugins", "installed_plugins.json");
|
|
29729
30070
|
}
|
|
29730
30071
|
function getInstallMarkerPath(targetDir) {
|
|
29731
|
-
return
|
|
30072
|
+
return resolve61(targetDir, INSTALL_MARKER_FILENAME);
|
|
29732
30073
|
}
|
|
29733
30074
|
async function readPackageManifest(packageRoot) {
|
|
29734
|
-
const raw2 = await
|
|
30075
|
+
const raw2 = await readFile39(resolve61(packageRoot, "package.json"), "utf-8");
|
|
29735
30076
|
return JSON.parse(raw2);
|
|
29736
30077
|
}
|
|
29737
30078
|
async function readJsonFileIfExists(pathValue) {
|
|
@@ -29739,7 +30080,7 @@ async function readJsonFileIfExists(pathValue) {
|
|
|
29739
30080
|
return null;
|
|
29740
30081
|
}
|
|
29741
30082
|
try {
|
|
29742
|
-
const raw2 = await
|
|
30083
|
+
const raw2 = await readFile39(pathValue, "utf-8");
|
|
29743
30084
|
return JSON.parse(raw2);
|
|
29744
30085
|
} catch {
|
|
29745
30086
|
return null;
|
|
@@ -29747,15 +30088,15 @@ async function readJsonFileIfExists(pathValue) {
|
|
|
29747
30088
|
}
|
|
29748
30089
|
async function readClaudePluginManifest(pluginDir) {
|
|
29749
30090
|
return await readJsonFileIfExists(
|
|
29750
|
-
|
|
30091
|
+
resolve61(pluginDir, ".claude-plugin", "plugin.json")
|
|
29751
30092
|
) ?? {};
|
|
29752
30093
|
}
|
|
29753
30094
|
async function readPluginManifestName(targetDir, pluginKind) {
|
|
29754
|
-
const manifestPath =
|
|
30095
|
+
const manifestPath = resolve61(targetDir, getPluginManifestRelativePath(pluginKind));
|
|
29755
30096
|
if (!await fileExists(manifestPath)) {
|
|
29756
30097
|
return void 0;
|
|
29757
30098
|
}
|
|
29758
|
-
const raw2 = await
|
|
30099
|
+
const raw2 = await readFile39(manifestPath, "utf-8");
|
|
29759
30100
|
const parsed = JSON.parse(raw2);
|
|
29760
30101
|
return parsed.name;
|
|
29761
30102
|
}
|
|
@@ -29765,7 +30106,7 @@ async function readInstallMetadata(targetDir) {
|
|
|
29765
30106
|
return null;
|
|
29766
30107
|
}
|
|
29767
30108
|
try {
|
|
29768
|
-
const raw2 = await
|
|
30109
|
+
const raw2 = await readFile39(markerPath, "utf-8");
|
|
29769
30110
|
return JSON.parse(raw2);
|
|
29770
30111
|
} catch {
|
|
29771
30112
|
return null;
|
|
@@ -29778,7 +30119,7 @@ async function getInstallStatus(targetDir, pluginKind) {
|
|
|
29778
30119
|
const info = await lstat(targetDir);
|
|
29779
30120
|
if (info.isSymbolicLink()) {
|
|
29780
30121
|
const symlinkTarget = await readlink(targetDir);
|
|
29781
|
-
const resolvedTarget =
|
|
30122
|
+
const resolvedTarget = resolve61(dirname15(targetDir), symlinkTarget);
|
|
29782
30123
|
const manifestName2 = await readPluginManifestName(resolvedTarget, pluginKind);
|
|
29783
30124
|
return {
|
|
29784
30125
|
exists: true,
|
|
@@ -29824,7 +30165,7 @@ async function installLink(paths) {
|
|
|
29824
30165
|
await ensureDir(dirname15(paths.targetDir));
|
|
29825
30166
|
await rm6(paths.targetDir, { recursive: true, force: true });
|
|
29826
30167
|
await ensureDir(dirname15(paths.targetDir));
|
|
29827
|
-
await symlink(
|
|
30168
|
+
await symlink(resolve61(paths.sourceDir), paths.targetDir, "dir");
|
|
29828
30169
|
}
|
|
29829
30170
|
async function removeInstallMarker(targetDir) {
|
|
29830
30171
|
const markerPath = getInstallMarkerPath(targetDir);
|
|
@@ -29838,13 +30179,13 @@ function normalizeAbsoluteInstallPath(pathValue, label) {
|
|
|
29838
30179
|
if (!isAbsolute7(expanded)) {
|
|
29839
30180
|
throw new Error(`${label} must be an absolute path.`);
|
|
29840
30181
|
}
|
|
29841
|
-
return
|
|
30182
|
+
return resolve61(expanded);
|
|
29842
30183
|
}
|
|
29843
30184
|
async function resolvePluginPaths(pluginKind, targetDir) {
|
|
29844
30185
|
const packageRoot = await findPackageRoot(getPluginRelativePath(pluginKind));
|
|
29845
30186
|
return {
|
|
29846
30187
|
packageRoot,
|
|
29847
|
-
sourceDir:
|
|
30188
|
+
sourceDir: resolve61(packageRoot, getPluginRelativePath(pluginKind)),
|
|
29848
30189
|
targetDir: targetDir ?? getDefaultPluginTargetDir(pluginKind)
|
|
29849
30190
|
};
|
|
29850
30191
|
}
|
|
@@ -29888,7 +30229,7 @@ async function writeClaudeMarketplaceFile(manifestPath, marketplace) {
|
|
|
29888
30229
|
}
|
|
29889
30230
|
if (await fileExists(manifestPath)) {
|
|
29890
30231
|
try {
|
|
29891
|
-
const prev = await
|
|
30232
|
+
const prev = await readFile39(manifestPath, "utf-8");
|
|
29892
30233
|
JSON.parse(prev);
|
|
29893
30234
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
29894
30235
|
await writeFile10(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
|
|
@@ -29969,8 +30310,8 @@ async function listClaudeMarketplaceCandidates() {
|
|
|
29969
30310
|
if (!entry.isDirectory()) {
|
|
29970
30311
|
continue;
|
|
29971
30312
|
}
|
|
29972
|
-
const candidateRoot =
|
|
29973
|
-
const manifestPath =
|
|
30313
|
+
const candidateRoot = resolve61(rootDir, entry.name);
|
|
30314
|
+
const manifestPath = resolve61(candidateRoot, ".claude-plugin", "marketplace.json");
|
|
29974
30315
|
if (!await fileExists(manifestPath)) {
|
|
29975
30316
|
continue;
|
|
29976
30317
|
}
|
|
@@ -29997,11 +30338,11 @@ async function listClaudeMarketplaceCandidates() {
|
|
|
29997
30338
|
if (!installLocation) {
|
|
29998
30339
|
continue;
|
|
29999
30340
|
}
|
|
30000
|
-
const candidateRoot =
|
|
30341
|
+
const candidateRoot = resolve61(expandHome(installLocation));
|
|
30001
30342
|
if (seen.has(candidateRoot)) {
|
|
30002
30343
|
continue;
|
|
30003
30344
|
}
|
|
30004
|
-
const manifestPath =
|
|
30345
|
+
const manifestPath = resolve61(candidateRoot, ".claude-plugin", "marketplace.json");
|
|
30005
30346
|
if (!await fileExists(manifestPath)) {
|
|
30006
30347
|
continue;
|
|
30007
30348
|
}
|
|
@@ -30029,14 +30370,14 @@ async function getPreferredClaudeMarketplace() {
|
|
|
30029
30370
|
name: candidate.name,
|
|
30030
30371
|
rootDir: candidate.rootDir,
|
|
30031
30372
|
manifestPath: candidate.manifestPath,
|
|
30032
|
-
targetDir:
|
|
30373
|
+
targetDir: resolve61(candidate.rootDir, "plugins", "syntaur")
|
|
30033
30374
|
};
|
|
30034
30375
|
}
|
|
30035
30376
|
async function registerKnownClaudeMarketplace(name, rootDir) {
|
|
30036
30377
|
const manifestPath = getClaudeKnownMarketplacesPath();
|
|
30037
30378
|
let existing = {};
|
|
30038
30379
|
if (await fileExists(manifestPath)) {
|
|
30039
|
-
const raw2 = await
|
|
30380
|
+
const raw2 = await readFile39(manifestPath, "utf-8");
|
|
30040
30381
|
try {
|
|
30041
30382
|
const parsed = JSON.parse(raw2);
|
|
30042
30383
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
@@ -30063,7 +30404,7 @@ async function registerKnownClaudeMarketplace(name, rootDir) {
|
|
|
30063
30404
|
existing[name].autoUpdate = true;
|
|
30064
30405
|
await ensureDir(dirname15(manifestPath));
|
|
30065
30406
|
if (await fileExists(manifestPath)) {
|
|
30066
|
-
const prev = await
|
|
30407
|
+
const prev = await readFile39(manifestPath, "utf-8");
|
|
30067
30408
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
30068
30409
|
await writeFile10(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
|
|
30069
30410
|
}
|
|
@@ -30077,11 +30418,11 @@ async function ensureKnownClaudeMarketplaceForRoot(options) {
|
|
|
30077
30418
|
return registerKnownClaudeMarketplace(options.name, options.rootDir);
|
|
30078
30419
|
}
|
|
30079
30420
|
async function setSyntaurPluginEnabled(options) {
|
|
30080
|
-
const settingsPath =
|
|
30421
|
+
const settingsPath = resolve61(homedir8(), ".claude", "settings.json");
|
|
30081
30422
|
const key = `syntaur@${options.marketplaceName}`;
|
|
30082
30423
|
let parsed = {};
|
|
30083
30424
|
if (await fileExists(settingsPath)) {
|
|
30084
|
-
const raw2 = await
|
|
30425
|
+
const raw2 = await readFile39(settingsPath, "utf-8");
|
|
30085
30426
|
try {
|
|
30086
30427
|
parsed = JSON.parse(raw2);
|
|
30087
30428
|
} catch {
|
|
@@ -30100,7 +30441,7 @@ async function setSyntaurPluginEnabled(options) {
|
|
|
30100
30441
|
await ensureDir(dirname15(settingsPath));
|
|
30101
30442
|
if (await fileExists(settingsPath)) {
|
|
30102
30443
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
30103
|
-
const prev = await
|
|
30444
|
+
const prev = await readFile39(settingsPath, "utf-8");
|
|
30104
30445
|
await writeFile10(`${settingsPath}.bak-${stamp}`, prev, "utf-8");
|
|
30105
30446
|
}
|
|
30106
30447
|
const tmpPath = `${settingsPath}.tmp`;
|
|
@@ -30114,9 +30455,9 @@ async function ensureClaudeUserMarketplace() {
|
|
|
30114
30455
|
if (existing) {
|
|
30115
30456
|
return existing;
|
|
30116
30457
|
}
|
|
30117
|
-
const rootDir =
|
|
30118
|
-
const manifestPath =
|
|
30119
|
-
await ensureDir(
|
|
30458
|
+
const rootDir = resolve61(getClaudeMarketplacesRoot(), "user-plugins");
|
|
30459
|
+
const manifestPath = resolve61(rootDir, ".claude-plugin", "marketplace.json");
|
|
30460
|
+
await ensureDir(resolve61(rootDir, "plugins"));
|
|
30120
30461
|
if (!await fileExists(manifestPath)) {
|
|
30121
30462
|
const scaffold = {
|
|
30122
30463
|
plugins: []
|
|
@@ -30135,7 +30476,7 @@ async function ensureClaudeUserMarketplace() {
|
|
|
30135
30476
|
name: "user-plugins",
|
|
30136
30477
|
rootDir,
|
|
30137
30478
|
manifestPath,
|
|
30138
|
-
targetDir:
|
|
30479
|
+
targetDir: resolve61(rootDir, "plugins", "syntaur")
|
|
30139
30480
|
};
|
|
30140
30481
|
}
|
|
30141
30482
|
async function detectClaudeMarketplaceForTarget(targetDir) {
|
|
@@ -30145,7 +30486,7 @@ async function detectClaudeMarketplaceForTarget(targetDir) {
|
|
|
30145
30486
|
return null;
|
|
30146
30487
|
}
|
|
30147
30488
|
const rootDir = dirname15(pluginsDir);
|
|
30148
|
-
const manifestPath =
|
|
30489
|
+
const manifestPath = resolve61(rootDir, ".claude-plugin", "marketplace.json");
|
|
30149
30490
|
if (!await fileExists(manifestPath)) {
|
|
30150
30491
|
return null;
|
|
30151
30492
|
}
|
|
@@ -30161,7 +30502,7 @@ async function detectClaudeMarketplaceForTarget(targetDir) {
|
|
|
30161
30502
|
async function findManagedClaudeMarketplacePluginDir() {
|
|
30162
30503
|
const marketplaces = await listClaudeMarketplaceCandidates();
|
|
30163
30504
|
for (const marketplace of marketplaces) {
|
|
30164
|
-
const targetDir =
|
|
30505
|
+
const targetDir = resolve61(marketplace.rootDir, "plugins", "syntaur");
|
|
30165
30506
|
const status = await getInstallStatus(targetDir, "claude");
|
|
30166
30507
|
if (status.exists && status.managed) {
|
|
30167
30508
|
return targetDir;
|
|
@@ -30286,7 +30627,7 @@ async function installManagedPlugin(options) {
|
|
|
30286
30627
|
`${paths.targetDir} already exists and is not a Syntaur-managed install. Remove it manually before installing Syntaur there.`
|
|
30287
30628
|
);
|
|
30288
30629
|
}
|
|
30289
|
-
if (desiredMode === "link" && existing.exists && existing.installMode === "link" && existing.symlinkTarget ===
|
|
30630
|
+
if (desiredMode === "link" && existing.exists && existing.installMode === "link" && existing.symlinkTarget === resolve61(paths.sourceDir) && !force) {
|
|
30290
30631
|
return {
|
|
30291
30632
|
targetDir: paths.targetDir,
|
|
30292
30633
|
sourceDir: paths.sourceDir,
|
|
@@ -30338,7 +30679,7 @@ async function readMarketplaceFile(marketplacePath) {
|
|
|
30338
30679
|
plugins: []
|
|
30339
30680
|
};
|
|
30340
30681
|
}
|
|
30341
|
-
const raw2 = await
|
|
30682
|
+
const raw2 = await readFile39(marketplacePath, "utf-8");
|
|
30342
30683
|
const parsed = JSON.parse(raw2);
|
|
30343
30684
|
return {
|
|
30344
30685
|
name: parsed.name ?? "local",
|
|
@@ -30505,13 +30846,13 @@ async function recommendMarketplacePath() {
|
|
|
30505
30846
|
return configuredOrManaged ?? getDefaultMarketplacePath();
|
|
30506
30847
|
}
|
|
30507
30848
|
async function isSyntaurDataInstalled() {
|
|
30508
|
-
return fileExists(
|
|
30849
|
+
return fileExists(resolve61(syntaurRoot(), "config.md"));
|
|
30509
30850
|
}
|
|
30510
30851
|
async function removeSyntaurData() {
|
|
30511
30852
|
await rm6(syntaurRoot(), { recursive: true, force: true });
|
|
30512
30853
|
}
|
|
30513
30854
|
async function getConfiguredProjectDir() {
|
|
30514
|
-
if (!await fileExists(
|
|
30855
|
+
if (!await fileExists(resolve61(syntaurRoot(), "config.md"))) {
|
|
30515
30856
|
return null;
|
|
30516
30857
|
}
|
|
30517
30858
|
return (await readConfig()).defaultProjectDir;
|
|
@@ -30580,24 +30921,24 @@ async function textPrompt(question, defaultValue) {
|
|
|
30580
30921
|
|
|
30581
30922
|
// src/utils/install-skills.ts
|
|
30582
30923
|
init_fs();
|
|
30583
|
-
import { readFile as
|
|
30584
|
-
import { resolve as
|
|
30924
|
+
import { readFile as readFile41, readdir as readdir25, mkdir as mkdir7, copyFile, rm as rm7, lstat as lstat2 } from "fs/promises";
|
|
30925
|
+
import { resolve as resolve63, relative as relative3, join as join11 } from "path";
|
|
30585
30926
|
import { homedir as homedir10 } from "os";
|
|
30586
30927
|
|
|
30587
30928
|
// src/utils/plugin-state.ts
|
|
30588
30929
|
init_fs();
|
|
30589
|
-
import { readFile as
|
|
30590
|
-
import { resolve as
|
|
30930
|
+
import { readFile as readFile40 } from "fs/promises";
|
|
30931
|
+
import { resolve as resolve62 } from "path";
|
|
30591
30932
|
import { homedir as homedir9 } from "os";
|
|
30592
30933
|
function settingsPathFor(agent) {
|
|
30593
|
-
if (agent === "claude") return
|
|
30934
|
+
if (agent === "claude") return resolve62(homedir9(), ".claude", "settings.json");
|
|
30594
30935
|
return null;
|
|
30595
30936
|
}
|
|
30596
30937
|
async function readJsonOrNull(path) {
|
|
30597
30938
|
if (!path) return null;
|
|
30598
30939
|
if (!await fileExists(path)) return null;
|
|
30599
30940
|
try {
|
|
30600
|
-
const raw2 = await
|
|
30941
|
+
const raw2 = await readFile40(path, "utf-8");
|
|
30601
30942
|
return JSON.parse(raw2);
|
|
30602
30943
|
} catch {
|
|
30603
30944
|
return null;
|
|
@@ -30647,11 +30988,11 @@ var KNOWN_SKILL_NAMES = [
|
|
|
30647
30988
|
var KNOWN_SKILLS = KNOWN_SKILL_NAMES;
|
|
30648
30989
|
async function getSkillsDir() {
|
|
30649
30990
|
const packageRoot = await findPackageRoot("skills");
|
|
30650
|
-
return
|
|
30991
|
+
return resolve63(packageRoot, "skills");
|
|
30651
30992
|
}
|
|
30652
30993
|
function defaultSkillTargetDir(target) {
|
|
30653
|
-
if (target === "claude") return
|
|
30654
|
-
return
|
|
30994
|
+
if (target === "claude") return resolve63(homedir10(), ".claude", "skills");
|
|
30995
|
+
return resolve63(homedir10(), ".codex", "skills");
|
|
30655
30996
|
}
|
|
30656
30997
|
async function walkFiles(root) {
|
|
30657
30998
|
const out = [];
|
|
@@ -30671,7 +31012,7 @@ async function walkFiles(root) {
|
|
|
30671
31012
|
}
|
|
30672
31013
|
async function filesEqual(a, b) {
|
|
30673
31014
|
try {
|
|
30674
|
-
const [ba, bb] = await Promise.all([
|
|
31015
|
+
const [ba, bb] = await Promise.all([readFile41(a), readFile41(b)]);
|
|
30675
31016
|
if (ba.length !== bb.length) return false;
|
|
30676
31017
|
return ba.equals(bb);
|
|
30677
31018
|
} catch {
|
|
@@ -30811,7 +31152,7 @@ async function uninstallSkills(options) {
|
|
|
30811
31152
|
if (await isSymlink(destDir)) continue;
|
|
30812
31153
|
const skillMd = join11(destDir, "SKILL.md");
|
|
30813
31154
|
if (!await fileExists(skillMd)) continue;
|
|
30814
|
-
const content = await
|
|
31155
|
+
const content = await readFile41(skillMd, "utf-8").catch(() => "");
|
|
30815
31156
|
const match = content.match(/^name:\s*(\S+)\s*$/m);
|
|
30816
31157
|
if (!match || match[1] !== skill) continue;
|
|
30817
31158
|
await rm7(destDir, { recursive: true, force: true });
|
|
@@ -31006,20 +31347,20 @@ import { realpathSync as realpathSync2 } from "fs";
|
|
|
31006
31347
|
init_paths();
|
|
31007
31348
|
init_fs();
|
|
31008
31349
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
31009
|
-
import { readFile as
|
|
31010
|
-
import { dirname as dirname17, join as join13, resolve as
|
|
31350
|
+
import { readFile as readFile43 } from "fs/promises";
|
|
31351
|
+
import { dirname as dirname17, join as join13, resolve as resolve64 } from "path";
|
|
31011
31352
|
import { spawn as spawn6 } from "child_process";
|
|
31012
31353
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
31013
31354
|
|
|
31014
31355
|
// src/utils/version.ts
|
|
31015
31356
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
31016
|
-
import { readFile as
|
|
31357
|
+
import { readFile as readFile42 } from "fs/promises";
|
|
31017
31358
|
import { dirname as dirname16, join as join12 } from "path";
|
|
31018
31359
|
async function readPackageVersion(scriptUrl) {
|
|
31019
31360
|
try {
|
|
31020
31361
|
const scriptPath = fileURLToPath5(scriptUrl);
|
|
31021
31362
|
const pkgRoot = dirname16(dirname16(scriptPath));
|
|
31022
|
-
const raw2 = await
|
|
31363
|
+
const raw2 = await readFile42(join12(pkgRoot, "package.json"), "utf-8");
|
|
31023
31364
|
const parsed = JSON.parse(raw2);
|
|
31024
31365
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
31025
31366
|
} catch {
|
|
@@ -31028,7 +31369,7 @@ async function readPackageVersion(scriptUrl) {
|
|
|
31028
31369
|
}
|
|
31029
31370
|
|
|
31030
31371
|
// src/utils/npx-prompt.ts
|
|
31031
|
-
var STATE_FILE =
|
|
31372
|
+
var STATE_FILE = resolve64(syntaurRoot(), "npx-install.json");
|
|
31032
31373
|
var META_ARGS2 = /* @__PURE__ */ new Set(["-h", "--help", "-V", "--version", "help"]);
|
|
31033
31374
|
var GLOBAL_VERSION_TIMEOUT_MS = 2e3;
|
|
31034
31375
|
function isRunningViaNpx(scriptUrl) {
|
|
@@ -31049,7 +31390,7 @@ function isRunningViaNpx(scriptUrl) {
|
|
|
31049
31390
|
async function readState() {
|
|
31050
31391
|
if (!await fileExists(STATE_FILE)) return null;
|
|
31051
31392
|
try {
|
|
31052
|
-
const raw2 = await
|
|
31393
|
+
const raw2 = await readFile43(STATE_FILE, "utf-8");
|
|
31053
31394
|
return JSON.parse(raw2);
|
|
31054
31395
|
} catch {
|
|
31055
31396
|
return null;
|
|
@@ -31108,7 +31449,7 @@ async function readGlobalVersion() {
|
|
|
31108
31449
|
try {
|
|
31109
31450
|
const manifestPath = join13(rootPath, "syntaur", "package.json");
|
|
31110
31451
|
if (!await fileExists(manifestPath)) return null;
|
|
31111
|
-
const raw2 = await
|
|
31452
|
+
const raw2 = await readFile43(manifestPath, "utf-8");
|
|
31112
31453
|
const parsed = JSON.parse(raw2);
|
|
31113
31454
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
31114
31455
|
} catch {
|
|
@@ -31466,16 +31807,16 @@ async function refreshPluginSkills(options, pm, runner, getManagedDir, resolveFr
|
|
|
31466
31807
|
// src/commands/install-statusline.ts
|
|
31467
31808
|
init_paths();
|
|
31468
31809
|
init_fs();
|
|
31469
|
-
import { readFile as
|
|
31470
|
-
import { resolve as
|
|
31810
|
+
import { readFile as readFile45, writeFile as writeFile12, copyFile as copyFile2, rm as rm8, stat as stat7, symlink as symlink2, unlink as unlink11, lstat as lstat3 } from "fs/promises";
|
|
31811
|
+
import { resolve as resolve66, dirname as dirname19 } from "path";
|
|
31471
31812
|
import { homedir as homedir12 } from "os";
|
|
31472
31813
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
31473
31814
|
|
|
31474
31815
|
// src/commands/configure-statusline.ts
|
|
31475
31816
|
init_paths();
|
|
31476
31817
|
init_fs();
|
|
31477
|
-
import { readFile as
|
|
31478
|
-
import { resolve as
|
|
31818
|
+
import { readFile as readFile44, writeFile as writeFile11 } from "fs/promises";
|
|
31819
|
+
import { resolve as resolve65, dirname as dirname18 } from "path";
|
|
31479
31820
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
31480
31821
|
import { checkbox, input as input2, confirm } from "@inquirer/prompts";
|
|
31481
31822
|
var AVAILABLE_SEGMENTS = [
|
|
@@ -31496,12 +31837,12 @@ var PRESETS = {
|
|
|
31496
31837
|
tracker: { segments: ["git", "assignment", "external", "session"], separator: " \xB7 " }
|
|
31497
31838
|
};
|
|
31498
31839
|
function getConfigPath(installRoot) {
|
|
31499
|
-
return
|
|
31840
|
+
return resolve65(installRoot, "statusline.config.json");
|
|
31500
31841
|
}
|
|
31501
31842
|
async function readConfig2(path) {
|
|
31502
31843
|
if (!await fileExists(path)) return null;
|
|
31503
31844
|
try {
|
|
31504
|
-
const raw2 = await
|
|
31845
|
+
const raw2 = await readFile44(path, "utf-8");
|
|
31505
31846
|
const parsed = JSON.parse(raw2);
|
|
31506
31847
|
if (!parsed || typeof parsed !== "object") return null;
|
|
31507
31848
|
const segments = Array.isArray(parsed.segments) ? parsed.segments.filter(isSegmentName) : [];
|
|
@@ -31654,7 +31995,7 @@ async function configureStatuslineCommand(options = {}) {
|
|
|
31654
31995
|
console.log(` segments: ${config.segments.join(", ")}`);
|
|
31655
31996
|
console.log(` separator: ${JSON.stringify(config.separator)}`);
|
|
31656
31997
|
if (config.wrap) console.log(` wrap: ${config.wrap}`);
|
|
31657
|
-
const script = options.statuslineScript ??
|
|
31998
|
+
const script = options.statuslineScript ?? resolve65(installRoot, "statusline.sh");
|
|
31658
31999
|
if (await fileExists(script)) {
|
|
31659
32000
|
console.log("");
|
|
31660
32001
|
console.log("Live preview:");
|
|
@@ -31685,11 +32026,11 @@ async function writeDefaultConfigIfMissing(installRoot) {
|
|
|
31685
32026
|
// src/commands/install-statusline.ts
|
|
31686
32027
|
function getPackageStatuslineSource() {
|
|
31687
32028
|
const here = dirname19(fileURLToPath8(import.meta.url));
|
|
31688
|
-
return
|
|
32029
|
+
return resolve66(here, "..", "statusline", "statusline.sh");
|
|
31689
32030
|
}
|
|
31690
32031
|
async function readSettingsJson(settingsPath) {
|
|
31691
32032
|
if (!await fileExists(settingsPath)) return {};
|
|
31692
|
-
const raw2 = await
|
|
32033
|
+
const raw2 = await readFile45(settingsPath, "utf-8");
|
|
31693
32034
|
if (raw2.trim() === "") return {};
|
|
31694
32035
|
try {
|
|
31695
32036
|
const parsed = JSON.parse(raw2);
|
|
@@ -31769,12 +32110,12 @@ async function installScript(sourceScript, destScript, link) {
|
|
|
31769
32110
|
}
|
|
31770
32111
|
async function installStatuslineCommand(options = {}) {
|
|
31771
32112
|
const mode = options.mode ?? "ask";
|
|
31772
|
-
const settingsPath = options.settingsPath ??
|
|
32113
|
+
const settingsPath = options.settingsPath ?? resolve66(homedir12(), ".claude", "settings.json");
|
|
31773
32114
|
const installRoot = options.installRoot ?? syntaurRoot();
|
|
31774
32115
|
const sourceScript = options.sourceScript ?? getPackageStatuslineSource();
|
|
31775
|
-
const destScript =
|
|
31776
|
-
const confPath =
|
|
31777
|
-
const backupPath =
|
|
32116
|
+
const destScript = resolve66(installRoot, "statusline.sh");
|
|
32117
|
+
const confPath = resolve66(installRoot, "statusline.conf");
|
|
32118
|
+
const backupPath = resolve66(installRoot, "statusline.backup.json");
|
|
31778
32119
|
if (!await fileExists(sourceScript)) {
|
|
31779
32120
|
throw new Error(
|
|
31780
32121
|
`Statusline source script not found at ${sourceScript}. Try re-installing syntaur (npm install -g syntaur) or pass --source-script explicitly.`
|
|
@@ -31810,7 +32151,7 @@ async function installStatuslineCommand(options = {}) {
|
|
|
31810
32151
|
if (parsed) {
|
|
31811
32152
|
wrapTarget = parsed;
|
|
31812
32153
|
} else {
|
|
31813
|
-
const wrapperPath =
|
|
32154
|
+
const wrapperPath = resolve66(installRoot, "statusline-wrapped.sh");
|
|
31814
32155
|
const wrapperBody = `#!/usr/bin/env bash
|
|
31815
32156
|
# Auto-generated by syntaur install-statusline.
|
|
31816
32157
|
# Executes the previously configured statusLine command.
|
|
@@ -31865,19 +32206,19 @@ async function chmodExec(path) {
|
|
|
31865
32206
|
}
|
|
31866
32207
|
}
|
|
31867
32208
|
async function uninstallStatuslineCommand(options = {}) {
|
|
31868
|
-
const settingsPath = options.settingsPath ??
|
|
32209
|
+
const settingsPath = options.settingsPath ?? resolve66(homedir12(), ".claude", "settings.json");
|
|
31869
32210
|
const installRoot = options.installRoot ?? syntaurRoot();
|
|
31870
|
-
const destScript =
|
|
31871
|
-
const confPath =
|
|
31872
|
-
const backupPath =
|
|
31873
|
-
const wrapperPath =
|
|
32211
|
+
const destScript = resolve66(installRoot, "statusline.sh");
|
|
32212
|
+
const confPath = resolve66(installRoot, "statusline.conf");
|
|
32213
|
+
const backupPath = resolve66(installRoot, "statusline.backup.json");
|
|
32214
|
+
const wrapperPath = resolve66(installRoot, "statusline-wrapped.sh");
|
|
31874
32215
|
const settings = await readSettingsJson(settingsPath);
|
|
31875
32216
|
const existing = extractExistingCommand(settings);
|
|
31876
32217
|
const ourCommand = `bash ${destScript}`;
|
|
31877
32218
|
let restored = null;
|
|
31878
32219
|
if (await fileExists(backupPath)) {
|
|
31879
32220
|
try {
|
|
31880
|
-
const raw2 = await
|
|
32221
|
+
const raw2 = await readFile45(backupPath, "utf-8");
|
|
31881
32222
|
const parsed = JSON.parse(raw2);
|
|
31882
32223
|
const prev = parsed?.previousStatusLine;
|
|
31883
32224
|
if (prev && typeof prev === "object" && typeof prev.command === "string") {
|
|
@@ -31898,7 +32239,7 @@ async function uninstallStatuslineCommand(options = {}) {
|
|
|
31898
32239
|
await writeSettingsJson(settingsPath, settings);
|
|
31899
32240
|
}
|
|
31900
32241
|
if (!options.keepScript) {
|
|
31901
|
-
const configPath2 =
|
|
32242
|
+
const configPath2 = resolve66(installRoot, "statusline.config.json");
|
|
31902
32243
|
for (const path of [destScript, confPath, backupPath, wrapperPath, configPath2]) {
|
|
31903
32244
|
try {
|
|
31904
32245
|
await rm8(path, { force: true });
|
|
@@ -32058,8 +32399,8 @@ init_config2();
|
|
|
32058
32399
|
// src/commands/cross-agent-install.ts
|
|
32059
32400
|
init_fs();
|
|
32060
32401
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
32061
|
-
import { dirname as dirname20, join as join15, resolve as
|
|
32062
|
-
import { cp as cp4, mkdir as mkdir9, readFile as
|
|
32402
|
+
import { dirname as dirname20, join as join15, resolve as resolve68 } from "path";
|
|
32403
|
+
import { cp as cp4, mkdir as mkdir9, readFile as readFile46 } from "fs/promises";
|
|
32063
32404
|
|
|
32064
32405
|
// src/commands/setup-adapter.ts
|
|
32065
32406
|
init_paths();
|
|
@@ -32068,7 +32409,7 @@ init_config2();
|
|
|
32068
32409
|
init_slug();
|
|
32069
32410
|
init_registry();
|
|
32070
32411
|
init_renderers();
|
|
32071
|
-
import { resolve as
|
|
32412
|
+
import { resolve as resolve67 } from "path";
|
|
32072
32413
|
async function setupAdapterCommand(framework, options) {
|
|
32073
32414
|
const { targets: known, warnings } = await resolveAgentTargets();
|
|
32074
32415
|
const target = known.find((t) => t.id === framework);
|
|
@@ -32097,13 +32438,13 @@ async function setupAdapterCommand(framework, options) {
|
|
|
32097
32438
|
}
|
|
32098
32439
|
const config = await readConfig();
|
|
32099
32440
|
const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
|
|
32100
|
-
const projectDir =
|
|
32101
|
-
const assignmentDir =
|
|
32102
|
-
const projectMdPath =
|
|
32441
|
+
const projectDir = resolve67(baseDir, options.project);
|
|
32442
|
+
const assignmentDir = resolve67(projectDir, "assignments", options.assignment);
|
|
32443
|
+
const projectMdPath = resolve67(projectDir, "project.md");
|
|
32103
32444
|
if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
|
|
32104
32445
|
throw new Error(`Project "${options.project}" not found at ${projectDir}.`);
|
|
32105
32446
|
}
|
|
32106
|
-
const assignmentMdPath2 =
|
|
32447
|
+
const assignmentMdPath2 = resolve67(assignmentDir, "assignment.md");
|
|
32107
32448
|
if (!await fileExists(assignmentDir) || !await fileExists(assignmentMdPath2)) {
|
|
32108
32449
|
throw new Error(
|
|
32109
32450
|
`Assignment "${options.assignment}" not found at ${assignmentDir}.`
|
|
@@ -32120,7 +32461,7 @@ async function setupAdapterCommand(framework, options) {
|
|
|
32120
32461
|
const upToDateFiles = [];
|
|
32121
32462
|
const skippedFiles = [];
|
|
32122
32463
|
for (const file of target.instructions.files) {
|
|
32123
|
-
const filePath =
|
|
32464
|
+
const filePath = resolve67(cwd, file.path);
|
|
32124
32465
|
const content = RENDERERS[file.renderer](rendererParams);
|
|
32125
32466
|
const status = await writeFileReport(filePath, content, {
|
|
32126
32467
|
force: options.force
|
|
@@ -32176,7 +32517,7 @@ async function installTier3Plugin(t, opts = {}) {
|
|
|
32176
32517
|
return "already-present";
|
|
32177
32518
|
}
|
|
32178
32519
|
try {
|
|
32179
|
-
const sourceDir =
|
|
32520
|
+
const sourceDir = resolve68(await findPackageRoot(plugin.source), plugin.source);
|
|
32180
32521
|
await mkdir9(dirname20(installDir), { recursive: true });
|
|
32181
32522
|
await cp4(sourceDir, installDir, { recursive: true, force: true });
|
|
32182
32523
|
console.log(`Tier 3 (${t.id}): installed ${plugin.kind} -> ${installDir}`);
|
|
@@ -32201,10 +32542,10 @@ function isNpxAvailable() {
|
|
|
32201
32542
|
}
|
|
32202
32543
|
}
|
|
32203
32544
|
async function readAssignmentContext() {
|
|
32204
|
-
const p =
|
|
32545
|
+
const p = resolve68(process.cwd(), ".syntaur", "context.json");
|
|
32205
32546
|
if (!await fileExists(p)) return null;
|
|
32206
32547
|
try {
|
|
32207
|
-
return JSON.parse(await
|
|
32548
|
+
return JSON.parse(await readFile46(p, "utf-8"));
|
|
32208
32549
|
} catch {
|
|
32209
32550
|
return null;
|
|
32210
32551
|
}
|
|
@@ -32284,7 +32625,7 @@ async function crossAgentInstallCommand(options) {
|
|
|
32284
32625
|
if (dryRun) {
|
|
32285
32626
|
for (const f of t.instructions.files) {
|
|
32286
32627
|
console.log(
|
|
32287
|
-
`${prefix}Tier 2 (${t.id}): ${
|
|
32628
|
+
`${prefix}Tier 2 (${t.id}): ${resolve68(process.cwd(), f.path)}`
|
|
32288
32629
|
);
|
|
32289
32630
|
}
|
|
32290
32631
|
continue;
|
|
@@ -32441,7 +32782,7 @@ async function setupCommand(options) {
|
|
|
32441
32782
|
}
|
|
32442
32783
|
|
|
32443
32784
|
// src/commands/uninstall.ts
|
|
32444
|
-
import { resolve as
|
|
32785
|
+
import { resolve as resolve69 } from "path";
|
|
32445
32786
|
init_paths();
|
|
32446
32787
|
function expandTargets(options) {
|
|
32447
32788
|
if (options.all) {
|
|
@@ -32521,7 +32862,7 @@ async function uninstallCommand(options) {
|
|
|
32521
32862
|
const configuredProjectDir = await getConfiguredProjectDir();
|
|
32522
32863
|
await removeSyntaurData();
|
|
32523
32864
|
console.log(`Removed ${syntaurRoot()}`);
|
|
32524
|
-
if (configuredProjectDir &&
|
|
32865
|
+
if (configuredProjectDir && resolve69(configuredProjectDir) !== resolve69(syntaurRoot(), "projects")) {
|
|
32525
32866
|
console.warn(
|
|
32526
32867
|
`Warning: config.md pointed to an external project directory (${configuredProjectDir}). That directory was not removed automatically.`
|
|
32527
32868
|
);
|
|
@@ -32543,8 +32884,8 @@ init_session_id();
|
|
|
32543
32884
|
init_cwd();
|
|
32544
32885
|
init_session_db();
|
|
32545
32886
|
init_agent_sessions();
|
|
32546
|
-
import { resolve as
|
|
32547
|
-
import { readFile as
|
|
32887
|
+
import { resolve as resolve70 } from "path";
|
|
32888
|
+
import { readFile as readFile47 } from "fs/promises";
|
|
32548
32889
|
async function trackSessionCommand(options, deps = {}) {
|
|
32549
32890
|
if (!options.agent) {
|
|
32550
32891
|
throw new Error("--agent <name> is required.");
|
|
@@ -32554,7 +32895,7 @@ async function trackSessionCommand(options, deps = {}) {
|
|
|
32554
32895
|
const cwd = process.cwd();
|
|
32555
32896
|
let legacyHint;
|
|
32556
32897
|
try {
|
|
32557
|
-
const raw2 = await
|
|
32898
|
+
const raw2 = await readFile47(resolve70(cwd, ".syntaur", "context.json"), "utf-8");
|
|
32558
32899
|
const parsed = JSON.parse(raw2);
|
|
32559
32900
|
if (typeof parsed.sessionId === "string") legacyHint = parsed.sessionId;
|
|
32560
32901
|
} catch {
|
|
@@ -32569,7 +32910,7 @@ async function trackSessionCommand(options, deps = {}) {
|
|
|
32569
32910
|
if (options.project) {
|
|
32570
32911
|
const config = await readConfig();
|
|
32571
32912
|
const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
|
|
32572
|
-
const projectDir =
|
|
32913
|
+
const projectDir = resolve70(baseDir, options.project);
|
|
32573
32914
|
if (!await fileExists(projectDir)) {
|
|
32574
32915
|
throw new Error(
|
|
32575
32916
|
`Project "${options.project}" not found at ${projectDir}.`
|
|
@@ -32702,8 +33043,8 @@ function formatInstallUrlHandlerError(err2) {
|
|
|
32702
33043
|
init_config2();
|
|
32703
33044
|
init_paths();
|
|
32704
33045
|
init_fs();
|
|
32705
|
-
import { resolve as
|
|
32706
|
-
import { readFile as
|
|
33046
|
+
import { resolve as resolve72, isAbsolute as isAbsolute8 } from "path";
|
|
33047
|
+
import { readFile as readFile48 } from "fs/promises";
|
|
32707
33048
|
import { select, confirm as confirm2, input as input3 } from "@inquirer/prompts";
|
|
32708
33049
|
async function browseCommand(options) {
|
|
32709
33050
|
const config = await readConfig();
|
|
@@ -32772,7 +33113,7 @@ async function pickAgent2(agents) {
|
|
|
32772
33113
|
return picked;
|
|
32773
33114
|
}
|
|
32774
33115
|
async function ensureWorktree(opts) {
|
|
32775
|
-
const assignmentPath =
|
|
33116
|
+
const assignmentPath = resolve72(
|
|
32776
33117
|
opts.projectsDir,
|
|
32777
33118
|
opts.projectSlug,
|
|
32778
33119
|
"assignments",
|
|
@@ -32782,7 +33123,7 @@ async function ensureWorktree(opts) {
|
|
|
32782
33123
|
if (!await fileExists(assignmentPath)) {
|
|
32783
33124
|
return void 0;
|
|
32784
33125
|
}
|
|
32785
|
-
const content = await
|
|
33126
|
+
const content = await readFile48(assignmentPath, "utf-8");
|
|
32786
33127
|
const { parseAssignmentFrontmatter: parseAssignmentFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
|
|
32787
33128
|
const fm = parseAssignmentFrontmatter2(content);
|
|
32788
33129
|
const { workspace } = fm;
|
|
@@ -32852,7 +33193,7 @@ async function ensureWorktree(opts) {
|
|
|
32852
33193
|
async function runCreate(opts) {
|
|
32853
33194
|
const { createWorktreeAndRecord: createWorktreeAndRecord2, GitWorktreeError: GitWorktreeError2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
32854
33195
|
const expandedWorktree = expandHome(opts.worktreePath);
|
|
32855
|
-
const absWorktree = isAbsolute8(expandedWorktree) ? expandedWorktree :
|
|
33196
|
+
const absWorktree = isAbsolute8(expandedWorktree) ? expandedWorktree : resolve72(expandedWorktree);
|
|
32856
33197
|
try {
|
|
32857
33198
|
await createWorktreeAndRecord2({
|
|
32858
33199
|
assignmentPath: opts.assignmentPath,
|
|
@@ -32881,7 +33222,7 @@ init_paths();
|
|
|
32881
33222
|
init_fs();
|
|
32882
33223
|
init_playbook();
|
|
32883
33224
|
init_playbooks();
|
|
32884
|
-
import { resolve as
|
|
33225
|
+
import { resolve as resolve73 } from "path";
|
|
32885
33226
|
async function createPlaybookCommand(name, options) {
|
|
32886
33227
|
if (!name.trim()) {
|
|
32887
33228
|
throw new Error("Playbook name cannot be empty.");
|
|
@@ -32894,7 +33235,7 @@ async function createPlaybookCommand(name, options) {
|
|
|
32894
33235
|
}
|
|
32895
33236
|
const dir = playbooksDir();
|
|
32896
33237
|
await ensureDir(dir);
|
|
32897
|
-
const filePath =
|
|
33238
|
+
const filePath = resolve73(dir, `${slug}.md`);
|
|
32898
33239
|
if (await fileExists(filePath)) {
|
|
32899
33240
|
throw new Error(
|
|
32900
33241
|
`Playbook "${slug}" already exists at ${filePath}
|
|
@@ -32916,8 +33257,8 @@ init_paths();
|
|
|
32916
33257
|
init_fs();
|
|
32917
33258
|
init_parser();
|
|
32918
33259
|
init_config2();
|
|
32919
|
-
import { readdir as readdir26, readFile as
|
|
32920
|
-
import { resolve as
|
|
33260
|
+
import { readdir as readdir26, readFile as readFile49 } from "fs/promises";
|
|
33261
|
+
import { resolve as resolve74 } from "path";
|
|
32921
33262
|
async function listPlaybooksCommand(options = {}) {
|
|
32922
33263
|
const dir = playbooksDir();
|
|
32923
33264
|
if (!await fileExists(dir)) {
|
|
@@ -32932,8 +33273,8 @@ async function listPlaybooksCommand(options = {}) {
|
|
|
32932
33273
|
);
|
|
32933
33274
|
const rows = [];
|
|
32934
33275
|
for (const entry of mdFiles) {
|
|
32935
|
-
const filePath =
|
|
32936
|
-
const raw2 = await
|
|
33276
|
+
const filePath = resolve74(dir, entry.name);
|
|
33277
|
+
const raw2 = await readFile49(filePath, "utf-8");
|
|
32937
33278
|
const parsed = parsePlaybook(raw2);
|
|
32938
33279
|
const slug = parsed.slug || entry.name.replace(/\.md$/, "");
|
|
32939
33280
|
const disabled = disabledSet.has(slug);
|
|
@@ -33056,14 +33397,14 @@ init_fs();
|
|
|
33056
33397
|
init_config2();
|
|
33057
33398
|
init_slug();
|
|
33058
33399
|
import { Command as Command2 } from "commander";
|
|
33059
|
-
import { readFile as
|
|
33060
|
-
import { resolve as
|
|
33400
|
+
import { readFile as readFile51 } from "fs/promises";
|
|
33401
|
+
import { resolve as resolve76 } from "path";
|
|
33061
33402
|
|
|
33062
33403
|
// src/commands/bundle.ts
|
|
33063
33404
|
init_paths();
|
|
33064
33405
|
import { Command } from "commander";
|
|
33065
|
-
import { mkdir as mkdir10, readFile as
|
|
33066
|
-
import { resolve as
|
|
33406
|
+
import { mkdir as mkdir10, readFile as readFile50, readdir as readdir27, rm as rm9, writeFile as writeFile13 } from "fs/promises";
|
|
33407
|
+
import { resolve as resolve75 } from "path";
|
|
33067
33408
|
init_parser2();
|
|
33068
33409
|
init_fs();
|
|
33069
33410
|
init_config2();
|
|
@@ -33081,7 +33422,7 @@ async function resolveBundleScope(options) {
|
|
|
33081
33422
|
throw new Error(`Invalid project slug: "${options.project}".`);
|
|
33082
33423
|
}
|
|
33083
33424
|
const config = await readConfig();
|
|
33084
|
-
const projectMd =
|
|
33425
|
+
const projectMd = resolve75(config.defaultProjectDir, options.project, "project.md");
|
|
33085
33426
|
if (!await fileExists(projectMd)) {
|
|
33086
33427
|
throw new Error(`Project "${options.project}" not found.`);
|
|
33087
33428
|
}
|
|
@@ -33151,10 +33492,10 @@ function pickNextPlanFile(planDir, existingFiles) {
|
|
|
33151
33492
|
const m = f.match(/^plan-v(\d+)\.md$/);
|
|
33152
33493
|
if (m) versions.add(parseInt(m[1], 10));
|
|
33153
33494
|
}
|
|
33154
|
-
if (versions.size === 0) return { target:
|
|
33495
|
+
if (versions.size === 0) return { target: resolve75(planDir, "plan.md"), version: 1 };
|
|
33155
33496
|
let n = 2;
|
|
33156
33497
|
while (versions.has(n)) n++;
|
|
33157
|
-
return { target:
|
|
33498
|
+
return { target: resolve75(planDir, `plan-v${n}.md`), version: n };
|
|
33158
33499
|
}
|
|
33159
33500
|
function dedupePreserveOrder(ids) {
|
|
33160
33501
|
const out = [];
|
|
@@ -33238,7 +33579,7 @@ bundleCommand.command("new").description("Create a new bundle from 2+ existing t
|
|
|
33238
33579
|
if (options.plan) {
|
|
33239
33580
|
const planDir = bundlePlanDir(sc.todosPath, sc.scopeId, id);
|
|
33240
33581
|
await ensureDir(planDir);
|
|
33241
|
-
const target =
|
|
33582
|
+
const target = resolve75(planDir, "plan.md");
|
|
33242
33583
|
const memberLines = items.map((it) => `- ${it.description} [t:${it.id}]`).join("\n");
|
|
33243
33584
|
const stub = [
|
|
33244
33585
|
"---",
|
|
@@ -33414,7 +33755,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
33414
33755
|
}
|
|
33415
33756
|
const repository = options.repository ?? process.cwd();
|
|
33416
33757
|
const parentBranch = options.parentBranch ?? "main";
|
|
33417
|
-
const worktreePath = options.worktreePath ??
|
|
33758
|
+
const worktreePath = options.worktreePath ?? resolve75(repository, ".worktrees", options.branch);
|
|
33418
33759
|
const checklist = await readChecklist(sc.todosPath, sc.checklistKey);
|
|
33419
33760
|
for (const memberId of bundle.todoIds) {
|
|
33420
33761
|
const item = checklist.items.find((i) => i.id === memberId);
|
|
@@ -33424,8 +33765,8 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
33424
33765
|
}
|
|
33425
33766
|
const bundlesFilePath = bundlesPath(sc.todosPath);
|
|
33426
33767
|
const checklistFilePath = checklistPath(sc.todosPath, sc.checklistKey);
|
|
33427
|
-
const bundlesSnapshot = await fileExists(bundlesFilePath) ? await
|
|
33428
|
-
const checklistSnapshot = await fileExists(checklistFilePath) ? await
|
|
33768
|
+
const bundlesSnapshot = await fileExists(bundlesFilePath) ? await readFile50(bundlesFilePath, "utf-8") : null;
|
|
33769
|
+
const checklistSnapshot = await fileExists(checklistFilePath) ? await readFile50(checklistFilePath, "utf-8") : null;
|
|
33429
33770
|
const record = async () => {
|
|
33430
33771
|
bundle.branch = options.branch;
|
|
33431
33772
|
bundle.worktreePath = worktreePath;
|
|
@@ -33441,7 +33782,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
33441
33782
|
try {
|
|
33442
33783
|
await writeBundles(sc.todosPath, bundles);
|
|
33443
33784
|
await writeChecklist(sc.todosPath, checklist);
|
|
33444
|
-
const ctxDir =
|
|
33785
|
+
const ctxDir = resolve75(worktreePath, ".syntaur");
|
|
33445
33786
|
await mkdir10(ctxDir, { recursive: true });
|
|
33446
33787
|
const payload = {
|
|
33447
33788
|
bundleId: bundle.id,
|
|
@@ -33455,7 +33796,7 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
33455
33796
|
repository,
|
|
33456
33797
|
boundAt: nowISO()
|
|
33457
33798
|
};
|
|
33458
|
-
await writeFile13(
|
|
33799
|
+
await writeFile13(resolve75(ctxDir, "context.json"), JSON.stringify(payload, null, 2) + "\n");
|
|
33459
33800
|
} catch (err2) {
|
|
33460
33801
|
try {
|
|
33461
33802
|
if (bundlesSnapshot === null) {
|
|
@@ -33645,7 +33986,7 @@ async function resolveScope(options) {
|
|
|
33645
33986
|
throw new Error(`Invalid project slug: "${options.project}".`);
|
|
33646
33987
|
}
|
|
33647
33988
|
const config = await readConfig();
|
|
33648
|
-
const projectMd =
|
|
33989
|
+
const projectMd = resolve76(config.defaultProjectDir, options.project, "project.md");
|
|
33649
33990
|
if (!await fileExists(projectMd)) {
|
|
33650
33991
|
throw new Error(`Project "${options.project}" not found.`);
|
|
33651
33992
|
}
|
|
@@ -33968,10 +34309,10 @@ todoCommand.command("archive").description("Archive completed todos and their lo
|
|
|
33968
34309
|
(e) => e.itemIds.every((id) => completedIds.has(id))
|
|
33969
34310
|
);
|
|
33970
34311
|
const archFile = archivePath(todosPath, workspace, checklist.archiveInterval);
|
|
33971
|
-
await ensureDir(
|
|
34312
|
+
await ensureDir(resolve76(todosPath, "archive"));
|
|
33972
34313
|
let archContent = "";
|
|
33973
34314
|
if (await fileExists(archFile)) {
|
|
33974
|
-
archContent = await
|
|
34315
|
+
archContent = await readFile51(archFile, "utf-8");
|
|
33975
34316
|
archContent = archContent.trimEnd() + "\n\n";
|
|
33976
34317
|
} else {
|
|
33977
34318
|
archContent = `---
|
|
@@ -34148,12 +34489,12 @@ function describeScope(scope) {
|
|
|
34148
34489
|
}
|
|
34149
34490
|
async function injectPromotedTodos(assignmentDir, todos, scopeLabel) {
|
|
34150
34491
|
const { resolve: resolvePath2 } = await import("path");
|
|
34151
|
-
const { readFile:
|
|
34492
|
+
const { readFile: readFile81 } = await import("fs/promises");
|
|
34152
34493
|
const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
34153
34494
|
const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
|
|
34154
34495
|
const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
|
|
34155
34496
|
const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
|
|
34156
|
-
let content = await
|
|
34497
|
+
let content = await readFile81(assignmentMdPath2, "utf-8");
|
|
34157
34498
|
content = appendTodosToAssignmentBody2(
|
|
34158
34499
|
content,
|
|
34159
34500
|
todos.map((t) => ({
|
|
@@ -34204,7 +34545,7 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
|
|
|
34204
34545
|
);
|
|
34205
34546
|
let target;
|
|
34206
34547
|
if (existingFiles.length === 0) {
|
|
34207
|
-
target =
|
|
34548
|
+
target = resolve76(planDir, "plan.md");
|
|
34208
34549
|
} else {
|
|
34209
34550
|
const versions = /* @__PURE__ */ new Set();
|
|
34210
34551
|
for (const f of existingFiles) {
|
|
@@ -34214,7 +34555,7 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
|
|
|
34214
34555
|
}
|
|
34215
34556
|
let n = 2;
|
|
34216
34557
|
while (versions.has(n)) n++;
|
|
34217
|
-
target =
|
|
34558
|
+
target = resolve76(planDir, `plan-v${n}.md`);
|
|
34218
34559
|
}
|
|
34219
34560
|
if (!await fileExists(target)) {
|
|
34220
34561
|
const stub = `---
|
|
@@ -34403,12 +34744,12 @@ backupCommand.command("config").description("Show or update backup configuration
|
|
|
34403
34744
|
|
|
34404
34745
|
// src/commands/doctor.ts
|
|
34405
34746
|
import { Command as Command4 } from "commander";
|
|
34406
|
-
import { readFile as
|
|
34407
|
-
import { isAbsolute as isAbsolute11, resolve as
|
|
34747
|
+
import { readFile as readFile62 } from "fs/promises";
|
|
34748
|
+
import { isAbsolute as isAbsolute11, resolve as resolve89 } from "path";
|
|
34408
34749
|
|
|
34409
34750
|
// src/utils/doctor/index.ts
|
|
34410
34751
|
import { fileURLToPath as fileURLToPath12 } from "url";
|
|
34411
|
-
import { readFile as
|
|
34752
|
+
import { readFile as readFile61 } from "fs/promises";
|
|
34412
34753
|
import { dirname as dirname25, join as join21 } from "path";
|
|
34413
34754
|
|
|
34414
34755
|
// src/utils/doctor/context.ts
|
|
@@ -34416,11 +34757,11 @@ init_config2();
|
|
|
34416
34757
|
init_paths();
|
|
34417
34758
|
init_fs();
|
|
34418
34759
|
import Database5 from "better-sqlite3";
|
|
34419
|
-
import { resolve as
|
|
34760
|
+
import { resolve as resolve77 } from "path";
|
|
34420
34761
|
async function buildCheckContext(cwd = process.cwd()) {
|
|
34421
34762
|
const config = await readConfig();
|
|
34422
34763
|
const root = syntaurRoot();
|
|
34423
|
-
const dbPath =
|
|
34764
|
+
const dbPath = resolve77(root, "syntaur.db");
|
|
34424
34765
|
let db6 = null;
|
|
34425
34766
|
let dbError = null;
|
|
34426
34767
|
if (await fileExists(dbPath)) {
|
|
@@ -34454,8 +34795,8 @@ function closeCheckContext(ctx) {
|
|
|
34454
34795
|
// src/utils/doctor/checks/env.ts
|
|
34455
34796
|
init_fs();
|
|
34456
34797
|
init_paths();
|
|
34457
|
-
import { resolve as
|
|
34458
|
-
import { readFile as
|
|
34798
|
+
import { resolve as resolve78, isAbsolute as isAbsolute9 } from "path";
|
|
34799
|
+
import { readFile as readFile52, stat as stat8 } from "fs/promises";
|
|
34459
34800
|
import { fileURLToPath as fileURLToPath10 } from "url";
|
|
34460
34801
|
import { dirname as dirname22, join as join17 } from "path";
|
|
34461
34802
|
var CATEGORY = "env";
|
|
@@ -34495,7 +34836,7 @@ var configValid = {
|
|
|
34495
34836
|
category: CATEGORY,
|
|
34496
34837
|
title: "~/.syntaur/config.md is valid",
|
|
34497
34838
|
async run(ctx) {
|
|
34498
|
-
const configPath2 =
|
|
34839
|
+
const configPath2 = resolve78(ctx.syntaurRoot, "config.md");
|
|
34499
34840
|
if (!await fileExists(configPath2)) {
|
|
34500
34841
|
return {
|
|
34501
34842
|
id: this.id,
|
|
@@ -34512,7 +34853,7 @@ var configValid = {
|
|
|
34512
34853
|
autoFixable: false
|
|
34513
34854
|
};
|
|
34514
34855
|
}
|
|
34515
|
-
const content = await
|
|
34856
|
+
const content = await readFile52(configPath2, "utf-8");
|
|
34516
34857
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
34517
34858
|
if (!fmMatch || fmMatch[1].trim() === "") {
|
|
34518
34859
|
return {
|
|
@@ -34792,7 +35133,7 @@ async function readLocalPkg() {
|
|
|
34792
35133
|
for (let i = 0; i < 6; i++) {
|
|
34793
35134
|
const candidate = join17(dir, "package.json");
|
|
34794
35135
|
try {
|
|
34795
|
-
const text = await
|
|
35136
|
+
const text = await readFile52(candidate, "utf-8");
|
|
34796
35137
|
return JSON.parse(text);
|
|
34797
35138
|
} catch {
|
|
34798
35139
|
dir = dirname22(dir);
|
|
@@ -34844,7 +35185,7 @@ function versionGte(a, b) {
|
|
|
34844
35185
|
|
|
34845
35186
|
// src/utils/doctor/checks/structure.ts
|
|
34846
35187
|
init_fs();
|
|
34847
|
-
import { resolve as
|
|
35188
|
+
import { resolve as resolve79 } from "path";
|
|
34848
35189
|
import { readdir as readdir28, stat as stat9 } from "fs/promises";
|
|
34849
35190
|
var CATEGORY2 = "structure";
|
|
34850
35191
|
var KNOWN_TOP_LEVEL = /* @__PURE__ */ new Set([
|
|
@@ -34864,7 +35205,7 @@ var projectsDir = {
|
|
|
34864
35205
|
category: CATEGORY2,
|
|
34865
35206
|
title: "projects/ directory exists",
|
|
34866
35207
|
async run(ctx) {
|
|
34867
|
-
const p =
|
|
35208
|
+
const p = resolve79(ctx.syntaurRoot, "projects");
|
|
34868
35209
|
if (!await fileExists(p)) {
|
|
34869
35210
|
return {
|
|
34870
35211
|
id: this.id,
|
|
@@ -34889,7 +35230,7 @@ var playbooksDir2 = {
|
|
|
34889
35230
|
category: CATEGORY2,
|
|
34890
35231
|
title: "playbooks/ directory exists",
|
|
34891
35232
|
async run(ctx) {
|
|
34892
|
-
const p =
|
|
35233
|
+
const p = resolve79(ctx.syntaurRoot, "playbooks");
|
|
34893
35234
|
if (!await fileExists(p)) {
|
|
34894
35235
|
return {
|
|
34895
35236
|
id: this.id,
|
|
@@ -34914,7 +35255,7 @@ var todosDirValid = {
|
|
|
34914
35255
|
category: CATEGORY2,
|
|
34915
35256
|
title: "todos/ directory is readable (if present)",
|
|
34916
35257
|
async run(ctx) {
|
|
34917
|
-
const p =
|
|
35258
|
+
const p = resolve79(ctx.syntaurRoot, "todos");
|
|
34918
35259
|
if (!await fileExists(p)) {
|
|
34919
35260
|
return {
|
|
34920
35261
|
id: this.id,
|
|
@@ -34945,7 +35286,7 @@ var serversDirValid = {
|
|
|
34945
35286
|
category: CATEGORY2,
|
|
34946
35287
|
title: "servers/ directory is readable (if present)",
|
|
34947
35288
|
async run(ctx) {
|
|
34948
|
-
const p =
|
|
35289
|
+
const p = resolve79(ctx.syntaurRoot, "servers");
|
|
34949
35290
|
if (!await fileExists(p)) {
|
|
34950
35291
|
return {
|
|
34951
35292
|
id: this.id,
|
|
@@ -34990,7 +35331,7 @@ var knownFilesRecognized = {
|
|
|
34990
35331
|
title: this.title,
|
|
34991
35332
|
status: "warn",
|
|
34992
35333
|
detail: `unexpected top-level entries: ${unexpected.join(", ")}`,
|
|
34993
|
-
affected: unexpected.map((n) =>
|
|
35334
|
+
affected: unexpected.map((n) => resolve79(ctx.syntaurRoot, n)),
|
|
34994
35335
|
remediation: {
|
|
34995
35336
|
kind: "manual",
|
|
34996
35337
|
suggestion: "Review these entries \u2014 they may be leftover state from older versions",
|
|
@@ -35019,7 +35360,7 @@ function pass2(check) {
|
|
|
35019
35360
|
|
|
35020
35361
|
// src/utils/doctor/checks/project.ts
|
|
35021
35362
|
init_fs();
|
|
35022
|
-
import { resolve as
|
|
35363
|
+
import { resolve as resolve80 } from "path";
|
|
35023
35364
|
import { readdir as readdir29, stat as stat10 } from "fs/promises";
|
|
35024
35365
|
var CATEGORY3 = "project";
|
|
35025
35366
|
var REQUIRED_PROJECT_FILES = [
|
|
@@ -35049,10 +35390,10 @@ async function listProjects2(ctx) {
|
|
|
35049
35390
|
for (const e of entries) {
|
|
35050
35391
|
if (!e.isDirectory()) continue;
|
|
35051
35392
|
if (e.name.startsWith(".") || e.name.startsWith("_")) continue;
|
|
35052
|
-
const projectDir =
|
|
35393
|
+
const projectDir = resolve80(dir, e.name);
|
|
35053
35394
|
let looksLikeProject = false;
|
|
35054
35395
|
for (const marker of PROJECT_MARKERS) {
|
|
35055
|
-
if (await fileExists(
|
|
35396
|
+
if (await fileExists(resolve80(projectDir, marker))) {
|
|
35056
35397
|
looksLikeProject = true;
|
|
35057
35398
|
break;
|
|
35058
35399
|
}
|
|
@@ -35071,7 +35412,7 @@ var requiredFiles = {
|
|
|
35071
35412
|
for (const projectDir of projects) {
|
|
35072
35413
|
const missing = [];
|
|
35073
35414
|
for (const rel of REQUIRED_PROJECT_FILES) {
|
|
35074
|
-
const p =
|
|
35415
|
+
const p = resolve80(projectDir, rel);
|
|
35075
35416
|
if (!await fileExists(p)) missing.push(rel);
|
|
35076
35417
|
}
|
|
35077
35418
|
if (missing.length === 0) continue;
|
|
@@ -35081,7 +35422,7 @@ var requiredFiles = {
|
|
|
35081
35422
|
title: this.title,
|
|
35082
35423
|
status: "error",
|
|
35083
35424
|
detail: `project at ${projectDir} is missing: ${missing.join(", ")}`,
|
|
35084
|
-
affected: missing.map((m) =>
|
|
35425
|
+
affected: missing.map((m) => resolve80(projectDir, m)),
|
|
35085
35426
|
remediation: {
|
|
35086
35427
|
kind: "manual",
|
|
35087
35428
|
suggestion: "Recreate the missing scaffold files from templates",
|
|
@@ -35104,7 +35445,7 @@ var manifestStale = {
|
|
|
35104
35445
|
const projects = await listProjects2(ctx);
|
|
35105
35446
|
const results = [];
|
|
35106
35447
|
for (const projectDir of projects) {
|
|
35107
|
-
const manifestPath =
|
|
35448
|
+
const manifestPath = resolve80(projectDir, "manifest.md");
|
|
35108
35449
|
if (!await fileExists(manifestPath)) continue;
|
|
35109
35450
|
const manifestMtime = (await stat10(manifestPath)).mtimeMs;
|
|
35110
35451
|
const newestAssignment = await newestAssignmentMtime(projectDir);
|
|
@@ -35153,7 +35494,7 @@ var orphanFiles = {
|
|
|
35153
35494
|
title: this.title,
|
|
35154
35495
|
status: "warn",
|
|
35155
35496
|
detail: `project at ${projectDir} has unexpected entries: ${orphans.join(", ")}`,
|
|
35156
|
-
affected: orphans.map((o) =>
|
|
35497
|
+
affected: orphans.map((o) => resolve80(projectDir, o)),
|
|
35157
35498
|
autoFixable: false
|
|
35158
35499
|
});
|
|
35159
35500
|
}
|
|
@@ -35163,7 +35504,7 @@ var orphanFiles = {
|
|
|
35163
35504
|
};
|
|
35164
35505
|
var projectChecks = [requiredFiles, manifestStale, orphanFiles];
|
|
35165
35506
|
async function newestAssignmentMtime(projectDir) {
|
|
35166
|
-
const assignmentsRoot =
|
|
35507
|
+
const assignmentsRoot = resolve80(projectDir, "assignments");
|
|
35167
35508
|
if (!await fileExists(assignmentsRoot)) return 0;
|
|
35168
35509
|
let newest = 0;
|
|
35169
35510
|
let entries;
|
|
@@ -35174,7 +35515,7 @@ async function newestAssignmentMtime(projectDir) {
|
|
|
35174
35515
|
}
|
|
35175
35516
|
for (const e of entries) {
|
|
35176
35517
|
if (!e.isDirectory()) continue;
|
|
35177
|
-
const assignmentMd =
|
|
35518
|
+
const assignmentMd = resolve80(assignmentsRoot, e.name, "assignment.md");
|
|
35178
35519
|
try {
|
|
35179
35520
|
const s = await stat10(assignmentMd);
|
|
35180
35521
|
if (s.mtimeMs > newest) newest = s.mtimeMs;
|
|
@@ -35199,8 +35540,8 @@ init_parser();
|
|
|
35199
35540
|
init_types();
|
|
35200
35541
|
init_paths();
|
|
35201
35542
|
init_assignment_walk();
|
|
35202
|
-
import { resolve as
|
|
35203
|
-
import { readFile as
|
|
35543
|
+
import { resolve as resolve81 } from "path";
|
|
35544
|
+
import { readFile as readFile53, readdir as readdir30 } from "fs/promises";
|
|
35204
35545
|
var CATEGORY4 = "assignment";
|
|
35205
35546
|
var STATUSES_REQUIRING_HANDOFF = /* @__PURE__ */ new Set(["review", "completed"]);
|
|
35206
35547
|
var PRE_WORKSPACE_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -35294,7 +35635,7 @@ var invalidStatus = {
|
|
|
35294
35635
|
const allowed = configuredStatuses(ctx);
|
|
35295
35636
|
const results = [];
|
|
35296
35637
|
for (const a of withAssignmentMd) {
|
|
35297
|
-
const path =
|
|
35638
|
+
const path = resolve81(a.assignmentDir, "assignment.md");
|
|
35298
35639
|
const parsed = await parseSafe4(path);
|
|
35299
35640
|
if (!parsed) continue;
|
|
35300
35641
|
if (!allowed.has(parsed.status)) {
|
|
@@ -35327,7 +35668,7 @@ var workspaceMissing = {
|
|
|
35327
35668
|
const terminal = terminalStatuses(ctx);
|
|
35328
35669
|
const results = [];
|
|
35329
35670
|
for (const a of withAssignmentMd) {
|
|
35330
|
-
const path =
|
|
35671
|
+
const path = resolve81(a.assignmentDir, "assignment.md");
|
|
35331
35672
|
const parsed = await parseSafe4(path);
|
|
35332
35673
|
if (!parsed) continue;
|
|
35333
35674
|
if (terminal.has(parsed.status)) continue;
|
|
@@ -35374,12 +35715,12 @@ var requiredFilesByStatus = {
|
|
|
35374
35715
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
35375
35716
|
const results = [];
|
|
35376
35717
|
for (const a of withAssignmentMd) {
|
|
35377
|
-
const assignmentPath =
|
|
35718
|
+
const assignmentPath = resolve81(a.assignmentDir, "assignment.md");
|
|
35378
35719
|
const parsed = await parseSafe4(assignmentPath);
|
|
35379
35720
|
if (!parsed) continue;
|
|
35380
35721
|
const missing = [];
|
|
35381
35722
|
if (STATUSES_REQUIRING_HANDOFF.has(parsed.status)) {
|
|
35382
|
-
const handoffPath =
|
|
35723
|
+
const handoffPath = resolve81(a.assignmentDir, "handoff.md");
|
|
35383
35724
|
if (!await fileExists(handoffPath)) missing.push("handoff.md");
|
|
35384
35725
|
}
|
|
35385
35726
|
if (missing.length === 0) continue;
|
|
@@ -35389,7 +35730,7 @@ var requiredFilesByStatus = {
|
|
|
35389
35730
|
title: this.title,
|
|
35390
35731
|
status: "warn",
|
|
35391
35732
|
detail: `${a.projectSlug}/${a.assignmentSlug} (status: ${parsed.status}) is missing ${missing.join(", ")}`,
|
|
35392
|
-
affected: missing.map((m) =>
|
|
35733
|
+
affected: missing.map((m) => resolve81(a.assignmentDir, m)),
|
|
35393
35734
|
remediation: {
|
|
35394
35735
|
kind: "manual",
|
|
35395
35736
|
suggestion: `Create the missing ${missing.join(" and ")} files for this assignment`,
|
|
@@ -35412,7 +35753,7 @@ var companionFilesScaffolded = {
|
|
|
35412
35753
|
for (const a of withAssignmentMd) {
|
|
35413
35754
|
const missing = [];
|
|
35414
35755
|
for (const filename of ["progress.md", "comments.md"]) {
|
|
35415
|
-
if (!await fileExists(
|
|
35756
|
+
if (!await fileExists(resolve81(a.assignmentDir, filename))) {
|
|
35416
35757
|
missing.push(filename);
|
|
35417
35758
|
}
|
|
35418
35759
|
}
|
|
@@ -35424,7 +35765,7 @@ var companionFilesScaffolded = {
|
|
|
35424
35765
|
title: this.title,
|
|
35425
35766
|
status: "warn",
|
|
35426
35767
|
detail: `${label} is missing ${missing.join(" and ")} (pre-v2.0 assignment \u2014 not required, but scaffolding them keeps the dashboard and CLIs consistent)`,
|
|
35427
|
-
affected: missing.map((m) =>
|
|
35768
|
+
affected: missing.map((m) => resolve81(a.assignmentDir, m)),
|
|
35428
35769
|
remediation: {
|
|
35429
35770
|
kind: "manual",
|
|
35430
35771
|
suggestion: `Create ${missing.join(" and ")} with the renderProgress/renderComments templates, or re-scaffold via the CLI`,
|
|
@@ -35457,7 +35798,7 @@ var typeDefinition = {
|
|
|
35457
35798
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
35458
35799
|
const results = [];
|
|
35459
35800
|
for (const a of withAssignmentMd) {
|
|
35460
|
-
const path =
|
|
35801
|
+
const path = resolve81(a.assignmentDir, "assignment.md");
|
|
35461
35802
|
const parsed = await parseSafe4(path);
|
|
35462
35803
|
if (!parsed) continue;
|
|
35463
35804
|
if (!parsed.type) continue;
|
|
@@ -35491,7 +35832,7 @@ var projectFrontmatterMatchesContainer = {
|
|
|
35491
35832
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
35492
35833
|
const results = [];
|
|
35493
35834
|
for (const a of withAssignmentMd) {
|
|
35494
|
-
const path =
|
|
35835
|
+
const path = resolve81(a.assignmentDir, "assignment.md");
|
|
35495
35836
|
const parsed = await parseSafe4(path);
|
|
35496
35837
|
if (!parsed) continue;
|
|
35497
35838
|
if (a.standalone) {
|
|
@@ -35542,13 +35883,13 @@ var draftMissingObjective = {
|
|
|
35542
35883
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
35543
35884
|
const results = [];
|
|
35544
35885
|
for (const a of withAssignmentMd) {
|
|
35545
|
-
const path =
|
|
35886
|
+
const path = resolve81(a.assignmentDir, "assignment.md");
|
|
35546
35887
|
const parsed = await parseSafe4(path);
|
|
35547
35888
|
if (!parsed) continue;
|
|
35548
35889
|
if (parsed.status !== "draft") continue;
|
|
35549
35890
|
let raw2;
|
|
35550
35891
|
try {
|
|
35551
|
-
raw2 = await
|
|
35892
|
+
raw2 = await readFile53(path, "utf-8");
|
|
35552
35893
|
} catch {
|
|
35553
35894
|
continue;
|
|
35554
35895
|
}
|
|
@@ -35581,7 +35922,7 @@ var readyToImplementMissingPlan = {
|
|
|
35581
35922
|
const { withAssignmentMd } = await listAssignments(ctx);
|
|
35582
35923
|
const results = [];
|
|
35583
35924
|
for (const a of withAssignmentMd) {
|
|
35584
|
-
const path =
|
|
35925
|
+
const path = resolve81(a.assignmentDir, "assignment.md");
|
|
35585
35926
|
const parsed = await parseSafe4(path);
|
|
35586
35927
|
if (!parsed) continue;
|
|
35587
35928
|
if (parsed.status !== "ready_to_implement") continue;
|
|
@@ -35590,7 +35931,7 @@ var readyToImplementMissingPlan = {
|
|
|
35590
35931
|
let hasPlanContent = false;
|
|
35591
35932
|
for (const f of planFiles) {
|
|
35592
35933
|
try {
|
|
35593
|
-
const c2 = await
|
|
35934
|
+
const c2 = await readFile53(resolve81(a.assignmentDir, f), "utf-8");
|
|
35594
35935
|
if (c2.trim().length > 0) {
|
|
35595
35936
|
hasPlanContent = true;
|
|
35596
35937
|
break;
|
|
@@ -35606,7 +35947,7 @@ var readyToImplementMissingPlan = {
|
|
|
35606
35947
|
title: this.title,
|
|
35607
35948
|
status: "warn",
|
|
35608
35949
|
detail: `${label} (status: ready_to_implement) has no plan.md or plan-v<N>.md`,
|
|
35609
|
-
affected: [
|
|
35950
|
+
affected: [resolve81(a.assignmentDir, "plan.md")],
|
|
35610
35951
|
remediation: {
|
|
35611
35952
|
kind: "manual",
|
|
35612
35953
|
suggestion: `Write a plan with '/plan-assignment' (or 'syntaur plan'), then re-mark ready_to_implement`,
|
|
@@ -35633,7 +35974,7 @@ var assignmentChecks = [
|
|
|
35633
35974
|
];
|
|
35634
35975
|
async function parseSafe4(path) {
|
|
35635
35976
|
try {
|
|
35636
|
-
const content = await
|
|
35977
|
+
const content = await readFile53(path, "utf-8");
|
|
35637
35978
|
return parseAssignmentFull(content);
|
|
35638
35979
|
} catch {
|
|
35639
35980
|
return null;
|
|
@@ -35652,7 +35993,7 @@ function pass4(check, detail) {
|
|
|
35652
35993
|
|
|
35653
35994
|
// src/utils/doctor/checks/dashboard.ts
|
|
35654
35995
|
init_fs();
|
|
35655
|
-
import { resolve as
|
|
35996
|
+
import { resolve as resolve82 } from "path";
|
|
35656
35997
|
var CATEGORY5 = "dashboard";
|
|
35657
35998
|
var dbReachable = {
|
|
35658
35999
|
id: "dashboard.db-reachable",
|
|
@@ -35666,7 +36007,7 @@ var dbReachable = {
|
|
|
35666
36007
|
title: this.title,
|
|
35667
36008
|
status: "error",
|
|
35668
36009
|
detail: `could not open syntaur.db: ${ctx.dbError ?? "unknown error"}`,
|
|
35669
|
-
affected: [
|
|
36010
|
+
affected: [resolve82(ctx.syntaurRoot, "syntaur.db")],
|
|
35670
36011
|
remediation: {
|
|
35671
36012
|
kind: "manual",
|
|
35672
36013
|
suggestion: "Start the dashboard once (`syntaur dashboard`) to initialize the DB, or restore it from backup",
|
|
@@ -35684,7 +36025,7 @@ var dbReachable = {
|
|
|
35684
36025
|
title: this.title,
|
|
35685
36026
|
status: "error",
|
|
35686
36027
|
detail: 'syntaur.db is missing the expected "sessions" table',
|
|
35687
|
-
affected: [
|
|
36028
|
+
affected: [resolve82(ctx.syntaurRoot, "syntaur.db")],
|
|
35688
36029
|
autoFixable: false
|
|
35689
36030
|
};
|
|
35690
36031
|
}
|
|
@@ -35696,7 +36037,7 @@ var dbReachable = {
|
|
|
35696
36037
|
title: this.title,
|
|
35697
36038
|
status: "error",
|
|
35698
36039
|
detail: `syntaur.db query failed: ${err2 instanceof Error ? err2.message : String(err2)}`,
|
|
35699
|
-
affected: [
|
|
36040
|
+
affected: [resolve82(ctx.syntaurRoot, "syntaur.db")],
|
|
35700
36041
|
autoFixable: false
|
|
35701
36042
|
};
|
|
35702
36043
|
}
|
|
@@ -35722,7 +36063,7 @@ var ghostSessions = {
|
|
|
35722
36063
|
const results = [];
|
|
35723
36064
|
for (const row of rows) {
|
|
35724
36065
|
if (!row.project_slug) continue;
|
|
35725
|
-
const projectPath =
|
|
36066
|
+
const projectPath = resolve82(projectsDir2, row.project_slug, "project.md");
|
|
35726
36067
|
if (!await fileExists(projectPath)) {
|
|
35727
36068
|
results.push({
|
|
35728
36069
|
id: this.id,
|
|
@@ -35741,7 +36082,7 @@ var ghostSessions = {
|
|
|
35741
36082
|
continue;
|
|
35742
36083
|
}
|
|
35743
36084
|
if (row.assignment_slug) {
|
|
35744
|
-
const assignmentPath =
|
|
36085
|
+
const assignmentPath = resolve82(
|
|
35745
36086
|
projectsDir2,
|
|
35746
36087
|
row.project_slug,
|
|
35747
36088
|
"assignments",
|
|
@@ -35793,8 +36134,8 @@ function skipped(check, reason) {
|
|
|
35793
36134
|
|
|
35794
36135
|
// src/utils/doctor/checks/integrations.ts
|
|
35795
36136
|
init_fs();
|
|
35796
|
-
import { resolve as
|
|
35797
|
-
import { readdir as readdir31, readFile as
|
|
36137
|
+
import { resolve as resolve83, dirname as dirname23, basename as basename8 } from "path";
|
|
36138
|
+
import { readdir as readdir31, readFile as readFile54 } from "fs/promises";
|
|
35798
36139
|
import { homedir as homedir14 } from "os";
|
|
35799
36140
|
var CATEGORY6 = "integrations";
|
|
35800
36141
|
var claudePluginLinked = {
|
|
@@ -35876,10 +36217,10 @@ var backupConfigured = {
|
|
|
35876
36217
|
}
|
|
35877
36218
|
};
|
|
35878
36219
|
async function readKnownMarketplaces() {
|
|
35879
|
-
const path =
|
|
36220
|
+
const path = resolve83(homedir14(), ".claude", "plugins", "known_marketplaces.json");
|
|
35880
36221
|
if (!await fileExists(path)) return {};
|
|
35881
36222
|
try {
|
|
35882
|
-
const raw2 = await
|
|
36223
|
+
const raw2 = await readFile54(path, "utf-8");
|
|
35883
36224
|
return JSON.parse(raw2);
|
|
35884
36225
|
} catch {
|
|
35885
36226
|
return {};
|
|
@@ -35913,7 +36254,7 @@ var claudeMarketplaceRegistered = {
|
|
|
35913
36254
|
};
|
|
35914
36255
|
}
|
|
35915
36256
|
const marketplaceRoot = dirname23(pluginsParent);
|
|
35916
|
-
const marketplaceManifest =
|
|
36257
|
+
const marketplaceManifest = resolve83(marketplaceRoot, ".claude-plugin", "marketplace.json");
|
|
35917
36258
|
if (!await fileExists(marketplaceManifest)) {
|
|
35918
36259
|
return {
|
|
35919
36260
|
id: this.id,
|
|
@@ -35932,7 +36273,7 @@ var claudeMarketplaceRegistered = {
|
|
|
35932
36273
|
}
|
|
35933
36274
|
let parsed = {};
|
|
35934
36275
|
try {
|
|
35935
|
-
parsed = JSON.parse(await
|
|
36276
|
+
parsed = JSON.parse(await readFile54(marketplaceManifest, "utf-8"));
|
|
35936
36277
|
} catch {
|
|
35937
36278
|
return {
|
|
35938
36279
|
id: this.id,
|
|
@@ -35964,7 +36305,7 @@ var claudeMarketplaceRegistered = {
|
|
|
35964
36305
|
title: this.title,
|
|
35965
36306
|
status: "error",
|
|
35966
36307
|
detail: issues.join("; "),
|
|
35967
|
-
affected: [marketplaceManifest,
|
|
36308
|
+
affected: [marketplaceManifest, resolve83(homedir14(), ".claude", "plugins", "known_marketplaces.json")],
|
|
35968
36309
|
remediation: {
|
|
35969
36310
|
kind: "manual",
|
|
35970
36311
|
suggestion: "Re-run install-plugin to ensure both files are in sync.",
|
|
@@ -36004,8 +36345,8 @@ function skipped2(check, reason) {
|
|
|
36004
36345
|
init_fs();
|
|
36005
36346
|
init_parser();
|
|
36006
36347
|
init_types();
|
|
36007
|
-
import { resolve as
|
|
36008
|
-
import { readFile as
|
|
36348
|
+
import { resolve as resolve84 } from "path";
|
|
36349
|
+
import { readFile as readFile55 } from "fs/promises";
|
|
36009
36350
|
var CATEGORY7 = "workspace";
|
|
36010
36351
|
var ASSIGNMENT_FIELDS2 = ["projectSlug", "assignmentSlug", "projectDir", "assignmentDir"];
|
|
36011
36352
|
var BUNDLE_FIELDS = ["bundleId", "bundleScope", "bundleScopeId"];
|
|
@@ -36027,12 +36368,12 @@ function isStandaloneSession(ctx) {
|
|
|
36027
36368
|
return !hasAnyAssignmentField(ctx) && !hasAnyBundleField(ctx) && hasSessionMeta;
|
|
36028
36369
|
}
|
|
36029
36370
|
async function loadContext(ctx) {
|
|
36030
|
-
const path =
|
|
36371
|
+
const path = resolve84(ctx.cwd, ".syntaur", "context.json");
|
|
36031
36372
|
if (!await fileExists(path)) {
|
|
36032
36373
|
return { data: null, path, exists: false, parseError: null };
|
|
36033
36374
|
}
|
|
36034
36375
|
try {
|
|
36035
|
-
const raw2 = await
|
|
36376
|
+
const raw2 = await readFile55(path, "utf-8");
|
|
36036
36377
|
return { data: JSON.parse(raw2), path, exists: true, parseError: null };
|
|
36037
36378
|
} catch (err2) {
|
|
36038
36379
|
return {
|
|
@@ -36126,7 +36467,7 @@ var contextAssignmentResolves = {
|
|
|
36126
36467
|
if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to resolve");
|
|
36127
36468
|
if (isBundleContext(data)) return skipped3(this, "bundle context \u2014 no assignment to resolve");
|
|
36128
36469
|
if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
|
|
36129
|
-
const assignmentMd =
|
|
36470
|
+
const assignmentMd = resolve84(data.assignmentDir, "assignment.md");
|
|
36130
36471
|
if (!await fileExists(assignmentMd)) {
|
|
36131
36472
|
return {
|
|
36132
36473
|
id: this.id,
|
|
@@ -36156,10 +36497,10 @@ var contextTerminal = {
|
|
|
36156
36497
|
if (isStandaloneSession(data)) return skipped3(this, "standalone session context \u2014 no assignment to check");
|
|
36157
36498
|
if (isBundleContext(data)) return skipped3(this, "bundle context \u2014 no assignment to check");
|
|
36158
36499
|
if (!data?.assignmentDir) return skipped3(this, "context has no assignmentDir");
|
|
36159
|
-
const assignmentMd =
|
|
36500
|
+
const assignmentMd = resolve84(data.assignmentDir, "assignment.md");
|
|
36160
36501
|
if (!await fileExists(assignmentMd)) return skipped3(this, "assignment file missing");
|
|
36161
36502
|
try {
|
|
36162
|
-
const content = await
|
|
36503
|
+
const content = await readFile55(assignmentMd, "utf-8");
|
|
36163
36504
|
const parsed = parseAssignmentFull(content);
|
|
36164
36505
|
const terminal = terminalStatuses2(ctx);
|
|
36165
36506
|
if (terminal.has(parsed.status)) {
|
|
@@ -36305,15 +36646,15 @@ var agentChecks = [agentsResolvable];
|
|
|
36305
36646
|
// src/utils/doctor/checks/terminal.ts
|
|
36306
36647
|
init_config2();
|
|
36307
36648
|
import { spawnSync as spawnSync9 } from "child_process";
|
|
36308
|
-
import { readFile as
|
|
36309
|
-
import { resolve as
|
|
36649
|
+
import { readFile as readFile56 } from "fs/promises";
|
|
36650
|
+
import { resolve as resolve85 } from "path";
|
|
36310
36651
|
init_paths();
|
|
36311
36652
|
init_fs();
|
|
36312
36653
|
var CATEGORY9 = "terminal";
|
|
36313
36654
|
async function readRawTerminalKey() {
|
|
36314
|
-
const configPath2 =
|
|
36655
|
+
const configPath2 = resolve85(syntaurRoot(), "config.md");
|
|
36315
36656
|
if (!await fileExists(configPath2)) return null;
|
|
36316
|
-
const content = await
|
|
36657
|
+
const content = await readFile56(configPath2, "utf-8");
|
|
36317
36658
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
36318
36659
|
if (!fmMatch) return null;
|
|
36319
36660
|
const line = fmMatch[1].split("\n").find((l) => /^terminal:\s*/.test(l));
|
|
@@ -36463,13 +36804,13 @@ var terminalChecks = [
|
|
|
36463
36804
|
|
|
36464
36805
|
// src/utils/doctor/checks/skills.ts
|
|
36465
36806
|
init_fs();
|
|
36466
|
-
import { resolve as
|
|
36467
|
-
import { readdir as readdir32, readFile as
|
|
36807
|
+
import { resolve as resolve86, join as join18 } from "path";
|
|
36808
|
+
import { readdir as readdir32, readFile as readFile57, lstat as lstat4 } from "fs/promises";
|
|
36468
36809
|
import { homedir as homedir15 } from "os";
|
|
36469
36810
|
var CATEGORY10 = "skills";
|
|
36470
36811
|
var skillTargets = [
|
|
36471
|
-
{ agent: "claude", dir:
|
|
36472
|
-
{ agent: "codex", dir:
|
|
36812
|
+
{ agent: "claude", dir: resolve86(homedir15(), ".claude", "skills"), label: "~/.claude/skills" },
|
|
36813
|
+
{ agent: "codex", dir: resolve86(homedir15(), ".codex", "skills"), label: "~/.codex/skills" }
|
|
36473
36814
|
];
|
|
36474
36815
|
var skillsDedupCheck = {
|
|
36475
36816
|
id: "skills.dedup",
|
|
@@ -36493,7 +36834,7 @@ var skillsDedupCheck = {
|
|
|
36493
36834
|
if (!KNOWN_SKILLS.includes(entry.name)) continue;
|
|
36494
36835
|
const skillMd = join18(dir, entry.name, "SKILL.md");
|
|
36495
36836
|
if (!await fileExists(skillMd)) continue;
|
|
36496
|
-
const content = await
|
|
36837
|
+
const content = await readFile57(skillMd, "utf-8").catch(() => "");
|
|
36497
36838
|
const match = content.match(/^name:\s*(\S+)\s*$/m);
|
|
36498
36839
|
if (!match || match[1] !== entry.name) continue;
|
|
36499
36840
|
let isSymlink2 = false;
|
|
@@ -36543,12 +36884,12 @@ var skillsChecks = [skillsDedupCheck];
|
|
|
36543
36884
|
|
|
36544
36885
|
// src/utils/doctor/checks/cross-agent.ts
|
|
36545
36886
|
init_fs();
|
|
36546
|
-
import { join as join19, resolve as
|
|
36547
|
-
import { readFile as
|
|
36887
|
+
import { join as join19, resolve as resolve87 } from "path";
|
|
36888
|
+
import { readFile as readFile59 } from "fs/promises";
|
|
36548
36889
|
|
|
36549
36890
|
// src/utils/skill-frontmatter.ts
|
|
36550
36891
|
import { createHash as createHash4 } from "crypto";
|
|
36551
|
-
import { readFile as
|
|
36892
|
+
import { readFile as readFile58 } from "fs/promises";
|
|
36552
36893
|
function stripQuotes(raw2) {
|
|
36553
36894
|
const t = raw2.trim();
|
|
36554
36895
|
if (t.length >= 2 && (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'"))) {
|
|
@@ -36592,7 +36933,7 @@ function readSkillIdentity(skillMdText) {
|
|
|
36592
36933
|
return { name, hasDescription };
|
|
36593
36934
|
}
|
|
36594
36935
|
async function sha256File(path) {
|
|
36595
|
-
return createHash4("sha256").update(await
|
|
36936
|
+
return createHash4("sha256").update(await readFile58(path)).digest("hex");
|
|
36596
36937
|
}
|
|
36597
36938
|
|
|
36598
36939
|
// src/utils/doctor/checks/cross-agent.ts
|
|
@@ -36609,7 +36950,7 @@ async function checkTargetSkillsIntegrity(installedDir, canonicalSkillsDir, know
|
|
|
36609
36950
|
}
|
|
36610
36951
|
let text;
|
|
36611
36952
|
try {
|
|
36612
|
-
text = await
|
|
36953
|
+
text = await readFile59(installedPath, "utf-8");
|
|
36613
36954
|
} catch {
|
|
36614
36955
|
problems.push({ skill, kind: "invalid-frontmatter" });
|
|
36615
36956
|
continue;
|
|
@@ -36686,7 +37027,7 @@ var crossAgentSkillsCheck = {
|
|
|
36686
37027
|
}
|
|
36687
37028
|
if (recorded && t.instructions) {
|
|
36688
37029
|
for (const f of t.instructions.files) {
|
|
36689
|
-
const p =
|
|
37030
|
+
const p = resolve87(ctx.cwd, f.path);
|
|
36690
37031
|
if (!await fileExists(p)) {
|
|
36691
37032
|
problems.push(`${t.displayName}: missing protocol file ${f.path} in cwd`);
|
|
36692
37033
|
affected.push(p);
|
|
@@ -36762,7 +37103,7 @@ var crossAgentChecks = [crossAgentSkillsCheck];
|
|
|
36762
37103
|
// src/utils/doctor/checks/bundles.ts
|
|
36763
37104
|
init_fs();
|
|
36764
37105
|
init_paths();
|
|
36765
|
-
import { resolve as
|
|
37106
|
+
import { resolve as resolve88 } from "path";
|
|
36766
37107
|
import { readdir as readdir33 } from "fs/promises";
|
|
36767
37108
|
import { spawnSync as spawnSync10 } from "child_process";
|
|
36768
37109
|
init_parser2();
|
|
@@ -36792,7 +37133,7 @@ async function listScopes(ctx) {
|
|
|
36792
37133
|
if (!e.isDirectory()) continue;
|
|
36793
37134
|
const slug = e.name;
|
|
36794
37135
|
if (typeof slug !== "string" || slug.startsWith(".")) continue;
|
|
36795
|
-
const projectMd =
|
|
37136
|
+
const projectMd = resolve88(ctx.config.defaultProjectDir, slug, "project.md");
|
|
36796
37137
|
if (!await fileExists(projectMd)) continue;
|
|
36797
37138
|
out.push({
|
|
36798
37139
|
scopeLabel: `project:${slug}`,
|
|
@@ -36985,7 +37326,7 @@ var bundleChecks = [
|
|
|
36985
37326
|
];
|
|
36986
37327
|
|
|
36987
37328
|
// src/utils/doctor/checks/plugin.ts
|
|
36988
|
-
import { readFile as
|
|
37329
|
+
import { readFile as readFile60 } from "fs/promises";
|
|
36989
37330
|
import { dirname as dirname24, join as join20 } from "path";
|
|
36990
37331
|
import { fileURLToPath as fileURLToPath11 } from "url";
|
|
36991
37332
|
var CATEGORY13 = "plugin";
|
|
@@ -36995,7 +37336,7 @@ async function readCliVersion() {
|
|
|
36995
37336
|
let dir = dirname24(fileURLToPath11(import.meta.url));
|
|
36996
37337
|
for (let i = 0; i < 8; i += 1) {
|
|
36997
37338
|
try {
|
|
36998
|
-
const parsed = JSON.parse(await
|
|
37339
|
+
const parsed = JSON.parse(await readFile60(join20(dir, "package.json"), "utf-8"));
|
|
36999
37340
|
if (typeof parsed.version === "string" && parsed.version.length > 0) return parsed.version;
|
|
37000
37341
|
} catch {
|
|
37001
37342
|
}
|
|
@@ -37205,7 +37546,7 @@ async function readVersion() {
|
|
|
37205
37546
|
let dir = dirname25(here);
|
|
37206
37547
|
for (let i = 0; i < 6; i++) {
|
|
37207
37548
|
try {
|
|
37208
|
-
const raw2 = await
|
|
37549
|
+
const raw2 = await readFile61(join21(dir, "package.json"), "utf-8");
|
|
37209
37550
|
const parsed = JSON.parse(raw2);
|
|
37210
37551
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
37211
37552
|
} catch {
|
|
@@ -37302,7 +37643,7 @@ var REQUIRED_WORKSPACE_FIELDS = [
|
|
|
37302
37643
|
];
|
|
37303
37644
|
var ISO_DATE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
|
|
37304
37645
|
async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
|
|
37305
|
-
const absolute = isAbsolute11(inputPath) ? inputPath :
|
|
37646
|
+
const absolute = isAbsolute11(inputPath) ? inputPath : resolve89(cwd, inputPath);
|
|
37306
37647
|
const errors = [];
|
|
37307
37648
|
const warnings = [];
|
|
37308
37649
|
if (!await fileExists(absolute)) {
|
|
@@ -37315,7 +37656,7 @@ async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
|
|
|
37315
37656
|
}
|
|
37316
37657
|
let content;
|
|
37317
37658
|
try {
|
|
37318
|
-
content = await
|
|
37659
|
+
content = await readFile62(absolute, "utf-8");
|
|
37319
37660
|
} catch (err2) {
|
|
37320
37661
|
return {
|
|
37321
37662
|
ok: false,
|
|
@@ -37682,8 +38023,8 @@ init_assignment_resolver();
|
|
|
37682
38023
|
init_frontmatter();
|
|
37683
38024
|
init_event_emit();
|
|
37684
38025
|
init_templates();
|
|
37685
|
-
import { resolve as
|
|
37686
|
-
import { readFile as
|
|
38026
|
+
import { resolve as resolve90 } from "path";
|
|
38027
|
+
import { readFile as readFile63 } from "fs/promises";
|
|
37687
38028
|
function shortId() {
|
|
37688
38029
|
return generateId().split("-")[0];
|
|
37689
38030
|
}
|
|
@@ -37714,7 +38055,7 @@ async function commentCommand(target, text, options = {}) {
|
|
|
37714
38055
|
if (!isValidSlug(target)) {
|
|
37715
38056
|
throw new Error(`Invalid assignment slug "${target}".`);
|
|
37716
38057
|
}
|
|
37717
|
-
assignmentDir =
|
|
38058
|
+
assignmentDir = resolve90(baseDir, options.project, "assignments", target);
|
|
37718
38059
|
assignmentRef = target;
|
|
37719
38060
|
projectSlug = options.project;
|
|
37720
38061
|
} else {
|
|
@@ -37726,13 +38067,13 @@ async function commentCommand(target, text, options = {}) {
|
|
|
37726
38067
|
assignmentRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
|
|
37727
38068
|
projectSlug = resolved.projectSlug;
|
|
37728
38069
|
}
|
|
37729
|
-
const commentsPath =
|
|
38070
|
+
const commentsPath = resolve90(assignmentDir, "comments.md");
|
|
37730
38071
|
const timestamp = nowTimestamp();
|
|
37731
38072
|
const author = options.author ?? process.env.USER ?? "unknown";
|
|
37732
38073
|
let currentContent;
|
|
37733
38074
|
let currentCount = 0;
|
|
37734
38075
|
if (await fileExists(commentsPath)) {
|
|
37735
|
-
currentContent = await
|
|
38076
|
+
currentContent = await readFile63(commentsPath, "utf-8");
|
|
37736
38077
|
const countMatch = currentContent.match(/^entryCount:\s*(\d+)/m);
|
|
37737
38078
|
if (countMatch) currentCount = parseInt(countMatch[1], 10);
|
|
37738
38079
|
} else {
|
|
@@ -37760,9 +38101,9 @@ ${entry}`;
|
|
|
37760
38101
|
}
|
|
37761
38102
|
await writeFileForce(commentsPath, next);
|
|
37762
38103
|
try {
|
|
37763
|
-
const assignmentMd =
|
|
38104
|
+
const assignmentMd = resolve90(assignmentDir, "assignment.md");
|
|
37764
38105
|
if (await fileExists(assignmentMd)) {
|
|
37765
|
-
const fm = parseAssignmentFrontmatter(await
|
|
38106
|
+
const fm = parseAssignmentFrontmatter(await readFile63(assignmentMd, "utf-8"));
|
|
37766
38107
|
emitEvent({
|
|
37767
38108
|
assignmentId: fm.id,
|
|
37768
38109
|
projectSlug,
|
|
@@ -37786,7 +38127,7 @@ ${entry}`;
|
|
|
37786
38127
|
}
|
|
37787
38128
|
|
|
37788
38129
|
// src/commands/capture.ts
|
|
37789
|
-
import { resolve as
|
|
38130
|
+
import { resolve as resolve94, relative as relative4, dirname as dirname26 } from "path";
|
|
37790
38131
|
import { copyFile as copyFile3, mkdir as mkdir12, realpath as realpath2, rm as rm14, stat as stat13, writeFile as writeFile15 } from "fs/promises";
|
|
37791
38132
|
import { existsSync as existsSync7 } from "fs";
|
|
37792
38133
|
|
|
@@ -37797,8 +38138,8 @@ init_config2();
|
|
|
37797
38138
|
init_slug();
|
|
37798
38139
|
init_assignment_resolver();
|
|
37799
38140
|
init_parser();
|
|
37800
|
-
import { resolve as
|
|
37801
|
-
import { readFile as
|
|
38141
|
+
import { resolve as resolve91 } from "path";
|
|
38142
|
+
import { readFile as readFile64 } from "fs/promises";
|
|
37802
38143
|
var AssignmentTargetError = class extends Error {
|
|
37803
38144
|
};
|
|
37804
38145
|
function classifyContext(ctx) {
|
|
@@ -37810,10 +38151,10 @@ function classifyContext(ctx) {
|
|
|
37810
38151
|
return "empty";
|
|
37811
38152
|
}
|
|
37812
38153
|
async function readAssignmentFrontmatterId(assignmentDir) {
|
|
37813
|
-
const path =
|
|
38154
|
+
const path = resolve91(assignmentDir, "assignment.md");
|
|
37814
38155
|
if (!await fileExists(path)) return null;
|
|
37815
38156
|
try {
|
|
37816
|
-
const content = await
|
|
38157
|
+
const content = await readFile64(path, "utf-8");
|
|
37817
38158
|
const [fm] = extractFrontmatter(content);
|
|
37818
38159
|
return getField(fm, "id");
|
|
37819
38160
|
} catch {
|
|
@@ -37821,10 +38162,10 @@ async function readAssignmentFrontmatterId(assignmentDir) {
|
|
|
37821
38162
|
}
|
|
37822
38163
|
}
|
|
37823
38164
|
async function readContextJson(cwd) {
|
|
37824
|
-
const path =
|
|
38165
|
+
const path = resolve91(cwd, ".syntaur", "context.json");
|
|
37825
38166
|
if (!await fileExists(path)) return null;
|
|
37826
38167
|
try {
|
|
37827
|
-
const raw2 = await
|
|
38168
|
+
const raw2 = await readFile64(path, "utf-8");
|
|
37828
38169
|
return JSON.parse(raw2);
|
|
37829
38170
|
} catch {
|
|
37830
38171
|
return null;
|
|
@@ -37845,15 +38186,15 @@ async function resolveAssignmentTarget(input4, opts = {}) {
|
|
|
37845
38186
|
if (!isValidSlug(input4)) {
|
|
37846
38187
|
throw new AssignmentTargetError(`Invalid assignment slug "${input4}".`);
|
|
37847
38188
|
}
|
|
37848
|
-
const projectDir =
|
|
37849
|
-
const projectMdPath =
|
|
38189
|
+
const projectDir = resolve91(baseDir, opts.project);
|
|
38190
|
+
const projectMdPath = resolve91(projectDir, "project.md");
|
|
37850
38191
|
if (!await fileExists(projectDir) || !await fileExists(projectMdPath)) {
|
|
37851
38192
|
throw new AssignmentTargetError(
|
|
37852
38193
|
`Project "${opts.project}" not found at ${projectDir}.`
|
|
37853
38194
|
);
|
|
37854
38195
|
}
|
|
37855
|
-
const assignmentDir =
|
|
37856
|
-
const assignmentMdPath2 =
|
|
38196
|
+
const assignmentDir = resolve91(projectDir, "assignments", input4);
|
|
38197
|
+
const assignmentMdPath2 = resolve91(assignmentDir, "assignment.md");
|
|
37857
38198
|
if (!await fileExists(assignmentMdPath2)) {
|
|
37858
38199
|
throw new AssignmentTargetError(
|
|
37859
38200
|
`Assignment "${input4}" not found in project "${opts.project}".`
|
|
@@ -37892,7 +38233,7 @@ async function resolveAssignmentTarget(input4, opts = {}) {
|
|
|
37892
38233
|
}
|
|
37893
38234
|
if (ctx.assignmentDir) {
|
|
37894
38235
|
const dir = expandHome(ctx.assignmentDir);
|
|
37895
|
-
const assignmentMdPath2 =
|
|
38236
|
+
const assignmentMdPath2 = resolve91(dir, "assignment.md");
|
|
37896
38237
|
if (!await fileExists(assignmentMdPath2)) {
|
|
37897
38238
|
throw new AssignmentTargetError(
|
|
37898
38239
|
`.syntaur/context.json points to a missing assignment dir: ${dir}.`
|
|
@@ -37921,8 +38262,8 @@ async function resolveAssignmentTarget(input4, opts = {}) {
|
|
|
37921
38262
|
`.syntaur/context.json contains invalid slugs: project="${ctx.projectSlug}" assignment="${ctx.assignmentSlug}".`
|
|
37922
38263
|
);
|
|
37923
38264
|
}
|
|
37924
|
-
const assignmentDir =
|
|
37925
|
-
const assignmentMdPath2 =
|
|
38265
|
+
const assignmentDir = resolve91(baseDir, ctx.projectSlug, "assignments", ctx.assignmentSlug);
|
|
38266
|
+
const assignmentMdPath2 = resolve91(assignmentDir, "assignment.md");
|
|
37926
38267
|
if (!await fileExists(assignmentMdPath2)) {
|
|
37927
38268
|
throw new AssignmentTargetError(
|
|
37928
38269
|
`.syntaur/context.json points to a missing assignment: ${assignmentDir}.`
|
|
@@ -38023,7 +38364,7 @@ async function captureScreenshot(mode) {
|
|
|
38023
38364
|
|
|
38024
38365
|
// src/utils/asciinema.ts
|
|
38025
38366
|
import { spawn as spawn9 } from "child_process";
|
|
38026
|
-
import { mkdtemp as mkdtemp3, readFile as
|
|
38367
|
+
import { mkdtemp as mkdtemp3, readFile as readFile65, rm as rm11 } from "fs/promises";
|
|
38027
38368
|
import { tmpdir as tmpdir4 } from "os";
|
|
38028
38369
|
import { join as join23 } from "path";
|
|
38029
38370
|
var SAFE_RE = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
@@ -38086,7 +38427,7 @@ async function captureAsciinema(opts) {
|
|
|
38086
38427
|
}
|
|
38087
38428
|
throw err2;
|
|
38088
38429
|
}
|
|
38089
|
-
const text = await
|
|
38430
|
+
const text = await readFile65(castPath, "utf8").catch(() => null);
|
|
38090
38431
|
if (text === null) {
|
|
38091
38432
|
throw new Error(
|
|
38092
38433
|
`asciinema produced no cast file at ${castPath} (exit ${exitCode}). Try running 'asciinema rec ${castPath}' directly to diagnose.`
|
|
@@ -38114,9 +38455,9 @@ async function captureAsciinema(opts) {
|
|
|
38114
38455
|
// src/utils/recording.ts
|
|
38115
38456
|
init_paths();
|
|
38116
38457
|
import { spawn as spawn10 } from "child_process";
|
|
38117
|
-
import { mkdir as mkdir11, mkdtemp as mkdtemp4, open as open6, readFile as
|
|
38458
|
+
import { mkdir as mkdir11, mkdtemp as mkdtemp4, open as open6, readFile as readFile66, rm as rm12, stat as stat12, unlink as unlink12, writeFile as writeFile14 } from "fs/promises";
|
|
38118
38459
|
import { tmpdir as tmpdir5 } from "os";
|
|
38119
|
-
import { join as join24, resolve as
|
|
38460
|
+
import { join as join24, resolve as resolve92 } from "path";
|
|
38120
38461
|
import { setTimeout as sleep } from "timers/promises";
|
|
38121
38462
|
function sigintPollIntervalMs() {
|
|
38122
38463
|
const raw2 = process.env.SYNTAUR_RECORDING_POLL_INTERVAL_MS;
|
|
@@ -38137,13 +38478,13 @@ function sigtermWaitMs() {
|
|
|
38137
38478
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : 1e3;
|
|
38138
38479
|
}
|
|
38139
38480
|
function pidfilePath() {
|
|
38140
|
-
return
|
|
38481
|
+
return resolve92(syntaurRoot(), "recording.pid");
|
|
38141
38482
|
}
|
|
38142
38483
|
function logPath2() {
|
|
38143
|
-
return
|
|
38484
|
+
return resolve92(syntaurRoot(), "recording.log");
|
|
38144
38485
|
}
|
|
38145
38486
|
function sidecarPath() {
|
|
38146
|
-
return
|
|
38487
|
+
return resolve92(syntaurRoot(), "recording.json");
|
|
38147
38488
|
}
|
|
38148
38489
|
function ffmpegArgs(device, fps, mp4Path) {
|
|
38149
38490
|
return [
|
|
@@ -38188,7 +38529,7 @@ async function acquirePidfile(pidfile) {
|
|
|
38188
38529
|
} catch (err2) {
|
|
38189
38530
|
if (err2.code !== "EEXIST") throw err2;
|
|
38190
38531
|
if (attempt === 1) throw err2;
|
|
38191
|
-
const existing = (await
|
|
38532
|
+
const existing = (await readFile66(pidfile, "utf-8").catch(() => "")).trim();
|
|
38192
38533
|
if (existing.startsWith(STARTING_SENTINEL_PREFIX)) {
|
|
38193
38534
|
const parentPidRaw = existing.slice(STARTING_SENTINEL_PREFIX.length);
|
|
38194
38535
|
const parentPid = Number.parseInt(parentPidRaw, 10);
|
|
@@ -38290,7 +38631,7 @@ async function startRecording(input4) {
|
|
|
38290
38631
|
logHandle = null;
|
|
38291
38632
|
if (warmupMs > 0) await sleep(warmupMs);
|
|
38292
38633
|
if (!await isProcessAlive(pid)) {
|
|
38293
|
-
const tail = await
|
|
38634
|
+
const tail = await readFile66(log, "utf-8").then((s) => s.split("\n").slice(-20).join("\n")).catch(() => "");
|
|
38294
38635
|
acquiredPid = null;
|
|
38295
38636
|
throw new Error(
|
|
38296
38637
|
`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}
|
|
@@ -38347,7 +38688,7 @@ ${tail}`
|
|
|
38347
38688
|
async function stopRecording() {
|
|
38348
38689
|
const pidfile = pidfilePath();
|
|
38349
38690
|
const sidecar = sidecarPath();
|
|
38350
|
-
const pidRaw = await
|
|
38691
|
+
const pidRaw = await readFile66(pidfile, "utf-8").catch(() => null);
|
|
38351
38692
|
if (pidRaw === null) {
|
|
38352
38693
|
throw new Error(
|
|
38353
38694
|
`No active recording found (no pidfile at ${pidfile}). Did you run --start?`
|
|
@@ -38357,7 +38698,7 @@ async function stopRecording() {
|
|
|
38357
38698
|
if (!Number.isInteger(pid) || pid <= 0) {
|
|
38358
38699
|
throw new Error(`Pidfile at ${pidfile} is corrupt (got "${pidRaw}").`);
|
|
38359
38700
|
}
|
|
38360
|
-
const sidecarRaw = await
|
|
38701
|
+
const sidecarRaw = await readFile66(sidecar, "utf-8").catch(() => null);
|
|
38361
38702
|
if (sidecarRaw === null) {
|
|
38362
38703
|
throw new Error(
|
|
38363
38704
|
`No recording sidecar at ${sidecar}. The recording state is inconsistent \u2014 delete ${pidfile} and re-run --start.`
|
|
@@ -38422,7 +38763,7 @@ async function stopRecording() {
|
|
|
38422
38763
|
// src/db/proof-db.ts
|
|
38423
38764
|
init_paths();
|
|
38424
38765
|
import Database6 from "better-sqlite3";
|
|
38425
|
-
import { resolve as
|
|
38766
|
+
import { resolve as resolve93 } from "path";
|
|
38426
38767
|
var db5 = null;
|
|
38427
38768
|
var PROOF_SCHEMA_VERSION = "1";
|
|
38428
38769
|
var SCHEMA_SQL5 = `
|
|
@@ -38442,7 +38783,7 @@ CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT);
|
|
|
38442
38783
|
`;
|
|
38443
38784
|
function initProofDb(dbPath) {
|
|
38444
38785
|
if (db5) return db5;
|
|
38445
|
-
const finalPath = dbPath ??
|
|
38786
|
+
const finalPath = dbPath ?? resolve93(syntaurRoot(), "syntaur.db");
|
|
38446
38787
|
db5 = new Database6(finalPath);
|
|
38447
38788
|
db5.pragma("journal_mode = WAL");
|
|
38448
38789
|
db5.exec(SCHEMA_SQL5);
|
|
@@ -38490,7 +38831,7 @@ function listArtifactsByAssignment(assignmentId) {
|
|
|
38490
38831
|
|
|
38491
38832
|
// src/utils/transcribers/elevenlabs.ts
|
|
38492
38833
|
import { spawn as spawn11 } from "child_process";
|
|
38493
|
-
import { mkdtemp as mkdtemp5, readFile as
|
|
38834
|
+
import { mkdtemp as mkdtemp5, readFile as readFile67, rm as rm13 } from "fs/promises";
|
|
38494
38835
|
import { tmpdir as tmpdir6 } from "os";
|
|
38495
38836
|
import { join as join25 } from "path";
|
|
38496
38837
|
var SCRIBE_URL = "https://api.elevenlabs.io/v1/speech-to-text";
|
|
@@ -38554,7 +38895,7 @@ async function extractAudio(videoAbsPath, wavOut) {
|
|
|
38554
38895
|
throw new TranscribeFfmpegError(`ffmpeg failed (exit ${result.code}): ${tail}`);
|
|
38555
38896
|
}
|
|
38556
38897
|
async function callScribe(wavPath, apiKey, opts) {
|
|
38557
|
-
const audio = await
|
|
38898
|
+
const audio = await readFile67(wavPath);
|
|
38558
38899
|
const form = new FormData();
|
|
38559
38900
|
form.set("file", new Blob([new Uint8Array(audio)], { type: "audio/wav" }), "audio.wav");
|
|
38560
38901
|
form.set("model_id", "scribe_v1");
|
|
@@ -38870,7 +39211,7 @@ async function captureCommand(target, options = {}) {
|
|
|
38870
39211
|
});
|
|
38871
39212
|
}
|
|
38872
39213
|
if (options.file) {
|
|
38873
|
-
const expanded = options.file.startsWith("~/") ?
|
|
39214
|
+
const expanded = options.file.startsWith("~/") ? resolve94(process.env.HOME ?? "", options.file.slice(2)) : resolve94(options.file);
|
|
38874
39215
|
if (!await fileExists(expanded)) {
|
|
38875
39216
|
throw new Error(`--file does not exist: ${options.file}`);
|
|
38876
39217
|
}
|
|
@@ -38911,7 +39252,7 @@ async function captureCommand(target, options = {}) {
|
|
|
38911
39252
|
}
|
|
38912
39253
|
initProofDb();
|
|
38913
39254
|
const subdir = criterionIndex === null ? "untagged" : String(criterionIndex);
|
|
38914
|
-
const destDir =
|
|
39255
|
+
const destDir = resolve94(proofDir(resolved.assignmentDir), subdir);
|
|
38915
39256
|
if (resolvedSource) await mkdir12(destDir, { recursive: true });
|
|
38916
39257
|
const ext = resolvedSource ? extensionForKind(kind) : null;
|
|
38917
39258
|
let id = null;
|
|
@@ -38920,7 +39261,7 @@ async function captureCommand(target, options = {}) {
|
|
|
38920
39261
|
let lastErr = null;
|
|
38921
39262
|
for (let attempt = 0; attempt < MAX_ID_RETRIES; attempt += 1) {
|
|
38922
39263
|
const candidate = generateArtifactId();
|
|
38923
|
-
const candidateAbsPath = resolvedSource && ext ?
|
|
39264
|
+
const candidateAbsPath = resolvedSource && ext ? resolve94(destDir, `${candidate}.${ext}`) : null;
|
|
38924
39265
|
const candidateRel = candidateAbsPath ? relative4(resolved.assignmentDir, candidateAbsPath) : null;
|
|
38925
39266
|
try {
|
|
38926
39267
|
insertArtifact({
|
|
@@ -38964,7 +39305,7 @@ async function captureCommand(target, options = {}) {
|
|
|
38964
39305
|
}
|
|
38965
39306
|
}
|
|
38966
39307
|
if (options.transcribe && kind === "video" && absPath && id) {
|
|
38967
|
-
const sidecarPath2 =
|
|
39308
|
+
const sidecarPath2 = resolve94(destDir, `${id}.transcript.md`);
|
|
38968
39309
|
if (existsSync7(sidecarPath2)) {
|
|
38969
39310
|
console.warn(
|
|
38970
39311
|
`transcript: ${sidecarPath2} already exists, skipping (delete to re-transcribe)`
|
|
@@ -38996,7 +39337,7 @@ async function captureCommand(target, options = {}) {
|
|
|
38996
39337
|
const tagSuffix = criterionIndex === null ? "untagged" : `criterion ${criterionIndex}`;
|
|
38997
39338
|
console.log(`Captured artifact ${id} (${kind}) for ${ref} \u2014 ${tagSuffix}.`);
|
|
38998
39339
|
if (relativeFilePath) {
|
|
38999
|
-
console.log(` file: ${
|
|
39340
|
+
console.log(` file: ${resolve94(resolved.assignmentDir, relativeFilePath)}`);
|
|
39000
39341
|
}
|
|
39001
39342
|
} catch (err2) {
|
|
39002
39343
|
if (options.stop && kind === "video" && shelloutCleanup && resolvedSource) {
|
|
@@ -39019,8 +39360,8 @@ async function captureCommand(target, options = {}) {
|
|
|
39019
39360
|
|
|
39020
39361
|
// src/commands/proof.ts
|
|
39021
39362
|
import { Command as Command6 } from "commander";
|
|
39022
|
-
import { readFile as
|
|
39023
|
-
import { resolve as
|
|
39363
|
+
import { readFile as readFile68, writeFile as writeFile16, rename as rename10, stat as stat14 } from "fs/promises";
|
|
39364
|
+
import { resolve as resolve95, relative as relative5, isAbsolute as isAbsolute12, dirname as dirname27 } from "path";
|
|
39024
39365
|
import { randomBytes as randomBytes4 } from "crypto";
|
|
39025
39366
|
|
|
39026
39367
|
// src/utils/acceptance-criteria-parse.ts
|
|
@@ -39260,11 +39601,11 @@ function renderProofHtml(params2, inlineFiles = /* @__PURE__ */ new Map(), trans
|
|
|
39260
39601
|
|
|
39261
39602
|
// src/commands/proof.ts
|
|
39262
39603
|
async function readAssignmentMeta(assignmentDir) {
|
|
39263
|
-
const path =
|
|
39604
|
+
const path = resolve95(assignmentDir, "assignment.md");
|
|
39264
39605
|
if (!await fileExists(path)) {
|
|
39265
39606
|
return { title: "", body: "" };
|
|
39266
39607
|
}
|
|
39267
|
-
const content = await
|
|
39608
|
+
const content = await readFile68(path, "utf-8");
|
|
39268
39609
|
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
39269
39610
|
let title = "";
|
|
39270
39611
|
if (fmMatch) {
|
|
@@ -39311,7 +39652,7 @@ async function loadInlineFiles(rows, assignmentDir) {
|
|
|
39311
39652
|
for (const r of rows) {
|
|
39312
39653
|
if (!r.file_path) continue;
|
|
39313
39654
|
if (r.kind !== "http" && r.kind !== "text") continue;
|
|
39314
|
-
const abs =
|
|
39655
|
+
const abs = resolve95(assignmentDir, r.file_path);
|
|
39315
39656
|
if (!isWithin(proofRoot, abs)) {
|
|
39316
39657
|
out.set(r.file_path, null);
|
|
39317
39658
|
continue;
|
|
@@ -39326,7 +39667,7 @@ async function loadInlineFiles(rows, assignmentDir) {
|
|
|
39326
39667
|
continue;
|
|
39327
39668
|
}
|
|
39328
39669
|
try {
|
|
39329
|
-
out.set(r.file_path, await
|
|
39670
|
+
out.set(r.file_path, await readFile68(abs, "utf-8"));
|
|
39330
39671
|
} catch {
|
|
39331
39672
|
out.set(r.file_path, null);
|
|
39332
39673
|
}
|
|
@@ -39338,14 +39679,14 @@ async function loadTranscriptSidecars(rows, assignmentDir) {
|
|
|
39338
39679
|
const proofRoot = proofDir(assignmentDir);
|
|
39339
39680
|
for (const r of rows) {
|
|
39340
39681
|
if (r.kind !== "video" || !r.file_path) continue;
|
|
39341
|
-
const videoAbs =
|
|
39342
|
-
const sidecar =
|
|
39682
|
+
const videoAbs = resolve95(assignmentDir, r.file_path);
|
|
39683
|
+
const sidecar = resolve95(dirname27(videoAbs), `${r.id}.transcript.md`);
|
|
39343
39684
|
if (!isWithin(proofRoot, sidecar)) continue;
|
|
39344
39685
|
if (!await fileExists(sidecar)) continue;
|
|
39345
39686
|
const st = await stat14(sidecar);
|
|
39346
39687
|
if (st.size > INLINE_TEXT_LIMIT_BYTES) continue;
|
|
39347
39688
|
try {
|
|
39348
|
-
out.set(r.id, await
|
|
39689
|
+
out.set(r.id, await readFile68(sidecar, "utf-8"));
|
|
39349
39690
|
} catch {
|
|
39350
39691
|
}
|
|
39351
39692
|
}
|
|
@@ -39379,8 +39720,8 @@ async function proofBuildCommand(target, options = {}) {
|
|
|
39379
39720
|
};
|
|
39380
39721
|
const md = renderProofMarkdown(renderParams);
|
|
39381
39722
|
const html = renderProofHtml(renderParams, inlineFiles, transcriptSidecars);
|
|
39382
|
-
const mdPath =
|
|
39383
|
-
const htmlPath =
|
|
39723
|
+
const mdPath = resolve95(resolved.assignmentDir, "proof.md");
|
|
39724
|
+
const htmlPath = resolve95(resolved.assignmentDir, "proof.html");
|
|
39384
39725
|
await atomicWrite(mdPath, md);
|
|
39385
39726
|
await atomicWrite(htmlPath, html);
|
|
39386
39727
|
console.log(`Wrote ${htmlPath}`);
|
|
@@ -39910,7 +40251,7 @@ function isScheduledSessionLive(sessionId, launchPid) {
|
|
|
39910
40251
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
39911
40252
|
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync3, rmSync as rmSync2, realpathSync as realpathSync4, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
39912
40253
|
import { homedir as homedir16, userInfo } from "os";
|
|
39913
|
-
import { dirname as dirname28, join as join26, resolve as
|
|
40254
|
+
import { dirname as dirname28, join as join26, resolve as resolve96 } from "path";
|
|
39914
40255
|
var LAUNCH_AGENT_LABEL = "com.syntaur.schedule.tick";
|
|
39915
40256
|
var LaunchAgentRefusalError = class extends Error {
|
|
39916
40257
|
constructor(message) {
|
|
@@ -39964,7 +40305,7 @@ function absolutize(p) {
|
|
|
39964
40305
|
try {
|
|
39965
40306
|
return realpathSync4(p);
|
|
39966
40307
|
} catch {
|
|
39967
|
-
return
|
|
40308
|
+
return resolve96(p);
|
|
39968
40309
|
}
|
|
39969
40310
|
}
|
|
39970
40311
|
function defaultRun(command, args) {
|
|
@@ -40320,8 +40661,8 @@ init_slug();
|
|
|
40320
40661
|
init_timestamp();
|
|
40321
40662
|
init_assignment_resolver();
|
|
40322
40663
|
init_assignment_todos();
|
|
40323
|
-
import { resolve as
|
|
40324
|
-
import { readFile as
|
|
40664
|
+
import { resolve as resolve97 } from "path";
|
|
40665
|
+
import { readFile as readFile69 } from "fs/promises";
|
|
40325
40666
|
async function requestCommand(target, text, options = {}) {
|
|
40326
40667
|
if (!text || !text.trim()) {
|
|
40327
40668
|
throw new Error("Request text cannot be empty.");
|
|
@@ -40337,7 +40678,7 @@ async function requestCommand(target, text, options = {}) {
|
|
|
40337
40678
|
if (!isValidSlug(target)) {
|
|
40338
40679
|
throw new Error(`Invalid assignment slug "${target}".`);
|
|
40339
40680
|
}
|
|
40340
|
-
assignmentDir =
|
|
40681
|
+
assignmentDir = resolve97(baseDir, options.project, "assignments", target);
|
|
40341
40682
|
targetRef = target;
|
|
40342
40683
|
} else {
|
|
40343
40684
|
const resolved = await resolveAssignmentById(baseDir, assignmentsDir(), target);
|
|
@@ -40347,12 +40688,12 @@ async function requestCommand(target, text, options = {}) {
|
|
|
40347
40688
|
assignmentDir = resolved.assignmentDir;
|
|
40348
40689
|
targetRef = resolved.standalone ? resolved.id : resolved.assignmentSlug;
|
|
40349
40690
|
}
|
|
40350
|
-
const assignmentMdPath2 =
|
|
40691
|
+
const assignmentMdPath2 = resolve97(assignmentDir, "assignment.md");
|
|
40351
40692
|
if (!await fileExists(assignmentMdPath2)) {
|
|
40352
40693
|
throw new Error(`assignment.md not found at ${assignmentMdPath2}`);
|
|
40353
40694
|
}
|
|
40354
40695
|
const source = options.from ?? process.env.SYNTAUR_ASSIGNMENT ?? "unknown";
|
|
40355
|
-
let content = await
|
|
40696
|
+
let content = await readFile69(assignmentMdPath2, "utf-8");
|
|
40356
40697
|
content = appendTodosToAssignmentBody(content, [
|
|
40357
40698
|
{ description: `${text.trim()} (from: ${source})` }
|
|
40358
40699
|
]);
|
|
@@ -40366,13 +40707,13 @@ init_fs();
|
|
|
40366
40707
|
init_paths();
|
|
40367
40708
|
init_config2();
|
|
40368
40709
|
import { Command as Command10 } from "commander";
|
|
40369
|
-
import { readFile as
|
|
40370
|
-
import { resolve as
|
|
40710
|
+
import { readFile as readFile70, readdir as readdir34 } from "fs/promises";
|
|
40711
|
+
import { resolve as resolve98 } from "path";
|
|
40371
40712
|
async function readContextAssignmentDir(cwd) {
|
|
40372
|
-
const path =
|
|
40713
|
+
const path = resolve98(cwd, ".syntaur", "context.json");
|
|
40373
40714
|
if (!await fileExists(path)) return null;
|
|
40374
40715
|
try {
|
|
40375
|
-
const raw2 = await
|
|
40716
|
+
const raw2 = await readFile70(path, "utf-8");
|
|
40376
40717
|
const ctx = JSON.parse(raw2);
|
|
40377
40718
|
if (typeof ctx.assignmentDir === "string" && ctx.assignmentDir.length > 0) {
|
|
40378
40719
|
return ctx.assignmentDir;
|
|
@@ -40386,9 +40727,9 @@ async function resolveAssignmentDir(opts) {
|
|
|
40386
40727
|
const cwd = opts.cwd ?? process.cwd();
|
|
40387
40728
|
if (opts.assignment) {
|
|
40388
40729
|
if (opts.project) {
|
|
40389
|
-
return
|
|
40730
|
+
return resolve98((await readConfig()).defaultProjectDir, opts.project, "assignments", opts.assignment);
|
|
40390
40731
|
}
|
|
40391
|
-
return
|
|
40732
|
+
return resolve98(assignmentsDir(), opts.assignment);
|
|
40392
40733
|
}
|
|
40393
40734
|
const fromCtx = await readContextAssignmentDir(cwd);
|
|
40394
40735
|
if (fromCtx) return fromCtx;
|
|
@@ -40584,17 +40925,17 @@ async function runPlanCreate(options) {
|
|
|
40584
40925
|
if (!await fileExists(assignmentDir)) {
|
|
40585
40926
|
throw new Error(`Assignment directory does not exist: ${assignmentDir}`);
|
|
40586
40927
|
}
|
|
40587
|
-
const assignmentMdPath2 =
|
|
40928
|
+
const assignmentMdPath2 = resolve98(assignmentDir, "assignment.md");
|
|
40588
40929
|
if (!await fileExists(assignmentMdPath2)) {
|
|
40589
40930
|
throw new Error(`Missing assignment.md at: ${assignmentMdPath2}`);
|
|
40590
40931
|
}
|
|
40591
|
-
const planPath =
|
|
40932
|
+
const planPath = resolve98(assignmentDir, "plan.md");
|
|
40592
40933
|
if (await fileExists(planPath) && !options.force) {
|
|
40593
40934
|
throw new Error(
|
|
40594
40935
|
"plan.md already exists. Use --force to overwrite, or `syntaur plan version` to create the next version."
|
|
40595
40936
|
);
|
|
40596
40937
|
}
|
|
40597
|
-
const assignmentMd = await
|
|
40938
|
+
const assignmentMd = await readFile70(assignmentMdPath2, "utf-8");
|
|
40598
40939
|
const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
|
|
40599
40940
|
const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
|
|
40600
40941
|
await writeFileForce(planPath, buildInitialPlanStub(slug));
|
|
@@ -40614,7 +40955,7 @@ async function runPlanVersion(options) {
|
|
|
40614
40955
|
if (!await fileExists(assignmentDir)) {
|
|
40615
40956
|
throw new Error(`Assignment directory does not exist: ${assignmentDir}`);
|
|
40616
40957
|
}
|
|
40617
|
-
const assignmentMdPath2 =
|
|
40958
|
+
const assignmentMdPath2 = resolve98(assignmentDir, "assignment.md");
|
|
40618
40959
|
if (!await fileExists(assignmentMdPath2)) {
|
|
40619
40960
|
throw new Error(`Missing assignment.md at: ${assignmentMdPath2}`);
|
|
40620
40961
|
}
|
|
@@ -40626,15 +40967,15 @@ async function runPlanVersion(options) {
|
|
|
40626
40967
|
}
|
|
40627
40968
|
const current = planFiles[planFiles.length - 1];
|
|
40628
40969
|
const next = nextPlanFileName(current.version);
|
|
40629
|
-
const newPath =
|
|
40970
|
+
const newPath = resolve98(assignmentDir, next.fileName);
|
|
40630
40971
|
if (await fileExists(newPath) && !options.force) {
|
|
40631
40972
|
throw new Error(`${next.fileName} already exists. Use --force to overwrite.`);
|
|
40632
40973
|
}
|
|
40633
|
-
const assignmentMd = await
|
|
40974
|
+
const assignmentMd = await readFile70(assignmentMdPath2, "utf-8");
|
|
40634
40975
|
const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
|
|
40635
40976
|
const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
|
|
40636
|
-
const oldPlanPath =
|
|
40637
|
-
const oldPlanContent = await
|
|
40977
|
+
const oldPlanPath = resolve98(assignmentDir, current.fileName);
|
|
40978
|
+
const oldPlanContent = await readFile70(oldPlanPath, "utf-8");
|
|
40638
40979
|
const oldBody = oldPlanContent.replace(/^---[\s\S]*?\n---\n?/, "");
|
|
40639
40980
|
const carriedTodos = extractUncheckedTodos(oldBody);
|
|
40640
40981
|
const stub = buildNewPlanStub({
|
|
@@ -40704,26 +41045,26 @@ init_cwd();
|
|
|
40704
41045
|
init_session_db();
|
|
40705
41046
|
init_agent_sessions();
|
|
40706
41047
|
import { Command as Command11 } from "commander";
|
|
40707
|
-
import { readFile as
|
|
40708
|
-
import { resolve as
|
|
41048
|
+
import { readFile as readFile71, readdir as readdir35, stat as stat15 } from "fs/promises";
|
|
41049
|
+
import { resolve as resolve99 } from "path";
|
|
40709
41050
|
async function readContext(cwd) {
|
|
40710
|
-
const path =
|
|
41051
|
+
const path = resolve99(cwd, ".syntaur", "context.json");
|
|
40711
41052
|
if (!await fileExists(path)) return null;
|
|
40712
41053
|
try {
|
|
40713
|
-
const raw2 = await
|
|
41054
|
+
const raw2 = await readFile71(path, "utf-8");
|
|
40714
41055
|
return JSON.parse(raw2);
|
|
40715
41056
|
} catch {
|
|
40716
41057
|
return null;
|
|
40717
41058
|
}
|
|
40718
41059
|
}
|
|
40719
41060
|
async function findLatestSessionSummary(assignmentDir) {
|
|
40720
|
-
const sessionsRoot =
|
|
41061
|
+
const sessionsRoot = resolve99(assignmentDir, "sessions");
|
|
40721
41062
|
if (!await fileExists(sessionsRoot)) return null;
|
|
40722
41063
|
const entries = await readdir35(sessionsRoot, { withFileTypes: true });
|
|
40723
41064
|
let best = null;
|
|
40724
41065
|
for (const entry of entries) {
|
|
40725
41066
|
if (!entry.isDirectory()) continue;
|
|
40726
|
-
const summaryPath =
|
|
41067
|
+
const summaryPath = resolve99(sessionsRoot, entry.name, "summary.md");
|
|
40727
41068
|
if (!await fileExists(summaryPath)) continue;
|
|
40728
41069
|
const st = await stat15(summaryPath);
|
|
40729
41070
|
if (best === null || st.mtime.getTime() > best.mtime.getTime()) {
|
|
@@ -40733,9 +41074,9 @@ async function findLatestSessionSummary(assignmentDir) {
|
|
|
40733
41074
|
return best;
|
|
40734
41075
|
}
|
|
40735
41076
|
async function findOpenHandoff(assignmentDir) {
|
|
40736
|
-
const handoffPath =
|
|
41077
|
+
const handoffPath = resolve99(assignmentDir, "handoff.md");
|
|
40737
41078
|
if (!await fileExists(handoffPath)) return null;
|
|
40738
|
-
const content = await
|
|
41079
|
+
const content = await readFile71(handoffPath, "utf-8");
|
|
40739
41080
|
const body = content.replace(/^---[\s\S]*?\n---\n?/, "").trim();
|
|
40740
41081
|
if (body.length === 0) return null;
|
|
40741
41082
|
if (/^<!--[\s\S]*-->$/.test(body)) return null;
|
|
@@ -40830,7 +41171,7 @@ async function resolveSaveTarget(options, cwd) {
|
|
|
40830
41171
|
let slug;
|
|
40831
41172
|
const ctx = await readContext(cwd);
|
|
40832
41173
|
if (options.assignment) {
|
|
40833
|
-
assignmentDir = options.project ?
|
|
41174
|
+
assignmentDir = options.project ? resolve99((await readConfig()).defaultProjectDir, options.project, "assignments", options.assignment) : resolve99(assignmentsDir(), options.assignment);
|
|
40834
41175
|
slug = options.assignment;
|
|
40835
41176
|
} else {
|
|
40836
41177
|
if (!ctx?.assignmentDir) {
|
|
@@ -40887,21 +41228,21 @@ function extractCreated(content) {
|
|
|
40887
41228
|
}
|
|
40888
41229
|
async function runSessionSave(options, cwd = process.cwd(), body) {
|
|
40889
41230
|
const { assignmentDir, slug, sessionId } = await resolveSaveTarget(options, cwd);
|
|
40890
|
-
if (!await fileExists(
|
|
41231
|
+
if (!await fileExists(resolve99(assignmentDir, "assignment.md"))) {
|
|
40891
41232
|
throw new Error(`No assignment found at ${assignmentDir} (missing assignment.md).`);
|
|
40892
41233
|
}
|
|
40893
|
-
const sessionDir =
|
|
40894
|
-
const summaryPath =
|
|
41234
|
+
const sessionDir = resolve99(assignmentDir, "sessions", sessionId);
|
|
41235
|
+
const summaryPath = resolve99(sessionDir, "summary.md");
|
|
40895
41236
|
const now = nowTimestamp();
|
|
40896
41237
|
let created = now;
|
|
40897
41238
|
if (await fileExists(summaryPath)) {
|
|
40898
|
-
const existing = await
|
|
41239
|
+
const existing = await readFile71(summaryPath, "utf-8");
|
|
40899
41240
|
created = extractCreated(existing) ?? now;
|
|
40900
41241
|
}
|
|
40901
41242
|
let sectionBody2 = body;
|
|
40902
41243
|
if (sectionBody2 === void 0) {
|
|
40903
41244
|
if (options.fromFile) {
|
|
40904
|
-
sectionBody2 = await
|
|
41245
|
+
sectionBody2 = await readFile71(resolve99(cwd, options.fromFile), "utf-8");
|
|
40905
41246
|
} else {
|
|
40906
41247
|
sectionBody2 = await readStdin();
|
|
40907
41248
|
}
|
|
@@ -40937,7 +41278,7 @@ async function runSessionRegister(rawStdin, options = {}, deps = {}) {
|
|
|
40937
41278
|
if (!isSafeSessionId(sessionId) || !cwd) return result;
|
|
40938
41279
|
result.sessionId = sessionId;
|
|
40939
41280
|
const transcriptPath = payload.transcript_path ?? "";
|
|
40940
|
-
const contextPath =
|
|
41281
|
+
const contextPath = resolve99(cwd, ".syntaur", "context.json");
|
|
40941
41282
|
const hasContextFile = await fileExists(contextPath);
|
|
40942
41283
|
const ctx = hasContextFile ? await readContext(cwd) : null;
|
|
40943
41284
|
if (ctx) {
|
|
@@ -41083,8 +41424,8 @@ sessionCommand.command("resolve-id").description(
|
|
|
41083
41424
|
// src/commands/worktree.ts
|
|
41084
41425
|
init_git_worktree();
|
|
41085
41426
|
import { Command as Command12 } from "commander";
|
|
41086
|
-
import { readFile as
|
|
41087
|
-
import { resolve as
|
|
41427
|
+
import { readFile as readFile72 } from "fs/promises";
|
|
41428
|
+
import { resolve as resolve101 } from "path";
|
|
41088
41429
|
init_fs();
|
|
41089
41430
|
init_paths();
|
|
41090
41431
|
init_config2();
|
|
@@ -41093,12 +41434,12 @@ init_state_machine();
|
|
|
41093
41434
|
|
|
41094
41435
|
// src/utils/path-canon.ts
|
|
41095
41436
|
import { realpathSync as realpathSync5 } from "fs";
|
|
41096
|
-
import { resolve as
|
|
41437
|
+
import { resolve as resolve100 } from "path";
|
|
41097
41438
|
function canonicalPath(p) {
|
|
41098
41439
|
try {
|
|
41099
|
-
return realpathSync5(
|
|
41440
|
+
return realpathSync5(resolve100(p));
|
|
41100
41441
|
} catch {
|
|
41101
|
-
return
|
|
41442
|
+
return resolve100(p).replace(/\/+$/, "");
|
|
41102
41443
|
}
|
|
41103
41444
|
}
|
|
41104
41445
|
|
|
@@ -41126,10 +41467,10 @@ function countSessionsByPath(dbPath, paths) {
|
|
|
41126
41467
|
init_timestamp();
|
|
41127
41468
|
init_frontmatter();
|
|
41128
41469
|
async function readContext2(cwd) {
|
|
41129
|
-
const path =
|
|
41470
|
+
const path = resolve101(cwd, ".syntaur", "context.json");
|
|
41130
41471
|
if (!await fileExists(path)) return null;
|
|
41131
41472
|
try {
|
|
41132
|
-
return JSON.parse(await
|
|
41473
|
+
return JSON.parse(await readFile72(path, "utf-8"));
|
|
41133
41474
|
} catch {
|
|
41134
41475
|
return null;
|
|
41135
41476
|
}
|
|
@@ -41138,12 +41479,12 @@ async function resolveAssignmentPath2(opts) {
|
|
|
41138
41479
|
if (opts.assignment) {
|
|
41139
41480
|
if (opts.project) {
|
|
41140
41481
|
const projectsDir2 = (await readConfig()).defaultProjectDir;
|
|
41141
|
-
return
|
|
41482
|
+
return resolve101(projectsDir2, opts.project, "assignments", opts.assignment, "assignment.md");
|
|
41142
41483
|
}
|
|
41143
|
-
return
|
|
41484
|
+
return resolve101(assignmentsDir(), opts.assignment, "assignment.md");
|
|
41144
41485
|
}
|
|
41145
41486
|
const ctx = await readContext2(opts.cwd);
|
|
41146
|
-
if (ctx?.assignmentDir) return
|
|
41487
|
+
if (ctx?.assignmentDir) return resolve101(ctx.assignmentDir, "assignment.md");
|
|
41147
41488
|
throw new Error(
|
|
41148
41489
|
"No active assignment. Pass --assignment <slug> [--project <slug>] or run from a workspace with .syntaur/context.json."
|
|
41149
41490
|
);
|
|
@@ -41154,7 +41495,7 @@ async function runWorktreeCreate(options, cwd = process.cwd()) {
|
|
|
41154
41495
|
}
|
|
41155
41496
|
const repository = options.repository ?? cwd;
|
|
41156
41497
|
const parentBranch = options.parentBranch ?? "main";
|
|
41157
|
-
const worktreePath = options.worktreePath ??
|
|
41498
|
+
const worktreePath = options.worktreePath ?? resolve101(repository, ".worktrees", options.branch);
|
|
41158
41499
|
const assignmentPath = await resolveAssignmentPath2({
|
|
41159
41500
|
assignment: options.assignment,
|
|
41160
41501
|
project: options.project,
|
|
@@ -41184,7 +41525,7 @@ async function runWorktreeRemove(options, cwd = process.cwd()) {
|
|
|
41184
41525
|
if (!await fileExists(assignmentPath)) {
|
|
41185
41526
|
throw new Error(`Assignment file not found: ${assignmentPath}`);
|
|
41186
41527
|
}
|
|
41187
|
-
const original = await
|
|
41528
|
+
const original = await readFile72(assignmentPath, "utf-8");
|
|
41188
41529
|
const fm = parseAssignmentFrontmatter(original);
|
|
41189
41530
|
const repository = options.repository ?? fm.workspace.repository ?? void 0;
|
|
41190
41531
|
const worktreePath = fm.workspace.worktreePath ?? void 0;
|
|
@@ -41250,7 +41591,7 @@ async function runWorktreeGc(options, cwd = process.cwd()) {
|
|
|
41250
41591
|
const owners = /* @__PURE__ */ new Map();
|
|
41251
41592
|
for (const entry of walk.withAssignmentMd) {
|
|
41252
41593
|
try {
|
|
41253
|
-
const content = await
|
|
41594
|
+
const content = await readFile72(resolve101(entry.assignmentDir, "assignment.md"), "utf-8");
|
|
41254
41595
|
const fm = parseAssignmentFrontmatter(content);
|
|
41255
41596
|
const wp = fm.workspace?.worktreePath;
|
|
41256
41597
|
if (!wp) continue;
|
|
@@ -41272,7 +41613,7 @@ async function runWorktreeGc(options, cwd = process.cwd()) {
|
|
|
41272
41613
|
const repoTop = rt ? canonicalPath(rt) : null;
|
|
41273
41614
|
const cwdTop = ct ? canonicalPath(ct) : null;
|
|
41274
41615
|
const mainPath = entries.length > 0 ? canonicalPath(entries[0].worktreePath) : null;
|
|
41275
|
-
const dbPath =
|
|
41616
|
+
const dbPath = resolve101(syntaurRoot(), "syntaur.db");
|
|
41276
41617
|
const candidates = [];
|
|
41277
41618
|
for (const entry of entries) {
|
|
41278
41619
|
const canon = canonicalPath(entry.worktreePath);
|
|
@@ -41491,8 +41832,8 @@ worktreeCommand.command("gc").description(
|
|
|
41491
41832
|
// src/commands/open.ts
|
|
41492
41833
|
init_fs();
|
|
41493
41834
|
import { Command as Command13 } from "commander";
|
|
41494
|
-
import { readFile as
|
|
41495
|
-
import { resolve as
|
|
41835
|
+
import { readFile as readFile73 } from "fs/promises";
|
|
41836
|
+
import { resolve as resolve102 } from "path";
|
|
41496
41837
|
init_frontmatter();
|
|
41497
41838
|
init_config2();
|
|
41498
41839
|
init_paths();
|
|
@@ -41546,13 +41887,13 @@ function openInTerminal(path, config) {
|
|
|
41546
41887
|
// src/commands/open.ts
|
|
41547
41888
|
async function runOpen(assignmentArg, options) {
|
|
41548
41889
|
const resolved = options.id ? await resolveAssignmentTarget(options.id, {}) : await resolveAssignmentTarget(assignmentArg, { project: options.project });
|
|
41549
|
-
const assignmentPath =
|
|
41890
|
+
const assignmentPath = resolve102(resolved.assignmentDir, "assignment.md");
|
|
41550
41891
|
if (!await fileExists(assignmentPath)) {
|
|
41551
41892
|
throw new SyntaurError(`Assignment file not found: ${assignmentPath}`, {
|
|
41552
41893
|
remediation: "check the assignment slug or --id"
|
|
41553
41894
|
});
|
|
41554
41895
|
}
|
|
41555
|
-
const fm = parseAssignmentFrontmatter(await
|
|
41896
|
+
const fm = parseAssignmentFrontmatter(await readFile73(assignmentPath, "utf-8"));
|
|
41556
41897
|
const worktreePath = fm.workspace?.worktreePath;
|
|
41557
41898
|
if (!worktreePath) {
|
|
41558
41899
|
throw new SyntaurError("No worktree recorded for this assignment.", {
|
|
@@ -41617,14 +41958,14 @@ init_config2();
|
|
|
41617
41958
|
init_fs();
|
|
41618
41959
|
init_slug();
|
|
41619
41960
|
import { Command as Command14 } from "commander";
|
|
41620
|
-
import { resolve as
|
|
41621
|
-
import { readFile as
|
|
41961
|
+
import { resolve as resolve104 } from "path";
|
|
41962
|
+
import { readFile as readFile75, readdir as readdir37, rm as rm15 } from "fs/promises";
|
|
41622
41963
|
|
|
41623
41964
|
// src/utils/project-indexes.ts
|
|
41624
41965
|
init_parser();
|
|
41625
41966
|
init_fs();
|
|
41626
|
-
import { readdir as readdir36, readFile as
|
|
41627
|
-
import { resolve as
|
|
41967
|
+
import { readdir as readdir36, readFile as readFile74 } from "fs/promises";
|
|
41968
|
+
import { resolve as resolve103 } from "path";
|
|
41628
41969
|
function nowIso3() {
|
|
41629
41970
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
41630
41971
|
}
|
|
@@ -41643,7 +41984,7 @@ function joinList(items) {
|
|
|
41643
41984
|
return items.length === 0 ? "\u2014" : items.map(escapeCell).join(", ");
|
|
41644
41985
|
}
|
|
41645
41986
|
async function rebuildResourcesIndex(projectDir) {
|
|
41646
|
-
const dir =
|
|
41987
|
+
const dir = resolve103(projectDir, "resources");
|
|
41647
41988
|
await ensureDir(dir);
|
|
41648
41989
|
const files = await listSlugFiles(dir);
|
|
41649
41990
|
const slug = readProjectSlug(projectDir);
|
|
@@ -41659,7 +42000,7 @@ async function rebuildResourcesIndex(projectDir) {
|
|
|
41659
42000
|
lines.push("| Name | Category | Source | Related Assignments | Updated |");
|
|
41660
42001
|
lines.push("|------|----------|--------|---------------------|---------|");
|
|
41661
42002
|
for (const fileName of files) {
|
|
41662
|
-
const content = await
|
|
42003
|
+
const content = await readFile74(resolve103(dir, fileName), "utf-8");
|
|
41663
42004
|
const parsed = parseResource(content);
|
|
41664
42005
|
const slugBase = fileName.replace(/\.md$/, "");
|
|
41665
42006
|
const name = parsed.name || slugBase;
|
|
@@ -41669,12 +42010,12 @@ async function rebuildResourcesIndex(projectDir) {
|
|
|
41669
42010
|
);
|
|
41670
42011
|
}
|
|
41671
42012
|
lines.push("");
|
|
41672
|
-
const indexPath =
|
|
42013
|
+
const indexPath = resolve103(dir, "_index.md");
|
|
41673
42014
|
await writeFileForce(indexPath, lines.join("\n"));
|
|
41674
42015
|
return { total: files.length, path: indexPath };
|
|
41675
42016
|
}
|
|
41676
42017
|
async function rebuildMemoriesIndex(projectDir) {
|
|
41677
|
-
const dir =
|
|
42018
|
+
const dir = resolve103(projectDir, "memories");
|
|
41678
42019
|
await ensureDir(dir);
|
|
41679
42020
|
const files = await listSlugFiles(dir);
|
|
41680
42021
|
const slug = readProjectSlug(projectDir);
|
|
@@ -41690,7 +42031,7 @@ async function rebuildMemoriesIndex(projectDir) {
|
|
|
41690
42031
|
lines.push("| Name | Source | Scope | Source Assignment | Updated |");
|
|
41691
42032
|
lines.push("|------|--------|-------|-------------------|---------|");
|
|
41692
42033
|
for (const fileName of files) {
|
|
41693
|
-
const content = await
|
|
42034
|
+
const content = await readFile74(resolve103(dir, fileName), "utf-8");
|
|
41694
42035
|
const parsed = parseMemory(content);
|
|
41695
42036
|
const slugBase = fileName.replace(/\.md$/, "");
|
|
41696
42037
|
const name = parsed.name || slugBase;
|
|
@@ -41700,7 +42041,7 @@ async function rebuildMemoriesIndex(projectDir) {
|
|
|
41700
42041
|
);
|
|
41701
42042
|
}
|
|
41702
42043
|
lines.push("");
|
|
41703
|
-
const indexPath =
|
|
42044
|
+
const indexPath = resolve103(dir, "_index.md");
|
|
41704
42045
|
await writeFileForce(indexPath, lines.join("\n"));
|
|
41705
42046
|
return { total: files.length, path: indexPath };
|
|
41706
42047
|
}
|
|
@@ -41764,8 +42105,8 @@ ${opts.body ?? "<!-- Add notes about this resource here. -->"}
|
|
|
41764
42105
|
}
|
|
41765
42106
|
async function resolveProjectDir(project) {
|
|
41766
42107
|
if (!isValidSlug(project)) throw new Error(`Invalid project slug: "${project}".`);
|
|
41767
|
-
const projectDir =
|
|
41768
|
-
if (!await fileExists(
|
|
42108
|
+
const projectDir = resolve104((await readConfig()).defaultProjectDir, project);
|
|
42109
|
+
if (!await fileExists(resolve104(projectDir, "project.md"))) {
|
|
41769
42110
|
throw new Error(`Project "${project}" not found at ${projectDir}.`);
|
|
41770
42111
|
}
|
|
41771
42112
|
return projectDir;
|
|
@@ -41778,7 +42119,7 @@ async function runResourceAdd(options) {
|
|
|
41778
42119
|
if (!isValidSlug(slug)) {
|
|
41779
42120
|
throw new Error(`Invalid resource slug: "${slug}".`);
|
|
41780
42121
|
}
|
|
41781
|
-
const filePath =
|
|
42122
|
+
const filePath = resolve104(projectDir, "resources", `${slug}.md`);
|
|
41782
42123
|
if (await fileExists(filePath) && !options.force) {
|
|
41783
42124
|
throw new Error(
|
|
41784
42125
|
`Resource "${slug}" already exists at ${filePath}. Use --force to overwrite.`
|
|
@@ -41795,7 +42136,7 @@ async function runResourceAdd(options) {
|
|
|
41795
42136
|
return { filePath, indexPath, total };
|
|
41796
42137
|
}
|
|
41797
42138
|
async function listResourceSlugs(projectDir) {
|
|
41798
|
-
const dir =
|
|
42139
|
+
const dir = resolve104(projectDir, "resources");
|
|
41799
42140
|
if (!await fileExists(dir)) return [];
|
|
41800
42141
|
const entries = await readdir37(dir, { withFileTypes: true });
|
|
41801
42142
|
return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_index.md").map((e) => e.name.slice(0, -3)).sort();
|
|
@@ -41805,16 +42146,16 @@ async function runResourceList(project) {
|
|
|
41805
42146
|
const slugs = await listResourceSlugs(projectDir);
|
|
41806
42147
|
const out = [];
|
|
41807
42148
|
for (const slug of slugs) {
|
|
41808
|
-
const parsed = parseResource(await
|
|
42149
|
+
const parsed = parseResource(await readFile75(resolve104(projectDir, "resources", `${slug}.md`), "utf-8"));
|
|
41809
42150
|
out.push({ slug, name: parsed.name, category: parsed.category, source: parsed.source, updated: parsed.updated });
|
|
41810
42151
|
}
|
|
41811
42152
|
return out;
|
|
41812
42153
|
}
|
|
41813
42154
|
async function runResourceShow(project, slug) {
|
|
41814
42155
|
const projectDir = await resolveProjectDir(project);
|
|
41815
|
-
const filePath =
|
|
42156
|
+
const filePath = resolve104(projectDir, "resources", `${slug}.md`);
|
|
41816
42157
|
if (!await fileExists(filePath)) throw new Error(`Resource "${slug}" not found in project "${project}".`);
|
|
41817
|
-
const parsed = parseResource(await
|
|
42158
|
+
const parsed = parseResource(await readFile75(filePath, "utf-8"));
|
|
41818
42159
|
return {
|
|
41819
42160
|
slug,
|
|
41820
42161
|
name: parsed.name,
|
|
@@ -41828,14 +42169,14 @@ async function runResourceShow(project, slug) {
|
|
|
41828
42169
|
}
|
|
41829
42170
|
async function runResourceUpdate(slug, options) {
|
|
41830
42171
|
const projectDir = await resolveProjectDir(options.project);
|
|
41831
|
-
const filePath =
|
|
42172
|
+
const filePath = resolve104(projectDir, "resources", `${slug}.md`);
|
|
41832
42173
|
if (!await fileExists(filePath)) {
|
|
41833
42174
|
throw new Error(`Resource "${slug}" not found in project "${options.project}".`);
|
|
41834
42175
|
}
|
|
41835
42176
|
if (options.name === void 0 && options.source === void 0 && options.category === void 0 && options.relatedAssignments === void 0) {
|
|
41836
42177
|
throw new Error("Provide at least one of --name, --source, --category, --related-assignments.");
|
|
41837
42178
|
}
|
|
41838
|
-
const original = await
|
|
42179
|
+
const original = await readFile75(filePath, "utf-8");
|
|
41839
42180
|
const content = editResourceFrontmatter(original, {
|
|
41840
42181
|
name: options.name,
|
|
41841
42182
|
category: options.category,
|
|
@@ -41848,7 +42189,7 @@ async function runResourceUpdate(slug, options) {
|
|
|
41848
42189
|
}
|
|
41849
42190
|
async function runResourceRemove(slug, options) {
|
|
41850
42191
|
const projectDir = await resolveProjectDir(options.project);
|
|
41851
|
-
const filePath =
|
|
42192
|
+
const filePath = resolve104(projectDir, "resources", `${slug}.md`);
|
|
41852
42193
|
if (!await fileExists(filePath)) {
|
|
41853
42194
|
throw new Error(`Resource "${slug}" not found in project "${options.project}".`);
|
|
41854
42195
|
}
|
|
@@ -41931,8 +42272,8 @@ init_config2();
|
|
|
41931
42272
|
init_fs();
|
|
41932
42273
|
init_slug();
|
|
41933
42274
|
import { Command as Command15 } from "commander";
|
|
41934
|
-
import { resolve as
|
|
41935
|
-
import { readFile as
|
|
42275
|
+
import { resolve as resolve105 } from "path";
|
|
42276
|
+
import { readFile as readFile76, readdir as readdir38, rm as rm16 } from "fs/promises";
|
|
41936
42277
|
init_parser();
|
|
41937
42278
|
function nowIso5() {
|
|
41938
42279
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
@@ -41996,8 +42337,8 @@ ${opts.body ?? "<!-- Capture the load-bearing context for this memory here. -->"
|
|
|
41996
42337
|
}
|
|
41997
42338
|
async function resolveProjectDir2(project) {
|
|
41998
42339
|
if (!isValidSlug(project)) throw new Error(`Invalid project slug: "${project}".`);
|
|
41999
|
-
const projectDir =
|
|
42000
|
-
if (!await fileExists(
|
|
42340
|
+
const projectDir = resolve105((await readConfig()).defaultProjectDir, project);
|
|
42341
|
+
if (!await fileExists(resolve105(projectDir, "project.md"))) {
|
|
42001
42342
|
throw new Error(`Project "${project}" not found at ${projectDir}.`);
|
|
42002
42343
|
}
|
|
42003
42344
|
return projectDir;
|
|
@@ -42010,7 +42351,7 @@ async function runMemoryAdd(options) {
|
|
|
42010
42351
|
if (!isValidSlug(slug)) {
|
|
42011
42352
|
throw new Error(`Invalid memory slug: "${slug}".`);
|
|
42012
42353
|
}
|
|
42013
|
-
const filePath =
|
|
42354
|
+
const filePath = resolve105(projectDir, "memories", `${slug}.md`);
|
|
42014
42355
|
if (await fileExists(filePath) && !options.force) {
|
|
42015
42356
|
throw new Error(
|
|
42016
42357
|
`Memory "${slug}" already exists at ${filePath}. Use --force to overwrite.`
|
|
@@ -42028,7 +42369,7 @@ async function runMemoryAdd(options) {
|
|
|
42028
42369
|
return { filePath, indexPath, total };
|
|
42029
42370
|
}
|
|
42030
42371
|
async function listMemorySlugs(projectDir) {
|
|
42031
|
-
const dir =
|
|
42372
|
+
const dir = resolve105(projectDir, "memories");
|
|
42032
42373
|
if (!await fileExists(dir)) return [];
|
|
42033
42374
|
const entries = await readdir38(dir, { withFileTypes: true });
|
|
42034
42375
|
return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_index.md").map((e) => e.name.slice(0, -3)).sort();
|
|
@@ -42038,16 +42379,16 @@ async function runMemoryList(project) {
|
|
|
42038
42379
|
const slugs = await listMemorySlugs(projectDir);
|
|
42039
42380
|
const out = [];
|
|
42040
42381
|
for (const slug of slugs) {
|
|
42041
|
-
const parsed = parseMemory(await
|
|
42382
|
+
const parsed = parseMemory(await readFile76(resolve105(projectDir, "memories", `${slug}.md`), "utf-8"));
|
|
42042
42383
|
out.push({ slug, name: parsed.name, scope: parsed.scope, source: parsed.source, updated: parsed.updated });
|
|
42043
42384
|
}
|
|
42044
42385
|
return out;
|
|
42045
42386
|
}
|
|
42046
42387
|
async function runMemoryShow(project, slug) {
|
|
42047
42388
|
const projectDir = await resolveProjectDir2(project);
|
|
42048
|
-
const filePath =
|
|
42389
|
+
const filePath = resolve105(projectDir, "memories", `${slug}.md`);
|
|
42049
42390
|
if (!await fileExists(filePath)) throw new Error(`Memory "${slug}" not found in project "${project}".`);
|
|
42050
|
-
const parsed = parseMemory(await
|
|
42391
|
+
const parsed = parseMemory(await readFile76(filePath, "utf-8"));
|
|
42051
42392
|
return {
|
|
42052
42393
|
slug,
|
|
42053
42394
|
name: parsed.name,
|
|
@@ -42062,7 +42403,7 @@ async function runMemoryShow(project, slug) {
|
|
|
42062
42403
|
}
|
|
42063
42404
|
async function runMemoryUpdate(slug, options) {
|
|
42064
42405
|
const projectDir = await resolveProjectDir2(options.project);
|
|
42065
|
-
const filePath =
|
|
42406
|
+
const filePath = resolve105(projectDir, "memories", `${slug}.md`);
|
|
42066
42407
|
if (!await fileExists(filePath)) {
|
|
42067
42408
|
throw new Error(`Memory "${slug}" not found in project "${options.project}".`);
|
|
42068
42409
|
}
|
|
@@ -42071,7 +42412,7 @@ async function runMemoryUpdate(slug, options) {
|
|
|
42071
42412
|
"Provide at least one of --name, --source, --scope, --source-assignment, --related-assignments."
|
|
42072
42413
|
);
|
|
42073
42414
|
}
|
|
42074
|
-
const original = await
|
|
42415
|
+
const original = await readFile76(filePath, "utf-8");
|
|
42075
42416
|
const content = editMemoryFrontmatter(original, {
|
|
42076
42417
|
name: options.name,
|
|
42077
42418
|
source: options.source,
|
|
@@ -42085,7 +42426,7 @@ async function runMemoryUpdate(slug, options) {
|
|
|
42085
42426
|
}
|
|
42086
42427
|
async function runMemoryRemove(slug, options) {
|
|
42087
42428
|
const projectDir = await resolveProjectDir2(options.project);
|
|
42088
|
-
const filePath =
|
|
42429
|
+
const filePath = resolve105(projectDir, "memories", `${slug}.md`);
|
|
42089
42430
|
if (!await fileExists(filePath)) {
|
|
42090
42431
|
throw new Error(`Memory "${slug}" not found in project "${options.project}".`);
|
|
42091
42432
|
}
|
|
@@ -42174,8 +42515,8 @@ init_derive();
|
|
|
42174
42515
|
init_recompute();
|
|
42175
42516
|
init_query();
|
|
42176
42517
|
import { Command as Command16 } from "commander";
|
|
42177
|
-
import { readFile as
|
|
42178
|
-
import { dirname as dirname29, resolve as
|
|
42518
|
+
import { readFile as readFile77 } from "fs/promises";
|
|
42519
|
+
import { dirname as dirname29, resolve as resolve106 } from "path";
|
|
42179
42520
|
var AGE_PATTERN = /^(\d+)([dhwm])$/i;
|
|
42180
42521
|
function parseAgeToCutoff(age) {
|
|
42181
42522
|
const match = age.match(AGE_PATTERN);
|
|
@@ -42194,7 +42535,7 @@ function parseAgeToCutoff(age) {
|
|
|
42194
42535
|
}
|
|
42195
42536
|
function assignmentMdPath(item) {
|
|
42196
42537
|
if (item.projectSlug) {
|
|
42197
|
-
return
|
|
42538
|
+
return resolve106(
|
|
42198
42539
|
defaultProjectDir(),
|
|
42199
42540
|
item.projectSlug,
|
|
42200
42541
|
"assignments",
|
|
@@ -42202,13 +42543,13 @@ function assignmentMdPath(item) {
|
|
|
42202
42543
|
"assignment.md"
|
|
42203
42544
|
);
|
|
42204
42545
|
}
|
|
42205
|
-
return
|
|
42546
|
+
return resolve106(assignmentsDir(), item.id, "assignment.md");
|
|
42206
42547
|
}
|
|
42207
42548
|
async function loadTags(item) {
|
|
42208
42549
|
const path = assignmentMdPath(item);
|
|
42209
42550
|
if (!await fileExists(path)) return [];
|
|
42210
42551
|
try {
|
|
42211
|
-
const content = await
|
|
42552
|
+
const content = await readFile77(path, "utf-8");
|
|
42212
42553
|
return parseAssignmentFrontmatter(content).tags;
|
|
42213
42554
|
} catch {
|
|
42214
42555
|
return [];
|
|
@@ -42272,11 +42613,11 @@ async function loadQueryItem(item, terminalStatuses3, now, declarations) {
|
|
|
42272
42613
|
const path = assignmentMdPath(item);
|
|
42273
42614
|
if (!await fileExists(path)) return null;
|
|
42274
42615
|
try {
|
|
42275
|
-
const content = await
|
|
42616
|
+
const content = await readFile77(path, "utf-8");
|
|
42276
42617
|
const fm = parseAssignmentFrontmatter(content);
|
|
42277
42618
|
const body = content.replace(/^---\n[\s\S]*?\n---/, "");
|
|
42278
42619
|
const assignmentDir = dirname29(path);
|
|
42279
|
-
const projectDir = item.projectSlug ?
|
|
42620
|
+
const projectDir = item.projectSlug ? resolve106(defaultProjectDir(), item.projectSlug) : null;
|
|
42280
42621
|
const facts = await computeFacts({ assignmentDir, frontmatter: fm, body, projectDir, terminalStatuses: terminalStatuses3, declarations });
|
|
42281
42622
|
const history = fm.statusHistory;
|
|
42282
42623
|
const lastHeadlineChange = [...history].reverse().find((e) => e.from !== e.to || e.from === null);
|
|
@@ -42556,8 +42897,116 @@ var timelineCommand = new Command18("timeline").description(
|
|
|
42556
42897
|
}
|
|
42557
42898
|
});
|
|
42558
42899
|
|
|
42559
|
-
// src/commands/
|
|
42900
|
+
// src/commands/inbox.ts
|
|
42901
|
+
init_config2();
|
|
42902
|
+
init_paths();
|
|
42903
|
+
init_api();
|
|
42560
42904
|
import { Command as Command19 } from "commander";
|
|
42905
|
+
async function runInbox(options) {
|
|
42906
|
+
const config = await readConfig();
|
|
42907
|
+
const projectsDir2 = config.defaultProjectDir;
|
|
42908
|
+
const assignmentsDir2 = assignmentsDir();
|
|
42909
|
+
const limit = parseLimit3(options.limit);
|
|
42910
|
+
const types = parseTypes(options.type);
|
|
42911
|
+
const resolved = await getStatusConfig();
|
|
42912
|
+
const headline = (resolved.derive ?? DEFAULT_DERIVE_CONFIG).headline;
|
|
42913
|
+
const blockedParkedStatuses = new Set([headline.blocked, headline.parked].filter(Boolean));
|
|
42914
|
+
const statusConfig = { ...resolved, blockedParkedStatuses };
|
|
42915
|
+
return computeInbox({
|
|
42916
|
+
projectsDir: projectsDir2,
|
|
42917
|
+
assignmentsDir: assignmentsDir2,
|
|
42918
|
+
project: options.project,
|
|
42919
|
+
types,
|
|
42920
|
+
limit,
|
|
42921
|
+
statusConfig
|
|
42922
|
+
});
|
|
42923
|
+
}
|
|
42924
|
+
function parseLimit3(raw2) {
|
|
42925
|
+
if (raw2 === void 0) return void 0;
|
|
42926
|
+
const n = parseInt(raw2, 10);
|
|
42927
|
+
if (Number.isNaN(n) || n <= 0) {
|
|
42928
|
+
throw new Error(`Invalid --limit value: "${raw2}". Must be a positive integer.`);
|
|
42929
|
+
}
|
|
42930
|
+
return n;
|
|
42931
|
+
}
|
|
42932
|
+
function parseTypes(raw2) {
|
|
42933
|
+
if (raw2 === void 0) return void 0;
|
|
42934
|
+
const parts = raw2.split(",").map((s) => s.trim()).filter(Boolean);
|
|
42935
|
+
if (parts.length === 0) return void 0;
|
|
42936
|
+
const known = new Set(INBOX_CATEGORIES);
|
|
42937
|
+
const unknown = parts.filter((p) => !known.has(p));
|
|
42938
|
+
if (unknown.length > 0) {
|
|
42939
|
+
throw new Error(
|
|
42940
|
+
`Unknown --type categor${unknown.length > 1 ? "ies" : "y"}: ${unknown.map((u) => `"${u}"`).join(", ")}. Valid: ${INBOX_CATEGORIES.join(", ")}.`
|
|
42941
|
+
);
|
|
42942
|
+
}
|
|
42943
|
+
return parts;
|
|
42944
|
+
}
|
|
42945
|
+
var CATEGORY_LABEL = {
|
|
42946
|
+
review: "review",
|
|
42947
|
+
blocked: "blocked",
|
|
42948
|
+
question: "question",
|
|
42949
|
+
"plan-approval": "plan-approval"
|
|
42950
|
+
};
|
|
42951
|
+
function humanizeAge(ageMs) {
|
|
42952
|
+
const sec = Math.floor(ageMs / 1e3);
|
|
42953
|
+
if (sec < 60) return sec <= 0 ? "just now" : `${sec}s ago`;
|
|
42954
|
+
const min = Math.floor(sec / 60);
|
|
42955
|
+
if (min < 60) return `${min}m ago`;
|
|
42956
|
+
const hr = Math.floor(min / 60);
|
|
42957
|
+
if (hr < 24) return `${hr}h ago`;
|
|
42958
|
+
const day = Math.floor(hr / 24);
|
|
42959
|
+
if (day < 7) return `${day}d ago`;
|
|
42960
|
+
const wk = Math.floor(day / 7);
|
|
42961
|
+
return `${wk}w ago`;
|
|
42962
|
+
}
|
|
42963
|
+
function locator(item) {
|
|
42964
|
+
if (item.project === null) return item.assignmentId;
|
|
42965
|
+
return `${item.project}/${item.assignmentSlug}`;
|
|
42966
|
+
}
|
|
42967
|
+
function renderHeader(result) {
|
|
42968
|
+
if (result.total === 0) return "Nothing needs you.";
|
|
42969
|
+
const noun = result.total === 1 ? "item needs" : "items need";
|
|
42970
|
+
const counts = INBOX_CATEGORIES.filter((c2) => result.counts[c2] > 0).map((c2) => `${CATEGORY_LABEL[c2]} ${result.counts[c2]}`).join(" ");
|
|
42971
|
+
return `${result.total} ${noun} you \xB7 ${counts}`;
|
|
42972
|
+
}
|
|
42973
|
+
function renderHuman2(result) {
|
|
42974
|
+
const lines = [renderHeader(result)];
|
|
42975
|
+
if (result.total === 0) return lines.join("\n");
|
|
42976
|
+
for (const category of INBOX_CATEGORIES) {
|
|
42977
|
+
const items = result.items.filter((i) => i.category === category);
|
|
42978
|
+
if (items.length === 0) continue;
|
|
42979
|
+
lines.push("");
|
|
42980
|
+
lines.push(`${CATEGORY_LABEL[category]} (${result.counts[category]})`);
|
|
42981
|
+
for (const item of items) {
|
|
42982
|
+
lines.push(` ${item.title} [${locator(item)}] ${humanizeAge(item.ageMs)}`);
|
|
42983
|
+
if (item.summary) lines.push(` ${item.summary}`);
|
|
42984
|
+
lines.push(` \u2192 ${item.action.command}`);
|
|
42985
|
+
}
|
|
42986
|
+
}
|
|
42987
|
+
return lines.join("\n");
|
|
42988
|
+
}
|
|
42989
|
+
var inboxCommand = new Command19("inbox").description(
|
|
42990
|
+
"One triage view of everything awaiting a human: assignments in review, blocked, with an unanswered question, or with a plan awaiting approval. Read-only \u2014 prints the exact action command for each item; never mutates."
|
|
42991
|
+
).option("--project <slug>", "Restrict to one project").option(
|
|
42992
|
+
"--type <list>",
|
|
42993
|
+
`Comma-separated category filter (${INBOX_CATEGORIES.join(", ")})`
|
|
42994
|
+
).option("--limit <n>", "Maximum number of items to show").option("--json", "Emit the structured InboxResult JSON instead of the grouped view").action(async (options) => {
|
|
42995
|
+
try {
|
|
42996
|
+
const result = await runInbox(options);
|
|
42997
|
+
if (options.json) {
|
|
42998
|
+
console.log(JSON.stringify(result, null, 2));
|
|
42999
|
+
} else {
|
|
43000
|
+
console.log(renderHuman2(result));
|
|
43001
|
+
}
|
|
43002
|
+
} catch (error) {
|
|
43003
|
+
console.error("Error:", error instanceof Error ? error.message : String(error));
|
|
43004
|
+
process.exit(1);
|
|
43005
|
+
}
|
|
43006
|
+
});
|
|
43007
|
+
|
|
43008
|
+
// src/commands/views.ts
|
|
43009
|
+
import { Command as Command20 } from "commander";
|
|
42561
43010
|
|
|
42562
43011
|
// src/utils/saved-view-builder.ts
|
|
42563
43012
|
var KNOWN_FILTER_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -42883,7 +43332,7 @@ async function runViewsDelete(id) {
|
|
|
42883
43332
|
function addConfigFlags(cmd) {
|
|
42884
43333
|
return cmd.option("--workspace <ws>", "Scope the view to a workspace (default: global)").option("--global", "Make the view global (workspace = null)").option("--view-mode <mode>", `View mode (${VIEW_MODES.join("|")})`).option("--sort-field <field>", `Sort field (${SORT_FIELDS.join("|")})`).option("--sort-direction <dir>", `Sort direction (${SORT_DIRECTIONS.join("|")})`).option("--status <vals>", 'Status filter, comma-separated ("all"/"" clears)').option("--type <vals>", 'Type filter, comma-separated ("all"/"" clears)').option("--priority <vals>", 'Priority filter, comma-separated ("all"/"" clears)').option("--assignee <vals>", 'Assignee filter, comma-separated ("all"/"" clears)').option("--project-filter <vals>", 'Project filter, comma-separated ("all"/"" clears)').option("--tags <vals>", 'Tags filter, comma-separated ("all"/"" clears)').option("--activity <val>", `Activity filter (${ACTIVITIES.join("|")}; "all" clears)`).option("--date-range-field <field>", `Date range field (${DATE_RANGE_FIELDS.join("|")})`).option("--date-range-preset <preset>", `Date range preset (${DATE_RANGE_PRESETS.join("|")})`).option("--date-from <YYYY-MM-DD>", "Date range start (exclusive with --date-range-preset)").option("--date-to <YYYY-MM-DD>", "Date range end (exclusive with --date-range-preset)").option("--clear-date-range", "Remove the date-range filter").option("--search <text>", 'Search text filter ("" clears)').option("--query <expr>", 'AQL filter query ("" clears)').option("--collapsed <vals>", "List-view collapsed section ids, comma-separated").option("--kanban-hidden <vals>", "Kanban hidden column ids, comma-separated").option("--table-hidden <vals>", `Table hidden column ids (${TABLE_COLUMN_IDS.join("|")}), comma-separated`).option("--json", "Output the resulting view as JSON");
|
|
42885
43334
|
}
|
|
42886
|
-
var viewsCommand = new
|
|
43335
|
+
var viewsCommand = new Command20("views").description(
|
|
42887
43336
|
"Manage saved views (~/.syntaur/saved-views.json)"
|
|
42888
43337
|
);
|
|
42889
43338
|
addConfigFlags(
|
|
@@ -42937,9 +43386,9 @@ init_paths();
|
|
|
42937
43386
|
init_fs();
|
|
42938
43387
|
init_timestamp();
|
|
42939
43388
|
init_frontmatter();
|
|
42940
|
-
import { Command as
|
|
42941
|
-
import { readFile as
|
|
42942
|
-
import { resolve as
|
|
43389
|
+
import { Command as Command21 } from "commander";
|
|
43390
|
+
import { readFile as readFile78 } from "fs/promises";
|
|
43391
|
+
import { resolve as resolve107 } from "path";
|
|
42943
43392
|
function renameAssignmentStatusRefs(content, id, newId, now) {
|
|
42944
43393
|
const fm = parseAssignmentFrontmatter(content);
|
|
42945
43394
|
const updates = { updated: now };
|
|
@@ -42960,12 +43409,12 @@ function fail3(error) {
|
|
|
42960
43409
|
process.exit(1);
|
|
42961
43410
|
}
|
|
42962
43411
|
function configPath() {
|
|
42963
|
-
return
|
|
43412
|
+
return resolve107(syntaurRoot(), "config.md");
|
|
42964
43413
|
}
|
|
42965
43414
|
async function readStatusBlock() {
|
|
42966
43415
|
const p = configPath();
|
|
42967
43416
|
if (!await fileExists(p)) return null;
|
|
42968
|
-
const content = await
|
|
43417
|
+
const content = await readFile78(p, "utf-8");
|
|
42969
43418
|
return parseStatusConfig(content);
|
|
42970
43419
|
}
|
|
42971
43420
|
async function requireStatusBlock() {
|
|
@@ -43249,7 +43698,7 @@ async function runStatusRename(id, opts) {
|
|
|
43249
43698
|
printBlockDiff(before, after);
|
|
43250
43699
|
const now2 = nowTimestamp();
|
|
43251
43700
|
for (const a of affected) {
|
|
43252
|
-
const original = await
|
|
43701
|
+
const original = await readFile78(a.path, "utf-8");
|
|
43253
43702
|
const rewritten = renameAssignmentStatusRefs(original, id, newId, now2);
|
|
43254
43703
|
console.log(`
|
|
43255
43704
|
--- ${a.display}/assignment.md`);
|
|
@@ -43260,9 +43709,9 @@ async function runStatusRename(id, opts) {
|
|
|
43260
43709
|
}
|
|
43261
43710
|
const cfgPath = configPath();
|
|
43262
43711
|
const buffers = /* @__PURE__ */ new Map();
|
|
43263
|
-
buffers.set(cfgPath, await fileExists(cfgPath) ? await
|
|
43712
|
+
buffers.set(cfgPath, await fileExists(cfgPath) ? await readFile78(cfgPath, "utf-8") : "");
|
|
43264
43713
|
for (const a of affected) {
|
|
43265
|
-
buffers.set(a.path, await
|
|
43714
|
+
buffers.set(a.path, await readFile78(a.path, "utf-8"));
|
|
43266
43715
|
}
|
|
43267
43716
|
const now = nowTimestamp();
|
|
43268
43717
|
try {
|
|
@@ -43357,7 +43806,7 @@ function printList(result) {
|
|
|
43357
43806
|
}
|
|
43358
43807
|
}
|
|
43359
43808
|
}
|
|
43360
|
-
var statusCommand = new
|
|
43809
|
+
var statusCommand = new Command21("status").description(
|
|
43361
43810
|
"Manage assignment statuses + transitions (the statuses: block in ~/.syntaur/config.md)"
|
|
43362
43811
|
);
|
|
43363
43812
|
statusCommand.command("list").description("List the current statuses, order, and transitions").option("--json", "Output as JSON").action(async (opts) => {
|
|
@@ -43463,14 +43912,14 @@ init_paths();
|
|
|
43463
43912
|
init_config2();
|
|
43464
43913
|
init_timestamp();
|
|
43465
43914
|
init_frontmatter();
|
|
43466
|
-
import { Command as
|
|
43467
|
-
import { readFile as
|
|
43468
|
-
import { resolve as
|
|
43915
|
+
import { Command as Command22 } from "commander";
|
|
43916
|
+
import { readFile as readFile79 } from "fs/promises";
|
|
43917
|
+
import { resolve as resolve108 } from "path";
|
|
43469
43918
|
async function readContext3(cwd) {
|
|
43470
|
-
const path =
|
|
43919
|
+
const path = resolve108(cwd, ".syntaur", "context.json");
|
|
43471
43920
|
if (!await fileExists(path)) return null;
|
|
43472
43921
|
try {
|
|
43473
|
-
return JSON.parse(await
|
|
43922
|
+
return JSON.parse(await readFile79(path, "utf-8"));
|
|
43474
43923
|
} catch {
|
|
43475
43924
|
return null;
|
|
43476
43925
|
}
|
|
@@ -43479,12 +43928,12 @@ async function resolveAssignmentPath3(opts) {
|
|
|
43479
43928
|
if (opts.assignment) {
|
|
43480
43929
|
if (opts.project) {
|
|
43481
43930
|
const projectsDir2 = (await readConfig()).defaultProjectDir;
|
|
43482
|
-
return
|
|
43931
|
+
return resolve108(projectsDir2, opts.project, "assignments", opts.assignment, "assignment.md");
|
|
43483
43932
|
}
|
|
43484
|
-
return
|
|
43933
|
+
return resolve108(assignmentsDir(), opts.assignment, "assignment.md");
|
|
43485
43934
|
}
|
|
43486
43935
|
const ctx = await readContext3(opts.cwd);
|
|
43487
|
-
if (ctx?.assignmentDir) return
|
|
43936
|
+
if (ctx?.assignmentDir) return resolve108(ctx.assignmentDir, "assignment.md");
|
|
43488
43937
|
throw new Error(
|
|
43489
43938
|
"No active assignment. Pass --assignment <slug> [--project <slug>] or run from a workspace with .syntaur/context.json."
|
|
43490
43939
|
);
|
|
@@ -43521,7 +43970,7 @@ async function runWorkspaceSet(options, cwd = process.cwd()) {
|
|
|
43521
43970
|
${pre.errors.map((e) => ` - ${e}`).join("\n")}`
|
|
43522
43971
|
);
|
|
43523
43972
|
}
|
|
43524
|
-
const original = await
|
|
43973
|
+
const original = await readFile79(path, "utf-8");
|
|
43525
43974
|
let next = updateAssignmentWorkspace(original, partial);
|
|
43526
43975
|
next = updateAssignmentFile(next, { updated: nowTimestamp() });
|
|
43527
43976
|
await writeFileForce(path, next);
|
|
@@ -43535,7 +43984,7 @@ ${post.errors.map((e) => ` - ${e}`).join("\n")}`
|
|
|
43535
43984
|
}
|
|
43536
43985
|
return { path, fields };
|
|
43537
43986
|
}
|
|
43538
|
-
var workspaceCommand = new
|
|
43987
|
+
var workspaceCommand = new Command22("workspace").description(
|
|
43539
43988
|
"Manage the active assignment workspace binding"
|
|
43540
43989
|
);
|
|
43541
43990
|
workspaceCommand.command("set").description("Set the four workspace.* frontmatter fields atomically (validates + bumps updated)").option("--repository <path>", "Repository root").option("--worktree-path <path>", "Worktree path (typically <repo>/.worktrees/<branch>)").option("--branch <name>", "Branch name").option("--parent-branch <name>", "Parent branch (typically main)").option("--assignment <slug>", "Assignment slug (UUID for standalone). Defaults to .syntaur/context.json").option("--project <slug>", "Project slug. Required with --assignment for a project-nested assignment").action(async (options) => {
|
|
@@ -43557,14 +44006,14 @@ init_paths();
|
|
|
43557
44006
|
init_config2();
|
|
43558
44007
|
init_timestamp();
|
|
43559
44008
|
init_templates();
|
|
43560
|
-
import { Command as
|
|
43561
|
-
import { readFile as
|
|
43562
|
-
import { resolve as
|
|
44009
|
+
import { Command as Command23 } from "commander";
|
|
44010
|
+
import { readFile as readFile80 } from "fs/promises";
|
|
44011
|
+
import { resolve as resolve109 } from "path";
|
|
43563
44012
|
async function readContext4(cwd) {
|
|
43564
|
-
const path =
|
|
44013
|
+
const path = resolve109(cwd, ".syntaur", "context.json");
|
|
43565
44014
|
if (!await fileExists(path)) return null;
|
|
43566
44015
|
try {
|
|
43567
|
-
return JSON.parse(await
|
|
44016
|
+
return JSON.parse(await readFile80(path, "utf-8"));
|
|
43568
44017
|
} catch {
|
|
43569
44018
|
return null;
|
|
43570
44019
|
}
|
|
@@ -43574,11 +44023,11 @@ async function resolveAssignmentDir2(opts) {
|
|
|
43574
44023
|
if (opts.project) {
|
|
43575
44024
|
const projectsDir2 = (await readConfig()).defaultProjectDir;
|
|
43576
44025
|
return {
|
|
43577
|
-
dir:
|
|
44026
|
+
dir: resolve109(projectsDir2, opts.project, "assignments", opts.assignment),
|
|
43578
44027
|
slug: opts.assignment
|
|
43579
44028
|
};
|
|
43580
44029
|
}
|
|
43581
|
-
return { dir:
|
|
44030
|
+
return { dir: resolve109(assignmentsDir(), opts.assignment), slug: opts.assignment };
|
|
43582
44031
|
}
|
|
43583
44032
|
const ctx = await readContext4(opts.cwd);
|
|
43584
44033
|
if (ctx?.assignmentDir) {
|
|
@@ -43640,17 +44089,17 @@ async function runProgressLog(text, options, cwd = process.cwd()) {
|
|
|
43640
44089
|
project: options.project,
|
|
43641
44090
|
cwd
|
|
43642
44091
|
});
|
|
43643
|
-
if (!await fileExists(
|
|
44092
|
+
if (!await fileExists(resolve109(dir, "assignment.md"))) {
|
|
43644
44093
|
throw new Error(`No assignment found at ${dir} (missing assignment.md).`);
|
|
43645
44094
|
}
|
|
43646
|
-
const path =
|
|
44095
|
+
const path = resolve109(dir, "progress.md");
|
|
43647
44096
|
const now = nowTimestamp();
|
|
43648
|
-
const content = await fileExists(path) ? await
|
|
44097
|
+
const content = await fileExists(path) ? await readFile80(path, "utf-8") : renderProgress({ assignment: slug, timestamp: now });
|
|
43649
44098
|
const next = appendProgressEntry(content, text, now);
|
|
43650
44099
|
await writeFileForce(path, next);
|
|
43651
44100
|
return path;
|
|
43652
44101
|
}
|
|
43653
|
-
var progressCommand = new
|
|
44102
|
+
var progressCommand = new Command23("progress").description(
|
|
43654
44103
|
"Record progress on the active assignment"
|
|
43655
44104
|
);
|
|
43656
44105
|
progressCommand.command("log").description("Append a timestamped entry to the assignment's progress.md").argument("<text>", "Progress entry text").option("--assignment <slug>", "Assignment slug (UUID for standalone). Defaults to .syntaur/context.json").option("--project <slug>", "Project slug. Required with --assignment for a project-nested assignment").action(async (text, options) => {
|
|
@@ -43720,7 +44169,7 @@ function spliceDashDashFromArgv(argv) {
|
|
|
43720
44169
|
}
|
|
43721
44170
|
}
|
|
43722
44171
|
var captureDashDashArgv = [];
|
|
43723
|
-
var program = new
|
|
44172
|
+
var program = new Command24();
|
|
43724
44173
|
var version = await readPackageVersion(import.meta.url) ?? "0.0.0";
|
|
43725
44174
|
program.name("syntaur").description("CLI scaffolding tool for the Syntaur protocol").version(version);
|
|
43726
44175
|
program.command("init").description("Initialize ~/.syntaur/ directory structure and config").option("--force", "Overwrite existing config file").action(
|
|
@@ -44055,6 +44504,7 @@ program.addCommand(memoryCommand);
|
|
|
44055
44504
|
program.addCommand(lsCommand);
|
|
44056
44505
|
program.addCommand(searchCommand);
|
|
44057
44506
|
program.addCommand(timelineCommand);
|
|
44507
|
+
program.addCommand(inboxCommand);
|
|
44058
44508
|
program.addCommand(viewsCommand);
|
|
44059
44509
|
program.addCommand(statusCommand);
|
|
44060
44510
|
program.addCommand(workspaceCommand);
|