syntaur 0.56.0 → 0.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/dashboard/dist/assets/_basePickBy-BSxL8bBc.js +1 -0
- package/dashboard/dist/assets/{_baseUniq-C6ARYdEJ.js → _baseUniq-1f9ohhNp.js} +1 -1
- package/dashboard/dist/assets/arc-DlPK9j9g.js +1 -0
- package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-eoW8_dbN.js → architectureDiagram-2XIMDMQ5-CcV5llaa.js} +3 -3
- package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ--XxaNbBK.js → blockDiagram-WCTKOSBZ-DGkYzINJ.js} +1 -1
- package/dashboard/dist/assets/{c4Diagram-IC4MRINW-D2B-NJq6.js → c4Diagram-IC4MRINW-CI4Z5c6N.js} +1 -1
- package/dashboard/dist/assets/channel-Qr2eMXkR.js +1 -0
- package/dashboard/dist/assets/{chunk-4BX2VUAB-CY34rkdT.js → chunk-4BX2VUAB-C8KasqJp.js} +1 -1
- package/dashboard/dist/assets/chunk-55IACEB6-CgAEilyk.js +1 -0
- package/dashboard/dist/assets/{chunk-FMBD7UC4-D00VtmIk.js → chunk-FMBD7UC4-DsNiby6p.js} +1 -1
- package/dashboard/dist/assets/chunk-JSJVCQXG-4eCDFRIx.js +1 -0
- package/dashboard/dist/assets/chunk-KX2RTZJC-DHia_zig.js +1 -0
- package/dashboard/dist/assets/{chunk-NQ4KR5QH-DnYhUmZY.js → chunk-NQ4KR5QH-V-IiQwer.js} +2 -2
- package/dashboard/dist/assets/{chunk-QZHKN3VN-CqCcFoFI.js → chunk-QZHKN3VN-BXTS8E6J.js} +1 -1
- package/dashboard/dist/assets/{chunk-WL4C6EOR-Bwx5h46l.js → chunk-WL4C6EOR-BuLlUWn0.js} +4 -4
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-DHkm1twH.js +1 -0
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-DHkm1twH.js +1 -0
- package/dashboard/dist/assets/clone-ChZeNkMI.js +1 -0
- package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-QUZroYuH.js → cose-bilkent-S5V4N54A-B1M1ENTo.js} +1 -1
- package/dashboard/dist/assets/{dagre-KLK3FWXG-D8hYiZ7i.js → dagre-KLK3FWXG-3pyNBzWY.js} +2 -2
- package/dashboard/dist/assets/diagram-E7M64L7V-B5-5pbKh.js +24 -0
- package/dashboard/dist/assets/diagram-IFDJBPK2-CTx5NFFi.js +43 -0
- package/dashboard/dist/assets/{diagram-P4PSJMXO-GcqkAPB2.js → diagram-P4PSJMXO-B5KRvZqb.js} +2 -2
- package/dashboard/dist/assets/{erDiagram-INFDFZHY-DQnXbhhn.js → erDiagram-INFDFZHY-BhVWsRrc.js} +3 -3
- package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-DSmXtiZK.js → flowDiagram-PKNHOUZH-CuoB0thO.js} +1 -1
- package/dashboard/dist/assets/ganttDiagram-A5KZAMGK-yNNalQY9.js +292 -0
- package/dashboard/dist/assets/gitGraphDiagram-K3NZZRJ6-DfEhHzOH.js +65 -0
- package/dashboard/dist/assets/{graph-Czw8ZNXY.js → graph-NaP7lLuY.js} +1 -1
- package/dashboard/dist/assets/index-BG_Ed2-k.js +644 -0
- package/dashboard/dist/assets/index-BeL-DOH-.css +1 -0
- package/dashboard/dist/assets/infoDiagram-LFFYTUFH-CDAMAxDE.js +2 -0
- package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-39XaFufR.js → ishikawaDiagram-PHBUUO56-DMRl5xeW.js} +5 -5
- package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-DCMzi84v.js → journeyDiagram-4ABVD52K-DtuQQjW_.js} +1 -1
- package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-RSNF4GmM.js → kanban-definition-K7BYSVSG-DYGt44vU.js} +7 -7
- package/dashboard/dist/assets/{layout-AOYFASCy.js → layout-B9sS0Gu9.js} +1 -1
- package/dashboard/dist/assets/linear-DQcNFWB2.js +1 -0
- package/dashboard/dist/assets/mermaid.core-CzhsZ1QZ.js +255 -0
- package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-Ck4L1K7y.js → mindmap-definition-YRQLILUH-CL8mKZYJ.js} +3 -3
- package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-BHEH_9Yh.js → pieDiagram-SKSYHLDU-BULUJrhI.js} +3 -3
- package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-DScQHhsU.js → quadrantDiagram-337W2JSQ-CWQC3mf-.js} +4 -4
- package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-DLmxwUdt.js → requirementDiagram-Z7DCOOCP-CYadvMn7.js} +3 -3
- package/dashboard/dist/assets/sankeyDiagram-WA2Y5GQK-e2AhGJiF.js +10 -0
- package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-woFPqQIY.js → sequenceDiagram-2WXFIKYE-CeWKKFdg.js} +3 -3
- package/dashboard/dist/assets/stateDiagram-RAJIS63D-BvN-wCps.js +1 -0
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-BV7kxiIj.js +1 -0
- package/dashboard/dist/assets/{timeline-definition-YZTLITO2-CGVOTXAD.js → timeline-definition-YZTLITO2-DOLRfgbL.js} +4 -4
- package/dashboard/dist/assets/{treemap-KZPCXAKY-CGmqtjaL.js → treemap-KZPCXAKY-VqhsqWzF.js} +1 -1
- package/dashboard/dist/assets/vennDiagram-LZ73GAT5-Dt-knC6b.js +34 -0
- package/dashboard/dist/assets/{xychartDiagram-JWTSCODW--uOFgr6-.js → xychartDiagram-JWTSCODW-A3enOtVP.js} +3 -3
- package/dashboard/dist/index.html +2 -2
- package/dist/dashboard/server.js +208 -131
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.js +584 -591
- package/dist/index.js.map +1 -1
- package/dist/launch/index.js.map +1 -1
- package/package.json +1 -1
- package/platforms/claude-code/.claude-plugin/plugin.json +1 -1
- package/platforms/codex/.codex-plugin/plugin.json +1 -1
- package/platforms/hermes/plugins/syntaur/__pycache__/__init__.cpython-312.pyc +0 -0
- package/platforms/hermes/plugins/syntaur/__pycache__/boundary.cpython-312.pyc +0 -0
- package/dashboard/dist/assets/_basePickBy-BboQhTYn.js +0 -1
- package/dashboard/dist/assets/arc-D76wUYJ-.js +0 -1
- package/dashboard/dist/assets/channel-BPykMjmL.js +0 -1
- package/dashboard/dist/assets/chunk-55IACEB6-CLXE1Ejn.js +0 -1
- package/dashboard/dist/assets/chunk-JSJVCQXG-_EITJTaI.js +0 -1
- package/dashboard/dist/assets/chunk-KX2RTZJC-DrqZI_kX.js +0 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-z8L393gl.js +0 -1
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-z8L393gl.js +0 -1
- package/dashboard/dist/assets/clone--rMJOGpf.js +0 -1
- package/dashboard/dist/assets/diagram-E7M64L7V-Cl_n980P.js +0 -24
- package/dashboard/dist/assets/diagram-IFDJBPK2-01DdmzmS.js +0 -43
- package/dashboard/dist/assets/ganttDiagram-A5KZAMGK-BLyt9LDp.js +0 -292
- package/dashboard/dist/assets/gitGraphDiagram-K3NZZRJ6-FWlr0I_j.js +0 -65
- package/dashboard/dist/assets/index-EntCfH3I.css +0 -1
- package/dashboard/dist/assets/index-zHNBGpC7.js +0 -602
- package/dashboard/dist/assets/infoDiagram-LFFYTUFH-CygGWMzd.js +0 -2
- package/dashboard/dist/assets/linear-Bf-cRRMe.js +0 -1
- package/dashboard/dist/assets/mermaid.core-7QJzPWTu.js +0 -255
- package/dashboard/dist/assets/sankeyDiagram-WA2Y5GQK-B6OZtKmg.js +0 -10
- package/dashboard/dist/assets/stateDiagram-RAJIS63D-Db9HV_HG.js +0 -1
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-DZsj07hg.js +0 -1
- package/dashboard/dist/assets/vennDiagram-LZ73GAT5-DAuyqqKn.js +0 -34
package/dist/index.js
CHANGED
|
@@ -1483,6 +1483,7 @@ __export(parser_exports, {
|
|
|
1483
1483
|
readLog: () => readLog,
|
|
1484
1484
|
serializeChecklist: () => serializeChecklist,
|
|
1485
1485
|
serializeChecklistItem: () => serializeChecklistItem,
|
|
1486
|
+
serializeLog: () => serializeLog,
|
|
1486
1487
|
serializeLogEntry: () => serializeLogEntry,
|
|
1487
1488
|
serializeMetaToken: () => serializeMetaToken,
|
|
1488
1489
|
writeChecklist: () => writeChecklist
|
|
@@ -1610,27 +1611,60 @@ function statusToMarker(item) {
|
|
|
1610
1611
|
return item.session ? `>:${sanitizeSession(item.session)}` : ">";
|
|
1611
1612
|
}
|
|
1612
1613
|
}
|
|
1614
|
+
function escapeDescription(description) {
|
|
1615
|
+
return description.replace(/\\/g, "\\\\").replace(/#/g, "\\#").replace(/\[/g, "\\[");
|
|
1616
|
+
}
|
|
1617
|
+
function unescapeDescription(escaped) {
|
|
1618
|
+
let out = "";
|
|
1619
|
+
for (let i = 0; i < escaped.length; i++) {
|
|
1620
|
+
if (escaped[i] === "\\" && i + 1 < escaped.length) {
|
|
1621
|
+
const next = escaped[i + 1];
|
|
1622
|
+
if (next === "\\" || next === "#" || next === "[") {
|
|
1623
|
+
out += next;
|
|
1624
|
+
i++;
|
|
1625
|
+
continue;
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
out += escaped[i];
|
|
1629
|
+
}
|
|
1630
|
+
return out;
|
|
1631
|
+
}
|
|
1632
|
+
function findStructuralCut(rest) {
|
|
1633
|
+
for (let i = 0; i < rest.length; i++) {
|
|
1634
|
+
const ch = rest[i];
|
|
1635
|
+
if (ch !== "#" && ch !== "[") continue;
|
|
1636
|
+
let backslashes = 0;
|
|
1637
|
+
let j = i - 1;
|
|
1638
|
+
while (j >= 0 && rest[j] === "\\") {
|
|
1639
|
+
backslashes++;
|
|
1640
|
+
j--;
|
|
1641
|
+
}
|
|
1642
|
+
if (backslashes % 2 === 1) continue;
|
|
1643
|
+
if (ch === "#") {
|
|
1644
|
+
if (/[a-zA-Z0-9_-]/.test(rest[i + 1] ?? "")) return i;
|
|
1645
|
+
} else {
|
|
1646
|
+
return i;
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
return rest.length;
|
|
1650
|
+
}
|
|
1613
1651
|
function parseChecklistItem(line) {
|
|
1614
1652
|
const match = line.match(ITEM_REGEX);
|
|
1615
1653
|
if (!match) return null;
|
|
1616
1654
|
const marker = match[1];
|
|
1617
1655
|
const rest = match[2];
|
|
1618
1656
|
const { status, session } = parseStatus2(marker);
|
|
1619
|
-
const
|
|
1657
|
+
const cut = findStructuralCut(rest);
|
|
1658
|
+
const description = unescapeDescription(rest.slice(0, cut).trim());
|
|
1659
|
+
const tail = rest.slice(cut);
|
|
1660
|
+
const idMatch = tail.match(ID_REGEX);
|
|
1620
1661
|
const id = idMatch ? idMatch[1] : "";
|
|
1621
1662
|
const tags = [];
|
|
1622
1663
|
let tagMatch;
|
|
1623
1664
|
const tagRegex = new RegExp(TAG_REGEX.source, "g");
|
|
1624
|
-
while ((tagMatch = tagRegex.exec(
|
|
1665
|
+
while ((tagMatch = tagRegex.exec(tail)) !== null) {
|
|
1625
1666
|
tags.push(tagMatch[1]);
|
|
1626
1667
|
}
|
|
1627
|
-
let description = rest;
|
|
1628
|
-
const firstTagIdx = rest.search(/#[a-zA-Z0-9_-]/);
|
|
1629
|
-
const firstIdIdx = rest.search(/\[t:[a-f0-9]{4}\]/);
|
|
1630
|
-
const cutPoints = [firstTagIdx, firstIdIdx].filter((i) => i >= 0);
|
|
1631
|
-
if (cutPoints.length > 0) {
|
|
1632
|
-
description = rest.slice(0, Math.min(...cutPoints)).trim();
|
|
1633
|
-
}
|
|
1634
1668
|
const meta = parseMetaToken(line);
|
|
1635
1669
|
return {
|
|
1636
1670
|
id,
|
|
@@ -1651,7 +1685,7 @@ function parseChecklistItem(line) {
|
|
|
1651
1685
|
function serializeChecklistItem(item) {
|
|
1652
1686
|
const marker = statusToMarker(item);
|
|
1653
1687
|
const tagStr = item.tags.map((t) => `#${t}`).join(" ");
|
|
1654
|
-
const parts = [`- [${marker}] ${item.description}`];
|
|
1688
|
+
const parts = [`- [${marker}] ${escapeDescription(item.description)}`];
|
|
1655
1689
|
if (tagStr) parts.push(tagStr);
|
|
1656
1690
|
parts.push(`[t:${item.id}]`);
|
|
1657
1691
|
const meta = serializeMetaToken(item);
|
|
@@ -1750,6 +1784,18 @@ function serializeLogEntry(entry) {
|
|
|
1750
1784
|
if (entry.status) lines.push(`**Status:** ${entry.status}`);
|
|
1751
1785
|
return lines.join("\n");
|
|
1752
1786
|
}
|
|
1787
|
+
function serializeLog(log) {
|
|
1788
|
+
const header = `---
|
|
1789
|
+
workspace: ${log.workspace}
|
|
1790
|
+
---
|
|
1791
|
+
|
|
1792
|
+
# Todo Log
|
|
1793
|
+
`;
|
|
1794
|
+
if (log.entries.length === 0) {
|
|
1795
|
+
return header;
|
|
1796
|
+
}
|
|
1797
|
+
return header + "\n" + log.entries.map(serializeLogEntry).join("\n\n") + "\n";
|
|
1798
|
+
}
|
|
1753
1799
|
function checklistPath(todosDir2, workspace) {
|
|
1754
1800
|
return resolve3(todosDir2, `${workspace}.md`);
|
|
1755
1801
|
}
|
|
@@ -8435,7 +8481,8 @@ __export(git_worktree_exports, {
|
|
|
8435
8481
|
listBranches: () => listBranches,
|
|
8436
8482
|
listWorktrees: () => listWorktrees,
|
|
8437
8483
|
recreateWorktree: () => recreateWorktree,
|
|
8438
|
-
removeWorktree: () => removeWorktree
|
|
8484
|
+
removeWorktree: () => removeWorktree,
|
|
8485
|
+
resolveBranchSha: () => resolveBranchSha
|
|
8439
8486
|
});
|
|
8440
8487
|
import { spawn } from "child_process";
|
|
8441
8488
|
import { readFile as readFile11 } from "fs/promises";
|
|
@@ -8550,6 +8597,18 @@ async function captureHeadSha(dir) {
|
|
|
8550
8597
|
const sha = result.stdout.trim();
|
|
8551
8598
|
return sha.length > 0 ? sha : null;
|
|
8552
8599
|
}
|
|
8600
|
+
async function resolveBranchSha(repository, branch) {
|
|
8601
|
+
const result = await run("git", [
|
|
8602
|
+
"-C",
|
|
8603
|
+
repository,
|
|
8604
|
+
"rev-parse",
|
|
8605
|
+
"--short",
|
|
8606
|
+
branch
|
|
8607
|
+
]);
|
|
8608
|
+
if (result.code !== 0) return null;
|
|
8609
|
+
const sha = result.stdout.trim();
|
|
8610
|
+
return sha.length > 0 ? sha : null;
|
|
8611
|
+
}
|
|
8553
8612
|
async function branchCheckedOutAt(repository, branch) {
|
|
8554
8613
|
const result = await run("git", ["-C", repository, "worktree", "list", "--porcelain"]);
|
|
8555
8614
|
if (result.code !== 0) return null;
|
|
@@ -12688,7 +12747,7 @@ async function scanSessions(opts = {}, deps = {}) {
|
|
|
12688
12747
|
const now = deps.now ?? (() => Date.now());
|
|
12689
12748
|
const statMtimeMs = deps.statMtimeMs ?? defaultStatMtimeMs2;
|
|
12690
12749
|
const openFiles = deps.openFiles ?? defaultOpenFiles;
|
|
12691
|
-
const
|
|
12750
|
+
const isPidAlive2 = deps.isPidAlive ?? defaultIsPidAlive;
|
|
12692
12751
|
const pidStartedAt = deps.pidStartedAt ?? defaultPidStartedAt;
|
|
12693
12752
|
const targets = (deps.targets ?? AGENT_TARGETS).filter((t) => t.sessions !== void 0);
|
|
12694
12753
|
const scanStartMs = now();
|
|
@@ -12767,7 +12826,7 @@ async function scanSessions(opts = {}, deps = {}) {
|
|
|
12767
12826
|
const sweepCandidates = [];
|
|
12768
12827
|
for (const row of activeRows) {
|
|
12769
12828
|
if (row.pid !== null) {
|
|
12770
|
-
const alive =
|
|
12829
|
+
const alive = isPidAlive2(row.pid) && (!row.pid_started_at || (pidStartedAt(row.pid) ?? row.pid_started_at) === row.pid_started_at);
|
|
12771
12830
|
if (alive) continue;
|
|
12772
12831
|
}
|
|
12773
12832
|
if (row.transcript_path) {
|
|
@@ -16465,7 +16524,7 @@ ${nextBody}${nextBody.endsWith("\n") ? "" : "\n"}`;
|
|
|
16465
16524
|
};
|
|
16466
16525
|
const entry = formatCommentEntry(comment);
|
|
16467
16526
|
let next = setTopLevelField(currentContent, "entryCount", String(currentCount + 1));
|
|
16468
|
-
next = setTopLevelField(next, "updated",
|
|
16527
|
+
next = setTopLevelField(next, "updated", timestamp);
|
|
16469
16528
|
if (next.includes("No comments yet.")) {
|
|
16470
16529
|
next = next.replace("No comments yet.", entry.trimEnd());
|
|
16471
16530
|
} else {
|
|
@@ -16525,7 +16584,7 @@ ${entry}`;
|
|
|
16525
16584
|
res.status(500).json({ error: "Failed to update resolved flag" });
|
|
16526
16585
|
return;
|
|
16527
16586
|
}
|
|
16528
|
-
const withUpdated = setTopLevelField(next, "updated",
|
|
16587
|
+
const withUpdated = setTopLevelField(next, "updated", nowTimestamp());
|
|
16529
16588
|
await writeFileForce(commentsPath, withUpdated);
|
|
16530
16589
|
const assignment = await getAssignmentDetail(projectsDir2, projectSlug, assignmentSlug);
|
|
16531
16590
|
res.json({ assignment });
|
|
@@ -17994,7 +18053,7 @@ async function appendCommentTo(assignmentDir, assignmentRef, req2, res, reloadDe
|
|
|
17994
18053
|
};
|
|
17995
18054
|
const entry = formatCommentEntry(comment);
|
|
17996
18055
|
let next = setTopLevelField(currentContent, "entryCount", String(currentCount + 1));
|
|
17997
|
-
next = setTopLevelField(next, "updated",
|
|
18056
|
+
next = setTopLevelField(next, "updated", timestamp);
|
|
17998
18057
|
if (next.includes("No comments yet.")) {
|
|
17999
18058
|
next = next.replace("No comments yet.", entry.trimEnd());
|
|
18000
18059
|
} else {
|
|
@@ -18037,7 +18096,7 @@ async function toggleCommentResolvedAt(assignmentDir, commentId, req2, res, relo
|
|
|
18037
18096
|
res.status(500).json({ error: "Failed to update resolved flag" });
|
|
18038
18097
|
return;
|
|
18039
18098
|
}
|
|
18040
|
-
const withUpdated = setTopLevelField(next, "updated",
|
|
18099
|
+
const withUpdated = setTopLevelField(next, "updated", nowTimestamp());
|
|
18041
18100
|
await writeFileForce(commentsPath, withUpdated);
|
|
18042
18101
|
const assignment = await reloadDetail();
|
|
18043
18102
|
res.json({ assignment });
|
|
@@ -21505,6 +21564,119 @@ async function readEvents(jobId) {
|
|
|
21505
21564
|
import { createHash as createHash3 } from "crypto";
|
|
21506
21565
|
import { open as open4, readFile as readFile22, stat as stat3, unlink as unlink6 } from "fs/promises";
|
|
21507
21566
|
import { resolve as resolve32 } from "path";
|
|
21567
|
+
|
|
21568
|
+
// src/schedules/triggers.ts
|
|
21569
|
+
import { Cron } from "croner";
|
|
21570
|
+
|
|
21571
|
+
// src/schedules/reset-window.ts
|
|
21572
|
+
var FIVE_HOURS_MS = 5 * 60 * 60 * 1e3;
|
|
21573
|
+
var ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
21574
|
+
function windowLengthMs(anchor) {
|
|
21575
|
+
return anchor.windowKind === "weekly" ? ONE_WEEK_MS : FIVE_HOURS_MS;
|
|
21576
|
+
}
|
|
21577
|
+
function predictReset(_provider, anchor) {
|
|
21578
|
+
const start = Date.parse(anchor.windowStartIso);
|
|
21579
|
+
if (Number.isNaN(start)) {
|
|
21580
|
+
throw new Error(`Invalid reset anchor windowStartIso: ${anchor.windowStartIso}`);
|
|
21581
|
+
}
|
|
21582
|
+
return new Date(start + windowLengthMs(anchor)).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
21583
|
+
}
|
|
21584
|
+
function verifyReset(provider, anchor, now) {
|
|
21585
|
+
const reset = predictReset(provider, anchor);
|
|
21586
|
+
if (now.getTime() >= Date.parse(reset)) return { eligible: true };
|
|
21587
|
+
return { eligible: false, rescheduleToIso: reset };
|
|
21588
|
+
}
|
|
21589
|
+
|
|
21590
|
+
// src/schedules/triggers.ts
|
|
21591
|
+
function iso(d) {
|
|
21592
|
+
return d.toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
21593
|
+
}
|
|
21594
|
+
function isRecurring(trigger) {
|
|
21595
|
+
return trigger.kind === "cron";
|
|
21596
|
+
}
|
|
21597
|
+
var notDue = { due: false };
|
|
21598
|
+
function evaluateTrigger(job, ctx) {
|
|
21599
|
+
const consumed = new Set(job.attempt.consumedEdges);
|
|
21600
|
+
const result = evaluateKind(job.trigger, job, ctx);
|
|
21601
|
+
if (result.due && result.dedupeKey && consumed.has(result.dedupeKey)) {
|
|
21602
|
+
return { ...result, due: false };
|
|
21603
|
+
}
|
|
21604
|
+
return result;
|
|
21605
|
+
}
|
|
21606
|
+
function evaluateKind(trigger, job, ctx) {
|
|
21607
|
+
const createdAtMs = Date.parse(job.createdAt);
|
|
21608
|
+
switch (trigger.kind) {
|
|
21609
|
+
case "at": {
|
|
21610
|
+
const at = Date.parse(trigger.at);
|
|
21611
|
+
const due = !Number.isNaN(at) && ctx.now.getTime() >= at;
|
|
21612
|
+
return { due, dedupeKey: `at:${trigger.at}`, nextFireIso: trigger.at };
|
|
21613
|
+
}
|
|
21614
|
+
case "in": {
|
|
21615
|
+
const anchor = Date.parse(trigger.anchorIso);
|
|
21616
|
+
const fireAt = anchor + trigger.durationMs;
|
|
21617
|
+
const due = !Number.isNaN(anchor) && ctx.now.getTime() >= fireAt;
|
|
21618
|
+
const fireIso = Number.isNaN(anchor) ? null : iso(new Date(fireAt));
|
|
21619
|
+
return { due, dedupeKey: `in:${fireAt}`, nextFireIso: fireIso };
|
|
21620
|
+
}
|
|
21621
|
+
case "cron":
|
|
21622
|
+
return evaluateCron(trigger, ctx.now, createdAtMs);
|
|
21623
|
+
case "after-reset":
|
|
21624
|
+
return evaluateAfterReset(trigger, ctx.now);
|
|
21625
|
+
case "when-status":
|
|
21626
|
+
return evaluateWhenStatus(trigger, job, ctx, createdAtMs);
|
|
21627
|
+
case "when-plan-lands":
|
|
21628
|
+
return evaluateWhenPlanLands(ctx, createdAtMs);
|
|
21629
|
+
}
|
|
21630
|
+
}
|
|
21631
|
+
function evaluateCron(trigger, now, createdAtMs) {
|
|
21632
|
+
let cron;
|
|
21633
|
+
try {
|
|
21634
|
+
cron = new Cron(trigger.expr, trigger.tz ? { timezone: trigger.tz } : {});
|
|
21635
|
+
} catch {
|
|
21636
|
+
return notDue;
|
|
21637
|
+
}
|
|
21638
|
+
const prevs = cron.previousRuns(1, new Date(now.getTime() + 1e3));
|
|
21639
|
+
let prev = prevs.length > 0 ? prevs[0] : null;
|
|
21640
|
+
if (prev && prev.getTime() > now.getTime()) prev = null;
|
|
21641
|
+
if (prev && !Number.isNaN(createdAtMs) && prev.getTime() < createdAtMs) prev = null;
|
|
21642
|
+
const next = cron.nextRun(now);
|
|
21643
|
+
if (!prev) return { due: false, nextFireIso: next ? iso(next) : null };
|
|
21644
|
+
return { due: true, dedupeKey: `cron:${iso(prev)}`, nextFireIso: next ? iso(next) : null };
|
|
21645
|
+
}
|
|
21646
|
+
function evaluateAfterReset(trigger, now) {
|
|
21647
|
+
const v = verifyReset(trigger.provider, trigger.anchor, now);
|
|
21648
|
+
const predicted = predictReset(trigger.provider, trigger.anchor);
|
|
21649
|
+
if (v.eligible) {
|
|
21650
|
+
return { due: true, dedupeKey: `after-reset:${trigger.anchor.windowStartIso}`, nextFireIso: predicted };
|
|
21651
|
+
}
|
|
21652
|
+
return { due: false, nextFireIso: predicted, rescheduleToIso: v.rescheduleToIso };
|
|
21653
|
+
}
|
|
21654
|
+
function evaluateWhenStatus(trigger, job, ctx, createdAtMs) {
|
|
21655
|
+
const fm = ctx.assignment;
|
|
21656
|
+
if (!fm) return notDue;
|
|
21657
|
+
const history = fm.statusHistory ?? [];
|
|
21658
|
+
for (let i = job.attempt.cursor; i < history.length; i++) {
|
|
21659
|
+
const atMs = Date.parse(history[i].at);
|
|
21660
|
+
const afterCreation = Number.isNaN(createdAtMs) || Number.isNaN(atMs) || atMs >= createdAtMs;
|
|
21661
|
+
if (history[i].to === trigger.status && afterCreation) {
|
|
21662
|
+
return { due: true, dedupeKey: `status:${i}:${history[i].at}`, nextCursor: i + 1 };
|
|
21663
|
+
}
|
|
21664
|
+
}
|
|
21665
|
+
return { due: false, nextCursor: history.length };
|
|
21666
|
+
}
|
|
21667
|
+
function evaluateWhenPlanLands(ctx, createdAtMs) {
|
|
21668
|
+
const fm = ctx.assignment;
|
|
21669
|
+
if (!fm) return notDue;
|
|
21670
|
+
const approval = fm.planApproval;
|
|
21671
|
+
if (!approval) return notDue;
|
|
21672
|
+
const approvedMs = Date.parse(approval.at);
|
|
21673
|
+
if (!Number.isNaN(createdAtMs) && !Number.isNaN(approvedMs) && approvedMs < createdAtMs) {
|
|
21674
|
+
return notDue;
|
|
21675
|
+
}
|
|
21676
|
+
return { due: true, dedupeKey: `plan:${approval.file}:${approval.digest}` };
|
|
21677
|
+
}
|
|
21678
|
+
|
|
21679
|
+
// src/schedules/attempt.ts
|
|
21508
21680
|
init_timestamp();
|
|
21509
21681
|
|
|
21510
21682
|
// src/schedules/types.ts
|
|
@@ -21703,6 +21875,15 @@ async function markLaunchFailed(job, reason) {
|
|
|
21703
21875
|
await appendEvent(job.id, "launch_failed", { reason });
|
|
21704
21876
|
return written;
|
|
21705
21877
|
}
|
|
21878
|
+
async function markCompleted(job) {
|
|
21879
|
+
const next = {
|
|
21880
|
+
...job,
|
|
21881
|
+
attempt: { ...job.attempt, state: "completed", claim: null }
|
|
21882
|
+
};
|
|
21883
|
+
const written = await writeJob(next);
|
|
21884
|
+
await appendEvent(job.id, "completed", { reason: "one-shot session ended" });
|
|
21885
|
+
return written;
|
|
21886
|
+
}
|
|
21706
21887
|
var TransitionError = class extends Error {
|
|
21707
21888
|
constructor(message) {
|
|
21708
21889
|
super(message);
|
|
@@ -21790,10 +21971,11 @@ function retryJob(id) {
|
|
|
21790
21971
|
() => ({ claim: null, lastError: null })
|
|
21791
21972
|
);
|
|
21792
21973
|
}
|
|
21974
|
+
var ONE_SHOT_COMPLETE_GRACE_MS = 6e4;
|
|
21793
21975
|
async function reapStale(jobs, deps) {
|
|
21794
21976
|
const now = deps.now();
|
|
21795
21977
|
const isLive = deps.isSessionLive ?? (() => true);
|
|
21796
|
-
const out = { reaped: [], stuck: [] };
|
|
21978
|
+
const out = { reaped: [], stuck: [], completed: [] };
|
|
21797
21979
|
for (const job of jobs) {
|
|
21798
21980
|
const a = job.attempt;
|
|
21799
21981
|
if ((a.state === "claimed" || a.state === "launching") && a.claim && now.getTime() > a.claim.expiresAt) {
|
|
@@ -21802,7 +21984,17 @@ async function reapStale(jobs, deps) {
|
|
|
21802
21984
|
out.reaped.push(job.id);
|
|
21803
21985
|
continue;
|
|
21804
21986
|
}
|
|
21805
|
-
if (a.state
|
|
21987
|
+
if (a.state !== "running") continue;
|
|
21988
|
+
if (!isRecurring(job.trigger) && a.sessionId && a.runningSince) {
|
|
21989
|
+
const graceMs = job.limits.maxRuntimeMs ?? ONE_SHOT_COMPLETE_GRACE_MS;
|
|
21990
|
+
const pastGrace = now.getTime() - Date.parse(a.runningSince) > graceMs;
|
|
21991
|
+
if (pastGrace && !isLive(a.sessionId, a.launchPid)) {
|
|
21992
|
+
await markCompleted(job);
|
|
21993
|
+
out.completed.push(job.id);
|
|
21994
|
+
continue;
|
|
21995
|
+
}
|
|
21996
|
+
}
|
|
21997
|
+
if (job.limits.maxRuntimeMs && a.runningSince) {
|
|
21806
21998
|
const overrun = now.getTime() - Date.parse(a.runningSince) > job.limits.maxRuntimeMs;
|
|
21807
21999
|
if (overrun && !isLive(a.sessionId, a.launchPid) && a.lastError !== "stuck:max-runtime") {
|
|
21808
22000
|
await writeJob({ ...job, attempt: { ...a, lastError: "stuck:max-runtime" } });
|
|
@@ -21986,117 +22178,6 @@ init_frontmatter();
|
|
|
21986
22178
|
import { readFile as readFile23 } from "fs/promises";
|
|
21987
22179
|
import { resolve as resolve34 } from "path";
|
|
21988
22180
|
|
|
21989
|
-
// src/schedules/triggers.ts
|
|
21990
|
-
import { Cron } from "croner";
|
|
21991
|
-
|
|
21992
|
-
// src/schedules/reset-window.ts
|
|
21993
|
-
var FIVE_HOURS_MS = 5 * 60 * 60 * 1e3;
|
|
21994
|
-
var ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
21995
|
-
function windowLengthMs(anchor) {
|
|
21996
|
-
return anchor.windowKind === "weekly" ? ONE_WEEK_MS : FIVE_HOURS_MS;
|
|
21997
|
-
}
|
|
21998
|
-
function predictReset(_provider, anchor) {
|
|
21999
|
-
const start = Date.parse(anchor.windowStartIso);
|
|
22000
|
-
if (Number.isNaN(start)) {
|
|
22001
|
-
throw new Error(`Invalid reset anchor windowStartIso: ${anchor.windowStartIso}`);
|
|
22002
|
-
}
|
|
22003
|
-
return new Date(start + windowLengthMs(anchor)).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
22004
|
-
}
|
|
22005
|
-
function verifyReset(provider, anchor, now) {
|
|
22006
|
-
const reset = predictReset(provider, anchor);
|
|
22007
|
-
if (now.getTime() >= Date.parse(reset)) return { eligible: true };
|
|
22008
|
-
return { eligible: false, rescheduleToIso: reset };
|
|
22009
|
-
}
|
|
22010
|
-
|
|
22011
|
-
// src/schedules/triggers.ts
|
|
22012
|
-
function iso(d) {
|
|
22013
|
-
return d.toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
22014
|
-
}
|
|
22015
|
-
function isRecurring(trigger) {
|
|
22016
|
-
return trigger.kind === "cron";
|
|
22017
|
-
}
|
|
22018
|
-
var notDue = { due: false };
|
|
22019
|
-
function evaluateTrigger(job, ctx) {
|
|
22020
|
-
const consumed = new Set(job.attempt.consumedEdges);
|
|
22021
|
-
const result = evaluateKind(job.trigger, job, ctx);
|
|
22022
|
-
if (result.due && result.dedupeKey && consumed.has(result.dedupeKey)) {
|
|
22023
|
-
return { ...result, due: false };
|
|
22024
|
-
}
|
|
22025
|
-
return result;
|
|
22026
|
-
}
|
|
22027
|
-
function evaluateKind(trigger, job, ctx) {
|
|
22028
|
-
const createdAtMs = Date.parse(job.createdAt);
|
|
22029
|
-
switch (trigger.kind) {
|
|
22030
|
-
case "at": {
|
|
22031
|
-
const at = Date.parse(trigger.at);
|
|
22032
|
-
const due = !Number.isNaN(at) && ctx.now.getTime() >= at;
|
|
22033
|
-
return { due, dedupeKey: `at:${trigger.at}`, nextFireIso: trigger.at };
|
|
22034
|
-
}
|
|
22035
|
-
case "in": {
|
|
22036
|
-
const anchor = Date.parse(trigger.anchorIso);
|
|
22037
|
-
const fireAt = anchor + trigger.durationMs;
|
|
22038
|
-
const due = !Number.isNaN(anchor) && ctx.now.getTime() >= fireAt;
|
|
22039
|
-
const fireIso = Number.isNaN(anchor) ? null : iso(new Date(fireAt));
|
|
22040
|
-
return { due, dedupeKey: `in:${fireAt}`, nextFireIso: fireIso };
|
|
22041
|
-
}
|
|
22042
|
-
case "cron":
|
|
22043
|
-
return evaluateCron(trigger, ctx.now, createdAtMs);
|
|
22044
|
-
case "after-reset":
|
|
22045
|
-
return evaluateAfterReset(trigger, ctx.now);
|
|
22046
|
-
case "when-status":
|
|
22047
|
-
return evaluateWhenStatus(trigger, job, ctx, createdAtMs);
|
|
22048
|
-
case "when-plan-lands":
|
|
22049
|
-
return evaluateWhenPlanLands(ctx, createdAtMs);
|
|
22050
|
-
}
|
|
22051
|
-
}
|
|
22052
|
-
function evaluateCron(trigger, now, createdAtMs) {
|
|
22053
|
-
let cron;
|
|
22054
|
-
try {
|
|
22055
|
-
cron = new Cron(trigger.expr, trigger.tz ? { timezone: trigger.tz } : {});
|
|
22056
|
-
} catch {
|
|
22057
|
-
return notDue;
|
|
22058
|
-
}
|
|
22059
|
-
const prevs = cron.previousRuns(1, new Date(now.getTime() + 1e3));
|
|
22060
|
-
let prev = prevs.length > 0 ? prevs[0] : null;
|
|
22061
|
-
if (prev && prev.getTime() > now.getTime()) prev = null;
|
|
22062
|
-
if (prev && !Number.isNaN(createdAtMs) && prev.getTime() < createdAtMs) prev = null;
|
|
22063
|
-
const next = cron.nextRun(now);
|
|
22064
|
-
if (!prev) return { due: false, nextFireIso: next ? iso(next) : null };
|
|
22065
|
-
return { due: true, dedupeKey: `cron:${iso(prev)}`, nextFireIso: next ? iso(next) : null };
|
|
22066
|
-
}
|
|
22067
|
-
function evaluateAfterReset(trigger, now) {
|
|
22068
|
-
const v = verifyReset(trigger.provider, trigger.anchor, now);
|
|
22069
|
-
const predicted = predictReset(trigger.provider, trigger.anchor);
|
|
22070
|
-
if (v.eligible) {
|
|
22071
|
-
return { due: true, dedupeKey: `after-reset:${trigger.anchor.windowStartIso}`, nextFireIso: predicted };
|
|
22072
|
-
}
|
|
22073
|
-
return { due: false, nextFireIso: predicted, rescheduleToIso: v.rescheduleToIso };
|
|
22074
|
-
}
|
|
22075
|
-
function evaluateWhenStatus(trigger, job, ctx, createdAtMs) {
|
|
22076
|
-
const fm = ctx.assignment;
|
|
22077
|
-
if (!fm) return notDue;
|
|
22078
|
-
const history = fm.statusHistory ?? [];
|
|
22079
|
-
for (let i = job.attempt.cursor; i < history.length; i++) {
|
|
22080
|
-
const atMs = Date.parse(history[i].at);
|
|
22081
|
-
const afterCreation = Number.isNaN(createdAtMs) || Number.isNaN(atMs) || atMs >= createdAtMs;
|
|
22082
|
-
if (history[i].to === trigger.status && afterCreation) {
|
|
22083
|
-
return { due: true, dedupeKey: `status:${i}:${history[i].at}`, nextCursor: i + 1 };
|
|
22084
|
-
}
|
|
22085
|
-
}
|
|
22086
|
-
return { due: false, nextCursor: history.length };
|
|
22087
|
-
}
|
|
22088
|
-
function evaluateWhenPlanLands(ctx, createdAtMs) {
|
|
22089
|
-
const fm = ctx.assignment;
|
|
22090
|
-
if (!fm) return notDue;
|
|
22091
|
-
const approval = fm.planApproval;
|
|
22092
|
-
if (!approval) return notDue;
|
|
22093
|
-
const approvedMs = Date.parse(approval.at);
|
|
22094
|
-
if (!Number.isNaN(createdAtMs) && !Number.isNaN(approvedMs) && approvedMs < createdAtMs) {
|
|
22095
|
-
return notDue;
|
|
22096
|
-
}
|
|
22097
|
-
return { due: true, dedupeKey: `plan:${approval.file}:${approval.digest}` };
|
|
22098
|
-
}
|
|
22099
|
-
|
|
22100
22181
|
// src/schedules/launch-ack.ts
|
|
22101
22182
|
init_session_id();
|
|
22102
22183
|
import { readdirSync } from "fs";
|
|
@@ -22178,11 +22259,12 @@ async function defaultResolvePlan(job) {
|
|
|
22178
22259
|
async function runTick(deps = {}) {
|
|
22179
22260
|
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
22180
22261
|
const attemptDeps = { now, isSessionLive: deps.isSessionLive };
|
|
22181
|
-
const result = { evaluated: 0, fired: [], failed: [], skipped: 0, reaped: [], stuck: [] };
|
|
22262
|
+
const result = { evaluated: 0, fired: [], failed: [], skipped: 0, reaped: [], stuck: [], completed: [] };
|
|
22182
22263
|
if (deps.reap !== false) {
|
|
22183
22264
|
const reap = await reapStale(await listJobs(), attemptDeps);
|
|
22184
22265
|
result.reaped = reap.reaped;
|
|
22185
22266
|
result.stuck = reap.stuck;
|
|
22267
|
+
result.completed = reap.completed;
|
|
22186
22268
|
}
|
|
22187
22269
|
const jobs = await listJobs();
|
|
22188
22270
|
for (const job of jobs) {
|
|
@@ -23537,6 +23619,9 @@ workspace: ${workspace}
|
|
|
23537
23619
|
await writeFileForce2(archFile, archContent);
|
|
23538
23620
|
checklist.items = checklist.items.filter((i) => !completedIds.has(i.id));
|
|
23539
23621
|
await writeChecklist(todosDir2, checklist);
|
|
23622
|
+
const archivedEntries = new Set(toArchive);
|
|
23623
|
+
log.entries = log.entries.filter((e) => !archivedEntries.has(e));
|
|
23624
|
+
await writeFileForce2(logPath(todosDir2, workspace), serializeLog(log));
|
|
23540
23625
|
for (const id of completedIds) {
|
|
23541
23626
|
await deleteAllAttachments(todosDir2, workspace, id);
|
|
23542
23627
|
}
|
|
@@ -24282,6 +24367,9 @@ workspace: ${slug}
|
|
|
24282
24367
|
checklist.workspace = slug;
|
|
24283
24368
|
checklist.items = checklist.items.filter((i) => !completedIds.has(i.id));
|
|
24284
24369
|
await writeChecklist(todosDir2, checklist);
|
|
24370
|
+
const archivedEntries = new Set(toArchive);
|
|
24371
|
+
log.entries = log.entries.filter((e) => !archivedEntries.has(e));
|
|
24372
|
+
await writeFileForce(logPath(todosDir2, slug), serializeLog(log));
|
|
24285
24373
|
for (const id of completedIds) {
|
|
24286
24374
|
await deleteAllAttachments(todosDir2, slug, id);
|
|
24287
24375
|
}
|
|
@@ -26934,9 +27022,11 @@ function createDashboardServer(options) {
|
|
|
26934
27022
|
return new Promise((resolvePromise, reject) => {
|
|
26935
27023
|
server.on("error", (err2) => {
|
|
26936
27024
|
if (err2.code === "EADDRINUSE") {
|
|
26937
|
-
|
|
26938
|
-
`Port ${port} is already in use
|
|
26939
|
-
)
|
|
27025
|
+
const inUse = new Error(
|
|
27026
|
+
`Port ${port} is already in use.`
|
|
27027
|
+
);
|
|
27028
|
+
inUse.code = "EADDRINUSE";
|
|
27029
|
+
reject(inUse);
|
|
26940
27030
|
} else {
|
|
26941
27031
|
reject(err2);
|
|
26942
27032
|
}
|
|
@@ -26979,6 +27069,54 @@ function createDashboardServer(options) {
|
|
|
26979
27069
|
// src/commands/dashboard.ts
|
|
26980
27070
|
init_paths();
|
|
26981
27071
|
init_fs();
|
|
27072
|
+
|
|
27073
|
+
// src/errors.ts
|
|
27074
|
+
var SyntaurError = class extends Error {
|
|
27075
|
+
/** Actionable next step printed as `→ try: <remediation>` on stderr. */
|
|
27076
|
+
remediation;
|
|
27077
|
+
/** Optional non-1 exit code (e.g. doctor's exit 2). Defaults to 1. */
|
|
27078
|
+
code;
|
|
27079
|
+
constructor(message, options = {
|
|
27080
|
+
remediation: ""
|
|
27081
|
+
}) {
|
|
27082
|
+
super(message);
|
|
27083
|
+
this.name = "SyntaurError";
|
|
27084
|
+
this.remediation = options.remediation;
|
|
27085
|
+
this.code = options.code ?? 1;
|
|
27086
|
+
if (options.cause !== void 0) {
|
|
27087
|
+
this.cause = options.cause;
|
|
27088
|
+
}
|
|
27089
|
+
}
|
|
27090
|
+
};
|
|
27091
|
+
function isSyntaurError(error) {
|
|
27092
|
+
return error instanceof SyntaurError;
|
|
27093
|
+
}
|
|
27094
|
+
function formatCliError(error) {
|
|
27095
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
27096
|
+
const lines = [`Error: ${message}`];
|
|
27097
|
+
if (isSyntaurError(error) && error.remediation) {
|
|
27098
|
+
lines.push(`\u2192 try: ${error.remediation}`);
|
|
27099
|
+
}
|
|
27100
|
+
return lines.join("\n");
|
|
27101
|
+
}
|
|
27102
|
+
function exitCodeFor(error) {
|
|
27103
|
+
if (isSyntaurError(error) && Number.isInteger(error.code) && error.code !== 0) {
|
|
27104
|
+
return error.code;
|
|
27105
|
+
}
|
|
27106
|
+
return 1;
|
|
27107
|
+
}
|
|
27108
|
+
function runCommand(fn) {
|
|
27109
|
+
return async (...args) => {
|
|
27110
|
+
try {
|
|
27111
|
+
await fn(...args);
|
|
27112
|
+
} catch (error) {
|
|
27113
|
+
console.error(formatCliError(error));
|
|
27114
|
+
process.exit(exitCodeFor(error));
|
|
27115
|
+
}
|
|
27116
|
+
};
|
|
27117
|
+
}
|
|
27118
|
+
|
|
27119
|
+
// src/commands/dashboard.ts
|
|
26982
27120
|
function didUserSpecifyDashboardPort(argv = process.argv) {
|
|
26983
27121
|
return argv.some((arg) => arg === "--port" || arg.startsWith("--port="));
|
|
26984
27122
|
}
|
|
@@ -27054,7 +27192,17 @@ async function dashboardCommand(options) {
|
|
|
27054
27192
|
serveStaticUi: mode === "static",
|
|
27055
27193
|
dashboardDistPath: dashboardDist
|
|
27056
27194
|
});
|
|
27057
|
-
|
|
27195
|
+
try {
|
|
27196
|
+
await server.start();
|
|
27197
|
+
} catch (err2) {
|
|
27198
|
+
if (err2?.code === "EADDRINUSE") {
|
|
27199
|
+
throw new SyntaurError(`Port ${port} is already in use.`, {
|
|
27200
|
+
remediation: `drop --port to let Syntaur auto-pick a free port, or run "lsof -i :${port}" to find what is holding it`,
|
|
27201
|
+
cause: err2
|
|
27202
|
+
});
|
|
27203
|
+
}
|
|
27204
|
+
throw err2;
|
|
27205
|
+
}
|
|
27058
27206
|
let viteProcess = null;
|
|
27059
27207
|
if (mode === "dev") {
|
|
27060
27208
|
const dashboardDir = resolve45(packageRoot, "dashboard");
|
|
@@ -35901,15 +36049,30 @@ var doctorCommand = new Command4("doctor").description("Diagnose Syntaur state a
|
|
|
35901
36049
|
}
|
|
35902
36050
|
try {
|
|
35903
36051
|
const report = await runChecks({ only: options.only });
|
|
36052
|
+
const FIX_NOOP_NOTE = "--fix is reserved but has no auto-fixable remediations in v1; nothing was changed.";
|
|
35904
36053
|
if (options.json) {
|
|
35905
|
-
|
|
36054
|
+
if (options.fix) {
|
|
36055
|
+
process.stdout.write(
|
|
36056
|
+
JSON.stringify(
|
|
36057
|
+
{ ...report, fix: { fixApplied: false, note: FIX_NOOP_NOTE } },
|
|
36058
|
+
null,
|
|
36059
|
+
2
|
|
36060
|
+
) + "\n"
|
|
36061
|
+
);
|
|
36062
|
+
} else {
|
|
36063
|
+
process.stdout.write(renderJson(report) + "\n");
|
|
36064
|
+
}
|
|
35906
36065
|
} else {
|
|
35907
36066
|
process.stdout.write(renderHuman(report, { verbose: options.verbose ?? false }) + "\n");
|
|
35908
36067
|
}
|
|
35909
|
-
if (options.fix
|
|
35910
|
-
|
|
35911
|
-
|
|
35912
|
-
|
|
36068
|
+
if (options.fix) {
|
|
36069
|
+
if (!options.json) {
|
|
36070
|
+
process.stdout.write(`
|
|
36071
|
+
note: ${FIX_NOOP_NOTE}
|
|
36072
|
+
`);
|
|
36073
|
+
}
|
|
36074
|
+
process.stderr.write(`note: ${FIX_NOOP_NOTE}
|
|
36075
|
+
`);
|
|
35913
36076
|
}
|
|
35914
36077
|
const hasError = report.summary.error > 0;
|
|
35915
36078
|
process.exit(hasError ? 1 : 0);
|
|
@@ -38335,6 +38498,37 @@ init_config2();
|
|
|
38335
38498
|
import { Command as Command8 } from "commander";
|
|
38336
38499
|
init_agent_sessions();
|
|
38337
38500
|
init_session_db();
|
|
38501
|
+
init_terminal_schema();
|
|
38502
|
+
|
|
38503
|
+
// src/schedules/liveness.ts
|
|
38504
|
+
init_agent_sessions();
|
|
38505
|
+
init_session_db();
|
|
38506
|
+
function isPidAlive(pid) {
|
|
38507
|
+
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
38508
|
+
try {
|
|
38509
|
+
process.kill(pid, 0);
|
|
38510
|
+
return true;
|
|
38511
|
+
} catch (err2) {
|
|
38512
|
+
const code = err2.code;
|
|
38513
|
+
if (code === "EPERM") return true;
|
|
38514
|
+
return false;
|
|
38515
|
+
}
|
|
38516
|
+
}
|
|
38517
|
+
function isScheduledSessionLive(sessionId, launchPid) {
|
|
38518
|
+
if (sessionId) {
|
|
38519
|
+
let row = null;
|
|
38520
|
+
try {
|
|
38521
|
+
initSessionDb();
|
|
38522
|
+
row = getSessionById(sessionId);
|
|
38523
|
+
} catch {
|
|
38524
|
+
return true;
|
|
38525
|
+
}
|
|
38526
|
+
if (!row) return true;
|
|
38527
|
+
return computeIsLive(row);
|
|
38528
|
+
}
|
|
38529
|
+
if (launchPid == null) return true;
|
|
38530
|
+
return isPidAlive(launchPid);
|
|
38531
|
+
}
|
|
38338
38532
|
|
|
38339
38533
|
// src/schedules/launchd.ts
|
|
38340
38534
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
@@ -38462,6 +38656,17 @@ function parseDurationMs(input4) {
|
|
|
38462
38656
|
const mult = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
|
|
38463
38657
|
return n * mult[(m[2] ?? "s").toLowerCase()];
|
|
38464
38658
|
}
|
|
38659
|
+
function validateTerminalChoice(value) {
|
|
38660
|
+
if (value == null) return null;
|
|
38661
|
+
const trimmed = value.trim();
|
|
38662
|
+
if (trimmed === "") return null;
|
|
38663
|
+
if (!TERMINAL_CHOICES.includes(trimmed)) {
|
|
38664
|
+
throw new Error(
|
|
38665
|
+
`--terminal "${trimmed}" is not a known choice \u2014 expected one of ${TERMINAL_CHOICES.join("|")}`
|
|
38666
|
+
);
|
|
38667
|
+
}
|
|
38668
|
+
return trimmed;
|
|
38669
|
+
}
|
|
38465
38670
|
function buildTrigger(opts) {
|
|
38466
38671
|
const chosen = [];
|
|
38467
38672
|
if (opts.at) chosen.push({ kind: "at", at: opts.at });
|
|
@@ -38515,7 +38720,7 @@ scheduleCommand.command("create").description("Create a scheduled job").required
|
|
|
38515
38720
|
wrap(async (opts) => {
|
|
38516
38721
|
const config = await readConfig();
|
|
38517
38722
|
const agentId = opts.agent ?? pickAgent(config).id;
|
|
38518
|
-
const terminal = opts.terminal
|
|
38723
|
+
const terminal = validateTerminalChoice(opts.terminal);
|
|
38519
38724
|
const unattended = !opts.interactive;
|
|
38520
38725
|
if (unattended) assertUnattendedTerminalSupported(terminal);
|
|
38521
38726
|
const limits = defaultLimits();
|
|
@@ -38617,15 +38822,15 @@ scheduleCommand.command("reschedule").description("Change a job's trigger and re
|
|
|
38617
38822
|
);
|
|
38618
38823
|
scheduleCommand.command("tick").description("Run one scheduler tick (the one authority): evaluate, fire due, reap").action(
|
|
38619
38824
|
wrap(async () => {
|
|
38620
|
-
const r = await runTick({ log: (m) => console.error(m) });
|
|
38825
|
+
const r = await runTick({ log: (m) => console.error(m), isSessionLive: isScheduledSessionLive });
|
|
38621
38826
|
console.log(
|
|
38622
|
-
`tick: evaluated ${r.evaluated}, fired ${r.fired.length}, failed ${r.failed.length}, reaped ${r.reaped.length}, stuck ${r.stuck.length}`
|
|
38827
|
+
`tick: evaluated ${r.evaluated}, fired ${r.fired.length}, failed ${r.failed.length}, reaped ${r.reaped.length}, stuck ${r.stuck.length}, completed ${r.completed.length}`
|
|
38623
38828
|
);
|
|
38624
38829
|
})
|
|
38625
38830
|
);
|
|
38626
38831
|
scheduleCommand.command("fire-due").description("Internal: fire currently-due jobs without reaping (accelerator path)").action(
|
|
38627
38832
|
wrap(async () => {
|
|
38628
|
-
const r = await runTick({ reap: false });
|
|
38833
|
+
const r = await runTick({ reap: false, isSessionLive: isScheduledSessionLive });
|
|
38629
38834
|
console.log(`fire-due: fired ${r.fired.length}, failed ${r.failed.length}`);
|
|
38630
38835
|
})
|
|
38631
38836
|
);
|
|
@@ -39501,14 +39706,14 @@ sessionCommand.command("resolve-id").description(
|
|
|
39501
39706
|
|
|
39502
39707
|
// src/commands/worktree.ts
|
|
39503
39708
|
init_git_worktree();
|
|
39709
|
+
import { Command as Command12 } from "commander";
|
|
39710
|
+
import { readFile as readFile68 } from "fs/promises";
|
|
39711
|
+
import { resolve as resolve95 } from "path";
|
|
39504
39712
|
init_fs();
|
|
39505
39713
|
init_paths();
|
|
39506
39714
|
init_config2();
|
|
39507
39715
|
init_timestamp();
|
|
39508
39716
|
init_frontmatter();
|
|
39509
|
-
import { Command as Command12 } from "commander";
|
|
39510
|
-
import { readFile as readFile68 } from "fs/promises";
|
|
39511
|
-
import { resolve as resolve95 } from "path";
|
|
39512
39717
|
async function readContext2(cwd) {
|
|
39513
39718
|
const path = resolve95(cwd, ".syntaur", "context.json");
|
|
39514
39719
|
if (!await fileExists(path)) return null;
|
|
@@ -39591,6 +39796,12 @@ async function runWorktreeRemove(options, cwd = process.cwd()) {
|
|
|
39591
39796
|
}
|
|
39592
39797
|
let branchDeleted = false;
|
|
39593
39798
|
if (options.deleteBranch && branch) {
|
|
39799
|
+
const sha = await resolveBranchSha(repository, branch);
|
|
39800
|
+
if (sha) {
|
|
39801
|
+
console.log(
|
|
39802
|
+
`Branch "${branch}" was at ${sha}. To recover it: git -C ${repository} branch ${branch} ${sha}`
|
|
39803
|
+
);
|
|
39804
|
+
}
|
|
39594
39805
|
const del = await deleteBranch(repository, branch);
|
|
39595
39806
|
if (!del.ok) {
|
|
39596
39807
|
throw new Error(
|
|
@@ -39650,15 +39861,31 @@ worktreeCommand.command("list").description("List the git worktrees of a reposit
|
|
|
39650
39861
|
});
|
|
39651
39862
|
worktreeCommand.command("remove").alias("prune").description(
|
|
39652
39863
|
"Remove an assignment's git worktree and clear its workspace.* fields. Branch deletion is opt-in."
|
|
39653
|
-
).option("--assignment <slug>", "Assignment slug (UUID for standalone). Defaults to .syntaur/context.json").option("--project <slug>", "Project slug. Required when --assignment is given for a project-nested assignment").option("--repository <path>", "Repository root (defaults to the recorded workspace.repository)").option("--delete-branch", "Also delete the branch after removing the worktree").option("--force", "Discard a dirty/locked worktree (passes --force to git)").action(async (options) => {
|
|
39864
|
+
).option("--assignment <slug>", "Assignment slug (UUID for standalone). Defaults to .syntaur/context.json").option("--project <slug>", "Project slug. Required when --assignment is given for a project-nested assignment").option("--repository <path>", "Repository root (defaults to the recorded workspace.repository)").option("--delete-branch", "Also delete the branch after removing the worktree").option("--force", "Discard a dirty/locked worktree (passes --force to git)").option("--yes", "Skip the confirmation prompt for a destructive --force removal (required for non-TTY)").action(async (options) => {
|
|
39654
39865
|
try {
|
|
39866
|
+
if (options.force && !options.yes) {
|
|
39867
|
+
if (!isInteractiveTerminal()) {
|
|
39868
|
+
throw new SyntaurError(
|
|
39869
|
+
"--force discards uncommitted work in the worktree, but there is no TTY to confirm.",
|
|
39870
|
+
{ remediation: "re-run with --yes to confirm the destructive removal" }
|
|
39871
|
+
);
|
|
39872
|
+
}
|
|
39873
|
+
const confirmed = await confirmPrompt(
|
|
39874
|
+
"--force will discard any uncommitted work in the worktree. Continue?",
|
|
39875
|
+
false
|
|
39876
|
+
);
|
|
39877
|
+
if (!confirmed) {
|
|
39878
|
+
console.log("Aborted. Nothing was removed.");
|
|
39879
|
+
return;
|
|
39880
|
+
}
|
|
39881
|
+
}
|
|
39655
39882
|
const { worktreePath, branchDeleted, workspaceCleared } = await runWorktreeRemove(options);
|
|
39656
39883
|
console.log(`Removed worktree at ${worktreePath}`);
|
|
39657
39884
|
if (branchDeleted) console.log("Deleted the branch.");
|
|
39658
39885
|
if (workspaceCleared) console.log("Cleared the assignment workspace fields.");
|
|
39659
39886
|
} catch (error) {
|
|
39660
|
-
console.error(
|
|
39661
|
-
process.exit(
|
|
39887
|
+
console.error(formatCliError(error));
|
|
39888
|
+
process.exit(exitCodeFor(error));
|
|
39662
39889
|
}
|
|
39663
39890
|
});
|
|
39664
39891
|
|
|
@@ -41568,358 +41795,187 @@ var captureDashDashArgv = [];
|
|
|
41568
41795
|
var program = new Command20();
|
|
41569
41796
|
var version = await readPackageVersion(import.meta.url) ?? "0.0.0";
|
|
41570
41797
|
program.name("syntaur").description("CLI scaffolding tool for the Syntaur protocol").version(version);
|
|
41571
|
-
program.command("init").description("Initialize ~/.syntaur/ directory structure and config").option("--force", "Overwrite existing config file").action(
|
|
41572
|
-
|
|
41798
|
+
program.command("init").description("Initialize ~/.syntaur/ directory structure and config").option("--force", "Overwrite existing config file").action(
|
|
41799
|
+
runCommand(async (options) => {
|
|
41573
41800
|
await initCommand(options);
|
|
41574
|
-
}
|
|
41575
|
-
|
|
41576
|
-
|
|
41577
|
-
|
|
41578
|
-
);
|
|
41579
|
-
process.exit(1);
|
|
41580
|
-
}
|
|
41581
|
-
});
|
|
41582
|
-
program.command("create-project").description("Create a new project with all required files").argument("<title>", "Project title").option("--slug <slug>", "Override auto-generated slug").option("--dir <path>", "Override default project directory").option("--workspace <workspace>", "Workspace for organizational grouping").action(async (title, options) => {
|
|
41583
|
-
try {
|
|
41801
|
+
})
|
|
41802
|
+
);
|
|
41803
|
+
program.command("create-project").description("Create a new project with all required files").argument("<title>", "Project title").option("--slug <slug>", "Override auto-generated slug").option("--dir <path>", "Override default project directory").option("--workspace <workspace>", "Workspace for organizational grouping").action(
|
|
41804
|
+
runCommand(async (title, options) => {
|
|
41584
41805
|
await createProjectCommand(title, options);
|
|
41585
|
-
}
|
|
41586
|
-
|
|
41587
|
-
"Error:",
|
|
41588
|
-
error instanceof Error ? error.message : String(error)
|
|
41589
|
-
);
|
|
41590
|
-
process.exit(1);
|
|
41591
|
-
}
|
|
41592
|
-
});
|
|
41806
|
+
})
|
|
41807
|
+
);
|
|
41593
41808
|
program.command("create-assignment").description("Create a new assignment within a project").argument("<title>", "Assignment title").option("--project <slug>", "Target project slug (required unless --one-off)").option("--one-off", "Create a standalone assignment at ~/.syntaur/assignments/<uuid>/").option("--slug <slug>", "Override auto-generated slug (display only for standalone; folder name for project-nested)").option(
|
|
41594
41809
|
"--priority <level>",
|
|
41595
41810
|
"Priority level (low|medium|high|critical)",
|
|
41596
41811
|
"medium"
|
|
41597
|
-
).option("--type <type>", "Assignment type (e.g. feature, bug, refactor)").option("--depends-on <slugs>", "Comma-separated dependency slugs (not allowed with --one-off)").option("--links <slugs>", "Comma-separated linked assignment slugs (projectSlug/assignmentSlug format)").option("--dir <path>", "Override default project directory (ignored for --one-off)").option("--with-todos", "Scaffold a ## Todos section in assignment.md (omitted by default; typically populated by /plan-assignment)").option("--workspace <slug>", "Workspace group slug (only valid with --one-off; mutually exclusive with --project)").option("--ready", "Create the assignment directly as ready_for_planning (skips the draft phase)").action(
|
|
41598
|
-
|
|
41812
|
+
).option("--type <type>", "Assignment type (e.g. feature, bug, refactor)").option("--depends-on <slugs>", "Comma-separated dependency slugs (not allowed with --one-off)").option("--links <slugs>", "Comma-separated linked assignment slugs (projectSlug/assignmentSlug format)").option("--dir <path>", "Override default project directory (ignored for --one-off)").option("--with-todos", "Scaffold a ## Todos section in assignment.md (omitted by default; typically populated by /plan-assignment)").option("--workspace <slug>", "Workspace group slug (only valid with --one-off; mutually exclusive with --project)").option("--ready", "Create the assignment directly as ready_for_planning (skips the draft phase)").action(
|
|
41813
|
+
runCommand(async (title, options) => {
|
|
41599
41814
|
await createAssignmentCommand(title, options);
|
|
41600
|
-
}
|
|
41601
|
-
|
|
41602
|
-
|
|
41603
|
-
|
|
41604
|
-
);
|
|
41605
|
-
process.exit(1);
|
|
41606
|
-
}
|
|
41607
|
-
});
|
|
41608
|
-
program.command("comment").description("Add a comment to an assignment (CLI-mediated, append-only)").argument("<assignment>", "Target assignment slug (with --project) or UUID (standalone)").argument("<text>", "Comment body").option("--project <slug>", "Project slug if the target is project-nested").option("--reply-to <id>", "ID of the comment this replies to").option("--type <type>", "Comment type: question | note | feedback", "note").option("--author <name>", 'Override author (default: $USER or "unknown")').option("--dir <path>", "Override default project directory").action(async (assignment, text, options) => {
|
|
41609
|
-
try {
|
|
41815
|
+
})
|
|
41816
|
+
);
|
|
41817
|
+
program.command("comment").description("Add a comment to an assignment (CLI-mediated, append-only)").argument("<assignment>", "Target assignment slug (with --project) or UUID (standalone)").argument("<text>", "Comment body").option("--project <slug>", "Project slug if the target is project-nested").option("--reply-to <id>", "ID of the comment this replies to").option("--type <type>", "Comment type: question | note | feedback", "note").option("--author <name>", 'Override author (default: $USER or "unknown")').option("--dir <path>", "Override default project directory").action(
|
|
41818
|
+
runCommand(async (assignment, text, options) => {
|
|
41610
41819
|
await commentCommand(assignment, text, options);
|
|
41611
|
-
}
|
|
41612
|
-
|
|
41613
|
-
|
|
41614
|
-
|
|
41615
|
-
);
|
|
41616
|
-
process.exit(1);
|
|
41617
|
-
}
|
|
41618
|
-
});
|
|
41619
|
-
program.command("capture").description("Capture a typed proof artifact for an assignment").argument("[target]", "Assignment slug (with --project) or UUID; falls back to .syntaur/context.json").option("--kind <type>", "Artifact kind: screenshot | video | asciinema | http | text").option("--file <path>", "Source file to ingest (forbidden for --kind=text)").option("--criterion <index>", "Optional 0-based criterion index to tag").option("--note <text>", "Optional note (required for --kind=text)").option("--project <slug>", "Project slug if the target is project-nested").option("--dir <path>", "Override default project directory").option("--interactive", "Interactive mode: drag a region (--kind=screenshot) or record a TTY (--kind=asciinema)").option("--window", "Screenshot mode: window picker (macOS only)").option("--fullscreen", "Screenshot mode: silent full-screen capture (macOS only)").option("--start", "Start ffmpeg screen recording in the background (macOS only). Stop with --stop.").option("--stop", "Stop the running ffmpeg recording and attach the mp4.").option("--device <index>", 'AVFoundation video device index for --start (default: 1). List devices: ffmpeg -f avfoundation -list_devices true -i ""').option("--fps <n>", "Frame rate for --start (default: 30)").option("--transcribe", "Auto-transcribe captured video to a <id>.transcript.md sidecar (kind=video only; requires ELEVENLABS_API_KEY + ffmpeg)").action(async (target, options) => {
|
|
41620
|
-
try {
|
|
41820
|
+
})
|
|
41821
|
+
);
|
|
41822
|
+
program.command("capture").description("Capture a typed proof artifact for an assignment").argument("[target]", "Assignment slug (with --project) or UUID; falls back to .syntaur/context.json").option("--kind <type>", "Artifact kind: screenshot | video | asciinema | http | text").option("--file <path>", "Source file to ingest (forbidden for --kind=text)").option("--criterion <index>", "Optional 0-based criterion index to tag").option("--note <text>", "Optional note (required for --kind=text)").option("--project <slug>", "Project slug if the target is project-nested").option("--dir <path>", "Override default project directory").option("--interactive", "Interactive mode: drag a region (--kind=screenshot) or record a TTY (--kind=asciinema)").option("--window", "Screenshot mode: window picker (macOS only)").option("--fullscreen", "Screenshot mode: silent full-screen capture (macOS only)").option("--start", "Start ffmpeg screen recording in the background (macOS only). Stop with --stop.").option("--stop", "Stop the running ffmpeg recording and attach the mp4.").option("--device <index>", 'AVFoundation video device index for --start (default: 1). List devices: ffmpeg -f avfoundation -list_devices true -i ""').option("--fps <n>", "Frame rate for --start (default: 30)").option("--transcribe", "Auto-transcribe captured video to a <id>.transcript.md sidecar (kind=video only; requires ELEVENLABS_API_KEY + ffmpeg)").action(
|
|
41823
|
+
runCommand(async (target, options) => {
|
|
41621
41824
|
await captureCommand(target, {
|
|
41622
41825
|
...options,
|
|
41623
41826
|
commandArgv: captureDashDashArgv
|
|
41624
41827
|
});
|
|
41625
|
-
}
|
|
41626
|
-
|
|
41627
|
-
|
|
41628
|
-
|
|
41629
|
-
);
|
|
41630
|
-
process.exit(1);
|
|
41631
|
-
}
|
|
41632
|
-
});
|
|
41633
|
-
program.command("request").description("Append a todo to another assignment (cross-assignment work request)").argument("<target>", "Target assignment slug (with --project) or UUID (standalone)").argument("<text>", "Todo text").option("--project <slug>", "Project slug if the target is project-nested").option("--from <source>", "Source assignment (default: $SYNTAUR_ASSIGNMENT)").option("--dir <path>", "Override default project directory").action(async (target, text, options) => {
|
|
41634
|
-
try {
|
|
41828
|
+
})
|
|
41829
|
+
);
|
|
41830
|
+
program.command("request").description("Append a todo to another assignment (cross-assignment work request)").argument("<target>", "Target assignment slug (with --project) or UUID (standalone)").argument("<text>", "Todo text").option("--project <slug>", "Project slug if the target is project-nested").option("--from <source>", "Source assignment (default: $SYNTAUR_ASSIGNMENT)").option("--dir <path>", "Override default project directory").action(
|
|
41831
|
+
runCommand(async (target, text, options) => {
|
|
41635
41832
|
await requestCommand(target, text, options);
|
|
41636
|
-
}
|
|
41637
|
-
|
|
41638
|
-
|
|
41639
|
-
|
|
41640
|
-
);
|
|
41641
|
-
process.exit(1);
|
|
41642
|
-
}
|
|
41643
|
-
});
|
|
41644
|
-
program.command("dashboard").description("Start the local Syntaur dashboard web UI").option("--port <number>", "Port to run the dashboard on", "4800").option("--dev", "Run the dashboard with the Vite dev server", false).option("--server-only", "Run only the API server without any UI", false).option("--api-only", "Deprecated alias for --server-only", false).option("--no-open", "Do not automatically open the browser").action(async (options) => {
|
|
41645
|
-
try {
|
|
41833
|
+
})
|
|
41834
|
+
);
|
|
41835
|
+
program.command("dashboard").description("Start the local Syntaur dashboard web UI").option("--port <number>", "Port to run the dashboard on", "4800").option("--dev", "Run the dashboard with the Vite dev server", false).option("--server-only", "Run only the API server without any UI", false).option("--api-only", "Deprecated alias for --server-only", false).option("--no-open", "Do not automatically open the browser").action(
|
|
41836
|
+
runCommand(async (options) => {
|
|
41646
41837
|
const autoPort = !didUserSpecifyDashboardPort();
|
|
41647
41838
|
await dashboardCommand({
|
|
41648
41839
|
...options,
|
|
41649
41840
|
autoPort
|
|
41650
41841
|
});
|
|
41651
|
-
}
|
|
41652
|
-
|
|
41653
|
-
|
|
41654
|
-
|
|
41655
|
-
);
|
|
41656
|
-
process.exit(1);
|
|
41657
|
-
}
|
|
41658
|
-
});
|
|
41659
|
-
program.command("assign").description("Set the assignee on an assignment").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--agent <name>", "Agent name to assign").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41660
|
-
try {
|
|
41842
|
+
})
|
|
41843
|
+
);
|
|
41844
|
+
program.command("assign").description("Set the assignee on an assignment").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--agent <name>", "Agent name to assign").option("--dir <path>", "Override default project directory").action(
|
|
41845
|
+
runCommand(async (assignment, options) => {
|
|
41661
41846
|
await assignCommand(assignment, options);
|
|
41662
|
-
}
|
|
41663
|
-
|
|
41664
|
-
|
|
41665
|
-
|
|
41666
|
-
);
|
|
41667
|
-
process.exit(1);
|
|
41668
|
-
}
|
|
41669
|
-
});
|
|
41670
|
-
program.command("unassign").description("Clear the assignee on an assignment (inverse of assign)").argument("<assignment>", "Assignment slug (UUID for standalone)").option("--project <slug>", "Target project slug").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41671
|
-
try {
|
|
41847
|
+
})
|
|
41848
|
+
);
|
|
41849
|
+
program.command("unassign").description("Clear the assignee on an assignment (inverse of assign)").argument("<assignment>", "Assignment slug (UUID for standalone)").option("--project <slug>", "Target project slug").option("--dir <path>", "Override default project directory").action(
|
|
41850
|
+
runCommand(async (assignment, options) => {
|
|
41672
41851
|
await unassignCommand(assignment, options);
|
|
41673
|
-
}
|
|
41674
|
-
|
|
41675
|
-
|
|
41676
|
-
|
|
41677
|
-
);
|
|
41678
|
-
process.exit(1);
|
|
41679
|
-
}
|
|
41680
|
-
});
|
|
41681
|
-
program.command("start").description("Assert implementation has started (alias of implement under derived status)").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--agent <name>", "Agent name (sets assignee if not already set)").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41682
|
-
try {
|
|
41852
|
+
})
|
|
41853
|
+
);
|
|
41854
|
+
program.command("start").description("Assert implementation has started (alias of implement under derived status)").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--agent <name>", "Agent name (sets assignee if not already set)").option("--dir <path>", "Override default project directory").action(
|
|
41855
|
+
runCommand(async (assignment, options) => {
|
|
41683
41856
|
await startCommand(assignment, options);
|
|
41684
|
-
}
|
|
41685
|
-
|
|
41686
|
-
|
|
41687
|
-
|
|
41688
|
-
);
|
|
41689
|
-
process.exit(1);
|
|
41690
|
-
}
|
|
41691
|
-
});
|
|
41692
|
-
program.command("archive").description("Archive an assignment or a project (hidden from normal views; restorable)").argument("<target>", "Assignment slug/UUID, or a project slug").option("--project <slug>", "Resolve <target> as an assignment within this project").option("--reason <text>", "Optional reason recorded with the archive").option("--dir <path>", "Override default project directory").action(async (target, options) => {
|
|
41693
|
-
try {
|
|
41857
|
+
})
|
|
41858
|
+
);
|
|
41859
|
+
program.command("archive").description("Archive an assignment or a project (hidden from normal views; restorable)").argument("<target>", "Assignment slug/UUID, or a project slug").option("--project <slug>", "Resolve <target> as an assignment within this project").option("--reason <text>", "Optional reason recorded with the archive").option("--dir <path>", "Override default project directory").action(
|
|
41860
|
+
runCommand(async (target, options) => {
|
|
41694
41861
|
await archiveCommand(target, options);
|
|
41695
|
-
}
|
|
41696
|
-
|
|
41697
|
-
|
|
41698
|
-
|
|
41699
|
-
});
|
|
41700
|
-
program.command("restore").description("Restore an archived assignment or project (preserves prior status)").argument("<target>", "Assignment slug/UUID, or a project slug").option("--project <slug>", "Resolve <target> as an assignment within this project").option("--dir <path>", "Override default project directory").action(async (target, options) => {
|
|
41701
|
-
try {
|
|
41862
|
+
})
|
|
41863
|
+
);
|
|
41864
|
+
program.command("restore").description("Restore an archived assignment or project (preserves prior status)").argument("<target>", "Assignment slug/UUID, or a project slug").option("--project <slug>", "Resolve <target> as an assignment within this project").option("--dir <path>", "Override default project directory").action(
|
|
41865
|
+
runCommand(async (target, options) => {
|
|
41702
41866
|
await restoreCommand(target, options);
|
|
41703
|
-
}
|
|
41704
|
-
|
|
41705
|
-
|
|
41706
|
-
|
|
41707
|
-
});
|
|
41708
|
-
program.command("shape").description("Recompute derived status; ready_for_planning follows once objective + ACs are real").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--agent <name>", "Agent name (sets assignee if not already set)").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41709
|
-
try {
|
|
41867
|
+
})
|
|
41868
|
+
);
|
|
41869
|
+
program.command("shape").description("Recompute derived status; ready_for_planning follows once objective + ACs are real").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--agent <name>", "Agent name (sets assignee if not already set)").option("--dir <path>", "Override default project directory").action(
|
|
41870
|
+
runCommand(async (assignment, options) => {
|
|
41710
41871
|
await shapeCommand(assignment, options);
|
|
41711
|
-
}
|
|
41712
|
-
|
|
41713
|
-
|
|
41714
|
-
|
|
41715
|
-
);
|
|
41716
|
-
process.exit(1);
|
|
41717
|
-
}
|
|
41718
|
-
});
|
|
41719
|
-
program.command("plan-ready").description("Approve the latest plan revision (file+digest bound); ready_to_implement derives from it").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--agent <name>", "Agent name (sets assignee if not already set)").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41720
|
-
try {
|
|
41872
|
+
})
|
|
41873
|
+
);
|
|
41874
|
+
program.command("plan-ready").description("Approve the latest plan revision (file+digest bound); ready_to_implement derives from it").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--agent <name>", "Agent name (sets assignee if not already set)").option("--dir <path>", "Override default project directory").action(
|
|
41875
|
+
runCommand(async (assignment, options) => {
|
|
41721
41876
|
await planReadyCommand(assignment, options);
|
|
41722
|
-
}
|
|
41723
|
-
|
|
41724
|
-
|
|
41725
|
-
|
|
41726
|
-
);
|
|
41727
|
-
process.exit(1);
|
|
41728
|
-
}
|
|
41729
|
-
});
|
|
41730
|
-
program.command("migrate-statuses").description("Suggest pending -> ready_for_planning promotions for fleshed-out assignments (use --apply to write)").option("--dir <path>", "Override default project directory").option("--apply", "Apply the migration (default: dry-run)").action(async (options) => {
|
|
41731
|
-
try {
|
|
41877
|
+
})
|
|
41878
|
+
);
|
|
41879
|
+
program.command("migrate-statuses").description("Suggest pending -> ready_for_planning promotions for fleshed-out assignments (use --apply to write)").option("--dir <path>", "Override default project directory").option("--apply", "Apply the migration (default: dry-run)").action(
|
|
41880
|
+
runCommand(async (options) => {
|
|
41732
41881
|
await migrateStatusesCommand(options);
|
|
41733
|
-
}
|
|
41734
|
-
|
|
41735
|
-
|
|
41736
|
-
|
|
41737
|
-
);
|
|
41738
|
-
process.exit(1);
|
|
41739
|
-
}
|
|
41740
|
-
});
|
|
41741
|
-
program.command("migrate-status-history").description("Seed a synthetic statusHistory entry on assignments that lack one (use --apply to write)").option("--dir <path>", "Override default project directory").option("--apply", "Apply the migration (default: dry-run)").action(async (options) => {
|
|
41742
|
-
try {
|
|
41882
|
+
})
|
|
41883
|
+
);
|
|
41884
|
+
program.command("migrate-status-history").description("Seed a synthetic statusHistory entry on assignments that lack one (use --apply to write)").option("--dir <path>", "Override default project directory").option("--apply", "Apply the migration (default: dry-run)").action(
|
|
41885
|
+
runCommand(async (options) => {
|
|
41743
41886
|
await migrateStatusHistoryCommand(options);
|
|
41744
|
-
}
|
|
41745
|
-
|
|
41746
|
-
|
|
41747
|
-
|
|
41748
|
-
);
|
|
41749
|
-
process.exit(1);
|
|
41750
|
-
}
|
|
41751
|
-
});
|
|
41752
|
-
program.command("migrate-derive").description("One-time migration to derived status: seed facts from current statuses, re-derive all, print a divergence report").option("--dir <path>", "Override default project directory").option("--dry-run", "Report what would change without writing").action(async (options) => {
|
|
41753
|
-
try {
|
|
41887
|
+
})
|
|
41888
|
+
);
|
|
41889
|
+
program.command("migrate-derive").description("One-time migration to derived status: seed facts from current statuses, re-derive all, print a divergence report").option("--dir <path>", "Override default project directory").option("--dry-run", "Report what would change without writing").action(
|
|
41890
|
+
runCommand(async (options) => {
|
|
41754
41891
|
await migrateDeriveCommand(options);
|
|
41755
|
-
}
|
|
41756
|
-
|
|
41757
|
-
|
|
41758
|
-
|
|
41759
|
-
});
|
|
41760
|
-
program.command("park").description("Park an assignment (intentional withhold); disposition derives to parked").argument("<assignment>", "Assignment slug or standalone UUID").option("--project <slug>", "Target project slug").option("--reason <text>", "Why it is parked (recorded in history)").option("--agent <name>", "Acting agent id").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41761
|
-
try {
|
|
41892
|
+
})
|
|
41893
|
+
);
|
|
41894
|
+
program.command("park").description("Park an assignment (intentional withhold); disposition derives to parked").argument("<assignment>", "Assignment slug or standalone UUID").option("--project <slug>", "Target project slug").option("--reason <text>", "Why it is parked (recorded in history)").option("--agent <name>", "Acting agent id").option("--dir <path>", "Override default project directory").action(
|
|
41895
|
+
runCommand(async (assignment, options) => {
|
|
41762
41896
|
await parkCommand(assignment, options);
|
|
41763
|
-
}
|
|
41764
|
-
|
|
41765
|
-
|
|
41766
|
-
|
|
41767
|
-
});
|
|
41768
|
-
program.command("unpark").description("Unpark an assignment; status re-derives from facts").argument("<assignment>", "Assignment slug or standalone UUID").option("--project <slug>", "Target project slug").option("--agent <name>", "Acting agent id").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41769
|
-
try {
|
|
41897
|
+
})
|
|
41898
|
+
);
|
|
41899
|
+
program.command("unpark").description("Unpark an assignment; status re-derives from facts").argument("<assignment>", "Assignment slug or standalone UUID").option("--project <slug>", "Target project slug").option("--agent <name>", "Acting agent id").option("--dir <path>", "Override default project directory").action(
|
|
41900
|
+
runCommand(async (assignment, options) => {
|
|
41770
41901
|
await unparkCommand(assignment, options);
|
|
41771
|
-
}
|
|
41772
|
-
|
|
41773
|
-
|
|
41774
|
-
|
|
41775
|
-
});
|
|
41776
|
-
program.command("request-review").description("Request review (sets reviewRequested); the review phase derives from it").argument("<assignment>", "Assignment slug or standalone UUID").option("--project <slug>", "Target project slug").option("--clear", "Clear the review request instead").option("--agent <name>", "Acting agent id").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41777
|
-
try {
|
|
41902
|
+
})
|
|
41903
|
+
);
|
|
41904
|
+
program.command("request-review").description("Request review (sets reviewRequested); the review phase derives from it").argument("<assignment>", "Assignment slug or standalone UUID").option("--project <slug>", "Target project slug").option("--clear", "Clear the review request instead").option("--agent <name>", "Acting agent id").option("--dir <path>", "Override default project directory").action(
|
|
41905
|
+
runCommand(async (assignment, options) => {
|
|
41778
41906
|
await requestReviewCommand(assignment, options);
|
|
41779
|
-
}
|
|
41780
|
-
|
|
41781
|
-
process.exit(1);
|
|
41782
|
-
}
|
|
41783
|
-
});
|
|
41907
|
+
})
|
|
41908
|
+
);
|
|
41784
41909
|
var factCommand = program.command("fact").description("Manage custom asserted facts declared under statuses.facts");
|
|
41785
|
-
factCommand.command("set").description("Set a declared custom fact (bool/number); status re-derives from it").argument("<assignment>", "Assignment slug or standalone UUID").argument("<name>", "Declared fact name (statuses.facts)").argument("<value>", "Value (bool: true/false; number: any finite number)").option("--project <slug>", "Target project slug").option("--agent <name>", "Acting agent id").option("--dir <path>", "Override default project directory").action(
|
|
41786
|
-
|
|
41910
|
+
factCommand.command("set").description("Set a declared custom fact (bool/number); status re-derives from it").argument("<assignment>", "Assignment slug or standalone UUID").argument("<name>", "Declared fact name (statuses.facts)").argument("<value>", "Value (bool: true/false; number: any finite number)").option("--project <slug>", "Target project slug").option("--agent <name>", "Acting agent id").option("--dir <path>", "Override default project directory").action(
|
|
41911
|
+
runCommand(async (assignment, name, value, options) => {
|
|
41787
41912
|
await factSetCommand(assignment, name, value, options);
|
|
41788
|
-
}
|
|
41789
|
-
|
|
41790
|
-
|
|
41791
|
-
|
|
41792
|
-
});
|
|
41793
|
-
program.command("attest").description("Record an attestation (agent reviewed a revision with a verdict); revision-bound").argument("<assignment>", "Assignment slug or standalone UUID").argument("<fact>", "Declared attestation fact name (statuses.facts)").option("--verdict <verdict>", "approved | changes-requested", "approved").option("--note <text>", "Optional note recorded on the attestation").option("--agent <id>", "Acting agent id (else the bound session, else human)").option("--project <slug>", "Target project slug").option("--dir <path>", "Override default project directory").action(async (assignment, fact, options) => {
|
|
41794
|
-
try {
|
|
41913
|
+
})
|
|
41914
|
+
);
|
|
41915
|
+
program.command("attest").description("Record an attestation (agent reviewed a revision with a verdict); revision-bound").argument("<assignment>", "Assignment slug or standalone UUID").argument("<fact>", "Declared attestation fact name (statuses.facts)").option("--verdict <verdict>", "approved | changes-requested", "approved").option("--note <text>", "Optional note recorded on the attestation").option("--agent <id>", "Acting agent id (else the bound session, else human)").option("--project <slug>", "Target project slug").option("--dir <path>", "Override default project directory").action(
|
|
41916
|
+
runCommand(async (assignment, fact, options) => {
|
|
41795
41917
|
await attestCommand(assignment, fact, options);
|
|
41796
|
-
}
|
|
41797
|
-
|
|
41798
|
-
|
|
41799
|
-
|
|
41800
|
-
});
|
|
41801
|
-
program.command("recompute").description("Recompute derived status for one assignment or --all (headless reconcile)").argument("[assignment]", "Assignment slug or standalone UUID").option("--all", "Recompute every assignment (projects + standalone)").option("--project <slug>", "Target project slug").option("--agent <name>", "Acting agent id").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41802
|
-
try {
|
|
41918
|
+
})
|
|
41919
|
+
);
|
|
41920
|
+
program.command("recompute").description("Recompute derived status for one assignment or --all (headless reconcile)").argument("[assignment]", "Assignment slug or standalone UUID").option("--all", "Recompute every assignment (projects + standalone)").option("--project <slug>", "Target project slug").option("--agent <name>", "Acting agent id").option("--dir <path>", "Override default project directory").action(
|
|
41921
|
+
runCommand(async (assignment, options) => {
|
|
41803
41922
|
await recomputeCommand(assignment, options);
|
|
41804
|
-
}
|
|
41805
|
-
|
|
41806
|
-
|
|
41807
|
-
|
|
41808
|
-
});
|
|
41809
|
-
program.command("implement").description("Assert implementation has started; status derives to in_progress when the plan is approved").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--agent <name>", "Agent name (sets assignee if not already set)").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41810
|
-
try {
|
|
41923
|
+
})
|
|
41924
|
+
);
|
|
41925
|
+
program.command("implement").description("Assert implementation has started; status derives to in_progress when the plan is approved").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--agent <name>", "Agent name (sets assignee if not already set)").option("--dir <path>", "Override default project directory").action(
|
|
41926
|
+
runCommand(async (assignment, options) => {
|
|
41811
41927
|
await implementCommand(assignment, options);
|
|
41812
|
-
}
|
|
41813
|
-
|
|
41814
|
-
|
|
41815
|
-
|
|
41816
|
-
);
|
|
41817
|
-
process.exit(1);
|
|
41818
|
-
}
|
|
41819
|
-
});
|
|
41820
|
-
program.command("complete").description("Transition an assignment to completed").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41821
|
-
try {
|
|
41928
|
+
})
|
|
41929
|
+
);
|
|
41930
|
+
program.command("complete").description("Transition an assignment to completed").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--dir <path>", "Override default project directory").action(
|
|
41931
|
+
runCommand(async (assignment, options) => {
|
|
41822
41932
|
await completeCommand(assignment, options);
|
|
41823
|
-
}
|
|
41824
|
-
|
|
41825
|
-
|
|
41826
|
-
|
|
41827
|
-
);
|
|
41828
|
-
process.exit(1);
|
|
41829
|
-
}
|
|
41830
|
-
});
|
|
41831
|
-
program.command("block").description("Assert a blocker (sets blockedReason); disposition derives to blocked").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--reason <text>", "Reason for blocking").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41832
|
-
try {
|
|
41933
|
+
})
|
|
41934
|
+
);
|
|
41935
|
+
program.command("block").description("Assert a blocker (sets blockedReason); disposition derives to blocked").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--reason <text>", "Reason for blocking").option("--dir <path>", "Override default project directory").action(
|
|
41936
|
+
runCommand(async (assignment, options) => {
|
|
41833
41937
|
await blockCommand(assignment, options);
|
|
41834
|
-
}
|
|
41835
|
-
|
|
41836
|
-
|
|
41837
|
-
|
|
41838
|
-
);
|
|
41839
|
-
process.exit(1);
|
|
41840
|
-
}
|
|
41841
|
-
});
|
|
41842
|
-
program.command("unblock").description("Clear the blocker; status re-derives from facts").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41843
|
-
try {
|
|
41938
|
+
})
|
|
41939
|
+
);
|
|
41940
|
+
program.command("unblock").description("Clear the blocker; status re-derives from facts").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--dir <path>", "Override default project directory").action(
|
|
41941
|
+
runCommand(async (assignment, options) => {
|
|
41844
41942
|
await unblockCommand(assignment, options);
|
|
41845
|
-
}
|
|
41846
|
-
|
|
41847
|
-
|
|
41848
|
-
|
|
41849
|
-
);
|
|
41850
|
-
process.exit(1);
|
|
41851
|
-
}
|
|
41852
|
-
});
|
|
41853
|
-
program.command("review").description("Request review; the review phase derives from it (or from all ACs checked)").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41854
|
-
try {
|
|
41943
|
+
})
|
|
41944
|
+
);
|
|
41945
|
+
program.command("review").description("Request review; the review phase derives from it (or from all ACs checked)").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--dir <path>", "Override default project directory").action(
|
|
41946
|
+
runCommand(async (assignment, options) => {
|
|
41855
41947
|
await reviewCommand(assignment, options);
|
|
41856
|
-
}
|
|
41857
|
-
|
|
41858
|
-
|
|
41859
|
-
|
|
41860
|
-
);
|
|
41861
|
-
process.exit(1);
|
|
41862
|
-
}
|
|
41863
|
-
});
|
|
41864
|
-
program.command("fail").description("Transition an assignment to failed").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41865
|
-
try {
|
|
41948
|
+
})
|
|
41949
|
+
);
|
|
41950
|
+
program.command("fail").description("Transition an assignment to failed").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--dir <path>", "Override default project directory").action(
|
|
41951
|
+
runCommand(async (assignment, options) => {
|
|
41866
41952
|
await failCommand(assignment, options);
|
|
41867
|
-
}
|
|
41868
|
-
|
|
41869
|
-
|
|
41870
|
-
|
|
41871
|
-
);
|
|
41872
|
-
process.exit(1);
|
|
41873
|
-
}
|
|
41874
|
-
});
|
|
41875
|
-
program.command("reopen").description("Reopen a completed or failed assignment").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--dir <path>", "Override default project directory").action(async (assignment, options) => {
|
|
41876
|
-
try {
|
|
41953
|
+
})
|
|
41954
|
+
);
|
|
41955
|
+
program.command("reopen").description("Reopen a completed or failed assignment").argument("<assignment>", "Assignment slug").option("--project <slug>", "Target project slug").option("--dir <path>", "Override default project directory").action(
|
|
41956
|
+
runCommand(async (assignment, options) => {
|
|
41877
41957
|
await reopenCommand(assignment, options);
|
|
41878
|
-
}
|
|
41879
|
-
|
|
41880
|
-
|
|
41881
|
-
|
|
41882
|
-
);
|
|
41883
|
-
process.exit(1);
|
|
41884
|
-
}
|
|
41885
|
-
});
|
|
41886
|
-
program.command("setup").description("Initialize Syntaur and optionally install plugins or launch the dashboard").option("--yes", "Skip interactive prompts and perform only the requested flags").option("--claude", "Install the Claude Code plugin").option("--codex", "Install the Codex plugin").option("--claude-dir <path>", "Install the Claude Code plugin at a specific path").option("--codex-dir <path>", "Install the Codex plugin at a specific path").option("--codex-marketplace-path <path>", "Write the Codex marketplace entry to a specific file").option("--dashboard", "Launch the dashboard after setup").option("--target <id>", "Install Syntaur into a cross-agent target. Built-in ids: pi, hermes, openclaw, cursor, opencode (plus any user descriptors in ~/.syntaur/targets/). Comma-separated for several").option("--agent <id>", "Alias for --target; cross-agent target id(s) to install into").option("--force", "Overwrite existing cross-agent protocol files / skills").option("--dry-run", "Print the cross-agent install actions without writing anything").action(async (options) => {
|
|
41887
|
-
try {
|
|
41958
|
+
})
|
|
41959
|
+
);
|
|
41960
|
+
program.command("setup").description("Initialize Syntaur and optionally install plugins or launch the dashboard").option("--yes", "Skip interactive prompts and perform only the requested flags").option("--claude", "Install the Claude Code plugin").option("--codex", "Install the Codex plugin").option("--claude-dir <path>", "Install the Claude Code plugin at a specific path").option("--codex-dir <path>", "Install the Codex plugin at a specific path").option("--codex-marketplace-path <path>", "Write the Codex marketplace entry to a specific file").option("--dashboard", "Launch the dashboard after setup").option("--target <id>", "Install Syntaur into a cross-agent target. Built-in ids: pi, hermes, openclaw, cursor, opencode (plus any user descriptors in ~/.syntaur/targets/). Comma-separated for several").option("--agent <id>", "Alias for --target; cross-agent target id(s) to install into").option("--force", "Overwrite existing cross-agent protocol files / skills").option("--dry-run", "Print the cross-agent install actions without writing anything").action(
|
|
41961
|
+
runCommand(async (options) => {
|
|
41888
41962
|
await setupCommand(options);
|
|
41889
|
-
}
|
|
41890
|
-
|
|
41891
|
-
|
|
41892
|
-
|
|
41893
|
-
);
|
|
41894
|
-
process.exit(1);
|
|
41895
|
-
}
|
|
41896
|
-
});
|
|
41897
|
-
program.command("install-plugin").description("Install the Syntaur Claude Code plugin").option("--force", "Overwrite an existing Syntaur-managed install").option("--target-dir <path>", "Install the plugin at a specific directory").option("--link", "Use a symlink instead of copying files (repo-local dev only)").option("--force-skills", "Overwrite user-edited skills in ~/.claude/skills").option("--skip-skills", "Do not install protocol skills into ~/.claude/skills").option("--enable", "Enable the plugin in ~/.claude/settings.json after install").action(async (options) => {
|
|
41898
|
-
try {
|
|
41963
|
+
})
|
|
41964
|
+
);
|
|
41965
|
+
program.command("install-plugin").description("Install the Syntaur Claude Code plugin").option("--force", "Overwrite an existing Syntaur-managed install").option("--target-dir <path>", "Install the plugin at a specific directory").option("--link", "Use a symlink instead of copying files (repo-local dev only)").option("--force-skills", "Overwrite user-edited skills in ~/.claude/skills").option("--skip-skills", "Do not install protocol skills into ~/.claude/skills").option("--enable", "Enable the plugin in ~/.claude/settings.json after install").action(
|
|
41966
|
+
runCommand(async (options) => {
|
|
41899
41967
|
await installPluginCommand({ ...options, promptForTarget: true });
|
|
41900
|
-
}
|
|
41901
|
-
|
|
41902
|
-
|
|
41903
|
-
|
|
41904
|
-
);
|
|
41905
|
-
process.exit(1);
|
|
41906
|
-
}
|
|
41907
|
-
});
|
|
41908
|
-
program.command("update").alias("upgrade").description("Self-update the global syntaur package and refresh the plugin/skills").option("--version <v>", "Update to a specific version instead of latest").option("--check", "Report whether an update is available; apply nothing").option("--dry-run", "Print what would happen without changing anything").option("--skip-refresh", "Update the package only; do not refresh the plugin/skills").option("--force-skills", "Overwrite user-edited skills during the refresh").option("--enable", "Enable the plugin in settings.json during the refresh").option("--pm <name>", "Override package-manager detection (npm|pnpm|yarn|bun)").option("--yes", "Assume yes for any confirmation (non-interactive)").action(async (options) => {
|
|
41909
|
-
try {
|
|
41968
|
+
})
|
|
41969
|
+
);
|
|
41970
|
+
program.command("update").alias("upgrade").description("Self-update the global syntaur package and refresh the plugin/skills").option("--version <v>", "Update to a specific version instead of latest").option("--check", "Report whether an update is available; apply nothing").option("--dry-run", "Print what would happen without changing anything").option("--skip-refresh", "Update the package only; do not refresh the plugin/skills").option("--force-skills", "Overwrite user-edited skills during the refresh").option("--enable", "Enable the plugin in settings.json during the refresh").option("--pm <name>", "Override package-manager detection (npm|pnpm|yarn|bun)").option("--yes", "Assume yes for any confirmation (non-interactive)").action(
|
|
41971
|
+
runCommand(async (options) => {
|
|
41910
41972
|
await updateCommand({ ...options, scriptUrl: import.meta.url });
|
|
41911
|
-
}
|
|
41912
|
-
|
|
41913
|
-
"Error:",
|
|
41914
|
-
error instanceof Error ? error.message : String(error)
|
|
41915
|
-
);
|
|
41916
|
-
process.exit(1);
|
|
41917
|
-
}
|
|
41918
|
-
});
|
|
41973
|
+
})
|
|
41974
|
+
);
|
|
41919
41975
|
program.command("install-statusline").description(
|
|
41920
41976
|
"Install the syntaur statusLine for Claude Code. Augments ~/.claude/settings.json; wraps any existing script by default."
|
|
41921
|
-
).option("--mode <mode>", "replace | wrap | skip | ask (default: ask, wrap in non-TTY)", "ask").option("--link", "Symlink the installed script to the package source (dev mode)").action(
|
|
41922
|
-
|
|
41977
|
+
).option("--mode <mode>", "replace | wrap | skip | ask (default: ask, wrap in non-TTY)", "ask").option("--link", "Symlink the installed script to the package source (dev mode)").action(
|
|
41978
|
+
runCommand(async (options) => {
|
|
41923
41979
|
const rawMode = (options.mode ?? "ask").toLowerCase();
|
|
41924
41980
|
const valid = ["replace", "wrap", "skip", "ask"];
|
|
41925
41981
|
if (!valid.includes(rawMode)) {
|
|
@@ -41931,21 +41987,15 @@ program.command("install-statusline").description(
|
|
|
41931
41987
|
mode: rawMode,
|
|
41932
41988
|
link: options.link
|
|
41933
41989
|
});
|
|
41934
|
-
}
|
|
41935
|
-
|
|
41936
|
-
process.exit(1);
|
|
41937
|
-
}
|
|
41938
|
-
});
|
|
41990
|
+
})
|
|
41991
|
+
);
|
|
41939
41992
|
program.command("uninstall-statusline").description(
|
|
41940
41993
|
"Remove the syntaur statusLine. Restores the previously configured command from backup if present."
|
|
41941
|
-
).option("--keep-script", "Leave ~/.syntaur/statusline.sh on disk (only edit settings.json)").action(
|
|
41942
|
-
|
|
41994
|
+
).option("--keep-script", "Leave ~/.syntaur/statusline.sh on disk (only edit settings.json)").action(
|
|
41995
|
+
runCommand(async (options) => {
|
|
41943
41996
|
await uninstallStatuslineCommand({ keepScript: options.keepScript });
|
|
41944
|
-
}
|
|
41945
|
-
|
|
41946
|
-
process.exit(1);
|
|
41947
|
-
}
|
|
41948
|
-
});
|
|
41997
|
+
})
|
|
41998
|
+
);
|
|
41949
41999
|
program.command("configure-statusline").description(
|
|
41950
42000
|
"Configure which segments (git, assignment, session, model, ctx, cwd, wrap) appear in the syntaur statusLine and in what order."
|
|
41951
42001
|
).option(
|
|
@@ -41954,55 +42004,31 @@ program.command("configure-statusline").description(
|
|
|
41954
42004
|
).option(
|
|
41955
42005
|
"--segments <list>",
|
|
41956
42006
|
'Comma-separated segment list, e.g. "git,assignment,session,model,ctx".'
|
|
41957
|
-
).option("--separator <string>", 'Segment separator (default " \xB7 ")').option("--wrap <path>", 'Path to an external statusline script to compose as a "wrap" segment').option("--preview", "Print the resolved config and a preview line without writing").action(
|
|
41958
|
-
|
|
42007
|
+
).option("--separator <string>", 'Segment separator (default " \xB7 ")').option("--wrap <path>", 'Path to an external statusline script to compose as a "wrap" segment').option("--preview", "Print the resolved config and a preview line without writing").action(
|
|
42008
|
+
runCommand(async (options) => {
|
|
41959
42009
|
await configureStatuslineCommand(options);
|
|
41960
|
-
}
|
|
41961
|
-
|
|
41962
|
-
|
|
41963
|
-
|
|
41964
|
-
});
|
|
41965
|
-
program.command("uninstall-skills").description("Remove Syntaur protocol skills from ~/.claude/skills and/or ~/.codex/skills").option("--claude", "Remove from ~/.claude/skills").option("--codex", "Remove from ~/.codex/skills").option("--all", "Remove from both").action(async (options) => {
|
|
41966
|
-
try {
|
|
42010
|
+
})
|
|
42011
|
+
);
|
|
42012
|
+
program.command("uninstall-skills").description("Remove Syntaur protocol skills from ~/.claude/skills and/or ~/.codex/skills").option("--claude", "Remove from ~/.claude/skills").option("--codex", "Remove from ~/.codex/skills").option("--all", "Remove from both").action(
|
|
42013
|
+
runCommand(async (options) => {
|
|
41967
42014
|
await uninstallSkillsCommand(options);
|
|
41968
|
-
}
|
|
41969
|
-
|
|
41970
|
-
|
|
41971
|
-
|
|
41972
|
-
});
|
|
41973
|
-
program.command("install-codex-plugin").description("Install the Syntaur Codex plugin and marketplace entry").option("--force", "Overwrite an existing Syntaur-managed install").option("--target-dir <path>", "Install the plugin at a specific directory").option("--marketplace-path <path>", "Write the marketplace entry to a specific file").option("--link", "Use a symlink instead of copying files (repo-local dev only)").option("--force-skills", "Overwrite user-edited skills in ~/.codex/skills").option("--skip-skills", "Do not install protocol skills into ~/.codex/skills").action(async (options) => {
|
|
41974
|
-
try {
|
|
42015
|
+
})
|
|
42016
|
+
);
|
|
42017
|
+
program.command("install-codex-plugin").description("Install the Syntaur Codex plugin and marketplace entry").option("--force", "Overwrite an existing Syntaur-managed install").option("--target-dir <path>", "Install the plugin at a specific directory").option("--marketplace-path <path>", "Write the marketplace entry to a specific file").option("--link", "Use a symlink instead of copying files (repo-local dev only)").option("--force-skills", "Overwrite user-edited skills in ~/.codex/skills").option("--skip-skills", "Do not install protocol skills into ~/.codex/skills").action(
|
|
42018
|
+
runCommand(async (options) => {
|
|
41975
42019
|
await installCodexPluginCommand({ ...options, promptForTarget: true });
|
|
41976
|
-
}
|
|
41977
|
-
|
|
41978
|
-
|
|
41979
|
-
|
|
41980
|
-
);
|
|
41981
|
-
process.exit(1);
|
|
41982
|
-
}
|
|
41983
|
-
});
|
|
41984
|
-
program.command("uninstall").description("Remove Syntaur integrations and optionally local data").option("--claude", "Remove only the Claude Code plugin").option("--codex", "Remove only the Codex plugin and marketplace entry").option("--data", "Remove ~/.syntaur data").option("--all", "Remove plugins and ~/.syntaur data").option("--yes", "Skip confirmation prompts").action(async (options) => {
|
|
41985
|
-
try {
|
|
42020
|
+
})
|
|
42021
|
+
);
|
|
42022
|
+
program.command("uninstall").description("Remove Syntaur integrations and optionally local data").option("--claude", "Remove only the Claude Code plugin").option("--codex", "Remove only the Codex plugin and marketplace entry").option("--data", "Remove ~/.syntaur data").option("--all", "Remove plugins and ~/.syntaur data").option("--yes", "Skip confirmation prompts").action(
|
|
42023
|
+
runCommand(async (options) => {
|
|
41986
42024
|
await uninstallCommand(options);
|
|
41987
|
-
}
|
|
41988
|
-
|
|
41989
|
-
|
|
41990
|
-
|
|
41991
|
-
);
|
|
41992
|
-
process.exit(1);
|
|
41993
|
-
}
|
|
41994
|
-
});
|
|
41995
|
-
program.command("setup-adapter").description("Generate adapter instruction files for a framework in the current directory").argument("<framework>", "Target framework: built-in ids cursor, codex, opencode, pi, openclaw, hermes (plus any user descriptor with an instructions adapter in ~/.syntaur/targets/)").option("--project <slug>", "Target project slug (required)").option("--assignment <slug>", "Target assignment slug (required)").option("--force", "Overwrite existing adapter files").option("--dir <path>", "Override default project directory").action(async (framework, options) => {
|
|
41996
|
-
try {
|
|
42025
|
+
})
|
|
42026
|
+
);
|
|
42027
|
+
program.command("setup-adapter").description("Generate adapter instruction files for a framework in the current directory").argument("<framework>", "Target framework: built-in ids cursor, codex, opencode, pi, openclaw, hermes (plus any user descriptor with an instructions adapter in ~/.syntaur/targets/)").option("--project <slug>", "Target project slug (required)").option("--assignment <slug>", "Target assignment slug (required)").option("--force", "Overwrite existing adapter files").option("--dir <path>", "Override default project directory").action(
|
|
42028
|
+
runCommand(async (framework, options) => {
|
|
41997
42029
|
await setupAdapterCommand(framework, options);
|
|
41998
|
-
}
|
|
41999
|
-
|
|
42000
|
-
"Error:",
|
|
42001
|
-
error instanceof Error ? error.message : String(error)
|
|
42002
|
-
);
|
|
42003
|
-
process.exit(1);
|
|
42004
|
-
}
|
|
42005
|
-
});
|
|
42030
|
+
})
|
|
42031
|
+
);
|
|
42006
42032
|
program.command("track-session").description("Register an agent session (optionally linked to a project/assignment)").option("--project <slug>", "Target project slug").option("--assignment <slug>", "Assignment slug").option("--agent <name>", "Agent name, e.g. claude, codex, cursor (required)").option(
|
|
42007
42033
|
"--session-id <id>",
|
|
42008
42034
|
"Session id from the agent runtime (real, not generated). Defaults to self-resolution via env / process-tree markers / transcript scan \u2014 pass explicitly only when registering a session other than the calling one."
|
|
@@ -42019,17 +42045,11 @@ program.command("track-session").description("Register an agent session (optiona
|
|
|
42019
42045
|
}
|
|
42020
42046
|
return n;
|
|
42021
42047
|
}
|
|
42022
|
-
).action(
|
|
42023
|
-
|
|
42048
|
+
).action(
|
|
42049
|
+
runCommand(async (options) => {
|
|
42024
42050
|
await trackSessionCommand(options);
|
|
42025
|
-
}
|
|
42026
|
-
|
|
42027
|
-
"Error:",
|
|
42028
|
-
error instanceof Error ? error.message : String(error)
|
|
42029
|
-
);
|
|
42030
|
-
process.exit(1);
|
|
42031
|
-
}
|
|
42032
|
-
});
|
|
42051
|
+
})
|
|
42052
|
+
);
|
|
42033
42053
|
program.command("url <url>").description(
|
|
42034
42054
|
"Open an assignment or session in the configured terminal + agent (handles syntaur:// deep links)"
|
|
42035
42055
|
).option(
|
|
@@ -42053,83 +42073,41 @@ program.command("install-url-handler").description(
|
|
|
42053
42073
|
process.exit(1);
|
|
42054
42074
|
}
|
|
42055
42075
|
});
|
|
42056
|
-
program.command("browse").description("Interactive TUI browser for projects and assignments").option("--agent <id>", "Bypass the agent picker and launch the given configured agent id").option("--no-worktree-prompt", "Skip the prompt to create a worktree when one is missing").action(
|
|
42057
|
-
|
|
42076
|
+
program.command("browse").description("Interactive TUI browser for projects and assignments").option("--agent <id>", "Bypass the agent picker and launch the given configured agent id").option("--no-worktree-prompt", "Skip the prompt to create a worktree when one is missing").action(
|
|
42077
|
+
runCommand(async (options) => {
|
|
42058
42078
|
await browseCommand(options);
|
|
42059
|
-
}
|
|
42060
|
-
|
|
42061
|
-
|
|
42062
|
-
|
|
42063
|
-
);
|
|
42064
|
-
process.exit(1);
|
|
42065
|
-
}
|
|
42066
|
-
});
|
|
42067
|
-
program.command("create-playbook").description("Create a new playbook").argument("<name>", "Playbook name").option("--slug <slug>", "Override auto-generated slug").option("--description <desc>", "Playbook description").action(async (name, options) => {
|
|
42068
|
-
try {
|
|
42079
|
+
})
|
|
42080
|
+
);
|
|
42081
|
+
program.command("create-playbook").description("Create a new playbook").argument("<name>", "Playbook name").option("--slug <slug>", "Override auto-generated slug").option("--description <desc>", "Playbook description").action(
|
|
42082
|
+
runCommand(async (name, options) => {
|
|
42069
42083
|
await createPlaybookCommand(name, options);
|
|
42070
|
-
}
|
|
42071
|
-
|
|
42072
|
-
|
|
42073
|
-
|
|
42074
|
-
);
|
|
42075
|
-
process.exit(1);
|
|
42076
|
-
}
|
|
42077
|
-
});
|
|
42078
|
-
program.command("list-playbooks").description("List playbooks (disabled playbooks are excluded unless --all is passed)").option("--all", "Include disabled playbooks").action(async (options) => {
|
|
42079
|
-
try {
|
|
42084
|
+
})
|
|
42085
|
+
);
|
|
42086
|
+
program.command("list-playbooks").description("List playbooks (disabled playbooks are excluded unless --all is passed)").option("--all", "Include disabled playbooks").action(
|
|
42087
|
+
runCommand(async (options) => {
|
|
42080
42088
|
await listPlaybooksCommand({ all: Boolean(options?.all) });
|
|
42081
|
-
}
|
|
42082
|
-
|
|
42083
|
-
|
|
42084
|
-
|
|
42085
|
-
);
|
|
42086
|
-
process.exit(1);
|
|
42087
|
-
}
|
|
42088
|
-
});
|
|
42089
|
-
program.command("enable-playbook").description("Enable a previously-disabled playbook").argument("<slug>", "Playbook slug").action(async (slug) => {
|
|
42090
|
-
try {
|
|
42089
|
+
})
|
|
42090
|
+
);
|
|
42091
|
+
program.command("enable-playbook").description("Enable a previously-disabled playbook").argument("<slug>", "Playbook slug").action(
|
|
42092
|
+
runCommand(async (slug) => {
|
|
42091
42093
|
await enablePlaybookCommand(slug);
|
|
42092
|
-
}
|
|
42093
|
-
|
|
42094
|
-
|
|
42095
|
-
|
|
42096
|
-
);
|
|
42097
|
-
process.exit(1);
|
|
42098
|
-
}
|
|
42099
|
-
});
|
|
42100
|
-
program.command("disable-playbook").description("Disable a playbook so agents no longer load it").argument("<slug>", "Playbook slug").action(async (slug) => {
|
|
42101
|
-
try {
|
|
42094
|
+
})
|
|
42095
|
+
);
|
|
42096
|
+
program.command("disable-playbook").description("Disable a playbook so agents no longer load it").argument("<slug>", "Playbook slug").action(
|
|
42097
|
+
runCommand(async (slug) => {
|
|
42102
42098
|
await disablePlaybookCommand(slug);
|
|
42103
|
-
}
|
|
42104
|
-
|
|
42105
|
-
|
|
42106
|
-
|
|
42107
|
-
);
|
|
42108
|
-
process.exit(1);
|
|
42109
|
-
}
|
|
42110
|
-
});
|
|
42111
|
-
program.command("delete-playbook").description("Delete a playbook from disk and regenerate the manifest").argument("<slug>", "Playbook slug").action(async (slug) => {
|
|
42112
|
-
try {
|
|
42099
|
+
})
|
|
42100
|
+
);
|
|
42101
|
+
program.command("delete-playbook").description("Delete a playbook from disk and regenerate the manifest").argument("<slug>", "Playbook slug").action(
|
|
42102
|
+
runCommand(async (slug) => {
|
|
42113
42103
|
await deletePlaybookCommand(slug);
|
|
42114
|
-
}
|
|
42115
|
-
|
|
42116
|
-
|
|
42117
|
-
|
|
42118
|
-
);
|
|
42119
|
-
process.exit(1);
|
|
42120
|
-
}
|
|
42121
|
-
});
|
|
42122
|
-
program.command("regen-playbook-manifest").description("Rebuild ~/.syntaur/playbooks/manifest.md from current playbook files").action(async () => {
|
|
42123
|
-
try {
|
|
42104
|
+
})
|
|
42105
|
+
);
|
|
42106
|
+
program.command("regen-playbook-manifest").description("Rebuild ~/.syntaur/playbooks/manifest.md from current playbook files").action(
|
|
42107
|
+
runCommand(async () => {
|
|
42124
42108
|
await regenPlaybookManifestCommand();
|
|
42125
|
-
}
|
|
42126
|
-
|
|
42127
|
-
"Error:",
|
|
42128
|
-
error instanceof Error ? error.message : String(error)
|
|
42129
|
-
);
|
|
42130
|
-
process.exit(1);
|
|
42131
|
-
}
|
|
42132
|
-
});
|
|
42109
|
+
})
|
|
42110
|
+
);
|
|
42133
42111
|
program.addCommand(todoCommand);
|
|
42134
42112
|
program.addCommand(backupCommand);
|
|
42135
42113
|
program.addCommand(doctorCommand);
|
|
@@ -42148,6 +42126,21 @@ program.addCommand(progressCommand);
|
|
|
42148
42126
|
program.addCommand(leaseCommand);
|
|
42149
42127
|
program.addCommand(scheduleCommand);
|
|
42150
42128
|
program.addCommand(usageCommand);
|
|
42129
|
+
program.addHelpText(
|
|
42130
|
+
"after",
|
|
42131
|
+
`
|
|
42132
|
+
Common workflow:
|
|
42133
|
+
$ syntaur setup Initialize Syntaur (plugins, dashboard)
|
|
42134
|
+
$ syntaur create-project "My App" Start a new project
|
|
42135
|
+
$ syntaur create-assignment --project my-app "Add login" Add a task to a project
|
|
42136
|
+
$ syntaur browse Interactive TUI: pick & launch work
|
|
42137
|
+
$ syntaur dashboard Open the local web dashboard
|
|
42138
|
+
$ syntaur doctor Diagnose Syntaur state & suggested fixes
|
|
42139
|
+
|
|
42140
|
+
Run 'syntaur <command> --help' for command-specific options.
|
|
42141
|
+
Migration/internal commands (migrate-*, regen-playbook-manifest) are advanced; most
|
|
42142
|
+
workflows never need them.`
|
|
42143
|
+
);
|
|
42151
42144
|
if (process.argv.length <= 2) {
|
|
42152
42145
|
process.argv.push(await getDefaultCommandName());
|
|
42153
42146
|
}
|