syntaur 0.74.0 → 0.76.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-CBNQaqzq.js → _basePickBy-BiwSunXO.js} +1 -1
- package/dashboard/dist/assets/{_baseUniq-Bqwz8hnN.js → _baseUniq-DsjKPXxP.js} +1 -1
- package/dashboard/dist/assets/{arc-B6lVW0Fc.js → arc-DlEs4wsF.js} +1 -1
- package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-eKpHkGki.js → architectureDiagram-2XIMDMQ5-DPvCrO57.js} +1 -1
- package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-D3sd7ccQ.js → blockDiagram-WCTKOSBZ-CpNdCY-r.js} +1 -1
- package/dashboard/dist/assets/{c4Diagram-IC4MRINW-0qW21hVQ.js → c4Diagram-IC4MRINW-CC29QJCs.js} +1 -1
- package/dashboard/dist/assets/channel-IutbH48W.js +1 -0
- package/dashboard/dist/assets/{chunk-4BX2VUAB-tDdoFSYw.js → chunk-4BX2VUAB-DKyy-k2D.js} +1 -1
- package/dashboard/dist/assets/{chunk-55IACEB6-BU45eS64.js → chunk-55IACEB6-DjobngQk.js} +1 -1
- package/dashboard/dist/assets/{chunk-FMBD7UC4-C0iT8QWM.js → chunk-FMBD7UC4-BUftm7dV.js} +1 -1
- package/dashboard/dist/assets/{chunk-JSJVCQXG-CELv9Y6Y.js → chunk-JSJVCQXG-Nv7rQv4t.js} +1 -1
- package/dashboard/dist/assets/{chunk-KX2RTZJC-CQA_hH8g.js → chunk-KX2RTZJC-Dg6UhNB9.js} +1 -1
- package/dashboard/dist/assets/{chunk-NQ4KR5QH-BDv-d6qz.js → chunk-NQ4KR5QH-D8neQrJ_.js} +1 -1
- package/dashboard/dist/assets/{chunk-QZHKN3VN-BUOeJd34.js → chunk-QZHKN3VN-Uj9c1naA.js} +1 -1
- package/dashboard/dist/assets/{chunk-WL4C6EOR-DBc-Hsx0.js → chunk-WL4C6EOR-DfeSsP3z.js} +1 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-8IywRj9I.js +1 -0
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-8IywRj9I.js +1 -0
- package/dashboard/dist/assets/clone-C6saGiCd.js +1 -0
- package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-C_Q4c3xo.js → cose-bilkent-S5V4N54A-CLfZNKcO.js} +1 -1
- package/dashboard/dist/assets/{dagre-KLK3FWXG-DdI10bBF.js → dagre-KLK3FWXG-DyJLICZx.js} +1 -1
- package/dashboard/dist/assets/{diagram-E7M64L7V-DtCF4Ea9.js → diagram-E7M64L7V-DhQc7Ta3.js} +1 -1
- package/dashboard/dist/assets/{diagram-IFDJBPK2-BVmpBmIK.js → diagram-IFDJBPK2-C6kFO7hB.js} +1 -1
- package/dashboard/dist/assets/{diagram-P4PSJMXO-BH4XFc0W.js → diagram-P4PSJMXO-B6oCiOXk.js} +1 -1
- package/dashboard/dist/assets/{erDiagram-INFDFZHY-CCjG3Ewp.js → erDiagram-INFDFZHY-BsMPaSwJ.js} +1 -1
- package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-V0PT07-Y.js → flowDiagram-PKNHOUZH-DLxEqKtZ.js} +1 -1
- package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-y_85pJZf.js → ganttDiagram-A5KZAMGK-D70pvqxG.js} +1 -1
- package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-B2maPPcL.js → gitGraphDiagram-K3NZZRJ6-D74VHtlE.js} +1 -1
- package/dashboard/dist/assets/{graph-DO1oCTrt.js → graph-C8bz_IEO.js} +1 -1
- package/dashboard/dist/assets/{index-BZwPAi8K.css → index-BetqH_3H.css} +1 -1
- package/dashboard/dist/assets/index-h-X_8om3.js +675 -0
- package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-BIaqpTlK.js → infoDiagram-LFFYTUFH-DivBd0Pz.js} +1 -1
- package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-BaBqTUzg.js → ishikawaDiagram-PHBUUO56-BGihUeOE.js} +1 -1
- package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-CS2l7gmE.js → journeyDiagram-4ABVD52K-C7U4cWHQ.js} +1 -1
- package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-B3Viag1o.js → kanban-definition-K7BYSVSG-CFp_hDTm.js} +1 -1
- package/dashboard/dist/assets/{layout-BQu5nxr5.js → layout-DMSDPqCs.js} +1 -1
- package/dashboard/dist/assets/{linear-DliLQN5_.js → linear-CCC-meYc.js} +1 -1
- package/dashboard/dist/assets/{mermaid.core-y_G2N_4o.js → mermaid.core-BDa2cc2K.js} +4 -4
- package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-EZz-bEA_.js → mindmap-definition-YRQLILUH-DLKvONhO.js} +1 -1
- package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-E67ZAs-E.js → pieDiagram-SKSYHLDU-DAJoGZ93.js} +1 -1
- package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-GU25jLyr.js → quadrantDiagram-337W2JSQ-Bo7haX1W.js} +1 -1
- package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-4Jfq0mB9.js → requirementDiagram-Z7DCOOCP-uEvGz33v.js} +1 -1
- package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-C22SY4ul.js → sankeyDiagram-WA2Y5GQK-cjYoCGCM.js} +1 -1
- package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-CkBh7V9t.js → sequenceDiagram-2WXFIKYE-CYXcNklt.js} +1 -1
- package/dashboard/dist/assets/{stateDiagram-RAJIS63D-n4DRlbfF.js → stateDiagram-RAJIS63D-B5We7jAw.js} +1 -1
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-CX9-EpBi.js +1 -0
- package/dashboard/dist/assets/{timeline-definition-YZTLITO2-CGD5ojK7.js → timeline-definition-YZTLITO2-CEqVmnVQ.js} +1 -1
- package/dashboard/dist/assets/{treemap-KZPCXAKY-EZfHxNz6.js → treemap-KZPCXAKY-CE1puPeN.js} +1 -1
- package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-B9x6fx-l.js → vennDiagram-LZ73GAT5-CiiuRUjK.js} +1 -1
- package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-ufzpkH1I.js → xychartDiagram-JWTSCODW-B0OuxFm9.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/dist/dashboard/server.js +509 -221
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.js +1210 -823
- package/dist/index.js.map +1 -1
- package/dist/launch/index.d.ts +69 -7
- package/dist/launch/index.js +229 -24
- package/dist/launch/index.js.map +1 -1
- package/package.json +1 -1
- package/platforms/claude-code/.claude-plugin/plugin.json +1 -1
- package/platforms/codex/.codex-plugin/plugin.json +1 -1
- package/platforms/hermes/plugins/syntaur/__pycache__/__init__.cpython-312.pyc +0 -0
- package/platforms/hermes/plugins/syntaur/__pycache__/boundary.cpython-312.pyc +0 -0
- package/dashboard/dist/assets/channel-BDsImlpM.js +0 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-BhdNnCQ2.js +0 -1
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-BhdNnCQ2.js +0 -1
- package/dashboard/dist/assets/clone-B5RwQsX7.js +0 -1
- package/dashboard/dist/assets/index-CG8rQF5o.js +0 -670
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-RpTmT3-9.js +0 -1
package/dist/index.js
CHANGED
|
@@ -2643,6 +2643,10 @@ function modelFlagArgs(agent) {
|
|
|
2643
2643
|
const m = agent.model?.trim();
|
|
2644
2644
|
return m ? ["--model", m] : [];
|
|
2645
2645
|
}
|
|
2646
|
+
function agentNameArgs(agent) {
|
|
2647
|
+
const n = agent.agentName?.trim();
|
|
2648
|
+
return n ? ["--agent", n] : [];
|
|
2649
|
+
}
|
|
2646
2650
|
function stripModelFlags(args) {
|
|
2647
2651
|
const out = [];
|
|
2648
2652
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -3998,6 +4002,26 @@ function validateAgentList(agents) {
|
|
|
3998
4002
|
`agent "${agent.id}" has invalid launchPrompt \u2014 must be a single line (no newlines)`
|
|
3999
4003
|
);
|
|
4000
4004
|
}
|
|
4005
|
+
if (agent.agentName !== void 0 && /[\r\n]/.test(agent.agentName)) {
|
|
4006
|
+
throw new AgentConfigError(
|
|
4007
|
+
`agent "${agent.id}" has invalid agentName \u2014 must be a single line (no newlines)`
|
|
4008
|
+
);
|
|
4009
|
+
}
|
|
4010
|
+
if (agent.workdir !== void 0 && /[\r\n]/.test(agent.workdir)) {
|
|
4011
|
+
throw new AgentConfigError(
|
|
4012
|
+
`agent "${agent.id}" has invalid workdir \u2014 must be a single line (no newlines)`
|
|
4013
|
+
);
|
|
4014
|
+
}
|
|
4015
|
+
if (agent.agentName !== void 0 && agent.agentName.trim() !== "" && agent.workdir !== void 0 && agent.workdir.trim() !== "") {
|
|
4016
|
+
throw new AgentConfigError(
|
|
4017
|
+
`agent "${agent.id}" sets both agentName and workdir \u2014 these are mutually exclusive`
|
|
4018
|
+
);
|
|
4019
|
+
}
|
|
4020
|
+
if (agent.agentName !== void 0 && agent.agentName.trim() !== "" && agent.model !== void 0 && agent.model.trim() !== "") {
|
|
4021
|
+
throw new AgentConfigError(
|
|
4022
|
+
`agent "${agent.id}" sets both agentName and model \u2014 the agent definition's own model is authoritative; remove the profile model`
|
|
4023
|
+
);
|
|
4024
|
+
}
|
|
4001
4025
|
validateSessionInvocation(agent, "resume", agent.resume);
|
|
4002
4026
|
validateSessionInvocation(agent, "fork", agent.fork);
|
|
4003
4027
|
if (agent.default) defaults++;
|
|
@@ -4818,6 +4842,8 @@ function parseAgentsConfig(content) {
|
|
|
4818
4842
|
...current.model ? { model: current.model } : {},
|
|
4819
4843
|
...current.playbook ? { playbook: current.playbook } : {},
|
|
4820
4844
|
...current.launchPrompt ? { launchPrompt: current.launchPrompt } : {},
|
|
4845
|
+
...current.agentName ? { agentName: current.agentName } : {},
|
|
4846
|
+
...current.workdir ? { workdir: current.workdir } : {},
|
|
4821
4847
|
...current.resume ? { resume: current.resume } : {},
|
|
4822
4848
|
...current.fork ? { fork: current.fork } : {}
|
|
4823
4849
|
});
|
|
@@ -5009,6 +5035,12 @@ function assignAgentField(target, key, rawValue) {
|
|
|
5009
5035
|
case "launchPrompt":
|
|
5010
5036
|
target.launchPrompt = value;
|
|
5011
5037
|
break;
|
|
5038
|
+
case "agentName":
|
|
5039
|
+
target.agentName = value;
|
|
5040
|
+
break;
|
|
5041
|
+
case "workdir":
|
|
5042
|
+
target.workdir = value;
|
|
5043
|
+
break;
|
|
5012
5044
|
}
|
|
5013
5045
|
}
|
|
5014
5046
|
function yamlQuoteScalar(value) {
|
|
@@ -5038,6 +5070,12 @@ function serializeAgentsConfig(agents) {
|
|
|
5038
5070
|
if (a.launchPrompt) {
|
|
5039
5071
|
lines.push(` launchPrompt: ${yamlQuoteScalar(a.launchPrompt)}`);
|
|
5040
5072
|
}
|
|
5073
|
+
if (a.agentName) {
|
|
5074
|
+
lines.push(` agentName: ${yamlQuoteScalar(a.agentName)}`);
|
|
5075
|
+
}
|
|
5076
|
+
if (a.workdir) {
|
|
5077
|
+
lines.push(` workdir: ${yamlQuoteScalar(a.workdir)}`);
|
|
5078
|
+
}
|
|
5041
5079
|
if (a.args && a.args.length > 0) {
|
|
5042
5080
|
lines.push(` args:`);
|
|
5043
5081
|
for (const arg of a.args) {
|
|
@@ -5685,7 +5723,9 @@ var init_config2 = __esm({
|
|
|
5685
5723
|
"resolveFromShellAliases",
|
|
5686
5724
|
"model",
|
|
5687
5725
|
"playbook",
|
|
5688
|
-
"launchPrompt"
|
|
5726
|
+
"launchPrompt",
|
|
5727
|
+
"agentName",
|
|
5728
|
+
"workdir"
|
|
5689
5729
|
]);
|
|
5690
5730
|
migratedConfigPaths = /* @__PURE__ */ new Set();
|
|
5691
5731
|
TerminalConfigError = class extends Error {
|
|
@@ -7269,6 +7309,21 @@ function resolveWorkspaceCwd(input4) {
|
|
|
7269
7309
|
invalidReason: `workspace path invalid for ${assignmentSlug}: tried worktreePath ${shown(worktreePath)} and repository ${shown(repository)} \u2014 neither is an existing directory`
|
|
7270
7310
|
};
|
|
7271
7311
|
}
|
|
7312
|
+
function resolveLaunchCwd(agent, worktreeCwd) {
|
|
7313
|
+
const wd = agent.workdir?.trim();
|
|
7314
|
+
if (wd) {
|
|
7315
|
+
const expanded = expandHome(wd);
|
|
7316
|
+
if (!isExistingDir(expanded)) {
|
|
7317
|
+
return {
|
|
7318
|
+
spawnCwd: worktreeCwd,
|
|
7319
|
+
worktreePath: worktreeCwd,
|
|
7320
|
+
invalidReason: `agent "${agent.id}" workdir ${agent.workdir} (resolved ${expanded}) is not an existing directory`
|
|
7321
|
+
};
|
|
7322
|
+
}
|
|
7323
|
+
return { spawnCwd: expanded, worktreePath: worktreeCwd, invalidReason: null };
|
|
7324
|
+
}
|
|
7325
|
+
return { spawnCwd: worktreeCwd, worktreePath: worktreeCwd, invalidReason: null };
|
|
7326
|
+
}
|
|
7272
7327
|
function formatFallbackCwdWarning(opts) {
|
|
7273
7328
|
const missing = [];
|
|
7274
7329
|
if (!opts.worktreePath) missing.push("worktreePath");
|
|
@@ -7280,6 +7335,7 @@ function formatFallbackCwdWarning(opts) {
|
|
|
7280
7335
|
var init_cwd = __esm({
|
|
7281
7336
|
"src/launch/cwd.ts"() {
|
|
7282
7337
|
"use strict";
|
|
7338
|
+
init_paths();
|
|
7283
7339
|
}
|
|
7284
7340
|
});
|
|
7285
7341
|
|
|
@@ -9220,8 +9276,8 @@ async function migrateFromMarkdown(projectsDir2) {
|
|
|
9220
9276
|
return allSessions.length;
|
|
9221
9277
|
}
|
|
9222
9278
|
async function parseMarkdownSessionsIndex(filePath, projectSlug) {
|
|
9223
|
-
const { readFile:
|
|
9224
|
-
const raw2 = await
|
|
9279
|
+
const { readFile: readFile82 } = await import("fs/promises");
|
|
9280
|
+
const raw2 = await readFile82(filePath, "utf-8");
|
|
9225
9281
|
const sessions = [];
|
|
9226
9282
|
const lines = raw2.split("\n");
|
|
9227
9283
|
let inTable = false;
|
|
@@ -13535,6 +13591,425 @@ var init_session_id = __esm({
|
|
|
13535
13591
|
}
|
|
13536
13592
|
});
|
|
13537
13593
|
|
|
13594
|
+
// src/targets/renderers.ts
|
|
13595
|
+
var RENDERERS;
|
|
13596
|
+
var init_renderers = __esm({
|
|
13597
|
+
"src/targets/renderers.ts"() {
|
|
13598
|
+
"use strict";
|
|
13599
|
+
init_cursor_rules();
|
|
13600
|
+
init_codex_agents();
|
|
13601
|
+
init_opencode_config();
|
|
13602
|
+
init_hermes_soul();
|
|
13603
|
+
RENDERERS = {
|
|
13604
|
+
codexAgents: (ctx) => renderCodexAgents(ctx),
|
|
13605
|
+
cursorProtocol: () => renderCursorProtocol(),
|
|
13606
|
+
cursorAssignment: (ctx) => renderCursorAssignment(ctx),
|
|
13607
|
+
openCodeConfig: (ctx) => renderOpenCodeConfig({ projectDir: ctx.projectDir }),
|
|
13608
|
+
hermesSoul: (ctx) => renderHermesSoul(ctx)
|
|
13609
|
+
};
|
|
13610
|
+
}
|
|
13611
|
+
});
|
|
13612
|
+
|
|
13613
|
+
// src/targets/user-descriptors.ts
|
|
13614
|
+
import { resolve as resolve29 } from "path";
|
|
13615
|
+
import { readFile as readFile20, readdir as readdir15 } from "fs/promises";
|
|
13616
|
+
function userTargetsDir() {
|
|
13617
|
+
return resolve29(syntaurRoot(), "targets");
|
|
13618
|
+
}
|
|
13619
|
+
function msg(err2) {
|
|
13620
|
+
return err2 instanceof Error ? err2.message : String(err2);
|
|
13621
|
+
}
|
|
13622
|
+
function expandHomeAndEnv(p) {
|
|
13623
|
+
const envExpanded = p.replace(
|
|
13624
|
+
/\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g,
|
|
13625
|
+
(_m, braced, bare) => {
|
|
13626
|
+
const name = braced ?? bare ?? "";
|
|
13627
|
+
const v = process.env[name];
|
|
13628
|
+
return v ?? "";
|
|
13629
|
+
}
|
|
13630
|
+
);
|
|
13631
|
+
return resolve29(expandHome(envExpanded));
|
|
13632
|
+
}
|
|
13633
|
+
function compileDetect(spec) {
|
|
13634
|
+
switch (spec.kind) {
|
|
13635
|
+
case "pathExists": {
|
|
13636
|
+
const p = expandHomeAndEnv(spec.path);
|
|
13637
|
+
return () => fileExists(p);
|
|
13638
|
+
}
|
|
13639
|
+
case "anyPathExists": {
|
|
13640
|
+
const ps = spec.paths.map(expandHomeAndEnv);
|
|
13641
|
+
return async () => {
|
|
13642
|
+
for (const p of ps) {
|
|
13643
|
+
if (await fileExists(p)) return true;
|
|
13644
|
+
}
|
|
13645
|
+
return false;
|
|
13646
|
+
};
|
|
13647
|
+
}
|
|
13648
|
+
case "envSet": {
|
|
13649
|
+
const env = spec.env;
|
|
13650
|
+
return async () => {
|
|
13651
|
+
const v = process.env[env];
|
|
13652
|
+
return typeof v === "string" && v.length > 0;
|
|
13653
|
+
};
|
|
13654
|
+
}
|
|
13655
|
+
}
|
|
13656
|
+
}
|
|
13657
|
+
function isPlainObject(v) {
|
|
13658
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
13659
|
+
}
|
|
13660
|
+
function validateDetect(detect, errors) {
|
|
13661
|
+
if (!isPlainObject(detect)) {
|
|
13662
|
+
errors.push("detect must be an object");
|
|
13663
|
+
return;
|
|
13664
|
+
}
|
|
13665
|
+
switch (detect.kind) {
|
|
13666
|
+
case "pathExists":
|
|
13667
|
+
if (typeof detect.path !== "string" || detect.path.length === 0)
|
|
13668
|
+
errors.push('detect.path must be a non-empty string for kind "pathExists"');
|
|
13669
|
+
break;
|
|
13670
|
+
case "anyPathExists":
|
|
13671
|
+
if (!Array.isArray(detect.paths) || detect.paths.length === 0 || !detect.paths.every((p) => typeof p === "string" && p.length > 0))
|
|
13672
|
+
errors.push('detect.paths must be a non-empty string[] for kind "anyPathExists"');
|
|
13673
|
+
break;
|
|
13674
|
+
case "envSet":
|
|
13675
|
+
if (typeof detect.env !== "string" || detect.env.length === 0)
|
|
13676
|
+
errors.push('detect.env must be a non-empty string for kind "envSet"');
|
|
13677
|
+
break;
|
|
13678
|
+
default:
|
|
13679
|
+
errors.push(
|
|
13680
|
+
`detect.kind must be one of pathExists|anyPathExists|envSet (got ${JSON.stringify(detect.kind)})`
|
|
13681
|
+
);
|
|
13682
|
+
}
|
|
13683
|
+
}
|
|
13684
|
+
function validateInstructions(instructions, errors) {
|
|
13685
|
+
if (!isPlainObject(instructions)) {
|
|
13686
|
+
errors.push("instructions must be an object");
|
|
13687
|
+
return;
|
|
13688
|
+
}
|
|
13689
|
+
if (!Array.isArray(instructions.files) || instructions.files.length === 0) {
|
|
13690
|
+
errors.push("instructions.files must be a non-empty array");
|
|
13691
|
+
return;
|
|
13692
|
+
}
|
|
13693
|
+
instructions.files.forEach((f, i) => {
|
|
13694
|
+
if (!isPlainObject(f)) {
|
|
13695
|
+
errors.push(`instructions.files[${i}] must be an object`);
|
|
13696
|
+
return;
|
|
13697
|
+
}
|
|
13698
|
+
if (typeof f.path !== "string" || f.path.length === 0)
|
|
13699
|
+
errors.push(`instructions.files[${i}].path must be a non-empty string`);
|
|
13700
|
+
if (typeof f.renderer !== "string" || !VALID_RENDERER_KEYS.has(f.renderer))
|
|
13701
|
+
errors.push(
|
|
13702
|
+
`instructions.files[${i}].renderer ${JSON.stringify(f.renderer)} is not a known renderer (valid: ${[...VALID_RENDERER_KEYS].join(", ")})`
|
|
13703
|
+
);
|
|
13704
|
+
});
|
|
13705
|
+
}
|
|
13706
|
+
function validateUserDescriptor(data, builtinIds) {
|
|
13707
|
+
const errors = [];
|
|
13708
|
+
if (!isPlainObject(data)) {
|
|
13709
|
+
return { ok: false, errors: ["descriptor must be a JSON object"] };
|
|
13710
|
+
}
|
|
13711
|
+
for (const k of Object.keys(data)) {
|
|
13712
|
+
if (!ALLOWED_TOP_KEYS.has(k)) errors.push(`unknown field "${k}"`);
|
|
13713
|
+
}
|
|
13714
|
+
if (typeof data.id !== "string" || data.id.length === 0) {
|
|
13715
|
+
errors.push("id is required and must be a non-empty string");
|
|
13716
|
+
} else if (!ID_RE.test(data.id)) {
|
|
13717
|
+
errors.push(`id "${data.id}" must match ${ID_RE.source}`);
|
|
13718
|
+
} else if (builtinIds.has(data.id)) {
|
|
13719
|
+
errors.push(
|
|
13720
|
+
`id "${data.id}" collides with a built-in agent (built-ins cannot be overridden)`
|
|
13721
|
+
);
|
|
13722
|
+
}
|
|
13723
|
+
if (typeof data.displayName !== "string" || data.displayName.trim().length === 0) {
|
|
13724
|
+
errors.push("displayName is required and must be a non-empty string");
|
|
13725
|
+
}
|
|
13726
|
+
if (data.skillsShAgentId !== void 0 && (typeof data.skillsShAgentId !== "string" || data.skillsShAgentId.length === 0)) {
|
|
13727
|
+
errors.push("skillsShAgentId must be a non-empty string when present");
|
|
13728
|
+
}
|
|
13729
|
+
if (data.detect === void 0) {
|
|
13730
|
+
errors.push("detect is required");
|
|
13731
|
+
} else {
|
|
13732
|
+
validateDetect(data.detect, errors);
|
|
13733
|
+
}
|
|
13734
|
+
if (data.skillsDir !== void 0) {
|
|
13735
|
+
if (!isPlainObject(data.skillsDir)) {
|
|
13736
|
+
errors.push("skillsDir must be an object");
|
|
13737
|
+
} else {
|
|
13738
|
+
for (const k of Object.keys(data.skillsDir)) {
|
|
13739
|
+
if (k !== "project" && k !== "global") errors.push(`skillsDir.${k} is not a valid key`);
|
|
13740
|
+
}
|
|
13741
|
+
if (data.skillsDir.project !== void 0 && typeof data.skillsDir.project !== "string")
|
|
13742
|
+
errors.push("skillsDir.project must be a string");
|
|
13743
|
+
if (data.skillsDir.global !== void 0 && typeof data.skillsDir.global !== "string")
|
|
13744
|
+
errors.push("skillsDir.global must be a string");
|
|
13745
|
+
}
|
|
13746
|
+
}
|
|
13747
|
+
if (data.instructions !== void 0) {
|
|
13748
|
+
validateInstructions(data.instructions, errors);
|
|
13749
|
+
}
|
|
13750
|
+
if (errors.length > 0) return { ok: false, errors };
|
|
13751
|
+
return { ok: true, value: data };
|
|
13752
|
+
}
|
|
13753
|
+
function compileDescriptor(desc) {
|
|
13754
|
+
const target = {
|
|
13755
|
+
id: desc.id,
|
|
13756
|
+
displayName: desc.displayName,
|
|
13757
|
+
detect: compileDetect(desc.detect)
|
|
13758
|
+
};
|
|
13759
|
+
if (desc.skillsShAgentId) target.skillsShAgentId = desc.skillsShAgentId;
|
|
13760
|
+
if (desc.skillsDir) {
|
|
13761
|
+
const skillsDir = {};
|
|
13762
|
+
if (desc.skillsDir.global) skillsDir.global = expandHomeAndEnv(desc.skillsDir.global);
|
|
13763
|
+
if (desc.skillsDir.project) skillsDir.project = desc.skillsDir.project;
|
|
13764
|
+
target.skillsDir = skillsDir;
|
|
13765
|
+
}
|
|
13766
|
+
if (desc.instructions) target.instructions = desc.instructions;
|
|
13767
|
+
return target;
|
|
13768
|
+
}
|
|
13769
|
+
async function loadUserDescriptors(opts = {}) {
|
|
13770
|
+
const dir = opts.dir ?? userTargetsDir();
|
|
13771
|
+
const builtinIds = opts.builtinIds ?? /* @__PURE__ */ new Set();
|
|
13772
|
+
const warnings = [];
|
|
13773
|
+
if (!await fileExists(dir)) return { targets: [], warnings };
|
|
13774
|
+
let files;
|
|
13775
|
+
try {
|
|
13776
|
+
files = (await readdir15(dir)).filter((f) => f.endsWith(".json")).sort();
|
|
13777
|
+
} catch (err2) {
|
|
13778
|
+
return { targets: [], warnings: [`could not read ${dir}: ${msg(err2)}`] };
|
|
13779
|
+
}
|
|
13780
|
+
const targets = [];
|
|
13781
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13782
|
+
for (const file of files) {
|
|
13783
|
+
const full = resolve29(dir, file);
|
|
13784
|
+
let raw2;
|
|
13785
|
+
try {
|
|
13786
|
+
raw2 = await readFile20(full, "utf-8");
|
|
13787
|
+
} catch (err2) {
|
|
13788
|
+
warnings.push(`skipped ${file}: ${msg(err2)}`);
|
|
13789
|
+
continue;
|
|
13790
|
+
}
|
|
13791
|
+
let parsed;
|
|
13792
|
+
try {
|
|
13793
|
+
parsed = JSON.parse(raw2);
|
|
13794
|
+
} catch (err2) {
|
|
13795
|
+
warnings.push(`skipped ${file}: invalid JSON: ${msg(err2)}`);
|
|
13796
|
+
continue;
|
|
13797
|
+
}
|
|
13798
|
+
const result = validateUserDescriptor(parsed, builtinIds);
|
|
13799
|
+
if (!result.ok) {
|
|
13800
|
+
warnings.push(`skipped ${file}: ${result.errors.join("; ")}`);
|
|
13801
|
+
continue;
|
|
13802
|
+
}
|
|
13803
|
+
if (seen.has(result.value.id)) {
|
|
13804
|
+
warnings.push(
|
|
13805
|
+
`skipped ${file}: duplicate id "${result.value.id}" (already loaded from an earlier file)`
|
|
13806
|
+
);
|
|
13807
|
+
continue;
|
|
13808
|
+
}
|
|
13809
|
+
seen.add(result.value.id);
|
|
13810
|
+
targets.push(compileDescriptor(result.value));
|
|
13811
|
+
}
|
|
13812
|
+
return { targets, warnings };
|
|
13813
|
+
}
|
|
13814
|
+
var ID_RE, VALID_RENDERER_KEYS, ALLOWED_TOP_KEYS;
|
|
13815
|
+
var init_user_descriptors = __esm({
|
|
13816
|
+
"src/targets/user-descriptors.ts"() {
|
|
13817
|
+
"use strict";
|
|
13818
|
+
init_fs();
|
|
13819
|
+
init_paths();
|
|
13820
|
+
init_renderers();
|
|
13821
|
+
ID_RE = /^[a-z0-9][a-z0-9_-]*$/;
|
|
13822
|
+
VALID_RENDERER_KEYS = new Set(Object.keys(RENDERERS));
|
|
13823
|
+
ALLOWED_TOP_KEYS = /* @__PURE__ */ new Set([
|
|
13824
|
+
"id",
|
|
13825
|
+
"displayName",
|
|
13826
|
+
"skillsShAgentId",
|
|
13827
|
+
"detect",
|
|
13828
|
+
"skillsDir",
|
|
13829
|
+
"instructions"
|
|
13830
|
+
]);
|
|
13831
|
+
}
|
|
13832
|
+
});
|
|
13833
|
+
|
|
13834
|
+
// src/targets/registry.ts
|
|
13835
|
+
import { homedir as homedir4 } from "os";
|
|
13836
|
+
import { join as join5, resolve as resolve30 } from "path";
|
|
13837
|
+
function home(...segments) {
|
|
13838
|
+
return resolve30(homedir4(), ...segments);
|
|
13839
|
+
}
|
|
13840
|
+
function hermesHome() {
|
|
13841
|
+
const env = process.env.HERMES_HOME;
|
|
13842
|
+
return env && env.length > 0 ? resolve30(env) : home(".hermes");
|
|
13843
|
+
}
|
|
13844
|
+
function hermesSkillsDir() {
|
|
13845
|
+
return resolve30(hermesHome(), "skills");
|
|
13846
|
+
}
|
|
13847
|
+
function isHermesHomeCustom() {
|
|
13848
|
+
return hermesHome() !== home(".hermes");
|
|
13849
|
+
}
|
|
13850
|
+
function codexHome() {
|
|
13851
|
+
const env = process.env.CODEX_HOME;
|
|
13852
|
+
return env && env.length > 0 ? resolve30(env) : home(".codex");
|
|
13853
|
+
}
|
|
13854
|
+
function toDiscovered(meta) {
|
|
13855
|
+
if (!meta) return null;
|
|
13856
|
+
return {
|
|
13857
|
+
sessionId: meta.sessionId,
|
|
13858
|
+
cwd: meta.cwd,
|
|
13859
|
+
startedAt: meta.startTs,
|
|
13860
|
+
endedAt: meta.endTs,
|
|
13861
|
+
transcriptPath: meta.path
|
|
13862
|
+
};
|
|
13863
|
+
}
|
|
13864
|
+
function getAgentTarget(id) {
|
|
13865
|
+
return AGENT_TARGETS_BY_ID[id];
|
|
13866
|
+
}
|
|
13867
|
+
async function resolveAgentTargets() {
|
|
13868
|
+
const { targets: user, warnings } = await loadUserDescriptors({
|
|
13869
|
+
builtinIds: new Set(AGENT_TARGETS.map((t) => t.id))
|
|
13870
|
+
});
|
|
13871
|
+
return { targets: [...AGENT_TARGETS, ...user], warnings };
|
|
13872
|
+
}
|
|
13873
|
+
var detectDir, claudeSessions, codexSessions, piSessions, AGENT_TARGETS, AGENT_TARGETS_BY_ID;
|
|
13874
|
+
var init_registry = __esm({
|
|
13875
|
+
"src/targets/registry.ts"() {
|
|
13876
|
+
"use strict";
|
|
13877
|
+
init_fs();
|
|
13878
|
+
init_cwd_extractor();
|
|
13879
|
+
init_user_descriptors();
|
|
13880
|
+
detectDir = (dir) => () => fileExists(dir);
|
|
13881
|
+
claudeSessions = {
|
|
13882
|
+
globs: (root) => [join5(root ?? home(".claude", "projects"), "*", "*.jsonl")],
|
|
13883
|
+
parse: async (file) => toDiscovered(await extractClaudeSessionMeta(file)),
|
|
13884
|
+
walk: async function* (opts = {}) {
|
|
13885
|
+
for await (const meta of walkClaudeProjects({ root: opts.root, sinceMtimeMs: opts.sinceMtimeMs })) {
|
|
13886
|
+
const d = toDiscovered(meta);
|
|
13887
|
+
if (d) yield d;
|
|
13888
|
+
}
|
|
13889
|
+
}
|
|
13890
|
+
};
|
|
13891
|
+
codexSessions = {
|
|
13892
|
+
globs: (root) => [join5(root ?? resolveCodexSessionsRoot(), "**", "*.jsonl")],
|
|
13893
|
+
parse: async (file) => toDiscovered(await extractCodexSessionMeta(file)),
|
|
13894
|
+
walk: async function* (opts = {}) {
|
|
13895
|
+
for await (const meta of walkCodexSessions({ root: opts.root, sinceMtimeMs: opts.sinceMtimeMs })) {
|
|
13896
|
+
const d = toDiscovered(meta);
|
|
13897
|
+
if (d) yield d;
|
|
13898
|
+
}
|
|
13899
|
+
}
|
|
13900
|
+
};
|
|
13901
|
+
piSessions = {
|
|
13902
|
+
globs: (root) => [join5(root ?? resolvePiSessionsRoot(), "*", "*.jsonl")],
|
|
13903
|
+
parse: async (file) => toDiscovered(await extractPiSessionMeta(file)),
|
|
13904
|
+
walk: async function* (opts = {}) {
|
|
13905
|
+
for await (const meta of walkPiSessions({ root: opts.root, sinceMtimeMs: opts.sinceMtimeMs })) {
|
|
13906
|
+
const d = toDiscovered(meta);
|
|
13907
|
+
if (d) yield d;
|
|
13908
|
+
}
|
|
13909
|
+
}
|
|
13910
|
+
};
|
|
13911
|
+
AGENT_TARGETS = [
|
|
13912
|
+
{
|
|
13913
|
+
id: "cursor",
|
|
13914
|
+
displayName: "Cursor",
|
|
13915
|
+
skillsShAgentId: "cursor",
|
|
13916
|
+
detect: detectDir(home(".cursor")),
|
|
13917
|
+
skillsDir: { global: home(".cursor", "skills") },
|
|
13918
|
+
instructions: {
|
|
13919
|
+
files: [
|
|
13920
|
+
{ path: ".cursor/rules/syntaur-protocol.mdc", renderer: "cursorProtocol" },
|
|
13921
|
+
{ path: ".cursor/rules/syntaur-assignment.mdc", renderer: "cursorAssignment" }
|
|
13922
|
+
]
|
|
13923
|
+
}
|
|
13924
|
+
},
|
|
13925
|
+
{
|
|
13926
|
+
// codex is BOTH an adapter (writes AGENTS.md) AND a native plugin.
|
|
13927
|
+
id: "codex",
|
|
13928
|
+
displayName: "Codex",
|
|
13929
|
+
skillsShAgentId: "codex",
|
|
13930
|
+
nativePlugin: "codex",
|
|
13931
|
+
detect: detectDir(codexHome()),
|
|
13932
|
+
skillsDir: { global: resolve30(codexHome(), "skills") },
|
|
13933
|
+
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] },
|
|
13934
|
+
sessions: codexSessions
|
|
13935
|
+
},
|
|
13936
|
+
{
|
|
13937
|
+
id: "opencode",
|
|
13938
|
+
displayName: "OpenCode",
|
|
13939
|
+
skillsShAgentId: "opencode",
|
|
13940
|
+
detect: detectDir(home(".config", "opencode")),
|
|
13941
|
+
skillsDir: { global: home(".config", "opencode", "skills") },
|
|
13942
|
+
instructions: {
|
|
13943
|
+
files: [
|
|
13944
|
+
{ path: "AGENTS.md", renderer: "codexAgents" },
|
|
13945
|
+
{ path: "opencode.json", renderer: "openCodeConfig" }
|
|
13946
|
+
]
|
|
13947
|
+
}
|
|
13948
|
+
},
|
|
13949
|
+
{
|
|
13950
|
+
// claude has NO adapter today (not in the old SUPPORTED_FRAMEWORKS) — the
|
|
13951
|
+
// full plugin path owns its skills/hooks/commands. Native-plugin only.
|
|
13952
|
+
id: "claude",
|
|
13953
|
+
displayName: "Claude Code",
|
|
13954
|
+
skillsShAgentId: "claude-code",
|
|
13955
|
+
nativePlugin: "claude",
|
|
13956
|
+
detect: detectDir(home(".claude")),
|
|
13957
|
+
skillsDir: { global: home(".claude", "skills") },
|
|
13958
|
+
sessions: claudeSessions,
|
|
13959
|
+
agentsDir: home(".claude", "agents")
|
|
13960
|
+
},
|
|
13961
|
+
{
|
|
13962
|
+
id: "pi",
|
|
13963
|
+
displayName: "Pi",
|
|
13964
|
+
skillsShAgentId: "pi",
|
|
13965
|
+
detect: detectDir(home(".pi")),
|
|
13966
|
+
skillsDir: { global: home(".pi", "agent", "skills") },
|
|
13967
|
+
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] },
|
|
13968
|
+
sessions: piSessions,
|
|
13969
|
+
tier3: {
|
|
13970
|
+
kind: "pi-extension",
|
|
13971
|
+
source: "platforms/pi/extensions/syntaur",
|
|
13972
|
+
installDir: () => home(".pi", "agent", "extensions", "syntaur"),
|
|
13973
|
+
entry: "index.ts"
|
|
13974
|
+
}
|
|
13975
|
+
},
|
|
13976
|
+
{
|
|
13977
|
+
id: "openclaw",
|
|
13978
|
+
displayName: "OpenClaw",
|
|
13979
|
+
skillsShAgentId: "openclaw",
|
|
13980
|
+
detect: detectDir(home(".openclaw")),
|
|
13981
|
+
skillsDir: { global: home(".openclaw", "skills") },
|
|
13982
|
+
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] },
|
|
13983
|
+
// OpenClaw runs on pi-coding-agent (design memo), so it reuses the pi
|
|
13984
|
+
// extension SOURCE; only the install dir differs.
|
|
13985
|
+
tier3: {
|
|
13986
|
+
kind: "pi-extension",
|
|
13987
|
+
source: "platforms/pi/extensions/syntaur",
|
|
13988
|
+
installDir: () => home(".openclaw", "extensions", "syntaur"),
|
|
13989
|
+
entry: "index.ts"
|
|
13990
|
+
}
|
|
13991
|
+
},
|
|
13992
|
+
{
|
|
13993
|
+
id: "hermes",
|
|
13994
|
+
displayName: "Hermes Agent",
|
|
13995
|
+
skillsShAgentId: "hermes-agent",
|
|
13996
|
+
detect: () => fileExists(hermesHome()),
|
|
13997
|
+
skillsDir: { global: hermesSkillsDir() },
|
|
13998
|
+
instructions: { files: [{ path: "SOUL.md", renderer: "hermesSoul" }] },
|
|
13999
|
+
tier3: {
|
|
14000
|
+
kind: "hermes-plugin",
|
|
14001
|
+
source: "platforms/hermes/plugins/syntaur",
|
|
14002
|
+
installDir: () => resolve30(hermesHome(), "plugins", "syntaur"),
|
|
14003
|
+
entry: "plugin.yaml"
|
|
14004
|
+
}
|
|
14005
|
+
}
|
|
14006
|
+
];
|
|
14007
|
+
AGENT_TARGETS_BY_ID = Object.fromEntries(
|
|
14008
|
+
AGENT_TARGETS.map((t) => [t.id, t])
|
|
14009
|
+
);
|
|
14010
|
+
}
|
|
14011
|
+
});
|
|
14012
|
+
|
|
13538
14013
|
// src/launch/launch-prompt.ts
|
|
13539
14014
|
function bareGrabSeed(params2) {
|
|
13540
14015
|
if (params2.projectSlug) {
|
|
@@ -13556,8 +14031,19 @@ function resolveTemplate(template, ctx) {
|
|
|
13556
14031
|
const warnings = [];
|
|
13557
14032
|
const prompt = template.replace(TOKEN_RE, (_match, boundary, token) => {
|
|
13558
14033
|
if (token === "assignment") {
|
|
14034
|
+
if (!ctx.assignmentDir) {
|
|
14035
|
+
warnings.push(`launchPrompt: "@assignment" has no assignment context here \u2014 left as literal text.`);
|
|
14036
|
+
return boundary + "@assignment";
|
|
14037
|
+
}
|
|
13559
14038
|
return boundary + assignmentPointer(ctx.id, ctx.assignmentDir);
|
|
13560
14039
|
}
|
|
14040
|
+
if (token === "worktree") {
|
|
14041
|
+
if (!ctx.worktreePath) {
|
|
14042
|
+
warnings.push(`launchPrompt: "@worktree" has no worktree path here \u2014 left as literal text.`);
|
|
14043
|
+
return boundary + "@worktree";
|
|
14044
|
+
}
|
|
14045
|
+
return boundary + ctx.worktreePath;
|
|
14046
|
+
}
|
|
13561
14047
|
if (!isValidSlug(token)) {
|
|
13562
14048
|
warnings.push(`launchPrompt: "@${token}" is not a valid playbook token \u2014 left as literal text.`);
|
|
13563
14049
|
return boundary + "@" + token;
|
|
@@ -13571,16 +14057,37 @@ function resolveTemplate(template, ctx) {
|
|
|
13571
14057
|
return { prompt, warnings };
|
|
13572
14058
|
}
|
|
13573
14059
|
function resolveLaunchPrompt(input4) {
|
|
13574
|
-
const {
|
|
14060
|
+
const {
|
|
14061
|
+
template,
|
|
14062
|
+
playbook,
|
|
14063
|
+
id,
|
|
14064
|
+
assignmentDir,
|
|
14065
|
+
projectSlug,
|
|
14066
|
+
assignmentSlug,
|
|
14067
|
+
worktreePath,
|
|
14068
|
+
spawnCwd,
|
|
14069
|
+
knownPlaybookSlugs
|
|
14070
|
+
} = input4;
|
|
13575
14071
|
if (template && template.trim()) {
|
|
13576
|
-
return resolveTemplate(template, { id, assignmentDir, knownPlaybookSlugs });
|
|
14072
|
+
return resolveTemplate(template, { id, assignmentDir, worktreePath, knownPlaybookSlugs });
|
|
13577
14073
|
}
|
|
13578
14074
|
const pb = playbook?.trim();
|
|
13579
14075
|
if (pb) {
|
|
13580
|
-
const
|
|
13581
|
-
|
|
14076
|
+
const clause = runPlaybookClause(pb);
|
|
14077
|
+
const prompt = assignmentDir ? `${assignmentPointer(id, assignmentDir)} Run ${clause} end-to-end.` : `Run ${clause} end-to-end.`;
|
|
14078
|
+
return { prompt, warnings: [] };
|
|
13582
14079
|
}
|
|
13583
|
-
|
|
14080
|
+
if (worktreePath && spawnCwd && worktreePath !== spawnCwd) {
|
|
14081
|
+
const grab = bareGrabSeed({ projectSlug, assignmentSlug: assignmentSlug ?? "", id });
|
|
14082
|
+
return {
|
|
14083
|
+
prompt: `The assignment's worktree is at ${worktreePath}. cd there, then grab the assignment with ${grab} and work it end-to-end.`,
|
|
14084
|
+
warnings: []
|
|
14085
|
+
};
|
|
14086
|
+
}
|
|
14087
|
+
if (!assignmentSlug && !id) {
|
|
14088
|
+
return { prompt: "", warnings: [] };
|
|
14089
|
+
}
|
|
14090
|
+
return { prompt: bareGrabSeed({ projectSlug, assignmentSlug: assignmentSlug ?? "", id }), warnings: [] };
|
|
13584
14091
|
}
|
|
13585
14092
|
function effectiveLaunchTemplate(input4) {
|
|
13586
14093
|
if (input4.launchPrompt && input4.launchPrompt.trim()) {
|
|
@@ -13590,6 +14097,14 @@ function effectiveLaunchTemplate(input4) {
|
|
|
13590
14097
|
if (pb) {
|
|
13591
14098
|
return `@assignment Run ${runPlaybookClause(pb)} end-to-end.`;
|
|
13592
14099
|
}
|
|
14100
|
+
if (input4.workdir && input4.workdir.trim()) {
|
|
14101
|
+
const grab = bareGrabSeed({
|
|
14102
|
+
projectSlug: input4.projectSlug,
|
|
14103
|
+
assignmentSlug: input4.assignmentSlug,
|
|
14104
|
+
id: input4.id
|
|
14105
|
+
});
|
|
14106
|
+
return `The assignment's worktree is at @worktree. cd there, then grab the assignment with ${grab} and work it end-to-end.`;
|
|
14107
|
+
}
|
|
13593
14108
|
return bareGrabSeed({
|
|
13594
14109
|
projectSlug: input4.projectSlug,
|
|
13595
14110
|
assignmentSlug: input4.assignmentSlug,
|
|
@@ -13616,15 +14131,17 @@ __export(launch_exports, {
|
|
|
13616
14131
|
});
|
|
13617
14132
|
import { spawn as spawn2 } from "child_process";
|
|
13618
14133
|
import { mkdir as mkdir2, writeFile as writeFile4 } from "fs/promises";
|
|
13619
|
-
import { isAbsolute as isAbsolute5, resolve as
|
|
14134
|
+
import { isAbsolute as isAbsolute5, resolve as resolve31 } from "path";
|
|
13620
14135
|
function shellQuote(arg) {
|
|
13621
14136
|
if (arg === "") return "''";
|
|
13622
14137
|
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
13623
14138
|
}
|
|
13624
14139
|
function buildAgentArgv(agent, prompt, env = process.env) {
|
|
13625
14140
|
const position = agent.promptArgPosition ?? "first";
|
|
13626
|
-
const
|
|
13627
|
-
const
|
|
14141
|
+
const prefix = agentNameArgs(agent);
|
|
14142
|
+
const baseArgs = agent.agentName ? [...agent.args ?? []] : applyModelFlag(agent, [...agent.args ?? []]);
|
|
14143
|
+
const positioned = position === "first" ? [prompt, ...baseArgs] : position === "last" ? [...baseArgs, prompt] : baseArgs;
|
|
14144
|
+
const agentArgs = [...prefix, ...positioned];
|
|
13628
14145
|
if (agent.resolveFromShellAliases) {
|
|
13629
14146
|
const requested = env.SHELL;
|
|
13630
14147
|
let shell = requested;
|
|
@@ -13652,9 +14169,9 @@ async function launchAgent(options) {
|
|
|
13652
14169
|
console.error(`Assignment not found: ${projectSlug}/${assignmentSlug}`);
|
|
13653
14170
|
process.exit(1);
|
|
13654
14171
|
}
|
|
13655
|
-
const projectDir =
|
|
13656
|
-
const assignmentDir =
|
|
13657
|
-
let
|
|
14172
|
+
const projectDir = resolve31(projectsDir2, projectSlug);
|
|
14173
|
+
const assignmentDir = resolve31(projectDir, "assignments", assignmentSlug);
|
|
14174
|
+
let worktreeDir;
|
|
13658
14175
|
if (cwdOverride) {
|
|
13659
14176
|
if (!isExistingDir(cwdOverride)) {
|
|
13660
14177
|
console.error(
|
|
@@ -13663,7 +14180,7 @@ async function launchAgent(options) {
|
|
|
13663
14180
|
exitWith(1);
|
|
13664
14181
|
return;
|
|
13665
14182
|
}
|
|
13666
|
-
|
|
14183
|
+
worktreeDir = cwdOverride;
|
|
13667
14184
|
} else {
|
|
13668
14185
|
const picked = resolveWorkspaceCwd({
|
|
13669
14186
|
worktreePath: detail.workspace.worktreePath,
|
|
@@ -13676,26 +14193,34 @@ async function launchAgent(options) {
|
|
|
13676
14193
|
exitWith(1);
|
|
13677
14194
|
return;
|
|
13678
14195
|
}
|
|
13679
|
-
|
|
14196
|
+
worktreeDir = picked.cwd;
|
|
13680
14197
|
const warning = picked.fallbackWarning ?? formatFallbackCwdWarning({
|
|
13681
14198
|
assignmentSlug,
|
|
13682
|
-
workspaceDir,
|
|
14199
|
+
workspaceDir: worktreeDir,
|
|
13683
14200
|
worktreePath: detail.workspace.worktreePath,
|
|
13684
14201
|
branch: detail.workspace.branch
|
|
13685
14202
|
});
|
|
13686
14203
|
if (warning) console.warn(warning);
|
|
13687
14204
|
}
|
|
13688
|
-
const
|
|
14205
|
+
const launchCwd = resolveLaunchCwd(agent, worktreeDir);
|
|
14206
|
+
if (launchCwd.invalidReason) {
|
|
14207
|
+
console.error(`syntaur: ${launchCwd.invalidReason} \u2014 refusing to launch.`);
|
|
14208
|
+
exitWith(1);
|
|
14209
|
+
return;
|
|
14210
|
+
}
|
|
14211
|
+
const spawnCwd = launchCwd.spawnCwd;
|
|
14212
|
+
const worktreePath = launchCwd.worktreePath;
|
|
14213
|
+
const contextDir = resolve31(worktreePath, ".syntaur");
|
|
13689
14214
|
await mkdir2(contextDir, { recursive: true });
|
|
13690
14215
|
const context = {
|
|
13691
14216
|
repository: detail.workspace.repository ?? null,
|
|
13692
14217
|
branch: detail.workspace.branch ?? null,
|
|
13693
14218
|
worktreePath: detail.workspace.worktreePath ?? null,
|
|
13694
|
-
workspaceRoot:
|
|
14219
|
+
workspaceRoot: worktreePath,
|
|
13695
14220
|
grabbedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
13696
14221
|
};
|
|
13697
14222
|
await writeFile4(
|
|
13698
|
-
|
|
14223
|
+
resolve31(contextDir, "context.json"),
|
|
13699
14224
|
JSON.stringify(context, null, 2) + "\n"
|
|
13700
14225
|
);
|
|
13701
14226
|
const knownPlaybookSlugs = await listPlaybookSlugs(playbooksDir());
|
|
@@ -13706,6 +14231,8 @@ async function launchAgent(options) {
|
|
|
13706
14231
|
assignmentDir,
|
|
13707
14232
|
projectSlug,
|
|
13708
14233
|
assignmentSlug,
|
|
14234
|
+
worktreePath,
|
|
14235
|
+
spawnCwd,
|
|
13709
14236
|
knownPlaybookSlugs
|
|
13710
14237
|
});
|
|
13711
14238
|
for (const warning of warnings) console.warn(warning);
|
|
@@ -13716,7 +14243,7 @@ async function launchAgent(options) {
|
|
|
13716
14243
|
const spawnImpl = options.spawnFn ?? spawn2;
|
|
13717
14244
|
return new Promise((resolvePromise) => {
|
|
13718
14245
|
const child = spawnImpl(argv.command, argv.args, {
|
|
13719
|
-
cwd:
|
|
14246
|
+
cwd: spawnCwd,
|
|
13720
14247
|
stdio: "inherit"
|
|
13721
14248
|
});
|
|
13722
14249
|
child.on("error", (err2) => {
|
|
@@ -13951,12 +14478,12 @@ var init_assignment_todos = __esm({
|
|
|
13951
14478
|
|
|
13952
14479
|
// src/utils/path-canon.ts
|
|
13953
14480
|
import { realpathSync as realpathSync2 } from "fs";
|
|
13954
|
-
import { resolve as
|
|
14481
|
+
import { resolve as resolve48 } from "path";
|
|
13955
14482
|
function canonicalPath(p) {
|
|
13956
14483
|
try {
|
|
13957
|
-
return realpathSync2(
|
|
14484
|
+
return realpathSync2(resolve48(p));
|
|
13958
14485
|
} catch {
|
|
13959
|
-
return
|
|
14486
|
+
return resolve48(p).replace(/\/+$/, "");
|
|
13960
14487
|
}
|
|
13961
14488
|
}
|
|
13962
14489
|
var init_path_canon = __esm({
|
|
@@ -13965,421 +14492,6 @@ var init_path_canon = __esm({
|
|
|
13965
14492
|
}
|
|
13966
14493
|
});
|
|
13967
14494
|
|
|
13968
|
-
// src/targets/renderers.ts
|
|
13969
|
-
var RENDERERS;
|
|
13970
|
-
var init_renderers = __esm({
|
|
13971
|
-
"src/targets/renderers.ts"() {
|
|
13972
|
-
"use strict";
|
|
13973
|
-
init_cursor_rules();
|
|
13974
|
-
init_codex_agents();
|
|
13975
|
-
init_opencode_config();
|
|
13976
|
-
init_hermes_soul();
|
|
13977
|
-
RENDERERS = {
|
|
13978
|
-
codexAgents: (ctx) => renderCodexAgents(ctx),
|
|
13979
|
-
cursorProtocol: () => renderCursorProtocol(),
|
|
13980
|
-
cursorAssignment: (ctx) => renderCursorAssignment(ctx),
|
|
13981
|
-
openCodeConfig: (ctx) => renderOpenCodeConfig({ projectDir: ctx.projectDir }),
|
|
13982
|
-
hermesSoul: (ctx) => renderHermesSoul(ctx)
|
|
13983
|
-
};
|
|
13984
|
-
}
|
|
13985
|
-
});
|
|
13986
|
-
|
|
13987
|
-
// src/targets/user-descriptors.ts
|
|
13988
|
-
import { resolve as resolve47 } from "path";
|
|
13989
|
-
import { readFile as readFile31, readdir as readdir19 } from "fs/promises";
|
|
13990
|
-
function userTargetsDir() {
|
|
13991
|
-
return resolve47(syntaurRoot(), "targets");
|
|
13992
|
-
}
|
|
13993
|
-
function msg(err2) {
|
|
13994
|
-
return err2 instanceof Error ? err2.message : String(err2);
|
|
13995
|
-
}
|
|
13996
|
-
function expandHomeAndEnv(p) {
|
|
13997
|
-
const envExpanded = p.replace(
|
|
13998
|
-
/\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g,
|
|
13999
|
-
(_m, braced, bare) => {
|
|
14000
|
-
const name = braced ?? bare ?? "";
|
|
14001
|
-
const v = process.env[name];
|
|
14002
|
-
return v ?? "";
|
|
14003
|
-
}
|
|
14004
|
-
);
|
|
14005
|
-
return resolve47(expandHome(envExpanded));
|
|
14006
|
-
}
|
|
14007
|
-
function compileDetect(spec) {
|
|
14008
|
-
switch (spec.kind) {
|
|
14009
|
-
case "pathExists": {
|
|
14010
|
-
const p = expandHomeAndEnv(spec.path);
|
|
14011
|
-
return () => fileExists(p);
|
|
14012
|
-
}
|
|
14013
|
-
case "anyPathExists": {
|
|
14014
|
-
const ps = spec.paths.map(expandHomeAndEnv);
|
|
14015
|
-
return async () => {
|
|
14016
|
-
for (const p of ps) {
|
|
14017
|
-
if (await fileExists(p)) return true;
|
|
14018
|
-
}
|
|
14019
|
-
return false;
|
|
14020
|
-
};
|
|
14021
|
-
}
|
|
14022
|
-
case "envSet": {
|
|
14023
|
-
const env = spec.env;
|
|
14024
|
-
return async () => {
|
|
14025
|
-
const v = process.env[env];
|
|
14026
|
-
return typeof v === "string" && v.length > 0;
|
|
14027
|
-
};
|
|
14028
|
-
}
|
|
14029
|
-
}
|
|
14030
|
-
}
|
|
14031
|
-
function isPlainObject(v) {
|
|
14032
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
14033
|
-
}
|
|
14034
|
-
function validateDetect(detect, errors) {
|
|
14035
|
-
if (!isPlainObject(detect)) {
|
|
14036
|
-
errors.push("detect must be an object");
|
|
14037
|
-
return;
|
|
14038
|
-
}
|
|
14039
|
-
switch (detect.kind) {
|
|
14040
|
-
case "pathExists":
|
|
14041
|
-
if (typeof detect.path !== "string" || detect.path.length === 0)
|
|
14042
|
-
errors.push('detect.path must be a non-empty string for kind "pathExists"');
|
|
14043
|
-
break;
|
|
14044
|
-
case "anyPathExists":
|
|
14045
|
-
if (!Array.isArray(detect.paths) || detect.paths.length === 0 || !detect.paths.every((p) => typeof p === "string" && p.length > 0))
|
|
14046
|
-
errors.push('detect.paths must be a non-empty string[] for kind "anyPathExists"');
|
|
14047
|
-
break;
|
|
14048
|
-
case "envSet":
|
|
14049
|
-
if (typeof detect.env !== "string" || detect.env.length === 0)
|
|
14050
|
-
errors.push('detect.env must be a non-empty string for kind "envSet"');
|
|
14051
|
-
break;
|
|
14052
|
-
default:
|
|
14053
|
-
errors.push(
|
|
14054
|
-
`detect.kind must be one of pathExists|anyPathExists|envSet (got ${JSON.stringify(detect.kind)})`
|
|
14055
|
-
);
|
|
14056
|
-
}
|
|
14057
|
-
}
|
|
14058
|
-
function validateInstructions(instructions, errors) {
|
|
14059
|
-
if (!isPlainObject(instructions)) {
|
|
14060
|
-
errors.push("instructions must be an object");
|
|
14061
|
-
return;
|
|
14062
|
-
}
|
|
14063
|
-
if (!Array.isArray(instructions.files) || instructions.files.length === 0) {
|
|
14064
|
-
errors.push("instructions.files must be a non-empty array");
|
|
14065
|
-
return;
|
|
14066
|
-
}
|
|
14067
|
-
instructions.files.forEach((f, i) => {
|
|
14068
|
-
if (!isPlainObject(f)) {
|
|
14069
|
-
errors.push(`instructions.files[${i}] must be an object`);
|
|
14070
|
-
return;
|
|
14071
|
-
}
|
|
14072
|
-
if (typeof f.path !== "string" || f.path.length === 0)
|
|
14073
|
-
errors.push(`instructions.files[${i}].path must be a non-empty string`);
|
|
14074
|
-
if (typeof f.renderer !== "string" || !VALID_RENDERER_KEYS.has(f.renderer))
|
|
14075
|
-
errors.push(
|
|
14076
|
-
`instructions.files[${i}].renderer ${JSON.stringify(f.renderer)} is not a known renderer (valid: ${[...VALID_RENDERER_KEYS].join(", ")})`
|
|
14077
|
-
);
|
|
14078
|
-
});
|
|
14079
|
-
}
|
|
14080
|
-
function validateUserDescriptor(data, builtinIds) {
|
|
14081
|
-
const errors = [];
|
|
14082
|
-
if (!isPlainObject(data)) {
|
|
14083
|
-
return { ok: false, errors: ["descriptor must be a JSON object"] };
|
|
14084
|
-
}
|
|
14085
|
-
for (const k of Object.keys(data)) {
|
|
14086
|
-
if (!ALLOWED_TOP_KEYS.has(k)) errors.push(`unknown field "${k}"`);
|
|
14087
|
-
}
|
|
14088
|
-
if (typeof data.id !== "string" || data.id.length === 0) {
|
|
14089
|
-
errors.push("id is required and must be a non-empty string");
|
|
14090
|
-
} else if (!ID_RE.test(data.id)) {
|
|
14091
|
-
errors.push(`id "${data.id}" must match ${ID_RE.source}`);
|
|
14092
|
-
} else if (builtinIds.has(data.id)) {
|
|
14093
|
-
errors.push(
|
|
14094
|
-
`id "${data.id}" collides with a built-in agent (built-ins cannot be overridden)`
|
|
14095
|
-
);
|
|
14096
|
-
}
|
|
14097
|
-
if (typeof data.displayName !== "string" || data.displayName.trim().length === 0) {
|
|
14098
|
-
errors.push("displayName is required and must be a non-empty string");
|
|
14099
|
-
}
|
|
14100
|
-
if (data.skillsShAgentId !== void 0 && (typeof data.skillsShAgentId !== "string" || data.skillsShAgentId.length === 0)) {
|
|
14101
|
-
errors.push("skillsShAgentId must be a non-empty string when present");
|
|
14102
|
-
}
|
|
14103
|
-
if (data.detect === void 0) {
|
|
14104
|
-
errors.push("detect is required");
|
|
14105
|
-
} else {
|
|
14106
|
-
validateDetect(data.detect, errors);
|
|
14107
|
-
}
|
|
14108
|
-
if (data.skillsDir !== void 0) {
|
|
14109
|
-
if (!isPlainObject(data.skillsDir)) {
|
|
14110
|
-
errors.push("skillsDir must be an object");
|
|
14111
|
-
} else {
|
|
14112
|
-
for (const k of Object.keys(data.skillsDir)) {
|
|
14113
|
-
if (k !== "project" && k !== "global") errors.push(`skillsDir.${k} is not a valid key`);
|
|
14114
|
-
}
|
|
14115
|
-
if (data.skillsDir.project !== void 0 && typeof data.skillsDir.project !== "string")
|
|
14116
|
-
errors.push("skillsDir.project must be a string");
|
|
14117
|
-
if (data.skillsDir.global !== void 0 && typeof data.skillsDir.global !== "string")
|
|
14118
|
-
errors.push("skillsDir.global must be a string");
|
|
14119
|
-
}
|
|
14120
|
-
}
|
|
14121
|
-
if (data.instructions !== void 0) {
|
|
14122
|
-
validateInstructions(data.instructions, errors);
|
|
14123
|
-
}
|
|
14124
|
-
if (errors.length > 0) return { ok: false, errors };
|
|
14125
|
-
return { ok: true, value: data };
|
|
14126
|
-
}
|
|
14127
|
-
function compileDescriptor(desc) {
|
|
14128
|
-
const target = {
|
|
14129
|
-
id: desc.id,
|
|
14130
|
-
displayName: desc.displayName,
|
|
14131
|
-
detect: compileDetect(desc.detect)
|
|
14132
|
-
};
|
|
14133
|
-
if (desc.skillsShAgentId) target.skillsShAgentId = desc.skillsShAgentId;
|
|
14134
|
-
if (desc.skillsDir) {
|
|
14135
|
-
const skillsDir = {};
|
|
14136
|
-
if (desc.skillsDir.global) skillsDir.global = expandHomeAndEnv(desc.skillsDir.global);
|
|
14137
|
-
if (desc.skillsDir.project) skillsDir.project = desc.skillsDir.project;
|
|
14138
|
-
target.skillsDir = skillsDir;
|
|
14139
|
-
}
|
|
14140
|
-
if (desc.instructions) target.instructions = desc.instructions;
|
|
14141
|
-
return target;
|
|
14142
|
-
}
|
|
14143
|
-
async function loadUserDescriptors(opts = {}) {
|
|
14144
|
-
const dir = opts.dir ?? userTargetsDir();
|
|
14145
|
-
const builtinIds = opts.builtinIds ?? /* @__PURE__ */ new Set();
|
|
14146
|
-
const warnings = [];
|
|
14147
|
-
if (!await fileExists(dir)) return { targets: [], warnings };
|
|
14148
|
-
let files;
|
|
14149
|
-
try {
|
|
14150
|
-
files = (await readdir19(dir)).filter((f) => f.endsWith(".json")).sort();
|
|
14151
|
-
} catch (err2) {
|
|
14152
|
-
return { targets: [], warnings: [`could not read ${dir}: ${msg(err2)}`] };
|
|
14153
|
-
}
|
|
14154
|
-
const targets = [];
|
|
14155
|
-
const seen = /* @__PURE__ */ new Set();
|
|
14156
|
-
for (const file of files) {
|
|
14157
|
-
const full = resolve47(dir, file);
|
|
14158
|
-
let raw2;
|
|
14159
|
-
try {
|
|
14160
|
-
raw2 = await readFile31(full, "utf-8");
|
|
14161
|
-
} catch (err2) {
|
|
14162
|
-
warnings.push(`skipped ${file}: ${msg(err2)}`);
|
|
14163
|
-
continue;
|
|
14164
|
-
}
|
|
14165
|
-
let parsed;
|
|
14166
|
-
try {
|
|
14167
|
-
parsed = JSON.parse(raw2);
|
|
14168
|
-
} catch (err2) {
|
|
14169
|
-
warnings.push(`skipped ${file}: invalid JSON: ${msg(err2)}`);
|
|
14170
|
-
continue;
|
|
14171
|
-
}
|
|
14172
|
-
const result = validateUserDescriptor(parsed, builtinIds);
|
|
14173
|
-
if (!result.ok) {
|
|
14174
|
-
warnings.push(`skipped ${file}: ${result.errors.join("; ")}`);
|
|
14175
|
-
continue;
|
|
14176
|
-
}
|
|
14177
|
-
if (seen.has(result.value.id)) {
|
|
14178
|
-
warnings.push(
|
|
14179
|
-
`skipped ${file}: duplicate id "${result.value.id}" (already loaded from an earlier file)`
|
|
14180
|
-
);
|
|
14181
|
-
continue;
|
|
14182
|
-
}
|
|
14183
|
-
seen.add(result.value.id);
|
|
14184
|
-
targets.push(compileDescriptor(result.value));
|
|
14185
|
-
}
|
|
14186
|
-
return { targets, warnings };
|
|
14187
|
-
}
|
|
14188
|
-
var ID_RE, VALID_RENDERER_KEYS, ALLOWED_TOP_KEYS;
|
|
14189
|
-
var init_user_descriptors = __esm({
|
|
14190
|
-
"src/targets/user-descriptors.ts"() {
|
|
14191
|
-
"use strict";
|
|
14192
|
-
init_fs();
|
|
14193
|
-
init_paths();
|
|
14194
|
-
init_renderers();
|
|
14195
|
-
ID_RE = /^[a-z0-9][a-z0-9_-]*$/;
|
|
14196
|
-
VALID_RENDERER_KEYS = new Set(Object.keys(RENDERERS));
|
|
14197
|
-
ALLOWED_TOP_KEYS = /* @__PURE__ */ new Set([
|
|
14198
|
-
"id",
|
|
14199
|
-
"displayName",
|
|
14200
|
-
"skillsShAgentId",
|
|
14201
|
-
"detect",
|
|
14202
|
-
"skillsDir",
|
|
14203
|
-
"instructions"
|
|
14204
|
-
]);
|
|
14205
|
-
}
|
|
14206
|
-
});
|
|
14207
|
-
|
|
14208
|
-
// src/targets/registry.ts
|
|
14209
|
-
import { homedir as homedir7 } from "os";
|
|
14210
|
-
import { join as join10, resolve as resolve48 } from "path";
|
|
14211
|
-
function home(...segments) {
|
|
14212
|
-
return resolve48(homedir7(), ...segments);
|
|
14213
|
-
}
|
|
14214
|
-
function hermesHome() {
|
|
14215
|
-
const env = process.env.HERMES_HOME;
|
|
14216
|
-
return env && env.length > 0 ? resolve48(env) : home(".hermes");
|
|
14217
|
-
}
|
|
14218
|
-
function hermesSkillsDir() {
|
|
14219
|
-
return resolve48(hermesHome(), "skills");
|
|
14220
|
-
}
|
|
14221
|
-
function isHermesHomeCustom() {
|
|
14222
|
-
return hermesHome() !== home(".hermes");
|
|
14223
|
-
}
|
|
14224
|
-
function codexHome() {
|
|
14225
|
-
const env = process.env.CODEX_HOME;
|
|
14226
|
-
return env && env.length > 0 ? resolve48(env) : home(".codex");
|
|
14227
|
-
}
|
|
14228
|
-
function toDiscovered(meta) {
|
|
14229
|
-
if (!meta) return null;
|
|
14230
|
-
return {
|
|
14231
|
-
sessionId: meta.sessionId,
|
|
14232
|
-
cwd: meta.cwd,
|
|
14233
|
-
startedAt: meta.startTs,
|
|
14234
|
-
endedAt: meta.endTs,
|
|
14235
|
-
transcriptPath: meta.path
|
|
14236
|
-
};
|
|
14237
|
-
}
|
|
14238
|
-
async function resolveAgentTargets() {
|
|
14239
|
-
const { targets: user, warnings } = await loadUserDescriptors({
|
|
14240
|
-
builtinIds: new Set(AGENT_TARGETS.map((t) => t.id))
|
|
14241
|
-
});
|
|
14242
|
-
return { targets: [...AGENT_TARGETS, ...user], warnings };
|
|
14243
|
-
}
|
|
14244
|
-
var detectDir, claudeSessions, codexSessions, piSessions, AGENT_TARGETS, AGENT_TARGETS_BY_ID;
|
|
14245
|
-
var init_registry = __esm({
|
|
14246
|
-
"src/targets/registry.ts"() {
|
|
14247
|
-
"use strict";
|
|
14248
|
-
init_fs();
|
|
14249
|
-
init_cwd_extractor();
|
|
14250
|
-
init_user_descriptors();
|
|
14251
|
-
detectDir = (dir) => () => fileExists(dir);
|
|
14252
|
-
claudeSessions = {
|
|
14253
|
-
globs: (root) => [join10(root ?? home(".claude", "projects"), "*", "*.jsonl")],
|
|
14254
|
-
parse: async (file) => toDiscovered(await extractClaudeSessionMeta(file)),
|
|
14255
|
-
walk: async function* (opts = {}) {
|
|
14256
|
-
for await (const meta of walkClaudeProjects({ root: opts.root, sinceMtimeMs: opts.sinceMtimeMs })) {
|
|
14257
|
-
const d = toDiscovered(meta);
|
|
14258
|
-
if (d) yield d;
|
|
14259
|
-
}
|
|
14260
|
-
}
|
|
14261
|
-
};
|
|
14262
|
-
codexSessions = {
|
|
14263
|
-
globs: (root) => [join10(root ?? resolveCodexSessionsRoot(), "**", "*.jsonl")],
|
|
14264
|
-
parse: async (file) => toDiscovered(await extractCodexSessionMeta(file)),
|
|
14265
|
-
walk: async function* (opts = {}) {
|
|
14266
|
-
for await (const meta of walkCodexSessions({ root: opts.root, sinceMtimeMs: opts.sinceMtimeMs })) {
|
|
14267
|
-
const d = toDiscovered(meta);
|
|
14268
|
-
if (d) yield d;
|
|
14269
|
-
}
|
|
14270
|
-
}
|
|
14271
|
-
};
|
|
14272
|
-
piSessions = {
|
|
14273
|
-
globs: (root) => [join10(root ?? resolvePiSessionsRoot(), "*", "*.jsonl")],
|
|
14274
|
-
parse: async (file) => toDiscovered(await extractPiSessionMeta(file)),
|
|
14275
|
-
walk: async function* (opts = {}) {
|
|
14276
|
-
for await (const meta of walkPiSessions({ root: opts.root, sinceMtimeMs: opts.sinceMtimeMs })) {
|
|
14277
|
-
const d = toDiscovered(meta);
|
|
14278
|
-
if (d) yield d;
|
|
14279
|
-
}
|
|
14280
|
-
}
|
|
14281
|
-
};
|
|
14282
|
-
AGENT_TARGETS = [
|
|
14283
|
-
{
|
|
14284
|
-
id: "cursor",
|
|
14285
|
-
displayName: "Cursor",
|
|
14286
|
-
skillsShAgentId: "cursor",
|
|
14287
|
-
detect: detectDir(home(".cursor")),
|
|
14288
|
-
skillsDir: { global: home(".cursor", "skills") },
|
|
14289
|
-
instructions: {
|
|
14290
|
-
files: [
|
|
14291
|
-
{ path: ".cursor/rules/syntaur-protocol.mdc", renderer: "cursorProtocol" },
|
|
14292
|
-
{ path: ".cursor/rules/syntaur-assignment.mdc", renderer: "cursorAssignment" }
|
|
14293
|
-
]
|
|
14294
|
-
}
|
|
14295
|
-
},
|
|
14296
|
-
{
|
|
14297
|
-
// codex is BOTH an adapter (writes AGENTS.md) AND a native plugin.
|
|
14298
|
-
id: "codex",
|
|
14299
|
-
displayName: "Codex",
|
|
14300
|
-
skillsShAgentId: "codex",
|
|
14301
|
-
nativePlugin: "codex",
|
|
14302
|
-
detect: detectDir(codexHome()),
|
|
14303
|
-
skillsDir: { global: resolve48(codexHome(), "skills") },
|
|
14304
|
-
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] },
|
|
14305
|
-
sessions: codexSessions
|
|
14306
|
-
},
|
|
14307
|
-
{
|
|
14308
|
-
id: "opencode",
|
|
14309
|
-
displayName: "OpenCode",
|
|
14310
|
-
skillsShAgentId: "opencode",
|
|
14311
|
-
detect: detectDir(home(".config", "opencode")),
|
|
14312
|
-
skillsDir: { global: home(".config", "opencode", "skills") },
|
|
14313
|
-
instructions: {
|
|
14314
|
-
files: [
|
|
14315
|
-
{ path: "AGENTS.md", renderer: "codexAgents" },
|
|
14316
|
-
{ path: "opencode.json", renderer: "openCodeConfig" }
|
|
14317
|
-
]
|
|
14318
|
-
}
|
|
14319
|
-
},
|
|
14320
|
-
{
|
|
14321
|
-
// claude has NO adapter today (not in the old SUPPORTED_FRAMEWORKS) — the
|
|
14322
|
-
// full plugin path owns its skills/hooks/commands. Native-plugin only.
|
|
14323
|
-
id: "claude",
|
|
14324
|
-
displayName: "Claude Code",
|
|
14325
|
-
skillsShAgentId: "claude-code",
|
|
14326
|
-
nativePlugin: "claude",
|
|
14327
|
-
detect: detectDir(home(".claude")),
|
|
14328
|
-
skillsDir: { global: home(".claude", "skills") },
|
|
14329
|
-
sessions: claudeSessions
|
|
14330
|
-
},
|
|
14331
|
-
{
|
|
14332
|
-
id: "pi",
|
|
14333
|
-
displayName: "Pi",
|
|
14334
|
-
skillsShAgentId: "pi",
|
|
14335
|
-
detect: detectDir(home(".pi")),
|
|
14336
|
-
skillsDir: { global: home(".pi", "agent", "skills") },
|
|
14337
|
-
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] },
|
|
14338
|
-
sessions: piSessions,
|
|
14339
|
-
tier3: {
|
|
14340
|
-
kind: "pi-extension",
|
|
14341
|
-
source: "platforms/pi/extensions/syntaur",
|
|
14342
|
-
installDir: () => home(".pi", "agent", "extensions", "syntaur"),
|
|
14343
|
-
entry: "index.ts"
|
|
14344
|
-
}
|
|
14345
|
-
},
|
|
14346
|
-
{
|
|
14347
|
-
id: "openclaw",
|
|
14348
|
-
displayName: "OpenClaw",
|
|
14349
|
-
skillsShAgentId: "openclaw",
|
|
14350
|
-
detect: detectDir(home(".openclaw")),
|
|
14351
|
-
skillsDir: { global: home(".openclaw", "skills") },
|
|
14352
|
-
instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] },
|
|
14353
|
-
// OpenClaw runs on pi-coding-agent (design memo), so it reuses the pi
|
|
14354
|
-
// extension SOURCE; only the install dir differs.
|
|
14355
|
-
tier3: {
|
|
14356
|
-
kind: "pi-extension",
|
|
14357
|
-
source: "platforms/pi/extensions/syntaur",
|
|
14358
|
-
installDir: () => home(".openclaw", "extensions", "syntaur"),
|
|
14359
|
-
entry: "index.ts"
|
|
14360
|
-
}
|
|
14361
|
-
},
|
|
14362
|
-
{
|
|
14363
|
-
id: "hermes",
|
|
14364
|
-
displayName: "Hermes Agent",
|
|
14365
|
-
skillsShAgentId: "hermes-agent",
|
|
14366
|
-
detect: () => fileExists(hermesHome()),
|
|
14367
|
-
skillsDir: { global: hermesSkillsDir() },
|
|
14368
|
-
instructions: { files: [{ path: "SOUL.md", renderer: "hermesSoul" }] },
|
|
14369
|
-
tier3: {
|
|
14370
|
-
kind: "hermes-plugin",
|
|
14371
|
-
source: "platforms/hermes/plugins/syntaur",
|
|
14372
|
-
installDir: () => resolve48(hermesHome(), "plugins", "syntaur"),
|
|
14373
|
-
entry: "plugin.yaml"
|
|
14374
|
-
}
|
|
14375
|
-
}
|
|
14376
|
-
];
|
|
14377
|
-
AGENT_TARGETS_BY_ID = Object.fromEntries(
|
|
14378
|
-
AGENT_TARGETS.map((t) => [t.id, t])
|
|
14379
|
-
);
|
|
14380
|
-
}
|
|
14381
|
-
});
|
|
14382
|
-
|
|
14383
14495
|
// src/sessions/agent-view.ts
|
|
14384
14496
|
import { execFile as execFile3 } from "child_process";
|
|
14385
14497
|
import { promisify as promisify3 } from "util";
|
|
@@ -14740,7 +14852,7 @@ import {
|
|
|
14740
14852
|
unlinkSync
|
|
14741
14853
|
} from "fs";
|
|
14742
14854
|
import { fileURLToPath as fileURLToPath9, pathToFileURL } from "url";
|
|
14743
|
-
import { dirname as dirname21, resolve as resolve74, join as
|
|
14855
|
+
import { dirname as dirname21, resolve as resolve74, join as join17 } from "path";
|
|
14744
14856
|
import { homedir as homedir13, tmpdir as tmpdir2 } from "os";
|
|
14745
14857
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
14746
14858
|
function syntaurRootMjs() {
|
|
@@ -14748,7 +14860,7 @@ function syntaurRootMjs() {
|
|
|
14748
14860
|
if (override3 && override3.length > 0) {
|
|
14749
14861
|
return override3;
|
|
14750
14862
|
}
|
|
14751
|
-
return
|
|
14863
|
+
return join17(homedir13(), ".syntaur");
|
|
14752
14864
|
}
|
|
14753
14865
|
async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
14754
14866
|
const { throwOnFailure } = options;
|
|
@@ -14781,19 +14893,19 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
|
14781
14893
|
const pkgRoot = resolve74(dirname21(fileURLToPath9(import.meta.url)), "..");
|
|
14782
14894
|
const cliBin = realpathSync4(resolve74(pkgRoot, "bin/syntaur.js"));
|
|
14783
14895
|
const nodeBin = process.execPath;
|
|
14784
|
-
const bundleParent =
|
|
14896
|
+
const bundleParent = join17(
|
|
14785
14897
|
homedir13(),
|
|
14786
14898
|
"Library",
|
|
14787
14899
|
"Application Support",
|
|
14788
14900
|
"Syntaur"
|
|
14789
14901
|
);
|
|
14790
|
-
const bundlePath =
|
|
14902
|
+
const bundlePath = join17(bundleParent, "syntaur-url.app");
|
|
14791
14903
|
mkdirSync3(bundleParent, { recursive: true });
|
|
14792
14904
|
if (existsSync6(bundlePath)) {
|
|
14793
14905
|
rmSync(bundlePath, { recursive: true, force: true });
|
|
14794
14906
|
}
|
|
14795
14907
|
const installedTerminals = detectInstalledTerminals();
|
|
14796
|
-
const scriptPath =
|
|
14908
|
+
const scriptPath = join17(
|
|
14797
14909
|
tmpdir2(),
|
|
14798
14910
|
`syntaur-url-handler-${process.pid}.applescript`
|
|
14799
14911
|
);
|
|
@@ -14812,7 +14924,7 @@ async function registerMacosUrlHandler(options = { throwOnFailure: false }) {
|
|
|
14812
14924
|
`osacompile exited with code ${compile.status}: ${compile.stderr || compile.stdout}`
|
|
14813
14925
|
);
|
|
14814
14926
|
}
|
|
14815
|
-
const infoPlistPath =
|
|
14927
|
+
const infoPlistPath = join17(bundlePath, "Contents", "Info.plist");
|
|
14816
14928
|
if (!existsSync6(infoPlistPath)) {
|
|
14817
14929
|
throw new Error(`osacompile did not produce ${infoPlistPath}`);
|
|
14818
14930
|
}
|
|
@@ -14907,7 +15019,7 @@ function detectInstalledTerminals() {
|
|
|
14907
15019
|
ghostty: "Ghostty.app",
|
|
14908
15020
|
warp: "Warp.app"
|
|
14909
15021
|
};
|
|
14910
|
-
const appDirs = ["/Applications",
|
|
15022
|
+
const appDirs = ["/Applications", join17(homedir13(), "Applications")];
|
|
14911
15023
|
for (const [id, bundleId] of Object.entries(bundleIds)) {
|
|
14912
15024
|
const r = spawnSync7(
|
|
14913
15025
|
"mdfind",
|
|
@@ -14919,7 +15031,7 @@ function detectInstalledTerminals() {
|
|
|
14919
15031
|
continue;
|
|
14920
15032
|
}
|
|
14921
15033
|
const name = bundleNames[id];
|
|
14922
|
-
if (name && appDirs.some((dir) => existsSync6(
|
|
15034
|
+
if (name && appDirs.some((dir) => existsSync6(join17(dir, name)))) {
|
|
14923
15035
|
installed.add(id);
|
|
14924
15036
|
}
|
|
14925
15037
|
}
|
|
@@ -15643,7 +15755,7 @@ __export(launchd_exports, {
|
|
|
15643
15755
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
15644
15756
|
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync3, rmSync as rmSync2, realpathSync as realpathSync5, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
15645
15757
|
import { homedir as homedir16, userInfo } from "os";
|
|
15646
|
-
import { dirname as dirname28, join as
|
|
15758
|
+
import { dirname as dirname28, join as join27, resolve as resolve99 } from "path";
|
|
15647
15759
|
function buildPlist(spec) {
|
|
15648
15760
|
const args = [spec.nodePath, spec.syntaurBin, ...spec.command ?? ["schedule", "tick"]];
|
|
15649
15761
|
const argXml = args.map((a) => ` <string>${escapeXml(a)}</string>`).join("\n");
|
|
@@ -15675,7 +15787,7 @@ function escapeXml(value) {
|
|
|
15675
15787
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
15676
15788
|
}
|
|
15677
15789
|
function defaultAcquireInstallLock(home2) {
|
|
15678
|
-
const lockPath =
|
|
15790
|
+
const lockPath = join27(home2, ".syntaur", "install-launch-agent.lock");
|
|
15679
15791
|
mkdirSync4(dirname28(lockPath), { recursive: true });
|
|
15680
15792
|
const fd = openSync2(lockPath, "wx");
|
|
15681
15793
|
return () => {
|
|
@@ -15711,10 +15823,10 @@ function resolveSpec(config, deps) {
|
|
|
15711
15823
|
nodePath: deps.nodePath ?? process.execPath,
|
|
15712
15824
|
syntaurBin: absolutize(deps.syntaurBin ?? process.argv[1] ?? "syntaur"),
|
|
15713
15825
|
intervalSeconds: deps.intervalSeconds ?? config.defaultIntervalSeconds,
|
|
15714
|
-
outLog:
|
|
15715
|
-
errLog:
|
|
15826
|
+
outLog: join27(home2, ".syntaur", "logs", config.outLogName),
|
|
15827
|
+
errLog: join27(home2, ".syntaur", "logs", config.errLogName)
|
|
15716
15828
|
};
|
|
15717
|
-
const plistPath =
|
|
15829
|
+
const plistPath = join27(home2, "Library", "LaunchAgents", `${spec.label}.plist`);
|
|
15718
15830
|
return { spec, plistPath, home: home2, uid };
|
|
15719
15831
|
}
|
|
15720
15832
|
function installAgent(config, deps) {
|
|
@@ -15724,8 +15836,8 @@ function installAgent(config, deps) {
|
|
|
15724
15836
|
const run3 = deps.run ?? defaultRun;
|
|
15725
15837
|
const releaseLock2 = (deps.acquireInstallLock ?? (() => defaultAcquireInstallLock(home2)))();
|
|
15726
15838
|
try {
|
|
15727
|
-
mkdirp(
|
|
15728
|
-
mkdirp(
|
|
15839
|
+
mkdirp(join27(home2, ".syntaur", "logs"));
|
|
15840
|
+
mkdirp(join27(home2, "Library", "LaunchAgents"));
|
|
15729
15841
|
writeFile17(plistPath, buildPlist(spec));
|
|
15730
15842
|
const domain = `gui/${uid}`;
|
|
15731
15843
|
run3("launchctl", ["bootout", `${domain}/${spec.label}`]);
|
|
@@ -20602,6 +20714,55 @@ function createAgentSessionsRouter(projectsDir2, broadcast, assignmentsDir2) {
|
|
|
20602
20714
|
init_config2();
|
|
20603
20715
|
init_agents_schema();
|
|
20604
20716
|
import { Router as Router5 } from "express";
|
|
20717
|
+
|
|
20718
|
+
// src/targets/agent-definitions.ts
|
|
20719
|
+
init_parser();
|
|
20720
|
+
init_registry();
|
|
20721
|
+
import { readdir as readdir16, readFile as readFile21 } from "fs/promises";
|
|
20722
|
+
import { join as join6 } from "path";
|
|
20723
|
+
async function collectMarkdown(dir, out) {
|
|
20724
|
+
let entries;
|
|
20725
|
+
try {
|
|
20726
|
+
entries = await readdir16(dir, { withFileTypes: true });
|
|
20727
|
+
} catch {
|
|
20728
|
+
return;
|
|
20729
|
+
}
|
|
20730
|
+
for (const entry of entries) {
|
|
20731
|
+
const full = join6(dir, entry.name);
|
|
20732
|
+
if (entry.isDirectory()) {
|
|
20733
|
+
await collectMarkdown(full, out);
|
|
20734
|
+
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
20735
|
+
out.push(full);
|
|
20736
|
+
}
|
|
20737
|
+
}
|
|
20738
|
+
}
|
|
20739
|
+
async function discoverClaudeAgents(root) {
|
|
20740
|
+
const dir = root ?? getAgentTarget("claude")?.agentsDir;
|
|
20741
|
+
if (!dir) return [];
|
|
20742
|
+
const files = [];
|
|
20743
|
+
await collectMarkdown(dir, files);
|
|
20744
|
+
files.sort();
|
|
20745
|
+
const byName = /* @__PURE__ */ new Map();
|
|
20746
|
+
for (const file of files) {
|
|
20747
|
+
let content;
|
|
20748
|
+
try {
|
|
20749
|
+
content = await readFile21(file, "utf-8");
|
|
20750
|
+
} catch {
|
|
20751
|
+
continue;
|
|
20752
|
+
}
|
|
20753
|
+
const [frontmatter] = extractFrontmatter(content);
|
|
20754
|
+
if (!frontmatter) continue;
|
|
20755
|
+
const name = getField(frontmatter, "name")?.trim();
|
|
20756
|
+
if (!name) continue;
|
|
20757
|
+
if (byName.has(name)) continue;
|
|
20758
|
+
const description = getField(frontmatter, "description")?.trim() || void 0;
|
|
20759
|
+
const model = getField(frontmatter, "model")?.trim() || void 0;
|
|
20760
|
+
byName.set(name, { name, description, model, path: file });
|
|
20761
|
+
}
|
|
20762
|
+
return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
20763
|
+
}
|
|
20764
|
+
|
|
20765
|
+
// src/dashboard/api-agents.ts
|
|
20605
20766
|
function mapAgentErrorToFieldErrors(err2) {
|
|
20606
20767
|
const message = err2.message;
|
|
20607
20768
|
let match = message.match(/^agent id "([^"]*)" is invalid/);
|
|
@@ -20689,6 +20850,38 @@ function mapAgentErrorToFieldErrors(err2) {
|
|
|
20689
20850
|
]
|
|
20690
20851
|
};
|
|
20691
20852
|
}
|
|
20853
|
+
match = message.match(/^agent "([^"]+)" has invalid agentName/);
|
|
20854
|
+
if (match) {
|
|
20855
|
+
return {
|
|
20856
|
+
error: message,
|
|
20857
|
+
fieldErrors: [{ id: match[1], field: "agentName", message: "must be a single line" }]
|
|
20858
|
+
};
|
|
20859
|
+
}
|
|
20860
|
+
match = message.match(/^agent "([^"]+)" has invalid workdir/);
|
|
20861
|
+
if (match) {
|
|
20862
|
+
return {
|
|
20863
|
+
error: message,
|
|
20864
|
+
fieldErrors: [{ id: match[1], field: "workdir", message: "must be a single line" }]
|
|
20865
|
+
};
|
|
20866
|
+
}
|
|
20867
|
+
match = message.match(/^agent "([^"]+)" sets both agentName and workdir/);
|
|
20868
|
+
if (match) {
|
|
20869
|
+
return {
|
|
20870
|
+
error: message,
|
|
20871
|
+
fieldErrors: [
|
|
20872
|
+
{ id: match[1], field: "workdir", message: "agentName and workdir are mutually exclusive" }
|
|
20873
|
+
]
|
|
20874
|
+
};
|
|
20875
|
+
}
|
|
20876
|
+
match = message.match(/^agent "([^"]+)" sets both agentName and model/);
|
|
20877
|
+
if (match) {
|
|
20878
|
+
return {
|
|
20879
|
+
error: message,
|
|
20880
|
+
fieldErrors: [
|
|
20881
|
+
{ id: match[1], field: "model", message: "remove the profile model; the agent defines its own" }
|
|
20882
|
+
]
|
|
20883
|
+
};
|
|
20884
|
+
}
|
|
20692
20885
|
return { error: message };
|
|
20693
20886
|
}
|
|
20694
20887
|
function coerceAgentRow(raw2, index) {
|
|
@@ -20836,10 +21029,47 @@ function coerceAgentRow(raw2, index) {
|
|
|
20836
21029
|
}
|
|
20837
21030
|
if (entry.launchPrompt.trim()) cleaned.launchPrompt = entry.launchPrompt;
|
|
20838
21031
|
}
|
|
21032
|
+
if (entry.agentName !== void 0) {
|
|
21033
|
+
if (typeof entry.agentName !== "string") {
|
|
21034
|
+
return {
|
|
21035
|
+
ok: false,
|
|
21036
|
+
status: 400,
|
|
21037
|
+
body: {
|
|
21038
|
+
error: `agents[${index}].agentName must be a string`,
|
|
21039
|
+
fieldErrors: [{ id, field: "agentName", message: "agentName must be a string" }]
|
|
21040
|
+
}
|
|
21041
|
+
};
|
|
21042
|
+
}
|
|
21043
|
+
const agentName = entry.agentName.trim();
|
|
21044
|
+
if (agentName) cleaned.agentName = agentName;
|
|
21045
|
+
}
|
|
21046
|
+
if (entry.workdir !== void 0) {
|
|
21047
|
+
if (typeof entry.workdir !== "string") {
|
|
21048
|
+
return {
|
|
21049
|
+
ok: false,
|
|
21050
|
+
status: 400,
|
|
21051
|
+
body: {
|
|
21052
|
+
error: `agents[${index}].workdir must be a string`,
|
|
21053
|
+
fieldErrors: [{ id, field: "workdir", message: "workdir must be a string" }]
|
|
21054
|
+
}
|
|
21055
|
+
};
|
|
21056
|
+
}
|
|
21057
|
+
const workdir = entry.workdir.trim();
|
|
21058
|
+
if (workdir) cleaned.workdir = workdir;
|
|
21059
|
+
}
|
|
20839
21060
|
return { ok: true, value: cleaned };
|
|
20840
21061
|
}
|
|
20841
21062
|
function createAgentsRouter() {
|
|
20842
21063
|
const router = Router5();
|
|
21064
|
+
router.get("/claude-discovered", async (_req, res) => {
|
|
21065
|
+
try {
|
|
21066
|
+
const agents = await discoverClaudeAgents();
|
|
21067
|
+
res.json({ agents });
|
|
21068
|
+
} catch (err2) {
|
|
21069
|
+
console.error("Error discovering Claude agents:", err2);
|
|
21070
|
+
res.status(500).json({ error: "Failed to discover Claude agents" });
|
|
21071
|
+
}
|
|
21072
|
+
});
|
|
20843
21073
|
router.get("/", async (_req, res) => {
|
|
20844
21074
|
try {
|
|
20845
21075
|
const config = await readConfig();
|
|
@@ -20902,8 +21132,8 @@ import { Router as Router6 } from "express";
|
|
|
20902
21132
|
// src/utils/terminal-probe.ts
|
|
20903
21133
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
20904
21134
|
import { existsSync as existsSync2 } from "fs";
|
|
20905
|
-
import { homedir as
|
|
20906
|
-
import { join as
|
|
21135
|
+
import { homedir as homedir5 } from "os";
|
|
21136
|
+
import { join as join7 } from "path";
|
|
20907
21137
|
var APP_BUNDLE_IDS = {
|
|
20908
21138
|
"terminal-app": "com.apple.Terminal",
|
|
20909
21139
|
iterm: "com.googlecode.iterm2",
|
|
@@ -20920,7 +21150,7 @@ var APP_FIXED_PATHS = {
|
|
|
20920
21150
|
"terminal-app": "/System/Applications/Utilities/Terminal.app"
|
|
20921
21151
|
};
|
|
20922
21152
|
function defaultApplicationsDirs() {
|
|
20923
|
-
return ["/Applications",
|
|
21153
|
+
return ["/Applications", join7(homedir5(), "Applications")];
|
|
20924
21154
|
}
|
|
20925
21155
|
function findAppBundle(terminal, dirs = defaultApplicationsDirs()) {
|
|
20926
21156
|
const fixed = APP_FIXED_PATHS[terminal];
|
|
@@ -20928,7 +21158,7 @@ function findAppBundle(terminal, dirs = defaultApplicationsDirs()) {
|
|
|
20928
21158
|
const bundleName = APP_BUNDLE_NAMES[terminal];
|
|
20929
21159
|
if (bundleName) {
|
|
20930
21160
|
for (const dir of dirs) {
|
|
20931
|
-
const candidate =
|
|
21161
|
+
const candidate = join7(dir, bundleName);
|
|
20932
21162
|
if (existsSync2(candidate)) return candidate;
|
|
20933
21163
|
}
|
|
20934
21164
|
}
|
|
@@ -20958,11 +21188,11 @@ var defaultCmuxLsappinfoRunner = () => {
|
|
|
20958
21188
|
function resolveCmuxCli(applicationsDirsOverride, cliDirsOverride, lsappinfoRunnerOverride) {
|
|
20959
21189
|
const bundle = findAppBundle("cmux", applicationsDirsOverride);
|
|
20960
21190
|
if (bundle) {
|
|
20961
|
-
const cli =
|
|
21191
|
+
const cli = join7(bundle, "Contents/Resources/bin/cmux");
|
|
20962
21192
|
if (existsSync2(cli)) return cli;
|
|
20963
21193
|
}
|
|
20964
21194
|
for (const dir of cliDirsOverride ?? CMUX_CLI_DIRS) {
|
|
20965
|
-
const cli =
|
|
21195
|
+
const cli = join7(dir, "cmux");
|
|
20966
21196
|
if (existsSync2(cli)) return cli;
|
|
20967
21197
|
}
|
|
20968
21198
|
if (process.platform === "darwin") {
|
|
@@ -20971,7 +21201,7 @@ function resolveCmuxCli(applicationsDirsOverride, cliDirsOverride, lsappinfoRunn
|
|
|
20971
21201
|
if (stdout) {
|
|
20972
21202
|
const match = stdout.match(/"LSBundlePath"="([^"]+)"/);
|
|
20973
21203
|
if (match) {
|
|
20974
|
-
const cli =
|
|
21204
|
+
const cli = join7(match[1], "Contents/Resources/bin/cmux");
|
|
20975
21205
|
if (existsSync2(cli)) return cli;
|
|
20976
21206
|
}
|
|
20977
21207
|
}
|
|
@@ -21058,6 +21288,7 @@ function parseOpenUrl(input4) {
|
|
|
21058
21288
|
}
|
|
21059
21289
|
const assignmentVals = url.searchParams.getAll("assignment");
|
|
21060
21290
|
const sessionVals = url.searchParams.getAll("session");
|
|
21291
|
+
const standaloneVals = url.searchParams.getAll("standalone");
|
|
21061
21292
|
if (assignmentVals.length > 1) {
|
|
21062
21293
|
throw new OpenUrlError(
|
|
21063
21294
|
"duplicate-param",
|
|
@@ -21070,10 +21301,17 @@ function parseOpenUrl(input4) {
|
|
|
21070
21301
|
"URL has more than one `session` query param"
|
|
21071
21302
|
);
|
|
21072
21303
|
}
|
|
21073
|
-
if (
|
|
21304
|
+
if (standaloneVals.length > 1) {
|
|
21305
|
+
throw new OpenUrlError(
|
|
21306
|
+
"duplicate-param",
|
|
21307
|
+
"URL has more than one `standalone` query param"
|
|
21308
|
+
);
|
|
21309
|
+
}
|
|
21310
|
+
const kindsPresent = assignmentVals.length + sessionVals.length + standaloneVals.length;
|
|
21311
|
+
if (kindsPresent > 1) {
|
|
21074
21312
|
throw new OpenUrlError(
|
|
21075
21313
|
"both-ids",
|
|
21076
|
-
"URL has
|
|
21314
|
+
"URL has more than one of `assignment`, `session`, `standalone` \u2014 only one is allowed"
|
|
21077
21315
|
);
|
|
21078
21316
|
}
|
|
21079
21317
|
const terminalVals = url.searchParams.getAll("terminal");
|
|
@@ -21123,6 +21361,37 @@ function parseOpenUrl(input4) {
|
|
|
21123
21361
|
}
|
|
21124
21362
|
prompt = value;
|
|
21125
21363
|
}
|
|
21364
|
+
const agentNameVals = url.searchParams.getAll("agentName");
|
|
21365
|
+
if (agentNameVals.length > 1) {
|
|
21366
|
+
throw new OpenUrlError(
|
|
21367
|
+
"duplicate-param",
|
|
21368
|
+
"URL has more than one `agentName` query param"
|
|
21369
|
+
);
|
|
21370
|
+
}
|
|
21371
|
+
let agentName;
|
|
21372
|
+
if (agentNameVals.length === 1 && agentNameVals[0].trim() !== "") {
|
|
21373
|
+
const value = agentNameVals[0];
|
|
21374
|
+
if (value.length > MAX_OPEN_PROMPT_LENGTH) {
|
|
21375
|
+
throw new OpenUrlError(
|
|
21376
|
+
"invalid-prompt",
|
|
21377
|
+
`\`agentName\` query param exceeds ${MAX_OPEN_PROMPT_LENGTH} characters`
|
|
21378
|
+
);
|
|
21379
|
+
}
|
|
21380
|
+
agentName = value;
|
|
21381
|
+
}
|
|
21382
|
+
if (standaloneVals.length === 1) {
|
|
21383
|
+
const id = standaloneVals[0];
|
|
21384
|
+
if (id.trim() === "") {
|
|
21385
|
+
throw new OpenUrlError("missing-id", "`standalone` query param is empty");
|
|
21386
|
+
}
|
|
21387
|
+
return {
|
|
21388
|
+
kind: "standalone",
|
|
21389
|
+
id,
|
|
21390
|
+
...terminal ? { terminal } : {},
|
|
21391
|
+
// standalone identifies the agent by `id`; keep an optional prompt override.
|
|
21392
|
+
...prompt !== void 0 ? { prompt } : {}
|
|
21393
|
+
};
|
|
21394
|
+
}
|
|
21126
21395
|
if (assignmentVals.length === 1) {
|
|
21127
21396
|
const id = assignmentVals[0];
|
|
21128
21397
|
if (id.trim() === "") {
|
|
@@ -21137,7 +21406,8 @@ function parseOpenUrl(input4) {
|
|
|
21137
21406
|
...terminal ? { terminal } : {},
|
|
21138
21407
|
...agent ? { agent } : {},
|
|
21139
21408
|
// assignment-only; keep '' (presence-significant) — hence !== undefined.
|
|
21140
|
-
...prompt !== void 0 ? { prompt } : {}
|
|
21409
|
+
...prompt !== void 0 ? { prompt } : {},
|
|
21410
|
+
...agentName ? { agentName } : {}
|
|
21141
21411
|
};
|
|
21142
21412
|
}
|
|
21143
21413
|
if (sessionVals.length === 1) {
|
|
@@ -21173,7 +21443,7 @@ function parseOpenUrl(input4) {
|
|
|
21173
21443
|
}
|
|
21174
21444
|
throw new OpenUrlError(
|
|
21175
21445
|
"missing-id",
|
|
21176
|
-
"URL must include
|
|
21446
|
+
"URL must include one of `assignment=<id>`, `session=<id>`, or `standalone=<agentId>`"
|
|
21177
21447
|
);
|
|
21178
21448
|
}
|
|
21179
21449
|
|
|
@@ -21249,8 +21519,60 @@ async function resolveLaunchPlan(input4) {
|
|
|
21249
21519
|
if (input4.kind === "assignment") {
|
|
21250
21520
|
return resolveAssignmentPlan(input4, terminal);
|
|
21251
21521
|
}
|
|
21522
|
+
if (input4.kind === "standalone") {
|
|
21523
|
+
return resolveStandalonePlan(input4, terminal);
|
|
21524
|
+
}
|
|
21252
21525
|
return resolveSessionPlan(input4, terminal);
|
|
21253
21526
|
}
|
|
21527
|
+
async function resolveStandalonePlan(input4, terminal) {
|
|
21528
|
+
const agentId = input4.agentId ?? input4.id;
|
|
21529
|
+
if (!agentId) {
|
|
21530
|
+
throw new LaunchError(
|
|
21531
|
+
"agent-not-configured",
|
|
21532
|
+
"A standalone launch requires an agent id."
|
|
21533
|
+
);
|
|
21534
|
+
}
|
|
21535
|
+
const agent = getAgents(input4.config).find((a) => a.id === agentId);
|
|
21536
|
+
if (!agent) {
|
|
21537
|
+
throw new LaunchError(
|
|
21538
|
+
"agent-not-configured",
|
|
21539
|
+
`Agent "${agentId}" requested for a standalone launch is not in your agents list.`
|
|
21540
|
+
);
|
|
21541
|
+
}
|
|
21542
|
+
const wd = agent.workdir?.trim();
|
|
21543
|
+
if (!wd) {
|
|
21544
|
+
throw new LaunchError(
|
|
21545
|
+
"workspace-path-invalid",
|
|
21546
|
+
`Agent "${agent.id}" has no workdir \u2014 a standalone launch requires a valid workdir.`
|
|
21547
|
+
);
|
|
21548
|
+
}
|
|
21549
|
+
const expanded = expandHome(wd);
|
|
21550
|
+
if (!isExistingDir(expanded)) {
|
|
21551
|
+
throw new LaunchError(
|
|
21552
|
+
"workspace-path-invalid",
|
|
21553
|
+
`Agent "${agent.id}" workdir ${agent.workdir} (resolved ${expanded}) is not an existing directory \u2014 a standalone launch requires a valid workdir.`
|
|
21554
|
+
);
|
|
21555
|
+
}
|
|
21556
|
+
const knownPlaybookSlugs = await listPlaybookSlugs(playbooksDir());
|
|
21557
|
+
const template = input4.promptOverride !== void 0 ? input4.promptOverride : agent.launchPrompt;
|
|
21558
|
+
const { prompt, warnings: promptWarnings } = resolveLaunchPrompt({
|
|
21559
|
+
template,
|
|
21560
|
+
playbook: agent.playbook,
|
|
21561
|
+
projectSlug: null,
|
|
21562
|
+
knownPlaybookSlugs
|
|
21563
|
+
});
|
|
21564
|
+
const { argv, shellFallbackWarning } = buildFreshArgv(agent, prompt);
|
|
21565
|
+
return {
|
|
21566
|
+
terminal,
|
|
21567
|
+
cwd: expanded,
|
|
21568
|
+
argv,
|
|
21569
|
+
env: process.env,
|
|
21570
|
+
agentId: agent.id,
|
|
21571
|
+
fallbackWarning: null,
|
|
21572
|
+
shellFallbackWarning,
|
|
21573
|
+
promptWarnings
|
|
21574
|
+
};
|
|
21575
|
+
}
|
|
21254
21576
|
async function resolveAssignmentPlan(input4, terminal) {
|
|
21255
21577
|
const resolved = await resolveAssignmentById(
|
|
21256
21578
|
input4.projectsDir,
|
|
@@ -21274,17 +21596,6 @@ async function resolveAssignmentPlan(input4, terminal) {
|
|
|
21274
21596
|
`Assignment ${input4.id} resolver returned a directory but detail could not be loaded`
|
|
21275
21597
|
);
|
|
21276
21598
|
}
|
|
21277
|
-
const picked = resolveWorkspaceCwd({
|
|
21278
|
-
worktreePath: detail.workspace.worktreePath,
|
|
21279
|
-
repository: detail.workspace.repository,
|
|
21280
|
-
branch: detail.workspace.branch,
|
|
21281
|
-
assignmentSlug: resolved.assignmentSlug
|
|
21282
|
-
});
|
|
21283
|
-
if (picked.cwd === null) {
|
|
21284
|
-
throw new LaunchError("workspace-path-invalid", picked.invalidReason);
|
|
21285
|
-
}
|
|
21286
|
-
const cwd = picked.cwd;
|
|
21287
|
-
const fallbackWarning = picked.fallbackWarning;
|
|
21288
21599
|
let agent;
|
|
21289
21600
|
if (input4.agentId) {
|
|
21290
21601
|
const found = getAgents(input4.config).find((a) => a.id === input4.agentId);
|
|
@@ -21298,6 +21609,30 @@ async function resolveAssignmentPlan(input4, terminal) {
|
|
|
21298
21609
|
} else {
|
|
21299
21610
|
agent = pickAgent(input4.config);
|
|
21300
21611
|
}
|
|
21612
|
+
if (input4.agentName !== void 0) {
|
|
21613
|
+
agent = { ...agent, agentName: input4.agentName };
|
|
21614
|
+
}
|
|
21615
|
+
const picked = resolveWorkspaceCwd({
|
|
21616
|
+
worktreePath: detail.workspace.worktreePath,
|
|
21617
|
+
repository: detail.workspace.repository,
|
|
21618
|
+
branch: detail.workspace.branch,
|
|
21619
|
+
assignmentSlug: resolved.assignmentSlug
|
|
21620
|
+
});
|
|
21621
|
+
if (picked.cwd === null) {
|
|
21622
|
+
throw new LaunchError("workspace-path-invalid", picked.invalidReason);
|
|
21623
|
+
}
|
|
21624
|
+
const launchCwd = resolveLaunchCwd(agent, picked.cwd);
|
|
21625
|
+
if (launchCwd.invalidReason) {
|
|
21626
|
+
throw new LaunchError("workspace-path-invalid", launchCwd.invalidReason);
|
|
21627
|
+
}
|
|
21628
|
+
const cwd = launchCwd.spawnCwd;
|
|
21629
|
+
const fallbackWarning = picked.fallbackWarning;
|
|
21630
|
+
const promptWarningsExtra = [];
|
|
21631
|
+
if (input4.agentName !== void 0 && input4.agentName.trim() && agent.model?.trim()) {
|
|
21632
|
+
promptWarningsExtra.push(
|
|
21633
|
+
`profile model "${agent.model.trim()}" suppressed: agent "${input4.agentName.trim()}" defines its own model`
|
|
21634
|
+
);
|
|
21635
|
+
}
|
|
21301
21636
|
const knownPlaybookSlugs = await listPlaybookSlugs(playbooksDir());
|
|
21302
21637
|
const template = input4.promptOverride !== void 0 ? input4.promptOverride : agent.launchPrompt;
|
|
21303
21638
|
const { prompt, warnings: promptWarnings } = resolveLaunchPrompt({
|
|
@@ -21307,6 +21642,8 @@ async function resolveAssignmentPlan(input4, terminal) {
|
|
|
21307
21642
|
assignmentDir: resolved.assignmentDir,
|
|
21308
21643
|
projectSlug: resolved.projectSlug,
|
|
21309
21644
|
assignmentSlug: resolved.assignmentSlug,
|
|
21645
|
+
worktreePath: launchCwd.worktreePath,
|
|
21646
|
+
spawnCwd: launchCwd.spawnCwd,
|
|
21310
21647
|
knownPlaybookSlugs
|
|
21311
21648
|
});
|
|
21312
21649
|
const { argv, shellFallbackWarning } = buildFreshArgv(agent, prompt);
|
|
@@ -21318,7 +21655,7 @@ async function resolveAssignmentPlan(input4, terminal) {
|
|
|
21318
21655
|
agentId: agent.id,
|
|
21319
21656
|
fallbackWarning,
|
|
21320
21657
|
shellFallbackWarning,
|
|
21321
|
-
promptWarnings
|
|
21658
|
+
promptWarnings: [...promptWarningsExtra, ...promptWarnings]
|
|
21322
21659
|
};
|
|
21323
21660
|
}
|
|
21324
21661
|
async function resolveSessionPlan(input4, terminal) {
|
|
@@ -21395,8 +21732,8 @@ async function resolveSessionPlan(input4, terminal) {
|
|
|
21395
21732
|
// src/launch/execute.ts
|
|
21396
21733
|
init_launch();
|
|
21397
21734
|
import { spawn as spawn3 } from "child_process";
|
|
21398
|
-
import { homedir as
|
|
21399
|
-
import { basename as basename5, join as
|
|
21735
|
+
import { homedir as homedir6 } from "os";
|
|
21736
|
+
import { basename as basename5, join as join8, resolve as resolve32 } from "path";
|
|
21400
21737
|
init_fs();
|
|
21401
21738
|
init_config2();
|
|
21402
21739
|
init_session_id();
|
|
@@ -21502,7 +21839,7 @@ async function registerLaunchAtBirth(plan, child) {
|
|
|
21502
21839
|
const sessionId = plan.session?.sessionId ?? null;
|
|
21503
21840
|
const procStart = captureProcessStartedAt(pid);
|
|
21504
21841
|
const envDir = process.env.SYNTAUR_RUNTIME_SESSIONS_DIR;
|
|
21505
|
-
const markerDir = envDir && envDir.length > 0 ? envDir :
|
|
21842
|
+
const markerDir = envDir && envDir.length > 0 ? envDir : join8(homedir6(), ".syntaur", "runtime", "sessions");
|
|
21506
21843
|
writeRuntimeMarker(
|
|
21507
21844
|
pid,
|
|
21508
21845
|
{
|
|
@@ -21515,7 +21852,7 @@ async function registerLaunchAtBirth(plan, child) {
|
|
|
21515
21852
|
markerDir
|
|
21516
21853
|
);
|
|
21517
21854
|
if (!sessionId) return;
|
|
21518
|
-
if (autoTrack === "workspaces-only" && !await fileExists(
|
|
21855
|
+
if (autoTrack === "workspaces-only" && !await fileExists(resolve32(plan.cwd, ".syntaur", "context.json"))) {
|
|
21519
21856
|
return;
|
|
21520
21857
|
}
|
|
21521
21858
|
const { initSessionDb: initSessionDb2 } = await Promise.resolve().then(() => (init_session_db(), session_db_exports));
|
|
@@ -21694,7 +22031,7 @@ init_launch_prompt();
|
|
|
21694
22031
|
init_paths();
|
|
21695
22032
|
init_fs();
|
|
21696
22033
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
21697
|
-
import { dirname as dirname7, resolve as
|
|
22034
|
+
import { dirname as dirname7, resolve as resolve33, join as join9 } from "path";
|
|
21698
22035
|
import { realpathSync, readFileSync as readFileSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
21699
22036
|
var NPX_PATTERNS = [
|
|
21700
22037
|
{ kind: "npm", re: /\/_npx\/([^/]+)\/node_modules(?:\/|$)/ },
|
|
@@ -21720,7 +22057,7 @@ function normalizeSlashes(p) {
|
|
|
21720
22057
|
}
|
|
21721
22058
|
function detectInstallKind(scriptUrl, opts = {}) {
|
|
21722
22059
|
const realpath3 = opts.realpath ?? realpathSync.native;
|
|
21723
|
-
const
|
|
22060
|
+
const readFile82 = opts.readFile ?? ((p) => readFileSync3(p, "utf-8"));
|
|
21724
22061
|
const ua = opts.envUserAgent !== void 0 ? opts.envUserAgent : process.env.npm_config_user_agent ?? "";
|
|
21725
22062
|
const resolved = resolveScriptPath(scriptUrl, realpath3);
|
|
21726
22063
|
if (resolved === null) {
|
|
@@ -21738,10 +22075,10 @@ function detectInstallKind(scriptUrl, opts = {}) {
|
|
|
21738
22075
|
}
|
|
21739
22076
|
let dir = dirname7(resolved);
|
|
21740
22077
|
for (let depth = 0; depth < 8; depth++) {
|
|
21741
|
-
const pkgJsonPath =
|
|
22078
|
+
const pkgJsonPath = join9(dir, "package.json");
|
|
21742
22079
|
let raw2;
|
|
21743
22080
|
try {
|
|
21744
|
-
raw2 =
|
|
22081
|
+
raw2 = readFile82(pkgJsonPath);
|
|
21745
22082
|
} catch {
|
|
21746
22083
|
const parent2 = dirname7(dir);
|
|
21747
22084
|
if (parent2 === dir) break;
|
|
@@ -21773,13 +22110,13 @@ function extractNpxHash(scriptUrl, opts = {}) {
|
|
|
21773
22110
|
return null;
|
|
21774
22111
|
}
|
|
21775
22112
|
function nudgeStampDir() {
|
|
21776
|
-
return
|
|
22113
|
+
return resolve33(syntaurRoot(), "npx-handler-nudge");
|
|
21777
22114
|
}
|
|
21778
22115
|
function sanitizeHash(hash) {
|
|
21779
22116
|
return hash.replace(/[^A-Za-z0-9_-]/g, "_") || "_";
|
|
21780
22117
|
}
|
|
21781
22118
|
function nudgeStampPath(hash) {
|
|
21782
|
-
return
|
|
22119
|
+
return join9(nudgeStampDir(), sanitizeHash(hash));
|
|
21783
22120
|
}
|
|
21784
22121
|
async function hasNudgedHash(hash) {
|
|
21785
22122
|
return fileExists(nudgeStampPath(hash));
|
|
@@ -21980,7 +22317,8 @@ function createLaunchPreflightRouter(projectsDir2, assignmentsDir2) {
|
|
|
21980
22317
|
playbook: agent.playbook,
|
|
21981
22318
|
projectSlug: resolved.projectSlug,
|
|
21982
22319
|
assignmentSlug: resolved.assignmentSlug,
|
|
21983
|
-
id: resolved.id
|
|
22320
|
+
id: resolved.id,
|
|
22321
|
+
workdir: agent.workdir
|
|
21984
22322
|
});
|
|
21985
22323
|
res.json({ template, knownPlaybookSlugs });
|
|
21986
22324
|
} catch (error) {
|
|
@@ -22224,7 +22562,7 @@ init_frontmatter();
|
|
|
22224
22562
|
init_event_emit();
|
|
22225
22563
|
init_assignment_walk();
|
|
22226
22564
|
init_timestamp();
|
|
22227
|
-
import { readFile as
|
|
22565
|
+
import { readFile as readFile22, writeFile as writeFile5, rm as rm2 } from "fs/promises";
|
|
22228
22566
|
import { dirname as dirname8 } from "path";
|
|
22229
22567
|
var StatusResolutionError = class extends Error {
|
|
22230
22568
|
constructor(message, code) {
|
|
@@ -22243,7 +22581,7 @@ async function scanAssignmentsByStatus(projectsDir2, standaloneDir, ids) {
|
|
|
22243
22581
|
const assignmentPath = `${entry.assignmentDir}/assignment.md`;
|
|
22244
22582
|
let content;
|
|
22245
22583
|
try {
|
|
22246
|
-
content = await
|
|
22584
|
+
content = await readFile22(assignmentPath, "utf-8");
|
|
22247
22585
|
} catch (err2) {
|
|
22248
22586
|
const code = err2?.code;
|
|
22249
22587
|
if (code === "ENOENT") {
|
|
@@ -22306,7 +22644,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
|
|
|
22306
22644
|
const list = affected.get(r.id) ?? [];
|
|
22307
22645
|
for (const a of list) {
|
|
22308
22646
|
try {
|
|
22309
|
-
const content = await
|
|
22647
|
+
const content = await readFile22(a.path, "utf-8");
|
|
22310
22648
|
buffer.set(a.path, content);
|
|
22311
22649
|
} catch (err2) {
|
|
22312
22650
|
const code = err2?.code;
|
|
@@ -22335,7 +22673,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
|
|
|
22335
22673
|
for (const a of list) {
|
|
22336
22674
|
let current;
|
|
22337
22675
|
try {
|
|
22338
|
-
current = await
|
|
22676
|
+
current = await readFile22(a.path, "utf-8");
|
|
22339
22677
|
} catch (err2) {
|
|
22340
22678
|
const code = err2?.code;
|
|
22341
22679
|
if (code === "ENOENT") {
|
|
@@ -22406,7 +22744,7 @@ async function applyStatusResolutions(resolutions, affected, validTargets) {
|
|
|
22406
22744
|
const list = affected.get(r.id) ?? [];
|
|
22407
22745
|
for (const a of list) {
|
|
22408
22746
|
try {
|
|
22409
|
-
const current = await
|
|
22747
|
+
const current = await readFile22(a.path, "utf-8");
|
|
22410
22748
|
const fm = parseAssignmentFrontmatter(current);
|
|
22411
22749
|
if (fm.status !== r.id) {
|
|
22412
22750
|
console.warn(
|
|
@@ -22457,7 +22795,7 @@ async function scanAssignmentsReferencingStatus(projectsDir2, standaloneDir, id)
|
|
|
22457
22795
|
const assignmentPath = `${entry.assignmentDir}/assignment.md`;
|
|
22458
22796
|
let content;
|
|
22459
22797
|
try {
|
|
22460
|
-
content = await
|
|
22798
|
+
content = await readFile22(assignmentPath, "utf-8");
|
|
22461
22799
|
} catch (err2) {
|
|
22462
22800
|
const code = err2?.code;
|
|
22463
22801
|
if (code === "ENOENT") continue;
|
|
@@ -22917,7 +23255,7 @@ import { Router as Router12 } from "express";
|
|
|
22917
23255
|
init_paths();
|
|
22918
23256
|
import Database3 from "better-sqlite3";
|
|
22919
23257
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
22920
|
-
import { resolve as
|
|
23258
|
+
import { resolve as resolve34 } from "path";
|
|
22921
23259
|
var db3 = null;
|
|
22922
23260
|
var LEASE_SCHEMA_VERSION = "1";
|
|
22923
23261
|
var SCHEMA_SQL3 = `
|
|
@@ -23041,7 +23379,7 @@ function isBusyError(err2) {
|
|
|
23041
23379
|
}
|
|
23042
23380
|
function initLeasesDb(dbPath) {
|
|
23043
23381
|
if (db3) return db3;
|
|
23044
|
-
const finalPath = dbPath ??
|
|
23382
|
+
const finalPath = dbPath ?? resolve34(syntaurRoot(), "syntaur.db");
|
|
23045
23383
|
db3 = new Database3(finalPath);
|
|
23046
23384
|
db3.pragma("journal_mode = WAL");
|
|
23047
23385
|
db3.pragma("busy_timeout = 5000");
|
|
@@ -23607,15 +23945,15 @@ init_fs();
|
|
|
23607
23945
|
init_paths();
|
|
23608
23946
|
init_timestamp();
|
|
23609
23947
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
23610
|
-
import { readFile as
|
|
23611
|
-
import { resolve as
|
|
23948
|
+
import { readFile as readFile23, readdir as readdir17, rm as rm3 } from "fs/promises";
|
|
23949
|
+
import { resolve as resolve35 } from "path";
|
|
23612
23950
|
function schedulesDir() {
|
|
23613
23951
|
const override3 = process.env.SYNTAUR_SCHEDULES_DIR;
|
|
23614
|
-
if (override3 && override3.length > 0) return
|
|
23615
|
-
return
|
|
23952
|
+
if (override3 && override3.length > 0) return resolve35(override3);
|
|
23953
|
+
return resolve35(syntaurRoot(), "schedules");
|
|
23616
23954
|
}
|
|
23617
23955
|
function jobPath(id) {
|
|
23618
|
-
return
|
|
23956
|
+
return resolve35(schedulesDir(), `${jobFileSafe(id)}.md`);
|
|
23619
23957
|
}
|
|
23620
23958
|
function jobFileSafe(id) {
|
|
23621
23959
|
if (!/^[A-Za-z0-9_-]+$/.test(id)) {
|
|
@@ -23740,7 +24078,7 @@ function validateJob(raw2) {
|
|
|
23740
24078
|
async function readJob(id) {
|
|
23741
24079
|
const path = jobPath(id);
|
|
23742
24080
|
if (!await fileExists(path)) return null;
|
|
23743
|
-
return parseJobFile(await
|
|
24081
|
+
return parseJobFile(await readFile23(path, "utf-8"));
|
|
23744
24082
|
}
|
|
23745
24083
|
async function writeJob(job) {
|
|
23746
24084
|
const next = { ...job, updatedAt: nowTimestamp() };
|
|
@@ -23750,7 +24088,7 @@ async function writeJob(job) {
|
|
|
23750
24088
|
async function listJobs() {
|
|
23751
24089
|
let names;
|
|
23752
24090
|
try {
|
|
23753
|
-
names = await
|
|
24091
|
+
names = await readdir17(schedulesDir());
|
|
23754
24092
|
} catch {
|
|
23755
24093
|
return [];
|
|
23756
24094
|
}
|
|
@@ -23758,7 +24096,7 @@ async function listJobs() {
|
|
|
23758
24096
|
for (const name of names) {
|
|
23759
24097
|
if (!name.endsWith(".md")) continue;
|
|
23760
24098
|
try {
|
|
23761
|
-
jobs.push(parseJobFile(await
|
|
24099
|
+
jobs.push(parseJobFile(await readFile23(resolve35(schedulesDir(), name), "utf-8")));
|
|
23762
24100
|
} catch {
|
|
23763
24101
|
}
|
|
23764
24102
|
}
|
|
@@ -23768,13 +24106,13 @@ async function listJobs() {
|
|
|
23768
24106
|
|
|
23769
24107
|
// src/schedules/event-log.ts
|
|
23770
24108
|
init_timestamp();
|
|
23771
|
-
import { appendFile, readFile as
|
|
23772
|
-
import { dirname as dirname9, resolve as
|
|
24109
|
+
import { appendFile, readFile as readFile24, mkdir as mkdir3 } from "fs/promises";
|
|
24110
|
+
import { dirname as dirname9, resolve as resolve36 } from "path";
|
|
23773
24111
|
function eventLogPath(jobId) {
|
|
23774
24112
|
if (!/^[A-Za-z0-9_-]+$/.test(jobId)) {
|
|
23775
24113
|
throw new Error(`Unsafe schedule id: ${JSON.stringify(jobId)}`);
|
|
23776
24114
|
}
|
|
23777
|
-
return
|
|
24115
|
+
return resolve36(schedulesDir(), `${jobId}.jsonl`);
|
|
23778
24116
|
}
|
|
23779
24117
|
async function appendEvent(jobId, type, data) {
|
|
23780
24118
|
const event = { type, at: nowTimestamp(), ...data ? { data } : {} };
|
|
@@ -23787,7 +24125,7 @@ async function appendEvent(jobId, type, data) {
|
|
|
23787
24125
|
async function readEvents(jobId) {
|
|
23788
24126
|
let content;
|
|
23789
24127
|
try {
|
|
23790
|
-
content = await
|
|
24128
|
+
content = await readFile24(eventLogPath(jobId), "utf-8");
|
|
23791
24129
|
} catch {
|
|
23792
24130
|
return [];
|
|
23793
24131
|
}
|
|
@@ -23806,8 +24144,8 @@ async function readEvents(jobId) {
|
|
|
23806
24144
|
|
|
23807
24145
|
// src/schedules/attempt.ts
|
|
23808
24146
|
import { createHash as createHash3 } from "crypto";
|
|
23809
|
-
import { open as open4, readFile as
|
|
23810
|
-
import { resolve as
|
|
24147
|
+
import { open as open4, readFile as readFile25, stat as stat5, unlink as unlink6 } from "fs/promises";
|
|
24148
|
+
import { resolve as resolve37 } from "path";
|
|
23811
24149
|
|
|
23812
24150
|
// src/schedules/triggers.ts
|
|
23813
24151
|
import { Cron } from "croner";
|
|
@@ -23986,7 +24324,7 @@ var LOCK_WAIT_MS2 = 50;
|
|
|
23986
24324
|
var LOCK_MAX_WAITS2 = 100;
|
|
23987
24325
|
var MAX_CONSUMED_EDGES = 50;
|
|
23988
24326
|
async function acquireJobLock(id) {
|
|
23989
|
-
const lockPath =
|
|
24327
|
+
const lockPath = resolve37(schedulesDir(), `${id}.lock`);
|
|
23990
24328
|
const token = `${process.pid}:${createHash3("sha256").update(`${Math.random()}${Date.now()}`).digest("hex").slice(0, 12)}`;
|
|
23991
24329
|
for (let attempt = 0; attempt <= LOCK_MAX_WAITS2; attempt++) {
|
|
23992
24330
|
try {
|
|
@@ -23995,7 +24333,7 @@ async function acquireJobLock(id) {
|
|
|
23995
24333
|
await handle.close();
|
|
23996
24334
|
return async () => {
|
|
23997
24335
|
try {
|
|
23998
|
-
const current = await
|
|
24336
|
+
const current = await readFile25(lockPath, "utf-8");
|
|
23999
24337
|
if (current === token) await unlink6(lockPath);
|
|
24000
24338
|
} catch {
|
|
24001
24339
|
}
|
|
@@ -24301,7 +24639,7 @@ async function reapStale(jobs, deps) {
|
|
|
24301
24639
|
|
|
24302
24640
|
// src/schedules/unattended.ts
|
|
24303
24641
|
import { existsSync as existsSync3 } from "fs";
|
|
24304
|
-
import { resolve as
|
|
24642
|
+
import { resolve as resolve38 } from "path";
|
|
24305
24643
|
var UnattendedRefusalError = class extends Error {
|
|
24306
24644
|
constructor(message) {
|
|
24307
24645
|
super(message);
|
|
@@ -24317,7 +24655,7 @@ function assertUnattendedTerminalSupported(terminal) {
|
|
|
24317
24655
|
}
|
|
24318
24656
|
function isKillSwitchEngaged() {
|
|
24319
24657
|
if (process.env.SYNTAUR_SCHEDULES_DISABLED === "1") return true;
|
|
24320
|
-
return existsSync3(
|
|
24658
|
+
return existsSync3(resolve38(schedulesDir(), "KILL"));
|
|
24321
24659
|
}
|
|
24322
24660
|
function canFire(job, deps) {
|
|
24323
24661
|
const killSwitch = deps.killSwitch ?? isKillSwitchEngaged;
|
|
@@ -24468,20 +24806,20 @@ init_config2();
|
|
|
24468
24806
|
init_paths();
|
|
24469
24807
|
init_assignment_resolver();
|
|
24470
24808
|
init_frontmatter();
|
|
24471
|
-
import { readFile as
|
|
24472
|
-
import { resolve as
|
|
24809
|
+
import { readFile as readFile26 } from "fs/promises";
|
|
24810
|
+
import { resolve as resolve39 } from "path";
|
|
24473
24811
|
|
|
24474
24812
|
// src/schedules/launch-ack.ts
|
|
24475
24813
|
init_session_id();
|
|
24476
24814
|
import { readdirSync as readdirSync2 } from "fs";
|
|
24477
|
-
import { homedir as
|
|
24478
|
-
import { join as
|
|
24815
|
+
import { homedir as homedir7 } from "os";
|
|
24816
|
+
import { join as join10 } from "path";
|
|
24479
24817
|
function defaultSleep(ms) {
|
|
24480
24818
|
return new Promise((r) => setTimeout(r, ms));
|
|
24481
24819
|
}
|
|
24482
24820
|
function runtimeSessionsDir() {
|
|
24483
24821
|
const override3 = process.env.SYNTAUR_RUNTIME_SESSIONS_DIR;
|
|
24484
|
-
return override3 && override3.length > 0 ? override3 :
|
|
24822
|
+
return override3 && override3.length > 0 ? override3 : join10(homedir7(), ".syntaur", "runtime", "sessions");
|
|
24485
24823
|
}
|
|
24486
24824
|
function defaultAckProbe(handle) {
|
|
24487
24825
|
const dir = runtimeSessionsDir();
|
|
@@ -24529,7 +24867,7 @@ async function defaultReadAssignment(assignmentId) {
|
|
|
24529
24867
|
const resolved = await resolveAssignmentById(projectsDir2, assignmentsDir(), assignmentId);
|
|
24530
24868
|
if (!resolved) return null;
|
|
24531
24869
|
try {
|
|
24532
|
-
const content = await
|
|
24870
|
+
const content = await readFile26(resolve39(resolved.assignmentDir, "assignment.md"), "utf-8");
|
|
24533
24871
|
return parseAssignmentFrontmatter(content);
|
|
24534
24872
|
} catch {
|
|
24535
24873
|
return null;
|
|
@@ -24621,7 +24959,7 @@ import { Router as Router14 } from "express";
|
|
|
24621
24959
|
// src/db/usage-db.ts
|
|
24622
24960
|
init_paths();
|
|
24623
24961
|
import Database4 from "better-sqlite3";
|
|
24624
|
-
import { resolve as
|
|
24962
|
+
import { resolve as resolve40 } from "path";
|
|
24625
24963
|
var db4 = null;
|
|
24626
24964
|
var USAGE_SCHEMA_VERSION = "1";
|
|
24627
24965
|
var SCHEMA_SQL4 = `
|
|
@@ -24695,7 +25033,7 @@ function nowIso2() {
|
|
|
24695
25033
|
}
|
|
24696
25034
|
function initUsageDb(dbPath) {
|
|
24697
25035
|
if (db4) return db4;
|
|
24698
|
-
const finalPath = dbPath ??
|
|
25036
|
+
const finalPath = dbPath ?? resolve40(syntaurRoot(), "syntaur.db");
|
|
24699
25037
|
db4 = new Database4(finalPath);
|
|
24700
25038
|
db4.pragma("journal_mode = WAL");
|
|
24701
25039
|
db4.pragma("busy_timeout = 5000");
|
|
@@ -25308,14 +25646,14 @@ init_fs();
|
|
|
25308
25646
|
init_parser();
|
|
25309
25647
|
init_events_db();
|
|
25310
25648
|
import { Router as Router15 } from "express";
|
|
25311
|
-
import { resolve as
|
|
25312
|
-
import { readFile as
|
|
25649
|
+
import { resolve as resolve41 } from "path";
|
|
25650
|
+
import { readFile as readFile27 } from "fs/promises";
|
|
25313
25651
|
function createEventsRouter(projectsDir2, assignmentsDir2) {
|
|
25314
25652
|
const router = Router15();
|
|
25315
25653
|
router.get("/projects/:slug/assignments/:aslug/events", async (req2, res) => {
|
|
25316
25654
|
try {
|
|
25317
25655
|
const { slug, aslug } = req2.params;
|
|
25318
|
-
const assignmentMdPath2 =
|
|
25656
|
+
const assignmentMdPath2 = resolve41(
|
|
25319
25657
|
projectsDir2,
|
|
25320
25658
|
slug,
|
|
25321
25659
|
"assignments",
|
|
@@ -25336,7 +25674,7 @@ function createEventsRouter(projectsDir2, assignmentsDir2) {
|
|
|
25336
25674
|
router.get("/standalone/assignments/:id/events", async (req2, res) => {
|
|
25337
25675
|
try {
|
|
25338
25676
|
const { id: dirId } = req2.params;
|
|
25339
|
-
const assignmentMdPath2 =
|
|
25677
|
+
const assignmentMdPath2 = resolve41(assignmentsDir2, dirId, "assignment.md");
|
|
25340
25678
|
const id = await readAssignmentId2(assignmentMdPath2) ?? dirId;
|
|
25341
25679
|
res.json({ events: loadEvents(id, req2.query) });
|
|
25342
25680
|
} catch (error) {
|
|
@@ -25348,7 +25686,7 @@ function createEventsRouter(projectsDir2, assignmentsDir2) {
|
|
|
25348
25686
|
}
|
|
25349
25687
|
async function readAssignmentId2(assignmentMdPath2) {
|
|
25350
25688
|
if (!await fileExists(assignmentMdPath2)) return null;
|
|
25351
|
-
const content = await
|
|
25689
|
+
const content = await readFile27(assignmentMdPath2, "utf-8");
|
|
25352
25690
|
const [fm] = extractFrontmatter(content);
|
|
25353
25691
|
const id = getField(fm, "id");
|
|
25354
25692
|
return id && id.length > 0 ? id : null;
|
|
@@ -25393,8 +25731,8 @@ init_assignment_walk();
|
|
|
25393
25731
|
init_parser();
|
|
25394
25732
|
init_facts();
|
|
25395
25733
|
init_state_machine();
|
|
25396
|
-
import { resolve as
|
|
25397
|
-
import { readFile as
|
|
25734
|
+
import { resolve as resolve42 } from "path";
|
|
25735
|
+
import { readFile as readFile28 } from "fs/promises";
|
|
25398
25736
|
|
|
25399
25737
|
// src/inbox/types.ts
|
|
25400
25738
|
var INBOX_CATEGORIES = [
|
|
@@ -25574,7 +25912,7 @@ async function computeInbox(opts) {
|
|
|
25574
25912
|
if (opts.project !== void 0 && entry.projectSlug !== opts.project) continue;
|
|
25575
25913
|
let parsed;
|
|
25576
25914
|
try {
|
|
25577
|
-
const content = await
|
|
25915
|
+
const content = await readFile28(resolve42(entry.assignmentDir, "assignment.md"), "utf-8");
|
|
25578
25916
|
parsed = parseAssignmentFull(content);
|
|
25579
25917
|
} catch {
|
|
25580
25918
|
continue;
|
|
@@ -25617,10 +25955,10 @@ async function computeInbox(opts) {
|
|
|
25617
25955
|
});
|
|
25618
25956
|
}
|
|
25619
25957
|
if (!typeFilter || typeFilter.has("question")) {
|
|
25620
|
-
const commentsPath =
|
|
25958
|
+
const commentsPath = resolve42(entry.assignmentDir, "comments.md");
|
|
25621
25959
|
if (await fileExists(commentsPath)) {
|
|
25622
25960
|
try {
|
|
25623
|
-
const content = await
|
|
25961
|
+
const content = await readFile28(commentsPath, "utf-8");
|
|
25624
25962
|
const parsedComments = parseComments(content);
|
|
25625
25963
|
for (const c2 of unresolvedQuestions(parsedComments.entries)) {
|
|
25626
25964
|
const since = resolveSince("question", parsed, now, c2);
|
|
@@ -25733,8 +26071,8 @@ init_fs();
|
|
|
25733
26071
|
init_playbook();
|
|
25734
26072
|
init_playbooks();
|
|
25735
26073
|
import { Router as Router17 } from "express";
|
|
25736
|
-
import { resolve as
|
|
25737
|
-
import { readFile as
|
|
26074
|
+
import { resolve as resolve43 } from "path";
|
|
26075
|
+
import { readFile as readFile29 } from "fs/promises";
|
|
25738
26076
|
function statusForPlaybookError(code) {
|
|
25739
26077
|
switch (code) {
|
|
25740
26078
|
case "manifest":
|
|
@@ -25815,8 +26153,8 @@ function createPlaybooksRouter(playbooksDir3) {
|
|
|
25815
26153
|
res.status(404).json({ error: `Playbook "${req2.params.slug}" not found` });
|
|
25816
26154
|
return;
|
|
25817
26155
|
}
|
|
25818
|
-
const filePath =
|
|
25819
|
-
const content = await
|
|
26156
|
+
const filePath = resolve43(playbooksDir3, resolved.filename);
|
|
26157
|
+
const content = await readFile29(filePath, "utf-8");
|
|
25820
26158
|
res.json({
|
|
25821
26159
|
documentType: "playbook",
|
|
25822
26160
|
title: `Edit Playbook: ${resolved.slug}`,
|
|
@@ -25841,7 +26179,7 @@ function createPlaybooksRouter(playbooksDir3) {
|
|
|
25841
26179
|
return;
|
|
25842
26180
|
}
|
|
25843
26181
|
await ensureDir(playbooksDir3);
|
|
25844
|
-
const filePath =
|
|
26182
|
+
const filePath = resolve43(playbooksDir3, `${slug}.md`);
|
|
25845
26183
|
if (await fileExists(filePath)) {
|
|
25846
26184
|
res.status(409).json({ error: `Playbook "${slug}" already exists` });
|
|
25847
26185
|
return;
|
|
@@ -25865,7 +26203,7 @@ function createPlaybooksRouter(playbooksDir3) {
|
|
|
25865
26203
|
res.status(404).json({ error: `Playbook "${req2.params.slug}" not found` });
|
|
25866
26204
|
return;
|
|
25867
26205
|
}
|
|
25868
|
-
const filePath =
|
|
26206
|
+
const filePath = resolve43(playbooksDir3, resolved.filename);
|
|
25869
26207
|
await writeFileForce(filePath, content);
|
|
25870
26208
|
await rebuildPlaybookManifest(playbooksDir3);
|
|
25871
26209
|
res.json({ slug: resolved.slug, path: filePath });
|
|
@@ -25913,7 +26251,7 @@ init_parser2();
|
|
|
25913
26251
|
init_fs();
|
|
25914
26252
|
init_paths();
|
|
25915
26253
|
import { Router as Router19 } from "express";
|
|
25916
|
-
import { readdir as
|
|
26254
|
+
import { readdir as readdir19 } from "fs/promises";
|
|
25917
26255
|
import { resolve as resolvePath, dirname as dirname11 } from "path";
|
|
25918
26256
|
import { rename as rename6, mkdir as mkdir5 } from "fs/promises";
|
|
25919
26257
|
init_slug();
|
|
@@ -25924,8 +26262,8 @@ init_api();
|
|
|
25924
26262
|
import { raw } from "express";
|
|
25925
26263
|
|
|
25926
26264
|
// src/todos/attachments.ts
|
|
25927
|
-
import { mkdir as mkdir4, readdir as
|
|
25928
|
-
import { resolve as
|
|
26265
|
+
import { mkdir as mkdir4, readdir as readdir18, stat as stat6, rename as rename5, rm as rm4, unlink as unlink7, writeFile as writeFile6, cp } from "fs/promises";
|
|
26266
|
+
import { resolve as resolve44, basename as basename6, dirname as dirname10, extname } from "path";
|
|
25929
26267
|
|
|
25930
26268
|
// src/utils/proof-artifact-id.ts
|
|
25931
26269
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
@@ -26036,12 +26374,12 @@ function sanitizeAttachmentName(name) {
|
|
|
26036
26374
|
return n;
|
|
26037
26375
|
}
|
|
26038
26376
|
function attachmentsRootDir(todosDir2) {
|
|
26039
|
-
return
|
|
26377
|
+
return resolve44(todosDir2, "attachments");
|
|
26040
26378
|
}
|
|
26041
26379
|
function attachmentDirFor(todosDir2, scopeId, todoId) {
|
|
26042
26380
|
assertScope(scopeId);
|
|
26043
26381
|
assertTodoId(todoId);
|
|
26044
|
-
return
|
|
26382
|
+
return resolve44(attachmentsRootDir(todosDir2), scopeId, todoId);
|
|
26045
26383
|
}
|
|
26046
26384
|
async function dirExists(p) {
|
|
26047
26385
|
try {
|
|
@@ -26055,7 +26393,7 @@ async function writeAttachment(todosDir2, scopeId, todoId, originalName, bytes)
|
|
|
26055
26393
|
await mkdir4(dir, { recursive: true });
|
|
26056
26394
|
const id = generateArtifactId();
|
|
26057
26395
|
const filename = sanitizeAttachmentName(originalName);
|
|
26058
|
-
await writeFile6(
|
|
26396
|
+
await writeFile6(resolve44(dir, `${id}__${filename}`), bytes);
|
|
26059
26397
|
return {
|
|
26060
26398
|
id,
|
|
26061
26399
|
filename,
|
|
@@ -26068,7 +26406,7 @@ async function listAttachments(todosDir2, scopeId, todoId) {
|
|
|
26068
26406
|
const dir = attachmentDirFor(todosDir2, scopeId, todoId);
|
|
26069
26407
|
let names;
|
|
26070
26408
|
try {
|
|
26071
|
-
names = await
|
|
26409
|
+
names = await readdir18(dir);
|
|
26072
26410
|
} catch {
|
|
26073
26411
|
return [];
|
|
26074
26412
|
}
|
|
@@ -26080,7 +26418,7 @@ async function listAttachments(todosDir2, scopeId, todoId) {
|
|
|
26080
26418
|
if (!ATTACHMENT_ID_RE.test(id)) continue;
|
|
26081
26419
|
const filename = stored.slice(sep2 + 2);
|
|
26082
26420
|
try {
|
|
26083
|
-
const st = await stat6(
|
|
26421
|
+
const st = await stat6(resolve44(dir, stored));
|
|
26084
26422
|
if (!st.isFile()) continue;
|
|
26085
26423
|
out.push({ id, filename, mime: mimeForName(filename), size: st.size, createdAt: st.mtime.toISOString() });
|
|
26086
26424
|
} catch {
|
|
@@ -26091,10 +26429,10 @@ async function listAttachments(todosDir2, scopeId, todoId) {
|
|
|
26091
26429
|
}
|
|
26092
26430
|
async function readScopeAttachments(todosDir2, scopeId) {
|
|
26093
26431
|
assertScope(scopeId);
|
|
26094
|
-
const scopeDir =
|
|
26432
|
+
const scopeDir = resolve44(attachmentsRootDir(todosDir2), scopeId);
|
|
26095
26433
|
let todoIds;
|
|
26096
26434
|
try {
|
|
26097
|
-
todoIds = await
|
|
26435
|
+
todoIds = await readdir18(scopeDir);
|
|
26098
26436
|
} catch {
|
|
26099
26437
|
return {};
|
|
26100
26438
|
}
|
|
@@ -26111,7 +26449,7 @@ async function resolveAttachmentFile(todosDir2, scopeId, todoId, attachmentId) {
|
|
|
26111
26449
|
const dir = attachmentDirFor(todosDir2, scopeId, todoId);
|
|
26112
26450
|
let names;
|
|
26113
26451
|
try {
|
|
26114
|
-
names = await
|
|
26452
|
+
names = await readdir18(dir);
|
|
26115
26453
|
} catch {
|
|
26116
26454
|
return null;
|
|
26117
26455
|
}
|
|
@@ -26119,7 +26457,7 @@ async function resolveAttachmentFile(todosDir2, scopeId, todoId, attachmentId) {
|
|
|
26119
26457
|
const stored = names.find((n) => n.startsWith(prefix));
|
|
26120
26458
|
if (!stored) return null;
|
|
26121
26459
|
const filename = stored.slice(prefix.length);
|
|
26122
|
-
return { path:
|
|
26460
|
+
return { path: resolve44(dir, stored), filename, mime: mimeForName(filename) };
|
|
26123
26461
|
}
|
|
26124
26462
|
async function deleteAttachment(todosDir2, scopeId, todoId, attachmentId) {
|
|
26125
26463
|
const resolved = await resolveAttachmentFile(todosDir2, scopeId, todoId, attachmentId);
|
|
@@ -26415,7 +26753,7 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
|
|
|
26415
26753
|
router.get("/", async (_req, res) => {
|
|
26416
26754
|
try {
|
|
26417
26755
|
await ensureDir(todosDir2);
|
|
26418
|
-
const files = await
|
|
26756
|
+
const files = await readdir19(todosDir2).catch(() => []);
|
|
26419
26757
|
const workspaces = [];
|
|
26420
26758
|
for (const file of files) {
|
|
26421
26759
|
if (typeof file !== "string") continue;
|
|
@@ -26536,7 +26874,7 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
|
|
|
26536
26874
|
try {
|
|
26537
26875
|
const { archivePath: archivePath2 } = await Promise.resolve().then(() => (init_parser2(), parser_exports));
|
|
26538
26876
|
const { resolve: resolve112 } = await import("path");
|
|
26539
|
-
const { readFile:
|
|
26877
|
+
const { readFile: readFile82 } = await import("fs/promises");
|
|
26540
26878
|
const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
26541
26879
|
const workspace = getWorkspaceParam(req2.params.workspace);
|
|
26542
26880
|
const outcome = await wsLock(workspace, async () => {
|
|
@@ -26555,7 +26893,7 @@ function createTodosRouter(todosDir2, broadcast, projectsDir2) {
|
|
|
26555
26893
|
await ensureDir(resolve112(todosDir2, "archive"));
|
|
26556
26894
|
let archContent = "";
|
|
26557
26895
|
if (await fileExists(archFile)) {
|
|
26558
|
-
archContent = await
|
|
26896
|
+
archContent = await readFile82(archFile, "utf-8");
|
|
26559
26897
|
archContent = archContent.trimEnd() + "\n\n";
|
|
26560
26898
|
} else {
|
|
26561
26899
|
archContent = `---
|
|
@@ -26856,7 +27194,7 @@ workspace: ${workspace}
|
|
|
26856
27194
|
const { readConfig: readConfig3 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
26857
27195
|
const { assignmentsDir: assignmentsDirFn } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
26858
27196
|
const { fileExists: fileExists2, writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
26859
|
-
const { readFile:
|
|
27197
|
+
const { readFile: readFile82 } = await import("fs/promises");
|
|
26860
27198
|
const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
|
|
26861
27199
|
const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
|
|
26862
27200
|
let assignmentRef;
|
|
@@ -26877,7 +27215,7 @@ workspace: ${workspace}
|
|
|
26877
27215
|
}
|
|
26878
27216
|
const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
|
|
26879
27217
|
if (!await fileExists2(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
|
|
26880
|
-
let content = await
|
|
27218
|
+
let content = await readFile82(assignmentMdPath2, "utf-8");
|
|
26881
27219
|
content = appendTodosToAssignmentBody2(
|
|
26882
27220
|
content,
|
|
26883
27221
|
items.map((it) => ({
|
|
@@ -27072,8 +27410,8 @@ init_fs();
|
|
|
27072
27410
|
init_paths();
|
|
27073
27411
|
init_slug();
|
|
27074
27412
|
import { Router as Router20 } from "express";
|
|
27075
|
-
import { mkdir as mkdir6, readFile as
|
|
27076
|
-
import { resolve as
|
|
27413
|
+
import { mkdir as mkdir6, readFile as readFile30, rename as rename7 } from "fs/promises";
|
|
27414
|
+
import { resolve as resolve45, dirname as dirname12 } from "path";
|
|
27077
27415
|
init_promote_todos();
|
|
27078
27416
|
init_api();
|
|
27079
27417
|
var WORKSPACE_REGEX2 = /^[a-z0-9_][a-z0-9-]*$/;
|
|
@@ -27090,7 +27428,7 @@ function params(req2) {
|
|
|
27090
27428
|
return req2.params;
|
|
27091
27429
|
}
|
|
27092
27430
|
async function projectExists(projectsDir2, slug) {
|
|
27093
|
-
return fileExists(
|
|
27431
|
+
return fileExists(resolve45(projectsDir2, slug, "project.md"));
|
|
27094
27432
|
}
|
|
27095
27433
|
async function ensureProjectTodosDir(projectsDir2, slug) {
|
|
27096
27434
|
const todosDir2 = projectTodosDir(projectsDir2, slug);
|
|
@@ -27107,7 +27445,7 @@ async function ensureProjectTodosDir(projectsDir2, slug) {
|
|
|
27107
27445
|
throw err2;
|
|
27108
27446
|
}
|
|
27109
27447
|
try {
|
|
27110
|
-
await mkdir6(
|
|
27448
|
+
await mkdir6(resolve45(todosDir2, "archive"), { recursive: false });
|
|
27111
27449
|
} catch (err2) {
|
|
27112
27450
|
const code = err2.code;
|
|
27113
27451
|
if (code === "EEXIST") return;
|
|
@@ -27315,7 +27653,7 @@ function createProjectTodosRouter(projectsDir2, broadcast, workspaceTodosDir) {
|
|
|
27315
27653
|
const archFile = archivePath(todosDir2, slug, checklist.archiveInterval);
|
|
27316
27654
|
let archContent = "";
|
|
27317
27655
|
if (await fileExists(archFile)) {
|
|
27318
|
-
archContent = await
|
|
27656
|
+
archContent = await readFile30(archFile, "utf-8");
|
|
27319
27657
|
archContent = archContent.trimEnd() + "\n\n";
|
|
27320
27658
|
} else {
|
|
27321
27659
|
archContent = `---
|
|
@@ -27786,17 +28124,17 @@ workspace: ${slug}
|
|
|
27786
28124
|
if (tg.includes("/")) {
|
|
27787
28125
|
const parts = tg.split("/");
|
|
27788
28126
|
if (parts.length !== 2) return { error: `Invalid target.assignment "${tg}"` };
|
|
27789
|
-
assignmentDir =
|
|
28127
|
+
assignmentDir = resolve45(projectsDir2, parts[0], "assignments", parts[1]);
|
|
27790
28128
|
assignmentRef = `${parts[0]}/${parts[1]}`;
|
|
27791
28129
|
} else if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(tg)) {
|
|
27792
|
-
assignmentDir =
|
|
28130
|
+
assignmentDir = resolve45(assignmentsDirFn(), tg);
|
|
27793
28131
|
assignmentRef = tg;
|
|
27794
28132
|
} else {
|
|
27795
28133
|
return { error: `Invalid target.assignment "${tg}"` };
|
|
27796
28134
|
}
|
|
27797
|
-
const assignmentMdPath2 =
|
|
28135
|
+
const assignmentMdPath2 = resolve45(assignmentDir, "assignment.md");
|
|
27798
28136
|
if (!await fileExists(assignmentMdPath2)) return { error: `Target assignment not found: ${assignmentMdPath2}` };
|
|
27799
|
-
let content = await
|
|
28137
|
+
let content = await readFile30(assignmentMdPath2, "utf-8");
|
|
27800
28138
|
content = appendTodosToAssignmentBody2(
|
|
27801
28139
|
content,
|
|
27802
28140
|
items.map((it) => ({
|
|
@@ -27999,7 +28337,7 @@ workspace: ${slug}
|
|
|
27999
28337
|
|
|
28000
28338
|
// src/dashboard/api-bundles.ts
|
|
28001
28339
|
import { Router as Router21 } from "express";
|
|
28002
|
-
import { readdir as
|
|
28340
|
+
import { readdir as readdir20 } from "fs/promises";
|
|
28003
28341
|
|
|
28004
28342
|
// src/todos/bundle-parser.ts
|
|
28005
28343
|
init_parser();
|
|
@@ -28007,7 +28345,7 @@ init_fs();
|
|
|
28007
28345
|
init_paths();
|
|
28008
28346
|
init_parser2();
|
|
28009
28347
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
28010
|
-
import { readFile as
|
|
28348
|
+
import { readFile as readFile31 } from "fs/promises";
|
|
28011
28349
|
var BUNDLE_ID_REGEX = /^[a-f0-9]{4}$/;
|
|
28012
28350
|
var SCOPE_VALUES = /* @__PURE__ */ new Set(["workspace", "project", "global"]);
|
|
28013
28351
|
var SCOPE_ID_REGEX = /^[a-z0-9_][a-z0-9_-]*$/;
|
|
@@ -28110,7 +28448,7 @@ ${lines}
|
|
|
28110
28448
|
async function readBundles(todosDir2) {
|
|
28111
28449
|
const path = bundlesPath(todosDir2);
|
|
28112
28450
|
if (!await fileExists(path)) return [];
|
|
28113
|
-
const content = await
|
|
28451
|
+
const content = await readFile31(path, "utf-8");
|
|
28114
28452
|
return parseBundles(content).bundles;
|
|
28115
28453
|
}
|
|
28116
28454
|
async function writeBundles(todosDir2, bundles) {
|
|
@@ -28163,7 +28501,7 @@ function createBundlesRouter(todosDir2, broadcast) {
|
|
|
28163
28501
|
try {
|
|
28164
28502
|
await ensureDir(todosDir2);
|
|
28165
28503
|
const bundles = await readBundles(todosDir2);
|
|
28166
|
-
const workspaceFiles = await
|
|
28504
|
+
const workspaceFiles = await readdir20(todosDir2).catch(() => []);
|
|
28167
28505
|
const itemsByKey = /* @__PURE__ */ new Map();
|
|
28168
28506
|
for (const f of workspaceFiles) {
|
|
28169
28507
|
if (typeof f !== "string") continue;
|
|
@@ -28216,7 +28554,7 @@ init_fs();
|
|
|
28216
28554
|
init_paths();
|
|
28217
28555
|
init_slug();
|
|
28218
28556
|
import { Router as Router22 } from "express";
|
|
28219
|
-
import { resolve as
|
|
28557
|
+
import { resolve as resolve46 } from "path";
|
|
28220
28558
|
init_parser2();
|
|
28221
28559
|
function deriveStatus2(bundle, items) {
|
|
28222
28560
|
const members = bundle.todoIds.map((id) => items.find((i) => i.id === id)).filter((i) => i !== void 0);
|
|
@@ -28258,7 +28596,7 @@ function createProjectBundlesRouter(projectsDir2, broadcast) {
|
|
|
28258
28596
|
router.get("/", async (req2, res) => {
|
|
28259
28597
|
try {
|
|
28260
28598
|
const slug = getProjectIdParam2(req2.params.projectId);
|
|
28261
|
-
const projectMd =
|
|
28599
|
+
const projectMd = resolve46(projectsDir2, slug, "project.md");
|
|
28262
28600
|
if (!await fileExists(projectMd)) {
|
|
28263
28601
|
notFound2(res, slug);
|
|
28264
28602
|
return;
|
|
@@ -28287,8 +28625,8 @@ init_fs();
|
|
|
28287
28625
|
init_config2();
|
|
28288
28626
|
import { execFile as execFile2 } from "child_process";
|
|
28289
28627
|
import { promisify as promisify2 } from "util";
|
|
28290
|
-
import { cp as cp2, mkdtemp, rm as rm5, readFile as
|
|
28291
|
-
import { resolve as
|
|
28628
|
+
import { cp as cp2, mkdtemp, rm as rm5, readFile as readFile32, writeFile as writeFile7, unlink as unlink8, stat as stat7, open as open5, rename as rename8 } from "fs/promises";
|
|
28629
|
+
import { resolve as resolve47, join as join11 } from "path";
|
|
28292
28630
|
import { tmpdir } from "os";
|
|
28293
28631
|
var exec2 = promisify2(execFile2);
|
|
28294
28632
|
var VALID_CATEGORIES = ["projects", "playbooks", "todos", "servers", "config"];
|
|
@@ -28328,7 +28666,7 @@ async function resolveCategoryPath(category) {
|
|
|
28328
28666
|
case "servers":
|
|
28329
28667
|
return { sourcePath: serversDir(), repoPath: "servers", isFile: false };
|
|
28330
28668
|
case "config":
|
|
28331
|
-
return { sourcePath:
|
|
28669
|
+
return { sourcePath: resolve47(syntaurRoot(), "config.md"), repoPath: "config.md", isFile: true };
|
|
28332
28670
|
}
|
|
28333
28671
|
}
|
|
28334
28672
|
async function checkGitInstalled() {
|
|
@@ -28339,7 +28677,7 @@ async function checkGitInstalled() {
|
|
|
28339
28677
|
}
|
|
28340
28678
|
}
|
|
28341
28679
|
async function acquireLock2() {
|
|
28342
|
-
const lockPath =
|
|
28680
|
+
const lockPath = resolve47(syntaurRoot(), LOCK_FILE_NAME);
|
|
28343
28681
|
await ensureDir(syntaurRoot());
|
|
28344
28682
|
try {
|
|
28345
28683
|
const handle = await open5(lockPath, "wx");
|
|
@@ -28348,7 +28686,7 @@ async function acquireLock2() {
|
|
|
28348
28686
|
return lockPath;
|
|
28349
28687
|
} catch (err2) {
|
|
28350
28688
|
if (err2.code === "EEXIST") {
|
|
28351
|
-
const pid = await
|
|
28689
|
+
const pid = await readFile32(lockPath, "utf-8").catch(() => "");
|
|
28352
28690
|
throw new Error(
|
|
28353
28691
|
`Backup operation already in progress (lock file at ${lockPath}, pid ${pid.trim() || "unknown"}). If stale, delete the file and retry.`
|
|
28354
28692
|
);
|
|
@@ -28386,7 +28724,7 @@ async function copyRecursive(src, dest) {
|
|
|
28386
28724
|
await ensureDir(dest);
|
|
28387
28725
|
await cp2(src, dest, { recursive: true, force: true });
|
|
28388
28726
|
} else {
|
|
28389
|
-
await ensureDir(
|
|
28727
|
+
await ensureDir(resolve47(dest, ".."));
|
|
28390
28728
|
await cp2(src, dest, { force: true });
|
|
28391
28729
|
}
|
|
28392
28730
|
}
|
|
@@ -28395,7 +28733,7 @@ function resolveCategoriesStrict(csv) {
|
|
|
28395
28733
|
return parseCategoriesStrict(parts);
|
|
28396
28734
|
}
|
|
28397
28735
|
async function readSanitizedConfig(configPath2) {
|
|
28398
|
-
const content = await
|
|
28736
|
+
const content = await readFile32(configPath2, "utf-8");
|
|
28399
28737
|
return content.replace(/^(\s*lastBackup:\s*).*$/m, "$1null").replace(/^(\s*lastRestore:\s*).*$/m, "$1null");
|
|
28400
28738
|
}
|
|
28401
28739
|
async function backupToGithub(overrides) {
|
|
@@ -28418,11 +28756,11 @@ async function backupToGithub(overrides) {
|
|
|
28418
28756
|
let tmpDir = null;
|
|
28419
28757
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
28420
28758
|
try {
|
|
28421
|
-
tmpDir = await mkdtemp(
|
|
28759
|
+
tmpDir = await mkdtemp(join11(tmpdir(), "syntaur-backup-"));
|
|
28422
28760
|
await cloneOrInit(repo, tmpDir);
|
|
28423
28761
|
for (const category of categories) {
|
|
28424
28762
|
const { sourcePath, repoPath, isFile } = await resolveCategoryPath(category);
|
|
28425
|
-
const destPath =
|
|
28763
|
+
const destPath = join11(tmpDir, repoPath);
|
|
28426
28764
|
if (isFile) {
|
|
28427
28765
|
await rm5(destPath, { force: true });
|
|
28428
28766
|
} else {
|
|
@@ -28434,7 +28772,7 @@ async function backupToGithub(overrides) {
|
|
|
28434
28772
|
}
|
|
28435
28773
|
if (category === "config") {
|
|
28436
28774
|
const sanitized = await readSanitizedConfig(sourcePath);
|
|
28437
|
-
await ensureDir(
|
|
28775
|
+
await ensureDir(resolve47(destPath, ".."));
|
|
28438
28776
|
await writeFile7(destPath, sanitized, "utf-8");
|
|
28439
28777
|
} else {
|
|
28440
28778
|
await copyRecursive(sourcePath, destPath);
|
|
@@ -28488,7 +28826,7 @@ async function backupToGithub(overrides) {
|
|
|
28488
28826
|
}
|
|
28489
28827
|
async function safeRestoreCategory(localPath, repoSrcPath, isFile) {
|
|
28490
28828
|
if (isFile) {
|
|
28491
|
-
await ensureDir(
|
|
28829
|
+
await ensureDir(resolve47(localPath, ".."));
|
|
28492
28830
|
await cp2(repoSrcPath, localPath, { force: true });
|
|
28493
28831
|
return;
|
|
28494
28832
|
}
|
|
@@ -28550,7 +28888,7 @@ async function restoreFromGithub(overrides) {
|
|
|
28550
28888
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
28551
28889
|
try {
|
|
28552
28890
|
await updateBackupConfig({ lastRestore: timestamp });
|
|
28553
|
-
tmpDir = await mkdtemp(
|
|
28891
|
+
tmpDir = await mkdtemp(join11(tmpdir(), "syntaur-restore-"));
|
|
28554
28892
|
await cloneOrInit(repo, tmpDir);
|
|
28555
28893
|
for (const category of categories) {
|
|
28556
28894
|
if (category === "config") {
|
|
@@ -28559,7 +28897,7 @@ async function restoreFromGithub(overrides) {
|
|
|
28559
28897
|
}
|
|
28560
28898
|
try {
|
|
28561
28899
|
const { sourcePath: localPath, repoPath, isFile } = await resolveCategoryPath(category);
|
|
28562
|
-
const repoSrcPath =
|
|
28900
|
+
const repoSrcPath = join11(tmpDir, repoPath);
|
|
28563
28901
|
if (!await fileExists(repoSrcPath)) {
|
|
28564
28902
|
console.warn(`Category "${category}" not found in backup repo, skipping.`);
|
|
28565
28903
|
continue;
|
|
@@ -28589,7 +28927,7 @@ async function restoreFromGithub(overrides) {
|
|
|
28589
28927
|
}
|
|
28590
28928
|
async function getBackupStatus() {
|
|
28591
28929
|
const config = await readConfig();
|
|
28592
|
-
const lockPath =
|
|
28930
|
+
const lockPath = resolve47(syntaurRoot(), LOCK_FILE_NAME);
|
|
28593
28931
|
const locked = await fileExists(lockPath);
|
|
28594
28932
|
return {
|
|
28595
28933
|
repo: config.backup?.repo ?? null,
|
|
@@ -30545,7 +30883,7 @@ init_git_worktree();
|
|
|
30545
30883
|
init_recompute();
|
|
30546
30884
|
init_event_emit();
|
|
30547
30885
|
init_transitions();
|
|
30548
|
-
import { readFile as
|
|
30886
|
+
import { readFile as readFile35 } from "fs/promises";
|
|
30549
30887
|
import { resolve as resolve54, basename as basename7 } from "path";
|
|
30550
30888
|
|
|
30551
30889
|
// src/utils/assignment-target.ts
|
|
@@ -30556,7 +30894,7 @@ init_slug();
|
|
|
30556
30894
|
init_assignment_resolver();
|
|
30557
30895
|
init_parser();
|
|
30558
30896
|
import { resolve as resolve53 } from "path";
|
|
30559
|
-
import { readFile as
|
|
30897
|
+
import { readFile as readFile33 } from "fs/promises";
|
|
30560
30898
|
var AssignmentTargetError = class extends Error {
|
|
30561
30899
|
};
|
|
30562
30900
|
function classifyContext(ctx) {
|
|
@@ -30569,7 +30907,7 @@ async function readAssignmentFrontmatterId(assignmentDir) {
|
|
|
30569
30907
|
const path = resolve53(assignmentDir, "assignment.md");
|
|
30570
30908
|
if (!await fileExists(path)) return null;
|
|
30571
30909
|
try {
|
|
30572
|
-
const content = await
|
|
30910
|
+
const content = await readFile33(path, "utf-8");
|
|
30573
30911
|
const [fm] = extractFrontmatter(content);
|
|
30574
30912
|
return getField(fm, "id");
|
|
30575
30913
|
} catch {
|
|
@@ -30580,7 +30918,7 @@ async function readContextJson(cwd) {
|
|
|
30580
30918
|
const path = resolve53(cwd, ".syntaur", "context.json");
|
|
30581
30919
|
if (!await fileExists(path)) return null;
|
|
30582
30920
|
try {
|
|
30583
|
-
const raw2 = await
|
|
30921
|
+
const raw2 = await readFile33(path, "utf-8");
|
|
30584
30922
|
return JSON.parse(raw2);
|
|
30585
30923
|
} catch {
|
|
30586
30924
|
return null;
|
|
@@ -30765,7 +31103,7 @@ init_session_id();
|
|
|
30765
31103
|
init_fs();
|
|
30766
31104
|
init_frontmatter();
|
|
30767
31105
|
init_recompute();
|
|
30768
|
-
import { readFile as
|
|
31106
|
+
import { readFile as readFile34 } from "fs/promises";
|
|
30769
31107
|
function computeDelta(stage, prevStage, fm) {
|
|
30770
31108
|
const writes = {};
|
|
30771
31109
|
if (stage === "implement") {
|
|
@@ -30783,7 +31121,7 @@ async function assertStageFactOnOpen(input4) {
|
|
|
30783
31121
|
const pre = computeDelta(
|
|
30784
31122
|
input4.stage,
|
|
30785
31123
|
input4.prevStage,
|
|
30786
|
-
parseAssignmentFrontmatter(await
|
|
31124
|
+
parseAssignmentFrontmatter(await readFile34(input4.assignmentPath, "utf-8"))
|
|
30787
31125
|
);
|
|
30788
31126
|
if (Object.keys(pre).length === 0) return;
|
|
30789
31127
|
const context = await resolveDeriveContext();
|
|
@@ -30833,7 +31171,7 @@ async function resolveTarget(assignment, options) {
|
|
|
30833
31171
|
async function inferActor(options) {
|
|
30834
31172
|
if (options.agent) return `agent:${options.agent}`;
|
|
30835
31173
|
try {
|
|
30836
|
-
const raw2 = await
|
|
31174
|
+
const raw2 = await readFile35(resolve54(process.cwd(), ".syntaur", "context.json"), "utf-8");
|
|
30837
31175
|
const ctx = JSON.parse(raw2);
|
|
30838
31176
|
if (ctx.sessionId) return `agent:${ctx.sessionId.slice(0, 8)}`;
|
|
30839
31177
|
} catch {
|
|
@@ -30842,7 +31180,7 @@ async function inferActor(options) {
|
|
|
30842
31180
|
}
|
|
30843
31181
|
async function emitDeriveEvent(target, type, actor, details) {
|
|
30844
31182
|
try {
|
|
30845
|
-
const fm = parseAssignmentFrontmatter(await
|
|
31183
|
+
const fm = parseAssignmentFrontmatter(await readFile35(target.assignmentPath, "utf-8"));
|
|
30846
31184
|
emitEvent({
|
|
30847
31185
|
assignmentId: fm.id,
|
|
30848
31186
|
projectSlug: target.projectDir ? basename7(target.projectDir) : null,
|
|
@@ -30903,7 +31241,7 @@ async function planApproveCommand(assignment, options) {
|
|
|
30903
31241
|
throw new Error("No plan file found (plan.md / plan-v*.md). Write a plan before approving.");
|
|
30904
31242
|
}
|
|
30905
31243
|
approvedFile = planFile;
|
|
30906
|
-
const planContent = await
|
|
31244
|
+
const planContent = await readFile35(resolve54(target2.assignmentDir, planFile), "utf-8");
|
|
30907
31245
|
return updatePlanApproval(content, {
|
|
30908
31246
|
file: planFile,
|
|
30909
31247
|
digest: planDigest(planContent),
|
|
@@ -30976,7 +31314,7 @@ async function attestCommand(assignment, fact, options) {
|
|
|
30976
31314
|
"No plan file found (plan.md / plan-v*.md). Write a plan before attesting a binds:plan fact."
|
|
30977
31315
|
);
|
|
30978
31316
|
}
|
|
30979
|
-
const planContent = await
|
|
31317
|
+
const planContent = await readFile35(resolve54(target2.assignmentDir, planFile), "utf-8");
|
|
30980
31318
|
record.file = planFile;
|
|
30981
31319
|
record.digest = planDigest(planContent);
|
|
30982
31320
|
} else if (binds === "commit") {
|
|
@@ -31067,13 +31405,13 @@ async function requestReviewCommand(assignment, options) {
|
|
|
31067
31405
|
}
|
|
31068
31406
|
const target = await resolveTarget(assignment, options);
|
|
31069
31407
|
const context = await resolveDeriveContext();
|
|
31070
|
-
const fm = parseAssignmentFrontmatter(await
|
|
31408
|
+
const fm = parseAssignmentFrontmatter(await readFile35(target.assignmentPath, "utf-8"));
|
|
31071
31409
|
await applyStageFact(assignment, options, target, fm, "review", "Review requested", context);
|
|
31072
31410
|
}
|
|
31073
31411
|
async function implementStartedCommand(assignment, options) {
|
|
31074
31412
|
const target = await resolveTarget(assignment, options);
|
|
31075
31413
|
const context = await resolveDeriveContext();
|
|
31076
|
-
const fm = parseAssignmentFrontmatter(await
|
|
31414
|
+
const fm = parseAssignmentFrontmatter(await readFile35(target.assignmentPath, "utf-8"));
|
|
31077
31415
|
if (fm.dependsOn.length > 0 && target.projectDir) {
|
|
31078
31416
|
const dep = await checkDependencies(target.projectDir, fm.dependsOn, context.terminalStatuses);
|
|
31079
31417
|
if (!dep.satisfied) {
|
|
@@ -31204,7 +31542,7 @@ init_timestamp();
|
|
|
31204
31542
|
init_assignment_resolver();
|
|
31205
31543
|
init_event_emit();
|
|
31206
31544
|
import { resolve as resolve55 } from "path";
|
|
31207
|
-
import { readFile as
|
|
31545
|
+
import { readFile as readFile36, writeFile as writeFile9 } from "fs/promises";
|
|
31208
31546
|
async function resolveTarget2(target, options) {
|
|
31209
31547
|
const config = await readConfig();
|
|
31210
31548
|
const baseDir = options.dir ? expandHome(options.dir) : config.defaultProjectDir;
|
|
@@ -31236,7 +31574,7 @@ async function resolveTarget2(target, options) {
|
|
|
31236
31574
|
return null;
|
|
31237
31575
|
}
|
|
31238
31576
|
async function writeArchiveState(filePath, archived, reason) {
|
|
31239
|
-
const content = await
|
|
31577
|
+
const content = await readFile36(filePath, "utf-8");
|
|
31240
31578
|
const updated = updateAssignmentFile(content, {
|
|
31241
31579
|
archived,
|
|
31242
31580
|
archivedAt: archived ? nowTimestamp() : null,
|
|
@@ -31248,7 +31586,7 @@ async function writeArchiveState(filePath, archived, reason) {
|
|
|
31248
31586
|
async function emitArchiveEvent(resolved, type, reason) {
|
|
31249
31587
|
if (resolved.kind !== "assignment") return;
|
|
31250
31588
|
try {
|
|
31251
|
-
const fm = parseAssignmentFrontmatter(await
|
|
31589
|
+
const fm = parseAssignmentFrontmatter(await readFile36(resolved.filePath, "utf-8"));
|
|
31252
31590
|
emitEvent({
|
|
31253
31591
|
assignmentId: fm.id,
|
|
31254
31592
|
projectSlug: fm.project,
|
|
@@ -31319,7 +31657,7 @@ init_frontmatter();
|
|
|
31319
31657
|
init_timestamp();
|
|
31320
31658
|
init_event_emit();
|
|
31321
31659
|
import { resolve as resolve56 } from "path";
|
|
31322
|
-
import { readdir as
|
|
31660
|
+
import { readdir as readdir21, readFile as readFile37 } from "fs/promises";
|
|
31323
31661
|
var PROMOTABLE_STATUSES = /* @__PURE__ */ new Set(["pending"]);
|
|
31324
31662
|
function objectiveIsFleshedOut(content) {
|
|
31325
31663
|
const match = content.match(/##\s+Objective\s*\n([\s\S]*?)(?=\n##\s+|$)/);
|
|
@@ -31337,7 +31675,7 @@ async function collectCandidates(baseDirs) {
|
|
|
31337
31675
|
const candidates = [];
|
|
31338
31676
|
for (const baseDir of baseDirs) {
|
|
31339
31677
|
if (!await fileExists(baseDir)) continue;
|
|
31340
|
-
const projects = await
|
|
31678
|
+
const projects = await readdir21(baseDir, { withFileTypes: true });
|
|
31341
31679
|
for (const m of projects) {
|
|
31342
31680
|
if (!m.isDirectory()) continue;
|
|
31343
31681
|
if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
|
|
@@ -31345,7 +31683,7 @@ async function collectCandidates(baseDirs) {
|
|
|
31345
31683
|
if (await fileExists(directAssignmentMd)) {
|
|
31346
31684
|
const fm = await parseSafe(directAssignmentMd);
|
|
31347
31685
|
if (fm && PROMOTABLE_STATUSES.has(fm.status)) {
|
|
31348
|
-
const content = await
|
|
31686
|
+
const content = await readFile37(directAssignmentMd, "utf-8");
|
|
31349
31687
|
if (objectiveIsFleshedOut(content) && hasAcceptanceCriteria(content)) {
|
|
31350
31688
|
candidates.push({
|
|
31351
31689
|
projectSlug: null,
|
|
@@ -31360,7 +31698,7 @@ async function collectCandidates(baseDirs) {
|
|
|
31360
31698
|
}
|
|
31361
31699
|
const assignmentsDir2 = resolve56(baseDir, m.name, "assignments");
|
|
31362
31700
|
if (!await fileExists(assignmentsDir2)) continue;
|
|
31363
|
-
const entries = await
|
|
31701
|
+
const entries = await readdir21(assignmentsDir2, { withFileTypes: true });
|
|
31364
31702
|
for (const a of entries) {
|
|
31365
31703
|
if (!a.isDirectory()) continue;
|
|
31366
31704
|
if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
|
|
@@ -31368,7 +31706,7 @@ async function collectCandidates(baseDirs) {
|
|
|
31368
31706
|
if (!await fileExists(assignmentMd)) continue;
|
|
31369
31707
|
const fm = await parseSafe(assignmentMd);
|
|
31370
31708
|
if (!fm || !PROMOTABLE_STATUSES.has(fm.status)) continue;
|
|
31371
|
-
const content = await
|
|
31709
|
+
const content = await readFile37(assignmentMd, "utf-8");
|
|
31372
31710
|
if (!objectiveIsFleshedOut(content)) continue;
|
|
31373
31711
|
if (!hasAcceptanceCriteria(content)) continue;
|
|
31374
31712
|
candidates.push({
|
|
@@ -31385,7 +31723,7 @@ async function collectCandidates(baseDirs) {
|
|
|
31385
31723
|
}
|
|
31386
31724
|
async function parseSafe(path) {
|
|
31387
31725
|
try {
|
|
31388
|
-
const content = await
|
|
31726
|
+
const content = await readFile37(path, "utf-8");
|
|
31389
31727
|
return parseAssignmentFrontmatter(content);
|
|
31390
31728
|
} catch {
|
|
31391
31729
|
return null;
|
|
@@ -31415,7 +31753,7 @@ async function migrateStatusesCommand(options) {
|
|
|
31415
31753
|
let migrated = 0;
|
|
31416
31754
|
await withSuppressedEvents(async () => {
|
|
31417
31755
|
for (const c2 of candidates) {
|
|
31418
|
-
const content = await
|
|
31756
|
+
const content = await readFile37(c2.assignmentMd, "utf-8");
|
|
31419
31757
|
const updated = appendStatusHistoryEntry(
|
|
31420
31758
|
updateAssignmentFile(content, {
|
|
31421
31759
|
status: c2.toStatus,
|
|
@@ -31438,10 +31776,10 @@ init_frontmatter();
|
|
|
31438
31776
|
init_event_emit();
|
|
31439
31777
|
init_types();
|
|
31440
31778
|
import { resolve as resolve57 } from "path";
|
|
31441
|
-
import { readdir as
|
|
31779
|
+
import { readdir as readdir22, readFile as readFile38 } from "fs/promises";
|
|
31442
31780
|
async function parseSafe2(path) {
|
|
31443
31781
|
try {
|
|
31444
|
-
return parseAssignmentFrontmatter(await
|
|
31782
|
+
return parseAssignmentFrontmatter(await readFile38(path, "utf-8"));
|
|
31445
31783
|
} catch {
|
|
31446
31784
|
return null;
|
|
31447
31785
|
}
|
|
@@ -31464,7 +31802,7 @@ async function collectTargets(baseDirs, terminalStatuses3) {
|
|
|
31464
31802
|
const seen = /* @__PURE__ */ new Set();
|
|
31465
31803
|
for (const baseDir of baseDirs) {
|
|
31466
31804
|
if (!await fileExists(baseDir)) continue;
|
|
31467
|
-
const entries = await
|
|
31805
|
+
const entries = await readdir22(baseDir, { withFileTypes: true });
|
|
31468
31806
|
for (const m of entries) {
|
|
31469
31807
|
if (!m.isDirectory()) continue;
|
|
31470
31808
|
if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
|
|
@@ -31485,7 +31823,7 @@ async function collectTargets(baseDirs, terminalStatuses3) {
|
|
|
31485
31823
|
}
|
|
31486
31824
|
const assignmentsBase = resolve57(baseDir, m.name, "assignments");
|
|
31487
31825
|
if (!await fileExists(assignmentsBase)) continue;
|
|
31488
|
-
const slugs = await
|
|
31826
|
+
const slugs = await readdir22(assignmentsBase, { withFileTypes: true });
|
|
31489
31827
|
for (const a of slugs) {
|
|
31490
31828
|
if (!a.isDirectory()) continue;
|
|
31491
31829
|
if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
|
|
@@ -31533,7 +31871,7 @@ async function migrateStatusHistoryCommand(options) {
|
|
|
31533
31871
|
await withSuppressedEvents(async () => {
|
|
31534
31872
|
for (const t of targets) {
|
|
31535
31873
|
try {
|
|
31536
|
-
const content = await
|
|
31874
|
+
const content = await readFile38(t.assignmentMd, "utf-8");
|
|
31537
31875
|
if (parseAssignmentFrontmatter(content).statusHistory.length > 0) continue;
|
|
31538
31876
|
const seededContent = appendStatusHistoryEntry(content, {
|
|
31539
31877
|
at: t.seedAt,
|
|
@@ -31562,10 +31900,10 @@ init_config2();
|
|
|
31562
31900
|
init_parser();
|
|
31563
31901
|
init_events_db();
|
|
31564
31902
|
import { resolve as resolve58 } from "path";
|
|
31565
|
-
import { readdir as
|
|
31903
|
+
import { readdir as readdir23, readFile as readFile39 } from "fs/promises";
|
|
31566
31904
|
async function parseSafe3(path) {
|
|
31567
31905
|
try {
|
|
31568
|
-
return parseAssignmentFull(await
|
|
31906
|
+
return parseAssignmentFull(await readFile39(path, "utf-8"));
|
|
31569
31907
|
} catch {
|
|
31570
31908
|
return null;
|
|
31571
31909
|
}
|
|
@@ -31598,7 +31936,7 @@ async function collectTargets2(baseDirs) {
|
|
|
31598
31936
|
const seen = /* @__PURE__ */ new Set();
|
|
31599
31937
|
for (const baseDir of baseDirs) {
|
|
31600
31938
|
if (!await fileExists(baseDir)) continue;
|
|
31601
|
-
const entries = await
|
|
31939
|
+
const entries = await readdir23(baseDir, { withFileTypes: true });
|
|
31602
31940
|
for (const m of entries) {
|
|
31603
31941
|
if (!m.isDirectory()) continue;
|
|
31604
31942
|
if (m.name.startsWith(".") || m.name.startsWith("_")) continue;
|
|
@@ -31622,7 +31960,7 @@ async function collectTargets2(baseDirs) {
|
|
|
31622
31960
|
}
|
|
31623
31961
|
const assignmentsBase = resolve58(baseDir, m.name, "assignments");
|
|
31624
31962
|
if (!await fileExists(assignmentsBase)) continue;
|
|
31625
|
-
const slugs = await
|
|
31963
|
+
const slugs = await readdir23(assignmentsBase, { withFileTypes: true });
|
|
31626
31964
|
for (const a of slugs) {
|
|
31627
31965
|
if (!a.isDirectory()) continue;
|
|
31628
31966
|
if (a.name.startsWith(".") || a.name.startsWith("_")) continue;
|
|
@@ -31707,7 +32045,7 @@ init_frontmatter();
|
|
|
31707
32045
|
init_facts();
|
|
31708
32046
|
init_derive();
|
|
31709
32047
|
init_recompute();
|
|
31710
|
-
import { readdir as
|
|
32048
|
+
import { readdir as readdir24, readFile as readFile40 } from "fs/promises";
|
|
31711
32049
|
import { resolve as resolve59 } from "path";
|
|
31712
32050
|
var IMPLEMENTATION_STATUSES = /* @__PURE__ */ new Set(["in_progress", "review", "code_review"]);
|
|
31713
32051
|
var REVIEW_STATUSES = /* @__PURE__ */ new Set(["review", "code_review"]);
|
|
@@ -31715,14 +32053,14 @@ async function listTargets(projectsDir2, standaloneDir) {
|
|
|
31715
32053
|
const targets = [];
|
|
31716
32054
|
let projects = [];
|
|
31717
32055
|
try {
|
|
31718
|
-
projects = await
|
|
32056
|
+
projects = await readdir24(projectsDir2);
|
|
31719
32057
|
} catch {
|
|
31720
32058
|
}
|
|
31721
32059
|
for (const project of projects) {
|
|
31722
32060
|
const projectDir = resolve59(projectsDir2, project);
|
|
31723
32061
|
let slugs = [];
|
|
31724
32062
|
try {
|
|
31725
|
-
slugs = await
|
|
32063
|
+
slugs = await readdir24(resolve59(projectDir, "assignments"));
|
|
31726
32064
|
} catch {
|
|
31727
32065
|
continue;
|
|
31728
32066
|
}
|
|
@@ -31733,7 +32071,7 @@ async function listTargets(projectsDir2, standaloneDir) {
|
|
|
31733
32071
|
}
|
|
31734
32072
|
let ids = [];
|
|
31735
32073
|
try {
|
|
31736
|
-
ids = await
|
|
32074
|
+
ids = await readdir24(standaloneDir);
|
|
31737
32075
|
} catch {
|
|
31738
32076
|
}
|
|
31739
32077
|
for (const id of ids) {
|
|
@@ -31793,7 +32131,7 @@ async function migrateDeriveCommand(options) {
|
|
|
31793
32131
|
for (const target of targets) {
|
|
31794
32132
|
let content;
|
|
31795
32133
|
try {
|
|
31796
|
-
content = await
|
|
32134
|
+
content = await readFile40(target.path, "utf-8");
|
|
31797
32135
|
} catch {
|
|
31798
32136
|
continue;
|
|
31799
32137
|
}
|
|
@@ -32007,10 +32345,10 @@ init_config2();
|
|
|
32007
32345
|
init_fs();
|
|
32008
32346
|
import {
|
|
32009
32347
|
cp as cp3,
|
|
32010
|
-
readdir as
|
|
32348
|
+
readdir as readdir25,
|
|
32011
32349
|
symlink,
|
|
32012
32350
|
lstat,
|
|
32013
|
-
readFile as
|
|
32351
|
+
readFile as readFile41,
|
|
32014
32352
|
readlink,
|
|
32015
32353
|
rename as rename9,
|
|
32016
32354
|
rm as rm6,
|
|
@@ -32071,7 +32409,7 @@ function getInstallMarkerPath(targetDir) {
|
|
|
32071
32409
|
return resolve64(targetDir, INSTALL_MARKER_FILENAME);
|
|
32072
32410
|
}
|
|
32073
32411
|
async function readPackageManifest(packageRoot) {
|
|
32074
|
-
const raw2 = await
|
|
32412
|
+
const raw2 = await readFile41(resolve64(packageRoot, "package.json"), "utf-8");
|
|
32075
32413
|
return JSON.parse(raw2);
|
|
32076
32414
|
}
|
|
32077
32415
|
async function readJsonFileIfExists(pathValue) {
|
|
@@ -32079,7 +32417,7 @@ async function readJsonFileIfExists(pathValue) {
|
|
|
32079
32417
|
return null;
|
|
32080
32418
|
}
|
|
32081
32419
|
try {
|
|
32082
|
-
const raw2 = await
|
|
32420
|
+
const raw2 = await readFile41(pathValue, "utf-8");
|
|
32083
32421
|
return JSON.parse(raw2);
|
|
32084
32422
|
} catch {
|
|
32085
32423
|
return null;
|
|
@@ -32095,7 +32433,7 @@ async function readPluginManifestName(targetDir, pluginKind) {
|
|
|
32095
32433
|
if (!await fileExists(manifestPath)) {
|
|
32096
32434
|
return void 0;
|
|
32097
32435
|
}
|
|
32098
|
-
const raw2 = await
|
|
32436
|
+
const raw2 = await readFile41(manifestPath, "utf-8");
|
|
32099
32437
|
const parsed = JSON.parse(raw2);
|
|
32100
32438
|
return parsed.name;
|
|
32101
32439
|
}
|
|
@@ -32105,7 +32443,7 @@ async function readInstallMetadata(targetDir) {
|
|
|
32105
32443
|
return null;
|
|
32106
32444
|
}
|
|
32107
32445
|
try {
|
|
32108
|
-
const raw2 = await
|
|
32446
|
+
const raw2 = await readFile41(markerPath, "utf-8");
|
|
32109
32447
|
return JSON.parse(raw2);
|
|
32110
32448
|
} catch {
|
|
32111
32449
|
return null;
|
|
@@ -32228,7 +32566,7 @@ async function writeClaudeMarketplaceFile(manifestPath, marketplace) {
|
|
|
32228
32566
|
}
|
|
32229
32567
|
if (await fileExists(manifestPath)) {
|
|
32230
32568
|
try {
|
|
32231
|
-
const prev = await
|
|
32569
|
+
const prev = await readFile41(manifestPath, "utf-8");
|
|
32232
32570
|
JSON.parse(prev);
|
|
32233
32571
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
32234
32572
|
await writeFile10(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
|
|
@@ -32301,7 +32639,7 @@ async function listClaudeMarketplaceCandidates() {
|
|
|
32301
32639
|
const [knownMarketplaces, activeMarketplaceNames, entries] = await Promise.all([
|
|
32302
32640
|
readKnownClaudeMarketplaceRecords(),
|
|
32303
32641
|
readInstalledClaudeMarketplaceNames(),
|
|
32304
|
-
|
|
32642
|
+
readdir25(rootDir, { withFileTypes: true })
|
|
32305
32643
|
]);
|
|
32306
32644
|
const candidates = [];
|
|
32307
32645
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -32376,7 +32714,7 @@ async function registerKnownClaudeMarketplace(name, rootDir) {
|
|
|
32376
32714
|
const manifestPath = getClaudeKnownMarketplacesPath();
|
|
32377
32715
|
let existing = {};
|
|
32378
32716
|
if (await fileExists(manifestPath)) {
|
|
32379
|
-
const raw2 = await
|
|
32717
|
+
const raw2 = await readFile41(manifestPath, "utf-8");
|
|
32380
32718
|
try {
|
|
32381
32719
|
const parsed = JSON.parse(raw2);
|
|
32382
32720
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
@@ -32403,7 +32741,7 @@ async function registerKnownClaudeMarketplace(name, rootDir) {
|
|
|
32403
32741
|
existing[name].autoUpdate = true;
|
|
32404
32742
|
await ensureDir(dirname15(manifestPath));
|
|
32405
32743
|
if (await fileExists(manifestPath)) {
|
|
32406
|
-
const prev = await
|
|
32744
|
+
const prev = await readFile41(manifestPath, "utf-8");
|
|
32407
32745
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
32408
32746
|
await writeFile10(`${manifestPath}.bak-${stamp}`, prev, "utf-8");
|
|
32409
32747
|
}
|
|
@@ -32421,7 +32759,7 @@ async function setSyntaurPluginEnabled(options) {
|
|
|
32421
32759
|
const key = `syntaur@${options.marketplaceName}`;
|
|
32422
32760
|
let parsed = {};
|
|
32423
32761
|
if (await fileExists(settingsPath)) {
|
|
32424
|
-
const raw2 = await
|
|
32762
|
+
const raw2 = await readFile41(settingsPath, "utf-8");
|
|
32425
32763
|
try {
|
|
32426
32764
|
parsed = JSON.parse(raw2);
|
|
32427
32765
|
} catch {
|
|
@@ -32440,7 +32778,7 @@ async function setSyntaurPluginEnabled(options) {
|
|
|
32440
32778
|
await ensureDir(dirname15(settingsPath));
|
|
32441
32779
|
if (await fileExists(settingsPath)) {
|
|
32442
32780
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
32443
|
-
const prev = await
|
|
32781
|
+
const prev = await readFile41(settingsPath, "utf-8");
|
|
32444
32782
|
await writeFile10(`${settingsPath}.bak-${stamp}`, prev, "utf-8");
|
|
32445
32783
|
}
|
|
32446
32784
|
const tmpPath = `${settingsPath}.tmp`;
|
|
@@ -32678,7 +33016,7 @@ async function readMarketplaceFile(marketplacePath) {
|
|
|
32678
33016
|
plugins: []
|
|
32679
33017
|
};
|
|
32680
33018
|
}
|
|
32681
|
-
const raw2 = await
|
|
33019
|
+
const raw2 = await readFile41(marketplacePath, "utf-8");
|
|
32682
33020
|
const parsed = JSON.parse(raw2);
|
|
32683
33021
|
return {
|
|
32684
33022
|
name: parsed.name ?? "local",
|
|
@@ -32920,13 +33258,13 @@ async function textPrompt(question, defaultValue) {
|
|
|
32920
33258
|
|
|
32921
33259
|
// src/utils/install-skills.ts
|
|
32922
33260
|
init_fs();
|
|
32923
|
-
import { readFile as
|
|
32924
|
-
import { resolve as resolve66, relative as relative3, join as
|
|
33261
|
+
import { readFile as readFile43, readdir as readdir26, mkdir as mkdir7, copyFile, rm as rm7, lstat as lstat2 } from "fs/promises";
|
|
33262
|
+
import { resolve as resolve66, relative as relative3, join as join12 } from "path";
|
|
32925
33263
|
import { homedir as homedir10 } from "os";
|
|
32926
33264
|
|
|
32927
33265
|
// src/utils/plugin-state.ts
|
|
32928
33266
|
init_fs();
|
|
32929
|
-
import { readFile as
|
|
33267
|
+
import { readFile as readFile42 } from "fs/promises";
|
|
32930
33268
|
import { resolve as resolve65 } from "path";
|
|
32931
33269
|
import { homedir as homedir9 } from "os";
|
|
32932
33270
|
function settingsPathFor(agent) {
|
|
@@ -32937,7 +33275,7 @@ async function readJsonOrNull(path) {
|
|
|
32937
33275
|
if (!path) return null;
|
|
32938
33276
|
if (!await fileExists(path)) return null;
|
|
32939
33277
|
try {
|
|
32940
|
-
const raw2 = await
|
|
33278
|
+
const raw2 = await readFile42(path, "utf-8");
|
|
32941
33279
|
return JSON.parse(raw2);
|
|
32942
33280
|
} catch {
|
|
32943
33281
|
return null;
|
|
@@ -32996,9 +33334,9 @@ function defaultSkillTargetDir(target) {
|
|
|
32996
33334
|
async function walkFiles(root) {
|
|
32997
33335
|
const out = [];
|
|
32998
33336
|
async function walk(dir) {
|
|
32999
|
-
const entries = await
|
|
33337
|
+
const entries = await readdir26(dir, { withFileTypes: true });
|
|
33000
33338
|
for (const entry of entries) {
|
|
33001
|
-
const full =
|
|
33339
|
+
const full = join12(dir, entry.name);
|
|
33002
33340
|
if (entry.isDirectory()) {
|
|
33003
33341
|
await walk(full);
|
|
33004
33342
|
} else if (entry.isFile()) {
|
|
@@ -33011,7 +33349,7 @@ async function walkFiles(root) {
|
|
|
33011
33349
|
}
|
|
33012
33350
|
async function filesEqual(a, b) {
|
|
33013
33351
|
try {
|
|
33014
|
-
const [ba, bb] = await Promise.all([
|
|
33352
|
+
const [ba, bb] = await Promise.all([readFile43(a), readFile43(b)]);
|
|
33015
33353
|
if (ba.length !== bb.length) return false;
|
|
33016
33354
|
return ba.equals(bb);
|
|
33017
33355
|
} catch {
|
|
@@ -33020,10 +33358,10 @@ async function filesEqual(a, b) {
|
|
|
33020
33358
|
}
|
|
33021
33359
|
async function copyDir(srcDir, destDir) {
|
|
33022
33360
|
await mkdir7(destDir, { recursive: true });
|
|
33023
|
-
const entries = await
|
|
33361
|
+
const entries = await readdir26(srcDir, { withFileTypes: true });
|
|
33024
33362
|
for (const entry of entries) {
|
|
33025
|
-
const src =
|
|
33026
|
-
const dest =
|
|
33363
|
+
const src = join12(srcDir, entry.name);
|
|
33364
|
+
const dest = join12(destDir, entry.name);
|
|
33027
33365
|
if (entry.isDirectory()) {
|
|
33028
33366
|
await copyDir(src, dest);
|
|
33029
33367
|
} else if (entry.isFile()) {
|
|
@@ -33036,7 +33374,7 @@ async function skillMatches(srcDir, destDir) {
|
|
|
33036
33374
|
const srcFiles = await walkFiles(srcDir);
|
|
33037
33375
|
for (const srcFile of srcFiles) {
|
|
33038
33376
|
const rel = relative3(srcDir, srcFile);
|
|
33039
|
-
const destFile =
|
|
33377
|
+
const destFile = join12(destDir, rel);
|
|
33040
33378
|
if (!await filesEqual(srcFile, destFile)) return false;
|
|
33041
33379
|
}
|
|
33042
33380
|
const destFiles = await walkFiles(destDir);
|
|
@@ -33074,12 +33412,12 @@ async function installSkillDir(srcDir, destDir, skillName, force) {
|
|
|
33074
33412
|
return { skill: skillName, status: "differs-preserved", targetPath: destDir };
|
|
33075
33413
|
}
|
|
33076
33414
|
async function discoverSkillNames(sourceDir) {
|
|
33077
|
-
const entries = await
|
|
33415
|
+
const entries = await readdir26(sourceDir, { withFileTypes: true });
|
|
33078
33416
|
const names = [];
|
|
33079
33417
|
for (const entry of entries) {
|
|
33080
33418
|
if (!entry.isDirectory()) continue;
|
|
33081
33419
|
if (entry.name.startsWith(".")) continue;
|
|
33082
|
-
if (await fileExists(
|
|
33420
|
+
if (await fileExists(join12(sourceDir, entry.name, "SKILL.md"))) {
|
|
33083
33421
|
names.push(entry.name);
|
|
33084
33422
|
}
|
|
33085
33423
|
}
|
|
@@ -33106,8 +33444,8 @@ async function installSkillsWithReport(options) {
|
|
|
33106
33444
|
const results = [];
|
|
33107
33445
|
await mkdir7(targetRoot, { recursive: true });
|
|
33108
33446
|
for (const skill of skillNames) {
|
|
33109
|
-
const srcDir =
|
|
33110
|
-
const destDir =
|
|
33447
|
+
const srcDir = join12(source, skill);
|
|
33448
|
+
const destDir = join12(targetRoot, skill);
|
|
33111
33449
|
results.push(await installSkillDir(srcDir, destDir, skill, force));
|
|
33112
33450
|
}
|
|
33113
33451
|
return { results };
|
|
@@ -33124,8 +33462,8 @@ async function installSkillsToDir(options) {
|
|
|
33124
33462
|
await mkdir7(options.targetDir, { recursive: true });
|
|
33125
33463
|
const results = [];
|
|
33126
33464
|
for (const skill of skillNames) {
|
|
33127
|
-
const srcDir =
|
|
33128
|
-
const destDir =
|
|
33465
|
+
const srcDir = join12(source, skill);
|
|
33466
|
+
const destDir = join12(options.targetDir, skill);
|
|
33129
33467
|
results.push(await installSkillDir(srcDir, destDir, skill, force));
|
|
33130
33468
|
}
|
|
33131
33469
|
return results;
|
|
@@ -33146,12 +33484,12 @@ async function uninstallSkills(options) {
|
|
|
33146
33484
|
}
|
|
33147
33485
|
const removed = [];
|
|
33148
33486
|
for (const skill of known) {
|
|
33149
|
-
const destDir =
|
|
33487
|
+
const destDir = join12(targetRoot, skill);
|
|
33150
33488
|
if (!await fileExists(destDir)) continue;
|
|
33151
33489
|
if (await isSymlink(destDir)) continue;
|
|
33152
|
-
const skillMd =
|
|
33490
|
+
const skillMd = join12(destDir, "SKILL.md");
|
|
33153
33491
|
if (!await fileExists(skillMd)) continue;
|
|
33154
|
-
const content = await
|
|
33492
|
+
const content = await readFile43(skillMd, "utf-8").catch(() => "");
|
|
33155
33493
|
const match = content.match(/^name:\s*(\S+)\s*$/m);
|
|
33156
33494
|
if (!match || match[1] !== skill) continue;
|
|
33157
33495
|
await rm7(destDir, { recursive: true, force: true });
|
|
@@ -33346,20 +33684,20 @@ import { realpathSync as realpathSync3 } from "fs";
|
|
|
33346
33684
|
init_paths();
|
|
33347
33685
|
init_fs();
|
|
33348
33686
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
33349
|
-
import { readFile as
|
|
33350
|
-
import { dirname as dirname17, join as
|
|
33687
|
+
import { readFile as readFile45 } from "fs/promises";
|
|
33688
|
+
import { dirname as dirname17, join as join14, resolve as resolve67 } from "path";
|
|
33351
33689
|
import { spawn as spawn6 } from "child_process";
|
|
33352
33690
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
33353
33691
|
|
|
33354
33692
|
// src/utils/version.ts
|
|
33355
33693
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
33356
|
-
import { readFile as
|
|
33357
|
-
import { dirname as dirname16, join as
|
|
33694
|
+
import { readFile as readFile44 } from "fs/promises";
|
|
33695
|
+
import { dirname as dirname16, join as join13 } from "path";
|
|
33358
33696
|
async function readPackageVersion(scriptUrl) {
|
|
33359
33697
|
try {
|
|
33360
33698
|
const scriptPath = fileURLToPath5(scriptUrl);
|
|
33361
33699
|
const pkgRoot = dirname16(dirname16(scriptPath));
|
|
33362
|
-
const raw2 = await
|
|
33700
|
+
const raw2 = await readFile44(join13(pkgRoot, "package.json"), "utf-8");
|
|
33363
33701
|
const parsed = JSON.parse(raw2);
|
|
33364
33702
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
33365
33703
|
} catch {
|
|
@@ -33389,7 +33727,7 @@ function isRunningViaNpx(scriptUrl) {
|
|
|
33389
33727
|
async function readState() {
|
|
33390
33728
|
if (!await fileExists(STATE_FILE)) return null;
|
|
33391
33729
|
try {
|
|
33392
|
-
const raw2 = await
|
|
33730
|
+
const raw2 = await readFile45(STATE_FILE, "utf-8");
|
|
33393
33731
|
return JSON.parse(raw2);
|
|
33394
33732
|
} catch {
|
|
33395
33733
|
return null;
|
|
@@ -33403,7 +33741,7 @@ async function resolveNpmBin() {
|
|
|
33403
33741
|
const nodeDir = dirname17(process.execPath);
|
|
33404
33742
|
const isWin = process.platform === "win32";
|
|
33405
33743
|
const npmName = isWin ? "npm.cmd" : "npm";
|
|
33406
|
-
const nearNode =
|
|
33744
|
+
const nearNode = join14(nodeDir, npmName);
|
|
33407
33745
|
if (await fileExists(nearNode)) {
|
|
33408
33746
|
return { cmd: nearNode, shell: false };
|
|
33409
33747
|
}
|
|
@@ -33446,9 +33784,9 @@ async function readGlobalVersion() {
|
|
|
33446
33784
|
});
|
|
33447
33785
|
if (!rootPath) return null;
|
|
33448
33786
|
try {
|
|
33449
|
-
const manifestPath =
|
|
33787
|
+
const manifestPath = join14(rootPath, "syntaur", "package.json");
|
|
33450
33788
|
if (!await fileExists(manifestPath)) return null;
|
|
33451
|
-
const raw2 = await
|
|
33789
|
+
const raw2 = await readFile45(manifestPath, "utf-8");
|
|
33452
33790
|
const parsed = JSON.parse(raw2);
|
|
33453
33791
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
33454
33792
|
} catch {
|
|
@@ -33567,7 +33905,7 @@ async function maybePromptInstall(scriptUrl) {
|
|
|
33567
33905
|
|
|
33568
33906
|
// src/commands/update.ts
|
|
33569
33907
|
import { existsSync as existsSync5 } from "fs";
|
|
33570
|
-
import { join as
|
|
33908
|
+
import { join as join15 } from "path";
|
|
33571
33909
|
import { homedir as homedir11 } from "os";
|
|
33572
33910
|
var PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
|
|
33573
33911
|
var LOCAL_MSG = "Running from a dev/linked checkout \u2014 `syntaur update` won't touch a linked install. Pull + rebuild in your repo, then `syntaur install-plugin --force` to refresh skills.";
|
|
@@ -33609,12 +33947,12 @@ var defaultRunner = (cmd, args, opts) => new Promise((resolvePromise) => {
|
|
|
33609
33947
|
child.on("close", (code) => resolvePromise({ code: code ?? -1, stdout, stderr }));
|
|
33610
33948
|
});
|
|
33611
33949
|
function bunGlobalNodeModulesDir(env) {
|
|
33612
|
-
const globalDir = env.BUN_INSTALL_GLOBAL_DIR ??
|
|
33613
|
-
return
|
|
33950
|
+
const globalDir = env.BUN_INSTALL_GLOBAL_DIR ?? join15(env.BUN_INSTALL ?? join15(homedir11(), ".bun"), "install", "global");
|
|
33951
|
+
return join15(globalDir, "node_modules");
|
|
33614
33952
|
}
|
|
33615
33953
|
async function defaultResolveFreshBin(pm, runner, env) {
|
|
33616
33954
|
const binFromPkgRoot = (pkgRoot) => {
|
|
33617
|
-
const entry =
|
|
33955
|
+
const entry = join15(pkgRoot, "syntaur", "bin", "syntaur.js");
|
|
33618
33956
|
return existsSync5(entry) ? { cmd: process.execPath, baseArgs: [entry] } : null;
|
|
33619
33957
|
};
|
|
33620
33958
|
try {
|
|
@@ -33626,7 +33964,7 @@ async function defaultResolveFreshBin(pm, runner, env) {
|
|
|
33626
33964
|
if (pm === "yarn") {
|
|
33627
33965
|
const res = await runner("yarn", ["global", "dir"], { env, captureStdout: true });
|
|
33628
33966
|
const dir = res.stdout.trim();
|
|
33629
|
-
return dir ? binFromPkgRoot(
|
|
33967
|
+
return dir ? binFromPkgRoot(join15(dir, "node_modules")) : null;
|
|
33630
33968
|
}
|
|
33631
33969
|
return binFromPkgRoot(bunGlobalNodeModulesDir(env));
|
|
33632
33970
|
} catch {
|
|
@@ -33806,7 +34144,7 @@ async function refreshPluginSkills(options, pm, runner, getManagedDir, resolveFr
|
|
|
33806
34144
|
// src/commands/install-statusline.ts
|
|
33807
34145
|
init_paths();
|
|
33808
34146
|
init_fs();
|
|
33809
|
-
import { readFile as
|
|
34147
|
+
import { readFile as readFile47, writeFile as writeFile12, copyFile as copyFile2, rm as rm8, stat as stat8, symlink as symlink2, unlink as unlink11, lstat as lstat3 } from "fs/promises";
|
|
33810
34148
|
import { resolve as resolve69, dirname as dirname19 } from "path";
|
|
33811
34149
|
import { homedir as homedir12 } from "os";
|
|
33812
34150
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
@@ -33814,7 +34152,7 @@ import { fileURLToPath as fileURLToPath8 } from "url";
|
|
|
33814
34152
|
// src/commands/configure-statusline.ts
|
|
33815
34153
|
init_paths();
|
|
33816
34154
|
init_fs();
|
|
33817
|
-
import { readFile as
|
|
34155
|
+
import { readFile as readFile46, writeFile as writeFile11 } from "fs/promises";
|
|
33818
34156
|
import { resolve as resolve68, dirname as dirname18 } from "path";
|
|
33819
34157
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
33820
34158
|
import { checkbox, input as input2, confirm } from "@inquirer/prompts";
|
|
@@ -33841,7 +34179,7 @@ function getConfigPath(installRoot) {
|
|
|
33841
34179
|
async function readConfig2(path) {
|
|
33842
34180
|
if (!await fileExists(path)) return null;
|
|
33843
34181
|
try {
|
|
33844
|
-
const raw2 = await
|
|
34182
|
+
const raw2 = await readFile46(path, "utf-8");
|
|
33845
34183
|
const parsed = JSON.parse(raw2);
|
|
33846
34184
|
if (!parsed || typeof parsed !== "object") return null;
|
|
33847
34185
|
const segments = Array.isArray(parsed.segments) ? parsed.segments.filter(isSegmentName) : [];
|
|
@@ -34029,7 +34367,7 @@ function getPackageStatuslineSource() {
|
|
|
34029
34367
|
}
|
|
34030
34368
|
async function readSettingsJson(settingsPath) {
|
|
34031
34369
|
if (!await fileExists(settingsPath)) return {};
|
|
34032
|
-
const raw2 = await
|
|
34370
|
+
const raw2 = await readFile47(settingsPath, "utf-8");
|
|
34033
34371
|
if (raw2.trim() === "") return {};
|
|
34034
34372
|
try {
|
|
34035
34373
|
const parsed = JSON.parse(raw2);
|
|
@@ -34217,7 +34555,7 @@ async function uninstallStatuslineCommand(options = {}) {
|
|
|
34217
34555
|
let restored = null;
|
|
34218
34556
|
if (await fileExists(backupPath)) {
|
|
34219
34557
|
try {
|
|
34220
|
-
const raw2 = await
|
|
34558
|
+
const raw2 = await readFile47(backupPath, "utf-8");
|
|
34221
34559
|
const parsed = JSON.parse(raw2);
|
|
34222
34560
|
const prev = parsed?.previousStatusLine;
|
|
34223
34561
|
if (prev && typeof prev === "object" && typeof prev.command === "string") {
|
|
@@ -34398,7 +34736,7 @@ init_config2();
|
|
|
34398
34736
|
// src/commands/cross-agent-install.ts
|
|
34399
34737
|
init_fs();
|
|
34400
34738
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
34401
|
-
import { dirname as dirname20, join as
|
|
34739
|
+
import { dirname as dirname20, join as join16, resolve as resolve71 } from "path";
|
|
34402
34740
|
import { cp as cp4, mkdir as mkdir9 } from "fs/promises";
|
|
34403
34741
|
|
|
34404
34742
|
// src/commands/setup-adapter.ts
|
|
@@ -34509,7 +34847,7 @@ async function installTier3Plugin(t, opts = {}) {
|
|
|
34509
34847
|
console.log(`${prefix}Tier 3 (${t.id}): ${plugin.source} -> ${installDir}`);
|
|
34510
34848
|
return "dry-run";
|
|
34511
34849
|
}
|
|
34512
|
-
if (await fileExists(
|
|
34850
|
+
if (await fileExists(join16(installDir, plugin.entry)) && !opts.force) {
|
|
34513
34851
|
console.log(
|
|
34514
34852
|
`Tier 3 (${t.id}): already installed at ${installDir} (use --force to overwrite).`
|
|
34515
34853
|
);
|
|
@@ -34887,7 +35225,7 @@ init_cwd();
|
|
|
34887
35225
|
init_session_db();
|
|
34888
35226
|
init_agent_sessions();
|
|
34889
35227
|
import { resolve as resolve73 } from "path";
|
|
34890
|
-
import { readFile as
|
|
35228
|
+
import { readFile as readFile48 } from "fs/promises";
|
|
34891
35229
|
async function trackSessionCommand(options, deps = {}) {
|
|
34892
35230
|
if (!options.agent) {
|
|
34893
35231
|
throw new Error("--agent <name> is required.");
|
|
@@ -34904,7 +35242,7 @@ async function trackSessionCommand(options, deps = {}) {
|
|
|
34904
35242
|
const cwd = process.cwd();
|
|
34905
35243
|
let legacyHint;
|
|
34906
35244
|
try {
|
|
34907
|
-
const raw2 = await
|
|
35245
|
+
const raw2 = await readFile48(resolve73(cwd, ".syntaur", "context.json"), "utf-8");
|
|
34908
35246
|
const parsed = JSON.parse(raw2);
|
|
34909
35247
|
if (typeof parsed.sessionId === "string") legacyHint = parsed.sessionId;
|
|
34910
35248
|
} catch {
|
|
@@ -34988,8 +35326,10 @@ async function urlCommand(input4, options = {}) {
|
|
|
34988
35326
|
projectsDir: projectsDir2,
|
|
34989
35327
|
assignmentsDir: assignmentsDir(),
|
|
34990
35328
|
terminalOverride: parsed.terminal,
|
|
34991
|
-
|
|
34992
|
-
|
|
35329
|
+
// Standalone identifies its agent by `id`; assignment may pin one via `agent=`.
|
|
35330
|
+
agentId: parsed.kind === "standalone" ? parsed.id : parsed.kind === "assignment" ? parsed.agent : void 0,
|
|
35331
|
+
promptOverride: parsed.kind === "assignment" || parsed.kind === "standalone" ? parsed.prompt : void 0,
|
|
35332
|
+
agentName: parsed.kind === "assignment" ? parsed.agentName : void 0
|
|
34993
35333
|
});
|
|
34994
35334
|
emitPlanWarnings(plan);
|
|
34995
35335
|
if (options.printPlan) {
|
|
@@ -35067,7 +35407,7 @@ init_config2();
|
|
|
35067
35407
|
init_paths();
|
|
35068
35408
|
init_fs();
|
|
35069
35409
|
import { resolve as resolve75, isAbsolute as isAbsolute8 } from "path";
|
|
35070
|
-
import { readFile as
|
|
35410
|
+
import { readFile as readFile49 } from "fs/promises";
|
|
35071
35411
|
import { select, confirm as confirm2, input as input3 } from "@inquirer/prompts";
|
|
35072
35412
|
async function browseCommand(options) {
|
|
35073
35413
|
const config = await readConfig();
|
|
@@ -35146,7 +35486,7 @@ async function ensureWorktree(opts) {
|
|
|
35146
35486
|
if (!await fileExists(assignmentPath)) {
|
|
35147
35487
|
return void 0;
|
|
35148
35488
|
}
|
|
35149
|
-
const content = await
|
|
35489
|
+
const content = await readFile49(assignmentPath, "utf-8");
|
|
35150
35490
|
const { parseAssignmentFrontmatter: parseAssignmentFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
|
|
35151
35491
|
const fm = parseAssignmentFrontmatter2(content);
|
|
35152
35492
|
const { workspace } = fm;
|
|
@@ -35280,7 +35620,7 @@ init_paths();
|
|
|
35280
35620
|
init_fs();
|
|
35281
35621
|
init_parser();
|
|
35282
35622
|
init_config2();
|
|
35283
|
-
import { readdir as
|
|
35623
|
+
import { readdir as readdir27, readFile as readFile50 } from "fs/promises";
|
|
35284
35624
|
import { resolve as resolve77 } from "path";
|
|
35285
35625
|
async function listPlaybooksCommand(options = {}) {
|
|
35286
35626
|
const dir = playbooksDir();
|
|
@@ -35290,14 +35630,14 @@ async function listPlaybooksCommand(options = {}) {
|
|
|
35290
35630
|
}
|
|
35291
35631
|
const config = await readConfig();
|
|
35292
35632
|
const disabledSet = new Set(config.playbooks.disabled);
|
|
35293
|
-
const entries = await
|
|
35633
|
+
const entries = await readdir27(dir, { withFileTypes: true });
|
|
35294
35634
|
const mdFiles = entries.filter(
|
|
35295
35635
|
(e) => e.isFile() && e.name.endsWith(".md") && !e.name.startsWith("_") && e.name !== "manifest.md"
|
|
35296
35636
|
);
|
|
35297
35637
|
const rows = [];
|
|
35298
35638
|
for (const entry of mdFiles) {
|
|
35299
35639
|
const filePath = resolve77(dir, entry.name);
|
|
35300
|
-
const raw2 = await
|
|
35640
|
+
const raw2 = await readFile50(filePath, "utf-8");
|
|
35301
35641
|
const parsed = parsePlaybook(raw2);
|
|
35302
35642
|
const slug = parsed.slug || entry.name.replace(/\.md$/, "");
|
|
35303
35643
|
const disabled = disabledSet.has(slug);
|
|
@@ -35420,13 +35760,13 @@ init_fs();
|
|
|
35420
35760
|
init_config2();
|
|
35421
35761
|
init_slug();
|
|
35422
35762
|
import { Command as Command2 } from "commander";
|
|
35423
|
-
import { readFile as
|
|
35763
|
+
import { readFile as readFile52 } from "fs/promises";
|
|
35424
35764
|
import { resolve as resolve79 } from "path";
|
|
35425
35765
|
|
|
35426
35766
|
// src/commands/bundle.ts
|
|
35427
35767
|
init_paths();
|
|
35428
35768
|
import { Command } from "commander";
|
|
35429
|
-
import { mkdir as mkdir10, readFile as
|
|
35769
|
+
import { mkdir as mkdir10, readFile as readFile51, readdir as readdir28, rm as rm9, writeFile as writeFile13 } from "fs/promises";
|
|
35430
35770
|
import { resolve as resolve78 } from "path";
|
|
35431
35771
|
init_parser2();
|
|
35432
35772
|
init_fs();
|
|
@@ -35719,7 +36059,7 @@ bundleCommand.command("plan").description("Create or open the bundle's shared pl
|
|
|
35719
36059
|
}
|
|
35720
36060
|
const planDir = bundlePlanDir(sc.todosPath, sc.scopeId, id);
|
|
35721
36061
|
await ensureDir(planDir);
|
|
35722
|
-
const existing = (await
|
|
36062
|
+
const existing = (await readdir28(planDir).catch(() => [])).filter((f) => /^plan(?:-v\d+)?\.md$/.test(f));
|
|
35723
36063
|
const { target } = pickNextPlanFile(planDir, existing);
|
|
35724
36064
|
const checklist = await readChecklist(sc.todosPath, sc.checklistKey);
|
|
35725
36065
|
if (!await fileExists(target)) {
|
|
@@ -35788,8 +36128,8 @@ bundleCommand.command("worktree").description("Create a git worktree for the bun
|
|
|
35788
36128
|
}
|
|
35789
36129
|
const bundlesFilePath = bundlesPath(sc.todosPath);
|
|
35790
36130
|
const checklistFilePath = checklistPath(sc.todosPath, sc.checklistKey);
|
|
35791
|
-
const bundlesSnapshot = await fileExists(bundlesFilePath) ? await
|
|
35792
|
-
const checklistSnapshot = await fileExists(checklistFilePath) ? await
|
|
36131
|
+
const bundlesSnapshot = await fileExists(bundlesFilePath) ? await readFile51(bundlesFilePath, "utf-8") : null;
|
|
36132
|
+
const checklistSnapshot = await fileExists(checklistFilePath) ? await readFile51(checklistFilePath, "utf-8") : null;
|
|
35793
36133
|
const record = async () => {
|
|
35794
36134
|
bundle.branch = options.branch;
|
|
35795
36135
|
bundle.worktreePath = worktreePath;
|
|
@@ -36345,7 +36685,7 @@ todoCommand.command("archive").description("Archive completed todos and their lo
|
|
|
36345
36685
|
await ensureDir(resolve79(todosPath, "archive"));
|
|
36346
36686
|
let archContent = "";
|
|
36347
36687
|
if (await fileExists(archFile)) {
|
|
36348
|
-
archContent = await
|
|
36688
|
+
archContent = await readFile52(archFile, "utf-8");
|
|
36349
36689
|
archContent = archContent.trimEnd() + "\n\n";
|
|
36350
36690
|
} else {
|
|
36351
36691
|
archContent = `---
|
|
@@ -36523,12 +36863,12 @@ function describeScope(scope) {
|
|
|
36523
36863
|
}
|
|
36524
36864
|
async function injectPromotedTodos(assignmentDir, todos, scopeLabel) {
|
|
36525
36865
|
const { resolve: resolvePath2 } = await import("path");
|
|
36526
|
-
const { readFile:
|
|
36866
|
+
const { readFile: readFile82 } = await import("fs/promises");
|
|
36527
36867
|
const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
36528
36868
|
const { appendTodosToAssignmentBody: appendTodosToAssignmentBody2, touchAssignmentUpdated: touchAssignmentUpdated2 } = await Promise.resolve().then(() => (init_assignment_todos(), assignment_todos_exports));
|
|
36529
36869
|
const { nowTimestamp: nowTimestamp3 } = await Promise.resolve().then(() => (init_timestamp(), timestamp_exports));
|
|
36530
36870
|
const assignmentMdPath2 = resolvePath2(assignmentDir, "assignment.md");
|
|
36531
|
-
let content = await
|
|
36871
|
+
let content = await readFile82(assignmentMdPath2, "utf-8");
|
|
36532
36872
|
content = appendTodosToAssignmentBody2(
|
|
36533
36873
|
content,
|
|
36534
36874
|
todos.map((t) => ({
|
|
@@ -36573,8 +36913,8 @@ todoCommand.command("plan").description("Create or open a plan directory for a t
|
|
|
36573
36913
|
}
|
|
36574
36914
|
const planDir = todoPlanDir(todosPath, workspace, id);
|
|
36575
36915
|
await ensureDir(planDir);
|
|
36576
|
-
const { readdir:
|
|
36577
|
-
const existingFiles = (await
|
|
36916
|
+
const { readdir: readdir41 } = await import("fs/promises");
|
|
36917
|
+
const existingFiles = (await readdir41(planDir).catch(() => [])).filter(
|
|
36578
36918
|
(f) => /^plan(?:-v\d+)?\.md$/.test(f)
|
|
36579
36919
|
);
|
|
36580
36920
|
let target;
|
|
@@ -36783,13 +37123,13 @@ backupCommand.command("config").description("Show or update backup configuration
|
|
|
36783
37123
|
|
|
36784
37124
|
// src/commands/doctor.ts
|
|
36785
37125
|
import { Command as Command4 } from "commander";
|
|
36786
|
-
import { readFile as
|
|
37126
|
+
import { readFile as readFile64 } from "fs/promises";
|
|
36787
37127
|
import { isAbsolute as isAbsolute11, resolve as resolve93 } from "path";
|
|
36788
37128
|
|
|
36789
37129
|
// src/utils/doctor/index.ts
|
|
36790
37130
|
import { fileURLToPath as fileURLToPath12 } from "url";
|
|
36791
|
-
import { readFile as
|
|
36792
|
-
import { dirname as dirname25, join as
|
|
37131
|
+
import { readFile as readFile63 } from "fs/promises";
|
|
37132
|
+
import { dirname as dirname25, join as join22 } from "path";
|
|
36793
37133
|
|
|
36794
37134
|
// src/utils/doctor/context.ts
|
|
36795
37135
|
init_config2();
|
|
@@ -36835,9 +37175,9 @@ function closeCheckContext(ctx) {
|
|
|
36835
37175
|
init_fs();
|
|
36836
37176
|
init_paths();
|
|
36837
37177
|
import { resolve as resolve81, isAbsolute as isAbsolute9 } from "path";
|
|
36838
|
-
import { readFile as
|
|
37178
|
+
import { readFile as readFile53, stat as stat9 } from "fs/promises";
|
|
36839
37179
|
import { fileURLToPath as fileURLToPath10 } from "url";
|
|
36840
|
-
import { dirname as dirname22, join as
|
|
37180
|
+
import { dirname as dirname22, join as join18 } from "path";
|
|
36841
37181
|
var CATEGORY = "env";
|
|
36842
37182
|
var syntaurRootExists = {
|
|
36843
37183
|
id: "env.syntaur-root-exists",
|
|
@@ -36892,7 +37232,7 @@ var configValid = {
|
|
|
36892
37232
|
autoFixable: false
|
|
36893
37233
|
};
|
|
36894
37234
|
}
|
|
36895
|
-
const content = await
|
|
37235
|
+
const content = await readFile53(configPath2, "utf-8");
|
|
36896
37236
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
36897
37237
|
if (!fmMatch || fmMatch[1].trim() === "") {
|
|
36898
37238
|
return {
|
|
@@ -37170,9 +37510,9 @@ async function readLocalPkg() {
|
|
|
37170
37510
|
const here = fileURLToPath10(import.meta.url);
|
|
37171
37511
|
let dir = dirname22(here);
|
|
37172
37512
|
for (let i = 0; i < 6; i++) {
|
|
37173
|
-
const candidate =
|
|
37513
|
+
const candidate = join18(dir, "package.json");
|
|
37174
37514
|
try {
|
|
37175
|
-
const text = await
|
|
37515
|
+
const text = await readFile53(candidate, "utf-8");
|
|
37176
37516
|
return JSON.parse(text);
|
|
37177
37517
|
} catch {
|
|
37178
37518
|
dir = dirname22(dir);
|
|
@@ -37225,7 +37565,7 @@ function versionGte(a, b) {
|
|
|
37225
37565
|
// src/utils/doctor/checks/structure.ts
|
|
37226
37566
|
init_fs();
|
|
37227
37567
|
import { resolve as resolve82 } from "path";
|
|
37228
|
-
import { readdir as
|
|
37568
|
+
import { readdir as readdir29, stat as stat10 } from "fs/promises";
|
|
37229
37569
|
var CATEGORY2 = "structure";
|
|
37230
37570
|
var KNOWN_TOP_LEVEL = /* @__PURE__ */ new Set([
|
|
37231
37571
|
"projects",
|
|
@@ -37356,7 +37696,7 @@ var knownFilesRecognized = {
|
|
|
37356
37696
|
category: CATEGORY2,
|
|
37357
37697
|
title: "No unexpected top-level entries under ~/.syntaur/",
|
|
37358
37698
|
async run(ctx) {
|
|
37359
|
-
const entries = await
|
|
37699
|
+
const entries = await readdir29(ctx.syntaurRoot, { withFileTypes: true });
|
|
37360
37700
|
const unexpected = [];
|
|
37361
37701
|
for (const e of entries) {
|
|
37362
37702
|
if (e.name.startsWith(".")) continue;
|
|
@@ -37400,7 +37740,7 @@ function pass2(check) {
|
|
|
37400
37740
|
// src/utils/doctor/checks/project.ts
|
|
37401
37741
|
init_fs();
|
|
37402
37742
|
import { resolve as resolve83 } from "path";
|
|
37403
|
-
import { readdir as
|
|
37743
|
+
import { readdir as readdir30, stat as stat11 } from "fs/promises";
|
|
37404
37744
|
var CATEGORY3 = "project";
|
|
37405
37745
|
var REQUIRED_PROJECT_FILES = [
|
|
37406
37746
|
"project.md",
|
|
@@ -37424,7 +37764,7 @@ var PROJECT_MARKERS = ["project.md", "manifest.md", "assignments"];
|
|
|
37424
37764
|
async function listProjects2(ctx) {
|
|
37425
37765
|
const dir = ctx.config.defaultProjectDir;
|
|
37426
37766
|
if (!await fileExists(dir)) return [];
|
|
37427
|
-
const entries = await
|
|
37767
|
+
const entries = await readdir30(dir, { withFileTypes: true });
|
|
37428
37768
|
const result = [];
|
|
37429
37769
|
for (const e of entries) {
|
|
37430
37770
|
if (!e.isDirectory()) continue;
|
|
@@ -37518,7 +37858,7 @@ var orphanFiles = {
|
|
|
37518
37858
|
const projects = await listProjects2(ctx);
|
|
37519
37859
|
const results = [];
|
|
37520
37860
|
for (const projectDir of projects) {
|
|
37521
|
-
const entries = await
|
|
37861
|
+
const entries = await readdir30(projectDir, { withFileTypes: true });
|
|
37522
37862
|
const orphans = [];
|
|
37523
37863
|
for (const e of entries) {
|
|
37524
37864
|
if (e.name.startsWith(".")) continue;
|
|
@@ -37548,7 +37888,7 @@ async function newestAssignmentMtime(projectDir) {
|
|
|
37548
37888
|
let newest = 0;
|
|
37549
37889
|
let entries;
|
|
37550
37890
|
try {
|
|
37551
|
-
entries = await
|
|
37891
|
+
entries = await readdir30(assignmentsRoot, { withFileTypes: true });
|
|
37552
37892
|
} catch {
|
|
37553
37893
|
return 0;
|
|
37554
37894
|
}
|
|
@@ -37580,7 +37920,7 @@ init_types();
|
|
|
37580
37920
|
init_paths();
|
|
37581
37921
|
init_assignment_walk();
|
|
37582
37922
|
import { resolve as resolve84 } from "path";
|
|
37583
|
-
import { readFile as
|
|
37923
|
+
import { readFile as readFile54, readdir as readdir31 } from "fs/promises";
|
|
37584
37924
|
var CATEGORY4 = "assignment";
|
|
37585
37925
|
var STATUSES_REQUIRING_HANDOFF = /* @__PURE__ */ new Set(["review", "completed"]);
|
|
37586
37926
|
var PRE_WORKSPACE_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -37928,7 +38268,7 @@ var draftMissingObjective = {
|
|
|
37928
38268
|
if (parsed.status !== "draft") continue;
|
|
37929
38269
|
let raw2;
|
|
37930
38270
|
try {
|
|
37931
|
-
raw2 = await
|
|
38271
|
+
raw2 = await readFile54(path, "utf-8");
|
|
37932
38272
|
} catch {
|
|
37933
38273
|
continue;
|
|
37934
38274
|
}
|
|
@@ -37965,12 +38305,12 @@ var readyToImplementMissingPlan = {
|
|
|
37965
38305
|
const parsed = await parseSafe4(path);
|
|
37966
38306
|
if (!parsed) continue;
|
|
37967
38307
|
if (parsed.status !== "ready_to_implement") continue;
|
|
37968
|
-
const entries = await
|
|
38308
|
+
const entries = await readdir31(a.assignmentDir).catch(() => []);
|
|
37969
38309
|
const planFiles = entries.filter((f) => /^plan(?:-v\d+)?\.md$/i.test(f));
|
|
37970
38310
|
let hasPlanContent = false;
|
|
37971
38311
|
for (const f of planFiles) {
|
|
37972
38312
|
try {
|
|
37973
|
-
const c2 = await
|
|
38313
|
+
const c2 = await readFile54(resolve84(a.assignmentDir, f), "utf-8");
|
|
37974
38314
|
if (c2.trim().length > 0) {
|
|
37975
38315
|
hasPlanContent = true;
|
|
37976
38316
|
break;
|
|
@@ -38013,7 +38353,7 @@ var assignmentChecks = [
|
|
|
38013
38353
|
];
|
|
38014
38354
|
async function parseSafe4(path) {
|
|
38015
38355
|
try {
|
|
38016
|
-
const content = await
|
|
38356
|
+
const content = await readFile54(path, "utf-8");
|
|
38017
38357
|
return parseAssignmentFull(content);
|
|
38018
38358
|
} catch {
|
|
38019
38359
|
return null;
|
|
@@ -38176,7 +38516,7 @@ function skipped(check, reason) {
|
|
|
38176
38516
|
// src/utils/doctor/checks/integrations.ts
|
|
38177
38517
|
init_fs();
|
|
38178
38518
|
import { resolve as resolve86, dirname as dirname23, basename as basename9 } from "path";
|
|
38179
|
-
import { readdir as
|
|
38519
|
+
import { readdir as readdir32, readFile as readFile55 } from "fs/promises";
|
|
38180
38520
|
import { homedir as homedir14 } from "os";
|
|
38181
38521
|
var CATEGORY6 = "integrations";
|
|
38182
38522
|
var claudePluginLinked = {
|
|
@@ -38239,7 +38579,7 @@ var backupConfigured = {
|
|
|
38239
38579
|
if (ctx.config.backup?.repo) return pass6(this);
|
|
38240
38580
|
const projectsDir2 = ctx.config.defaultProjectDir;
|
|
38241
38581
|
if (!await fileExists(projectsDir2)) return skipped2(this, "no projects dir");
|
|
38242
|
-
const entries = await
|
|
38582
|
+
const entries = await readdir32(projectsDir2, { withFileTypes: true });
|
|
38243
38583
|
const hasProjects = entries.some((e) => e.isDirectory() && !e.name.startsWith(".") && !e.name.startsWith("_"));
|
|
38244
38584
|
if (!hasProjects) return skipped2(this, "no projects yet");
|
|
38245
38585
|
return {
|
|
@@ -38261,7 +38601,7 @@ async function readKnownMarketplaces() {
|
|
|
38261
38601
|
const path = resolve86(homedir14(), ".claude", "plugins", "known_marketplaces.json");
|
|
38262
38602
|
if (!await fileExists(path)) return {};
|
|
38263
38603
|
try {
|
|
38264
|
-
const raw2 = await
|
|
38604
|
+
const raw2 = await readFile55(path, "utf-8");
|
|
38265
38605
|
return JSON.parse(raw2);
|
|
38266
38606
|
} catch {
|
|
38267
38607
|
return {};
|
|
@@ -38314,7 +38654,7 @@ var claudeMarketplaceRegistered = {
|
|
|
38314
38654
|
}
|
|
38315
38655
|
let parsed = {};
|
|
38316
38656
|
try {
|
|
38317
|
-
parsed = JSON.parse(await
|
|
38657
|
+
parsed = JSON.parse(await readFile55(marketplaceManifest, "utf-8"));
|
|
38318
38658
|
} catch {
|
|
38319
38659
|
return {
|
|
38320
38660
|
id: this.id,
|
|
@@ -38387,7 +38727,7 @@ init_fs();
|
|
|
38387
38727
|
init_parser();
|
|
38388
38728
|
init_types();
|
|
38389
38729
|
import { resolve as resolve87 } from "path";
|
|
38390
|
-
import { readFile as
|
|
38730
|
+
import { readFile as readFile56 } from "fs/promises";
|
|
38391
38731
|
var CATEGORY7 = "workspace";
|
|
38392
38732
|
var ASSIGNMENT_FIELDS2 = ["projectSlug", "assignmentSlug", "projectDir", "assignmentDir"];
|
|
38393
38733
|
var BUNDLE_FIELDS = ["bundleId", "bundleScope", "bundleScopeId"];
|
|
@@ -38419,7 +38759,7 @@ async function loadContext(ctx) {
|
|
|
38419
38759
|
return { data: null, path, exists: false, parseError: null };
|
|
38420
38760
|
}
|
|
38421
38761
|
try {
|
|
38422
|
-
const raw2 = await
|
|
38762
|
+
const raw2 = await readFile56(path, "utf-8");
|
|
38423
38763
|
return { data: JSON.parse(raw2), path, exists: true, parseError: null };
|
|
38424
38764
|
} catch (err2) {
|
|
38425
38765
|
return {
|
|
@@ -38531,7 +38871,7 @@ var contextTerminal = {
|
|
|
38531
38871
|
const assignmentMd = resolve87(data.assignmentDir, "assignment.md");
|
|
38532
38872
|
if (!await fileExists(assignmentMd)) return skipped3(this, "assignment file missing");
|
|
38533
38873
|
try {
|
|
38534
|
-
const content = await
|
|
38874
|
+
const content = await readFile56(assignmentMd, "utf-8");
|
|
38535
38875
|
const parsed = parseAssignmentFull(content);
|
|
38536
38876
|
const terminal = terminalStatuses2(ctx);
|
|
38537
38877
|
if (terminal.has(parsed.status)) {
|
|
@@ -38677,7 +39017,7 @@ var agentChecks = [agentsResolvable];
|
|
|
38677
39017
|
// src/utils/doctor/checks/terminal.ts
|
|
38678
39018
|
init_config2();
|
|
38679
39019
|
import { spawnSync as spawnSync9 } from "child_process";
|
|
38680
|
-
import { readFile as
|
|
39020
|
+
import { readFile as readFile57 } from "fs/promises";
|
|
38681
39021
|
import { resolve as resolve88 } from "path";
|
|
38682
39022
|
init_paths();
|
|
38683
39023
|
init_fs();
|
|
@@ -38685,7 +39025,7 @@ var CATEGORY9 = "terminal";
|
|
|
38685
39025
|
async function readRawTerminalKey() {
|
|
38686
39026
|
const configPath2 = resolve88(syntaurRoot(), "config.md");
|
|
38687
39027
|
if (!await fileExists(configPath2)) return null;
|
|
38688
|
-
const content = await
|
|
39028
|
+
const content = await readFile57(configPath2, "utf-8");
|
|
38689
39029
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
38690
39030
|
if (!fmMatch) return null;
|
|
38691
39031
|
const line = fmMatch[1].split("\n").find((l) => /^terminal:\s*/.test(l));
|
|
@@ -38835,8 +39175,8 @@ var terminalChecks = [
|
|
|
38835
39175
|
|
|
38836
39176
|
// src/utils/doctor/checks/skills.ts
|
|
38837
39177
|
init_fs();
|
|
38838
|
-
import { resolve as resolve89, join as
|
|
38839
|
-
import { readdir as
|
|
39178
|
+
import { resolve as resolve89, join as join19 } from "path";
|
|
39179
|
+
import { readdir as readdir33, readFile as readFile58, lstat as lstat4 } from "fs/promises";
|
|
38840
39180
|
import { homedir as homedir15 } from "os";
|
|
38841
39181
|
var CATEGORY10 = "skills";
|
|
38842
39182
|
var skillTargets = [
|
|
@@ -38856,21 +39196,21 @@ var skillsDedupCheck = {
|
|
|
38856
39196
|
const present = [];
|
|
38857
39197
|
let entries;
|
|
38858
39198
|
try {
|
|
38859
|
-
entries = await
|
|
39199
|
+
entries = await readdir33(dir, { withFileTypes: true });
|
|
38860
39200
|
} catch {
|
|
38861
39201
|
continue;
|
|
38862
39202
|
}
|
|
38863
39203
|
for (const entry of entries) {
|
|
38864
39204
|
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
|
|
38865
39205
|
if (!KNOWN_SKILLS.includes(entry.name)) continue;
|
|
38866
|
-
const skillMd =
|
|
39206
|
+
const skillMd = join19(dir, entry.name, "SKILL.md");
|
|
38867
39207
|
if (!await fileExists(skillMd)) continue;
|
|
38868
|
-
const content = await
|
|
39208
|
+
const content = await readFile58(skillMd, "utf-8").catch(() => "");
|
|
38869
39209
|
const match = content.match(/^name:\s*(\S+)\s*$/m);
|
|
38870
39210
|
if (!match || match[1] !== entry.name) continue;
|
|
38871
39211
|
let isSymlink2 = false;
|
|
38872
39212
|
try {
|
|
38873
|
-
isSymlink2 = (await lstat4(
|
|
39213
|
+
isSymlink2 = (await lstat4(join19(dir, entry.name))).isSymbolicLink();
|
|
38874
39214
|
} catch {
|
|
38875
39215
|
}
|
|
38876
39216
|
present.push({ name: entry.name, isSymlink: isSymlink2 });
|
|
@@ -38882,7 +39222,7 @@ var skillsDedupCheck = {
|
|
|
38882
39222
|
findings.push(
|
|
38883
39223
|
`${label}: ${nonSymlink.length} syntaur skill(s) installed globally while the syntaur plugin is enabled (${agent}) \u2014 duplicate registrations`
|
|
38884
39224
|
);
|
|
38885
|
-
for (const p of nonSymlink) affected.push(
|
|
39225
|
+
for (const p of nonSymlink) affected.push(join19(dir, p.name));
|
|
38886
39226
|
}
|
|
38887
39227
|
}
|
|
38888
39228
|
}
|
|
@@ -38915,12 +39255,12 @@ var skillsChecks = [skillsDedupCheck];
|
|
|
38915
39255
|
|
|
38916
39256
|
// src/utils/doctor/checks/cross-agent.ts
|
|
38917
39257
|
init_fs();
|
|
38918
|
-
import { join as
|
|
38919
|
-
import { readFile as
|
|
39258
|
+
import { join as join20, resolve as resolve90 } from "path";
|
|
39259
|
+
import { readFile as readFile60 } from "fs/promises";
|
|
38920
39260
|
|
|
38921
39261
|
// src/utils/skill-frontmatter.ts
|
|
38922
39262
|
import { createHash as createHash4 } from "crypto";
|
|
38923
|
-
import { readFile as
|
|
39263
|
+
import { readFile as readFile59 } from "fs/promises";
|
|
38924
39264
|
function stripQuotes(raw2) {
|
|
38925
39265
|
const t = raw2.trim();
|
|
38926
39266
|
if (t.length >= 2 && (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'"))) {
|
|
@@ -38964,7 +39304,7 @@ function readSkillIdentity(skillMdText) {
|
|
|
38964
39304
|
return { name, hasDescription };
|
|
38965
39305
|
}
|
|
38966
39306
|
async function sha256File(path) {
|
|
38967
|
-
return createHash4("sha256").update(await
|
|
39307
|
+
return createHash4("sha256").update(await readFile59(path)).digest("hex");
|
|
38968
39308
|
}
|
|
38969
39309
|
|
|
38970
39310
|
// src/utils/doctor/checks/cross-agent.ts
|
|
@@ -38974,14 +39314,14 @@ async function checkTargetSkillsIntegrity(installedDir, canonicalSkillsDir, know
|
|
|
38974
39314
|
const problems = [];
|
|
38975
39315
|
let valid = 0;
|
|
38976
39316
|
for (const skill of knownSkills) {
|
|
38977
|
-
const installedPath =
|
|
39317
|
+
const installedPath = join20(installedDir, skill, "SKILL.md");
|
|
38978
39318
|
if (!await fileExists(installedPath)) {
|
|
38979
39319
|
problems.push({ skill, kind: "missing" });
|
|
38980
39320
|
continue;
|
|
38981
39321
|
}
|
|
38982
39322
|
let text;
|
|
38983
39323
|
try {
|
|
38984
|
-
text = await
|
|
39324
|
+
text = await readFile60(installedPath, "utf-8");
|
|
38985
39325
|
} catch {
|
|
38986
39326
|
problems.push({ skill, kind: "invalid-frontmatter" });
|
|
38987
39327
|
continue;
|
|
@@ -38992,7 +39332,7 @@ async function checkTargetSkillsIntegrity(installedDir, canonicalSkillsDir, know
|
|
|
38992
39332
|
continue;
|
|
38993
39333
|
}
|
|
38994
39334
|
valid++;
|
|
38995
|
-
const canonicalPath2 =
|
|
39335
|
+
const canonicalPath2 = join20(canonicalSkillsDir, skill, "SKILL.md");
|
|
38996
39336
|
if (await fileExists(canonicalPath2)) {
|
|
38997
39337
|
const [installedHash, canonicalHash] = await Promise.all([
|
|
38998
39338
|
sha256File(installedPath),
|
|
@@ -39067,7 +39407,7 @@ var crossAgentSkillsCheck = {
|
|
|
39067
39407
|
}
|
|
39068
39408
|
if (t.tier3) {
|
|
39069
39409
|
const installDir = t.tier3.installDir();
|
|
39070
|
-
const installed2 = await fileExists(
|
|
39410
|
+
const installed2 = await fileExists(join20(installDir, t.tier3.entry));
|
|
39071
39411
|
lines.push(
|
|
39072
39412
|
`${t.displayName}: Tier-3 ${t.tier3.kind} ${installed2 ? "installed" : "absent"} (${installDir})`
|
|
39073
39413
|
);
|
|
@@ -39135,7 +39475,7 @@ var crossAgentChecks = [crossAgentSkillsCheck];
|
|
|
39135
39475
|
init_fs();
|
|
39136
39476
|
init_paths();
|
|
39137
39477
|
import { resolve as resolve91 } from "path";
|
|
39138
|
-
import { readdir as
|
|
39478
|
+
import { readdir as readdir34 } from "fs/promises";
|
|
39139
39479
|
import { spawnSync as spawnSync10 } from "child_process";
|
|
39140
39480
|
init_parser2();
|
|
39141
39481
|
var CATEGORY12 = "bundles";
|
|
@@ -39143,7 +39483,7 @@ async function listScopes(ctx) {
|
|
|
39143
39483
|
const out = [];
|
|
39144
39484
|
const td = todosDir();
|
|
39145
39485
|
if (await fileExists(td)) {
|
|
39146
|
-
const entries = await
|
|
39486
|
+
const entries = await readdir34(td).catch(() => []);
|
|
39147
39487
|
for (const f of entries) {
|
|
39148
39488
|
if (typeof f !== "string") continue;
|
|
39149
39489
|
if (!f.endsWith(".md") || f.endsWith("-log.md")) continue;
|
|
@@ -39159,7 +39499,7 @@ async function listScopes(ctx) {
|
|
|
39159
39499
|
}
|
|
39160
39500
|
}
|
|
39161
39501
|
if (await fileExists(ctx.config.defaultProjectDir)) {
|
|
39162
|
-
const projectEntries = await
|
|
39502
|
+
const projectEntries = await readdir34(ctx.config.defaultProjectDir, { withFileTypes: true }).catch(() => []);
|
|
39163
39503
|
for (const e of projectEntries) {
|
|
39164
39504
|
if (!e.isDirectory()) continue;
|
|
39165
39505
|
const slug = e.name;
|
|
@@ -39357,8 +39697,8 @@ var bundleChecks = [
|
|
|
39357
39697
|
];
|
|
39358
39698
|
|
|
39359
39699
|
// src/utils/doctor/checks/plugin.ts
|
|
39360
|
-
import { readFile as
|
|
39361
|
-
import { dirname as dirname24, join as
|
|
39700
|
+
import { readFile as readFile61 } from "fs/promises";
|
|
39701
|
+
import { dirname as dirname24, join as join21 } from "path";
|
|
39362
39702
|
import { fileURLToPath as fileURLToPath11 } from "url";
|
|
39363
39703
|
var CATEGORY13 = "plugin";
|
|
39364
39704
|
var PLUGIN_KINDS = ["claude", "codex"];
|
|
@@ -39367,7 +39707,7 @@ async function readCliVersion() {
|
|
|
39367
39707
|
let dir = dirname24(fileURLToPath11(import.meta.url));
|
|
39368
39708
|
for (let i = 0; i < 8; i += 1) {
|
|
39369
39709
|
try {
|
|
39370
|
-
const parsed = JSON.parse(await
|
|
39710
|
+
const parsed = JSON.parse(await readFile61(join21(dir, "package.json"), "utf-8"));
|
|
39371
39711
|
if (typeof parsed.version === "string" && parsed.version.length > 0) return parsed.version;
|
|
39372
39712
|
} catch {
|
|
39373
39713
|
}
|
|
@@ -39478,7 +39818,7 @@ var deriveConfigChecks = [deriveConfigValid];
|
|
|
39478
39818
|
// src/utils/doctor/checks/staleness.ts
|
|
39479
39819
|
init_config2();
|
|
39480
39820
|
import { resolve as resolve92 } from "path";
|
|
39481
|
-
import { readFile as
|
|
39821
|
+
import { readFile as readFile62 } from "fs/promises";
|
|
39482
39822
|
var CATEGORY15 = "staleness";
|
|
39483
39823
|
var stalenessConfigValid = {
|
|
39484
39824
|
id: "staleness.valid",
|
|
@@ -39487,7 +39827,7 @@ var stalenessConfigValid = {
|
|
|
39487
39827
|
async run(ctx) {
|
|
39488
39828
|
let content;
|
|
39489
39829
|
try {
|
|
39490
|
-
content = await
|
|
39830
|
+
content = await readFile62(resolve92(ctx.syntaurRoot, "config.md"), "utf-8");
|
|
39491
39831
|
} catch {
|
|
39492
39832
|
return {
|
|
39493
39833
|
id: this.id,
|
|
@@ -39640,7 +39980,7 @@ async function readVersion() {
|
|
|
39640
39980
|
let dir = dirname25(here);
|
|
39641
39981
|
for (let i = 0; i < 6; i++) {
|
|
39642
39982
|
try {
|
|
39643
|
-
const raw2 = await
|
|
39983
|
+
const raw2 = await readFile63(join22(dir, "package.json"), "utf-8");
|
|
39644
39984
|
const parsed = JSON.parse(raw2);
|
|
39645
39985
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
39646
39986
|
} catch {
|
|
@@ -39750,7 +40090,7 @@ async function validateAssignmentFile(inputPath, cwd = process.cwd()) {
|
|
|
39750
40090
|
}
|
|
39751
40091
|
let content;
|
|
39752
40092
|
try {
|
|
39753
|
-
content = await
|
|
40093
|
+
content = await readFile64(absolute, "utf-8");
|
|
39754
40094
|
} catch (err2) {
|
|
39755
40095
|
return {
|
|
39756
40096
|
ok: false,
|
|
@@ -39876,6 +40216,7 @@ note: ${FIX_NOOP_NOTE}
|
|
|
39876
40216
|
|
|
39877
40217
|
// src/commands/agents.ts
|
|
39878
40218
|
init_config2();
|
|
40219
|
+
init_paths();
|
|
39879
40220
|
import { Command as Command5 } from "commander";
|
|
39880
40221
|
var agentsCommand = new Command5("agents").description(
|
|
39881
40222
|
"Manage configurable agents used by `syntaur browse` and future launch flows"
|
|
@@ -39894,6 +40235,8 @@ agentsCommand.command("list").description("List configured agents (or built-in d
|
|
|
39894
40235
|
if (agent.model) flags.push(`model=${agent.model}`);
|
|
39895
40236
|
if (agent.playbook) flags.push(`playbook=${agent.playbook}`);
|
|
39896
40237
|
if (agent.launchPrompt) flags.push(`launchPrompt=${truncateForList(agent.launchPrompt)}`);
|
|
40238
|
+
if (agent.agentName) flags.push(`agentName=${agent.agentName}`);
|
|
40239
|
+
if (agent.workdir) flags.push(`workdir=${truncateForList(agent.workdir)}`);
|
|
39897
40240
|
const flagStr = flags.length > 0 ? ` [${flags.join(", ")}]` : "";
|
|
39898
40241
|
const args = agent.args && agent.args.length > 0 ? ` ${agent.args.join(" ")}` : "";
|
|
39899
40242
|
console.log(` ${agent.id.padEnd(12)} ${agent.label.padEnd(20)} ${agent.command}${args}${flagStr}`);
|
|
@@ -39902,7 +40245,7 @@ agentsCommand.command("list").description("List configured agents (or built-in d
|
|
|
39902
40245
|
reportAndExit(error);
|
|
39903
40246
|
}
|
|
39904
40247
|
});
|
|
39905
|
-
agentsCommand.command("add").description("Add a new agent to ~/.syntaur/config.md").requiredOption("--id <id>", "Agent id (slug)").requiredOption("--label <label>", "Display label").requiredOption("--command <command>", "Absolute path or bare binary name").option("--args <csv>", "Comma-separated default args").option("--prompt-arg-position <position>", "first | last | none").option("--default", "Mark this agent as the default launch target").option("--resolve-from-shell-aliases", "Run via $SHELL -i -c (for shell aliases)").option("--model <model>", "LLM model injected as --model <value> at launch").option("--playbook <slug>", "Playbook slug to run end-to-end on a fresh launch").option("--launch-prompt <text>", "Editable launch prompt with @assignment / @<playbook> tokens").option("--dry-run", "Validate and print the proposed config without writing").action(async (options) => {
|
|
40248
|
+
agentsCommand.command("add").description("Add a new agent to ~/.syntaur/config.md").requiredOption("--id <id>", "Agent id (slug)").requiredOption("--label <label>", "Display label").requiredOption("--command <command>", "Absolute path or bare binary name").option("--args <csv>", "Comma-separated default args").option("--prompt-arg-position <position>", "first | last | none").option("--default", "Mark this agent as the default launch target").option("--resolve-from-shell-aliases", "Run via $SHELL -i -c (for shell aliases)").option("--model <model>", "LLM model injected as --model <value> at launch").option("--playbook <slug>", "Playbook slug to run end-to-end on a fresh launch").option("--launch-prompt <text>", "Editable launch prompt with @assignment / @worktree / @<playbook> tokens").option("--agent-name <name>", "Claude agent identity injected as --agent <name> (Claude-compatible runners)").option("--workdir <path>", "Launch cwd override for directory-agents (pi/codex); mutually exclusive with --agent-name").option("--dry-run", "Validate and print the proposed config without writing").action(async (options) => {
|
|
39906
40249
|
try {
|
|
39907
40250
|
const agent = buildAgentFromOptions(options, null);
|
|
39908
40251
|
const mutation = {
|
|
@@ -39942,7 +40285,7 @@ agentsCommand.command("remove <id>").description("Remove an agent from ~/.syntau
|
|
|
39942
40285
|
reportAndExit(error);
|
|
39943
40286
|
}
|
|
39944
40287
|
});
|
|
39945
|
-
agentsCommand.command("set <id>").description("Update one or more fields on an existing agent").option("--label <label>", "Display label").option("--command <command>", "Absolute path or bare binary name").option("--args <csv>", "Comma-separated default args").option("--prompt-arg-position <position>", "first | last | none").option("--default", "Mark this agent as the default (clears any prior default)").option("--no-default", "Unset the default flag on this agent").option("--resolve-from-shell-aliases", "Run via $SHELL -i -c (for shell aliases)").option("--no-resolve-from-shell-aliases", "Disable shell-alias resolution for this agent").option("--model <model>", "LLM model injected as --model <value> (empty string clears)").option("--playbook <slug>", "Playbook slug to run on a fresh launch (empty string clears)").option("--launch-prompt <text>", "Editable launch prompt with @-tokens (empty string clears)").option("--dry-run", "Validate and print the proposed config without writing").action(async (id, options) => {
|
|
40288
|
+
agentsCommand.command("set <id>").description("Update one or more fields on an existing agent").option("--label <label>", "Display label").option("--command <command>", "Absolute path or bare binary name").option("--args <csv>", "Comma-separated default args").option("--prompt-arg-position <position>", "first | last | none").option("--default", "Mark this agent as the default (clears any prior default)").option("--no-default", "Unset the default flag on this agent").option("--resolve-from-shell-aliases", "Run via $SHELL -i -c (for shell aliases)").option("--no-resolve-from-shell-aliases", "Disable shell-alias resolution for this agent").option("--model <model>", "LLM model injected as --model <value> (empty string clears)").option("--playbook <slug>", "Playbook slug to run on a fresh launch (empty string clears)").option("--launch-prompt <text>", "Editable launch prompt with @-tokens (empty string clears)").option("--agent-name <name>", "Claude agent identity injected as --agent <name> (empty string clears)").option("--workdir <path>", "Launch cwd override for directory-agents (empty string clears)").option("--dry-run", "Validate and print the proposed config without writing").action(async (id, options) => {
|
|
39946
40289
|
try {
|
|
39947
40290
|
const mutation = {
|
|
39948
40291
|
kind: "set",
|
|
@@ -40003,6 +40346,36 @@ agentsCommand.command("reorder <ids>").description("Reorder agents (comma-separa
|
|
|
40003
40346
|
reportAndExit(error);
|
|
40004
40347
|
}
|
|
40005
40348
|
});
|
|
40349
|
+
agentsCommand.command("launch <id>").description("Launch a directory-agent standalone (no assignment) from its workdir").option("--prompt <text>", "One-shot launch prompt override for this launch only").option("--cwd <path>", "Override the agent workdir for this launch only").action(async (id, options) => {
|
|
40350
|
+
try {
|
|
40351
|
+
const config = await readConfig();
|
|
40352
|
+
const agents = getAgents(config);
|
|
40353
|
+
const agent = agents.find((a) => a.id === id);
|
|
40354
|
+
if (!agent) {
|
|
40355
|
+
throw new AgentConfigError(`unknown agent id "${id}"`);
|
|
40356
|
+
}
|
|
40357
|
+
let effectiveConfig = config;
|
|
40358
|
+
if (options.cwd !== void 0) {
|
|
40359
|
+
const cloned = { ...agent, workdir: expandHome(options.cwd) };
|
|
40360
|
+
effectiveConfig = { ...config, agents: agents.map((a) => a.id === id ? cloned : a) };
|
|
40361
|
+
}
|
|
40362
|
+
const projectsDir2 = config.defaultProjectDir || defaultProjectDir();
|
|
40363
|
+
const plan = await resolveLaunchPlan({
|
|
40364
|
+
kind: "standalone",
|
|
40365
|
+
id,
|
|
40366
|
+
agentId: id,
|
|
40367
|
+
config: effectiveConfig,
|
|
40368
|
+
projectsDir: projectsDir2,
|
|
40369
|
+
assignmentsDir: assignmentsDir(),
|
|
40370
|
+
promptOverride: options.prompt
|
|
40371
|
+
});
|
|
40372
|
+
if (plan.shellFallbackWarning) console.error(plan.shellFallbackWarning);
|
|
40373
|
+
for (const warning of plan.promptWarnings ?? []) console.error(warning);
|
|
40374
|
+
await executeLaunchPlan(plan);
|
|
40375
|
+
} catch (error) {
|
|
40376
|
+
reportAndExit(error);
|
|
40377
|
+
}
|
|
40378
|
+
});
|
|
40006
40379
|
function buildAgentFromOptions(options, existing) {
|
|
40007
40380
|
const agent = {
|
|
40008
40381
|
id: options.id,
|
|
@@ -40019,6 +40392,8 @@ function buildAgentFromOptions(options, existing) {
|
|
|
40019
40392
|
if (options.model && options.model.trim()) agent.model = options.model.trim();
|
|
40020
40393
|
if (options.playbook && options.playbook.trim()) agent.playbook = options.playbook.trim();
|
|
40021
40394
|
if (options.launchPrompt && options.launchPrompt.trim()) agent.launchPrompt = options.launchPrompt;
|
|
40395
|
+
if (options.agentName && options.agentName.trim()) agent.agentName = options.agentName.trim();
|
|
40396
|
+
if (options.workdir && options.workdir.trim()) agent.workdir = options.workdir.trim();
|
|
40022
40397
|
validateAgentList([...existing ? [] : [], agent]);
|
|
40023
40398
|
return agent;
|
|
40024
40399
|
}
|
|
@@ -40054,6 +40429,16 @@ function mergeOptionsIntoAgent(existing, options) {
|
|
|
40054
40429
|
if (options.launchPrompt.trim()) merged.launchPrompt = options.launchPrompt;
|
|
40055
40430
|
else delete merged.launchPrompt;
|
|
40056
40431
|
}
|
|
40432
|
+
if (options.agentName !== void 0) {
|
|
40433
|
+
const agentName = options.agentName.trim();
|
|
40434
|
+
if (agentName) merged.agentName = agentName;
|
|
40435
|
+
else delete merged.agentName;
|
|
40436
|
+
}
|
|
40437
|
+
if (options.workdir !== void 0) {
|
|
40438
|
+
const workdir = options.workdir.trim();
|
|
40439
|
+
if (workdir) merged.workdir = workdir;
|
|
40440
|
+
else delete merged.workdir;
|
|
40441
|
+
}
|
|
40057
40442
|
return merged;
|
|
40058
40443
|
}
|
|
40059
40444
|
function parseArgsCsv(csv) {
|
|
@@ -40094,6 +40479,8 @@ function formatAgentLine(a) {
|
|
|
40094
40479
|
if (a.model) flags.push(`model=${a.model}`);
|
|
40095
40480
|
if (a.playbook) flags.push(`playbook=${a.playbook}`);
|
|
40096
40481
|
if (a.launchPrompt) flags.push(`launchPrompt=${a.launchPrompt}`);
|
|
40482
|
+
if (a.agentName) flags.push(`agentName=${a.agentName}`);
|
|
40483
|
+
if (a.workdir) flags.push(`workdir=${a.workdir}`);
|
|
40097
40484
|
if (a.args && a.args.length > 0) flags.push(`args=[${a.args.join(", ")}]`);
|
|
40098
40485
|
const suffix = flags.length > 0 ? ` (${flags.join(", ")})` : "";
|
|
40099
40486
|
return `${a.id}: ${a.label} \u2192 ${a.command}${suffix}`;
|
|
@@ -40118,7 +40505,7 @@ init_frontmatter();
|
|
|
40118
40505
|
init_event_emit();
|
|
40119
40506
|
init_templates();
|
|
40120
40507
|
import { resolve as resolve94 } from "path";
|
|
40121
|
-
import { readFile as
|
|
40508
|
+
import { readFile as readFile65 } from "fs/promises";
|
|
40122
40509
|
function shortId() {
|
|
40123
40510
|
return generateId().split("-")[0];
|
|
40124
40511
|
}
|
|
@@ -40167,7 +40554,7 @@ async function commentCommand(target, text, options = {}) {
|
|
|
40167
40554
|
let currentContent;
|
|
40168
40555
|
let currentCount = 0;
|
|
40169
40556
|
if (await fileExists(commentsPath)) {
|
|
40170
|
-
currentContent = await
|
|
40557
|
+
currentContent = await readFile65(commentsPath, "utf-8");
|
|
40171
40558
|
const countMatch = currentContent.match(/^entryCount:\s*(\d+)/m);
|
|
40172
40559
|
if (countMatch) currentCount = parseInt(countMatch[1], 10);
|
|
40173
40560
|
} else {
|
|
@@ -40197,7 +40584,7 @@ ${entry}`;
|
|
|
40197
40584
|
try {
|
|
40198
40585
|
const assignmentMd = resolve94(assignmentDir, "assignment.md");
|
|
40199
40586
|
if (await fileExists(assignmentMd)) {
|
|
40200
|
-
const fm = parseAssignmentFrontmatter(await
|
|
40587
|
+
const fm = parseAssignmentFrontmatter(await readFile65(assignmentMd, "utf-8"));
|
|
40201
40588
|
emitEvent({
|
|
40202
40589
|
assignmentId: fm.id,
|
|
40203
40590
|
projectSlug,
|
|
@@ -40233,7 +40620,7 @@ init_fs();
|
|
|
40233
40620
|
import { spawn as spawn8 } from "child_process";
|
|
40234
40621
|
import { mkdtemp as mkdtemp2, rm as rm10, stat as stat12 } from "fs/promises";
|
|
40235
40622
|
import { tmpdir as tmpdir3 } from "os";
|
|
40236
|
-
import { join as
|
|
40623
|
+
import { join as join23 } from "path";
|
|
40237
40624
|
function argsFor(mode, pngPath) {
|
|
40238
40625
|
switch (mode) {
|
|
40239
40626
|
case "interactive":
|
|
@@ -40266,8 +40653,8 @@ async function captureScreenshot(mode) {
|
|
|
40266
40653
|
"screencapture is only available on macOS. Use --file <path> to attach an existing image."
|
|
40267
40654
|
);
|
|
40268
40655
|
}
|
|
40269
|
-
const tmpDir = await mkdtemp2(
|
|
40270
|
-
const pngPath =
|
|
40656
|
+
const tmpDir = await mkdtemp2(join23(tmpdir3(), "syntaur-screenshot-"));
|
|
40657
|
+
const pngPath = join23(tmpDir, "shot.png");
|
|
40271
40658
|
const cleanup = async () => {
|
|
40272
40659
|
await rm10(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
40273
40660
|
});
|
|
@@ -40305,9 +40692,9 @@ async function captureScreenshot(mode) {
|
|
|
40305
40692
|
|
|
40306
40693
|
// src/utils/asciinema.ts
|
|
40307
40694
|
import { spawn as spawn9 } from "child_process";
|
|
40308
|
-
import { mkdtemp as mkdtemp3, readFile as
|
|
40695
|
+
import { mkdtemp as mkdtemp3, readFile as readFile66, rm as rm11 } from "fs/promises";
|
|
40309
40696
|
import { tmpdir as tmpdir4 } from "os";
|
|
40310
|
-
import { join as
|
|
40697
|
+
import { join as join24 } from "path";
|
|
40311
40698
|
var SAFE_RE = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
40312
40699
|
function shellQuote2(s) {
|
|
40313
40700
|
if (s.length === 0) return `''`;
|
|
@@ -40344,8 +40731,8 @@ function runAsciinema(args, stdio) {
|
|
|
40344
40731
|
});
|
|
40345
40732
|
}
|
|
40346
40733
|
async function captureAsciinema(opts) {
|
|
40347
|
-
const tmpDir = await mkdtemp3(
|
|
40348
|
-
const castPath =
|
|
40734
|
+
const tmpDir = await mkdtemp3(join24(tmpdir4(), "syntaur-asciinema-"));
|
|
40735
|
+
const castPath = join24(tmpDir, "session.cast");
|
|
40349
40736
|
const cleanup = async () => {
|
|
40350
40737
|
await rm11(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
40351
40738
|
});
|
|
@@ -40368,7 +40755,7 @@ async function captureAsciinema(opts) {
|
|
|
40368
40755
|
}
|
|
40369
40756
|
throw err2;
|
|
40370
40757
|
}
|
|
40371
|
-
const text = await
|
|
40758
|
+
const text = await readFile66(castPath, "utf8").catch(() => null);
|
|
40372
40759
|
if (text === null) {
|
|
40373
40760
|
throw new Error(
|
|
40374
40761
|
`asciinema produced no cast file at ${castPath} (exit ${exitCode}). Try running 'asciinema rec ${castPath}' directly to diagnose.`
|
|
@@ -40396,9 +40783,9 @@ async function captureAsciinema(opts) {
|
|
|
40396
40783
|
// src/utils/recording.ts
|
|
40397
40784
|
init_paths();
|
|
40398
40785
|
import { spawn as spawn10 } from "child_process";
|
|
40399
|
-
import { mkdir as mkdir11, mkdtemp as mkdtemp4, open as open6, readFile as
|
|
40786
|
+
import { mkdir as mkdir11, mkdtemp as mkdtemp4, open as open6, readFile as readFile67, rm as rm12, stat as stat13, unlink as unlink12, writeFile as writeFile14 } from "fs/promises";
|
|
40400
40787
|
import { tmpdir as tmpdir5 } from "os";
|
|
40401
|
-
import { join as
|
|
40788
|
+
import { join as join25, resolve as resolve95 } from "path";
|
|
40402
40789
|
import { setTimeout as sleep } from "timers/promises";
|
|
40403
40790
|
function sigintPollIntervalMs() {
|
|
40404
40791
|
const raw2 = process.env.SYNTAUR_RECORDING_POLL_INTERVAL_MS;
|
|
@@ -40470,7 +40857,7 @@ async function acquirePidfile(pidfile) {
|
|
|
40470
40857
|
} catch (err2) {
|
|
40471
40858
|
if (err2.code !== "EEXIST") throw err2;
|
|
40472
40859
|
if (attempt === 1) throw err2;
|
|
40473
|
-
const existing = (await
|
|
40860
|
+
const existing = (await readFile67(pidfile, "utf-8").catch(() => "")).trim();
|
|
40474
40861
|
if (existing.startsWith(STARTING_SENTINEL_PREFIX)) {
|
|
40475
40862
|
const parentPidRaw = existing.slice(STARTING_SENTINEL_PREFIX.length);
|
|
40476
40863
|
const parentPid = Number.parseInt(parentPidRaw, 10);
|
|
@@ -40523,8 +40910,8 @@ async function startRecording(input4) {
|
|
|
40523
40910
|
let acquiredPid = null;
|
|
40524
40911
|
try {
|
|
40525
40912
|
logHandle = await open6(log, "w");
|
|
40526
|
-
tmpDir = await mkdtemp4(
|
|
40527
|
-
const mp4Path =
|
|
40913
|
+
tmpDir = await mkdtemp4(join25(tmpdir5(), "syntaur-recording-"));
|
|
40914
|
+
const mp4Path = join25(tmpDir, "recording.mp4");
|
|
40528
40915
|
let child;
|
|
40529
40916
|
try {
|
|
40530
40917
|
child = spawn10("ffmpeg", ffmpegArgs(input4.device, input4.fps, mp4Path), {
|
|
@@ -40572,7 +40959,7 @@ async function startRecording(input4) {
|
|
|
40572
40959
|
logHandle = null;
|
|
40573
40960
|
if (warmupMs > 0) await sleep(warmupMs);
|
|
40574
40961
|
if (!await isProcessAlive(pid)) {
|
|
40575
|
-
const tail = await
|
|
40962
|
+
const tail = await readFile67(log, "utf-8").then((s) => s.split("\n").slice(-20).join("\n")).catch(() => "");
|
|
40576
40963
|
acquiredPid = null;
|
|
40577
40964
|
throw new Error(
|
|
40578
40965
|
`ffmpeg exited during startup \u2014 likely macOS Screen Recording permission missing. Grant access to your terminal in System Settings \u2192 Privacy & Security \u2192 Screen Recording, then retry. Log: ${log}
|
|
@@ -40629,7 +41016,7 @@ ${tail}`
|
|
|
40629
41016
|
async function stopRecording() {
|
|
40630
41017
|
const pidfile = pidfilePath();
|
|
40631
41018
|
const sidecar = sidecarPath();
|
|
40632
|
-
const pidRaw = await
|
|
41019
|
+
const pidRaw = await readFile67(pidfile, "utf-8").catch(() => null);
|
|
40633
41020
|
if (pidRaw === null) {
|
|
40634
41021
|
throw new Error(
|
|
40635
41022
|
`No active recording found (no pidfile at ${pidfile}). Did you run --start?`
|
|
@@ -40639,7 +41026,7 @@ async function stopRecording() {
|
|
|
40639
41026
|
if (!Number.isInteger(pid) || pid <= 0) {
|
|
40640
41027
|
throw new Error(`Pidfile at ${pidfile} is corrupt (got "${pidRaw}").`);
|
|
40641
41028
|
}
|
|
40642
|
-
const sidecarRaw = await
|
|
41029
|
+
const sidecarRaw = await readFile67(sidecar, "utf-8").catch(() => null);
|
|
40643
41030
|
if (sidecarRaw === null) {
|
|
40644
41031
|
throw new Error(
|
|
40645
41032
|
`No recording sidecar at ${sidecar}. The recording state is inconsistent \u2014 delete ${pidfile} and re-run --start.`
|
|
@@ -40772,9 +41159,9 @@ function listArtifactsByAssignment(assignmentId) {
|
|
|
40772
41159
|
|
|
40773
41160
|
// src/utils/transcribers/elevenlabs.ts
|
|
40774
41161
|
import { spawn as spawn11 } from "child_process";
|
|
40775
|
-
import { mkdtemp as mkdtemp5, readFile as
|
|
41162
|
+
import { mkdtemp as mkdtemp5, readFile as readFile68, rm as rm13 } from "fs/promises";
|
|
40776
41163
|
import { tmpdir as tmpdir6 } from "os";
|
|
40777
|
-
import { join as
|
|
41164
|
+
import { join as join26 } from "path";
|
|
40778
41165
|
var SCRIBE_URL = "https://api.elevenlabs.io/v1/speech-to-text";
|
|
40779
41166
|
var NO_AUDIO_MARKERS = [
|
|
40780
41167
|
"Stream map '0:a:0' matches no streams",
|
|
@@ -40836,7 +41223,7 @@ async function extractAudio(videoAbsPath, wavOut) {
|
|
|
40836
41223
|
throw new TranscribeFfmpegError(`ffmpeg failed (exit ${result.code}): ${tail}`);
|
|
40837
41224
|
}
|
|
40838
41225
|
async function callScribe(wavPath, apiKey, opts) {
|
|
40839
|
-
const audio = await
|
|
41226
|
+
const audio = await readFile68(wavPath);
|
|
40840
41227
|
const form = new FormData();
|
|
40841
41228
|
form.set("file", new Blob([new Uint8Array(audio)], { type: "audio/wav" }), "audio.wav");
|
|
40842
41229
|
form.set("model_id", "scribe_v1");
|
|
@@ -40864,8 +41251,8 @@ var elevenLabsScribe = {
|
|
|
40864
41251
|
"ELEVENLABS_API_KEY is not set. Export it (e.g. `export ELEVENLABS_API_KEY=\u2026`) and re-run. A config-file slot will land later."
|
|
40865
41252
|
);
|
|
40866
41253
|
}
|
|
40867
|
-
const tmp = await mkdtemp5(
|
|
40868
|
-
const wav =
|
|
41254
|
+
const tmp = await mkdtemp5(join26(tmpdir6(), "syntaur-transcribe-"));
|
|
41255
|
+
const wav = join26(tmp, "audio.wav");
|
|
40869
41256
|
try {
|
|
40870
41257
|
await extractAudio(videoAbsPath, wav);
|
|
40871
41258
|
return await callScribe(wav, apiKey, opts);
|
|
@@ -41309,7 +41696,7 @@ async function captureCommand(target, options = {}) {
|
|
|
41309
41696
|
|
|
41310
41697
|
// src/commands/proof.ts
|
|
41311
41698
|
import { Command as Command6 } from "commander";
|
|
41312
|
-
import { readFile as
|
|
41699
|
+
import { readFile as readFile69, writeFile as writeFile16, rename as rename10, stat as stat15 } from "fs/promises";
|
|
41313
41700
|
import { resolve as resolve98, relative as relative5, isAbsolute as isAbsolute12, dirname as dirname27 } from "path";
|
|
41314
41701
|
import { randomBytes as randomBytes4 } from "crypto";
|
|
41315
41702
|
|
|
@@ -41554,7 +41941,7 @@ async function readAssignmentMeta(assignmentDir) {
|
|
|
41554
41941
|
if (!await fileExists(path)) {
|
|
41555
41942
|
return { title: "", body: "" };
|
|
41556
41943
|
}
|
|
41557
|
-
const content = await
|
|
41944
|
+
const content = await readFile69(path, "utf-8");
|
|
41558
41945
|
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
41559
41946
|
let title = "";
|
|
41560
41947
|
if (fmMatch) {
|
|
@@ -41616,7 +42003,7 @@ async function loadInlineFiles(rows, assignmentDir) {
|
|
|
41616
42003
|
continue;
|
|
41617
42004
|
}
|
|
41618
42005
|
try {
|
|
41619
|
-
out.set(r.file_path, await
|
|
42006
|
+
out.set(r.file_path, await readFile69(abs, "utf-8"));
|
|
41620
42007
|
} catch {
|
|
41621
42008
|
out.set(r.file_path, null);
|
|
41622
42009
|
}
|
|
@@ -41635,7 +42022,7 @@ async function loadTranscriptSidecars(rows, assignmentDir) {
|
|
|
41635
42022
|
const st = await stat15(sidecar);
|
|
41636
42023
|
if (st.size > INLINE_TEXT_LIMIT_BYTES) continue;
|
|
41637
42024
|
try {
|
|
41638
|
-
out.set(r.id, await
|
|
42025
|
+
out.set(r.id, await readFile69(sidecar, "utf-8"));
|
|
41639
42026
|
} catch {
|
|
41640
42027
|
}
|
|
41641
42028
|
}
|
|
@@ -42531,7 +42918,7 @@ init_timestamp();
|
|
|
42531
42918
|
init_assignment_resolver();
|
|
42532
42919
|
init_assignment_todos();
|
|
42533
42920
|
import { resolve as resolve100 } from "path";
|
|
42534
|
-
import { readFile as
|
|
42921
|
+
import { readFile as readFile70 } from "fs/promises";
|
|
42535
42922
|
async function requestCommand(target, text, options = {}) {
|
|
42536
42923
|
if (!text || !text.trim()) {
|
|
42537
42924
|
throw new Error("Request text cannot be empty.");
|
|
@@ -42562,7 +42949,7 @@ async function requestCommand(target, text, options = {}) {
|
|
|
42562
42949
|
throw new Error(`assignment.md not found at ${assignmentMdPath2}`);
|
|
42563
42950
|
}
|
|
42564
42951
|
const source = options.from ?? process.env.SYNTAUR_ASSIGNMENT ?? "unknown";
|
|
42565
|
-
let content = await
|
|
42952
|
+
let content = await readFile70(assignmentMdPath2, "utf-8");
|
|
42566
42953
|
content = appendTodosToAssignmentBody(content, [
|
|
42567
42954
|
{ description: `${text.trim()} (from: ${source})` }
|
|
42568
42955
|
]);
|
|
@@ -42577,7 +42964,7 @@ init_paths();
|
|
|
42577
42964
|
init_config2();
|
|
42578
42965
|
init_recompute();
|
|
42579
42966
|
import { Command as Command10 } from "commander";
|
|
42580
|
-
import { readFile as
|
|
42967
|
+
import { readFile as readFile71, readdir as readdir35 } from "fs/promises";
|
|
42581
42968
|
import { resolve as resolve101 } from "path";
|
|
42582
42969
|
init_session_id();
|
|
42583
42970
|
async function resolveAssignmentDir(opts) {
|
|
@@ -42604,7 +42991,7 @@ async function resolveAssignmentDir(opts) {
|
|
|
42604
42991
|
var PLAN_PATTERN = /^plan(?:-v(\d+))?\.md$/;
|
|
42605
42992
|
async function listPlanFiles(assignmentDir) {
|
|
42606
42993
|
if (!await fileExists(assignmentDir)) return [];
|
|
42607
|
-
const entries = await
|
|
42994
|
+
const entries = await readdir35(assignmentDir, { withFileTypes: true });
|
|
42608
42995
|
const out = [];
|
|
42609
42996
|
for (const e of entries) {
|
|
42610
42997
|
if (!e.isFile()) continue;
|
|
@@ -42799,7 +43186,7 @@ async function runPlanCreate(options) {
|
|
|
42799
43186
|
"plan.md already exists. Use --force to overwrite, or `syntaur plan version` to create the next version."
|
|
42800
43187
|
);
|
|
42801
43188
|
}
|
|
42802
|
-
const assignmentMd = await
|
|
43189
|
+
const assignmentMd = await readFile71(assignmentMdPath2, "utf-8");
|
|
42803
43190
|
const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
|
|
42804
43191
|
const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
|
|
42805
43192
|
await writeFileForce(planPath, buildInitialPlanStub(slug));
|
|
@@ -42836,11 +43223,11 @@ async function runPlanVersion(options) {
|
|
|
42836
43223
|
if (await fileExists(newPath) && !options.force) {
|
|
42837
43224
|
throw new Error(`${next.fileName} already exists. Use --force to overwrite.`);
|
|
42838
43225
|
}
|
|
42839
|
-
const assignmentMd = await
|
|
43226
|
+
const assignmentMd = await readFile71(assignmentMdPath2, "utf-8");
|
|
42840
43227
|
const slugMatch = assignmentMd.match(/^slug:\s*(.+?)\s*$/m);
|
|
42841
43228
|
const slug = slugMatch ? slugMatch[1].trim() : assignmentDir.split("/").pop() ?? "";
|
|
42842
43229
|
const oldPlanPath = resolve101(assignmentDir, current.fileName);
|
|
42843
|
-
const oldPlanContent = await
|
|
43230
|
+
const oldPlanContent = await readFile71(oldPlanPath, "utf-8");
|
|
42844
43231
|
const oldBody = oldPlanContent.replace(/^---[\s\S]*?\n---\n?/, "");
|
|
42845
43232
|
const carriedTodos = extractUncheckedTodos(oldBody);
|
|
42846
43233
|
const stub = buildNewPlanStub({
|
|
@@ -42911,7 +43298,7 @@ init_cwd();
|
|
|
42911
43298
|
init_session_db();
|
|
42912
43299
|
init_agent_sessions();
|
|
42913
43300
|
import { Command as Command11 } from "commander";
|
|
42914
|
-
import { readFile as
|
|
43301
|
+
import { readFile as readFile72, readdir as readdir36, stat as stat16 } from "fs/promises";
|
|
42915
43302
|
import { resolve as resolve102 } from "path";
|
|
42916
43303
|
init_engagement_db();
|
|
42917
43304
|
init_parser();
|
|
@@ -42919,7 +43306,7 @@ async function readContext(cwd) {
|
|
|
42919
43306
|
const path = resolve102(cwd, ".syntaur", "context.json");
|
|
42920
43307
|
if (!await fileExists(path)) return null;
|
|
42921
43308
|
try {
|
|
42922
|
-
const raw2 = await
|
|
43309
|
+
const raw2 = await readFile72(path, "utf-8");
|
|
42923
43310
|
return JSON.parse(raw2);
|
|
42924
43311
|
} catch {
|
|
42925
43312
|
return null;
|
|
@@ -42928,7 +43315,7 @@ async function readContext(cwd) {
|
|
|
42928
43315
|
async function findLatestSessionSummary(assignmentDir) {
|
|
42929
43316
|
const sessionsRoot = resolve102(assignmentDir, "sessions");
|
|
42930
43317
|
if (!await fileExists(sessionsRoot)) return null;
|
|
42931
|
-
const entries = await
|
|
43318
|
+
const entries = await readdir36(sessionsRoot, { withFileTypes: true });
|
|
42932
43319
|
let best = null;
|
|
42933
43320
|
for (const entry of entries) {
|
|
42934
43321
|
if (!entry.isDirectory()) continue;
|
|
@@ -42944,7 +43331,7 @@ async function findLatestSessionSummary(assignmentDir) {
|
|
|
42944
43331
|
async function findOpenHandoff(assignmentDir) {
|
|
42945
43332
|
const handoffPath = resolve102(assignmentDir, "handoff.md");
|
|
42946
43333
|
if (!await fileExists(handoffPath)) return null;
|
|
42947
|
-
const content = await
|
|
43334
|
+
const content = await readFile72(handoffPath, "utf-8");
|
|
42948
43335
|
const body = content.replace(/^---[\s\S]*?\n---\n?/, "").trim();
|
|
42949
43336
|
if (body.length === 0) return null;
|
|
42950
43337
|
if (/^<!--[\s\S]*-->$/.test(body)) return null;
|
|
@@ -42954,7 +43341,7 @@ async function readAssignmentTitle(assignmentDir) {
|
|
|
42954
43341
|
const path = resolve102(assignmentDir, "assignment.md");
|
|
42955
43342
|
if (!await fileExists(path)) return null;
|
|
42956
43343
|
try {
|
|
42957
|
-
const content = await
|
|
43344
|
+
const content = await readFile72(path, "utf-8");
|
|
42958
43345
|
const [fm] = extractFrontmatter(content);
|
|
42959
43346
|
return getField(fm, "title");
|
|
42960
43347
|
} catch {
|
|
@@ -43171,13 +43558,13 @@ async function runSessionSave(options, cwd = process.cwd(), body) {
|
|
|
43171
43558
|
const now = nowTimestamp();
|
|
43172
43559
|
let created = now;
|
|
43173
43560
|
if (await fileExists(summaryPath)) {
|
|
43174
|
-
const existing = await
|
|
43561
|
+
const existing = await readFile72(summaryPath, "utf-8");
|
|
43175
43562
|
created = extractCreated(existing) ?? now;
|
|
43176
43563
|
}
|
|
43177
43564
|
let sectionBody2 = body;
|
|
43178
43565
|
if (sectionBody2 === void 0) {
|
|
43179
43566
|
if (options.fromFile) {
|
|
43180
|
-
sectionBody2 = await
|
|
43567
|
+
sectionBody2 = await readFile72(resolve102(cwd, options.fromFile), "utf-8");
|
|
43181
43568
|
} else {
|
|
43182
43569
|
sectionBody2 = await readStdin();
|
|
43183
43570
|
}
|
|
@@ -43405,7 +43792,7 @@ sessionCommand.command("boundary").description(
|
|
|
43405
43792
|
// src/commands/worktree.ts
|
|
43406
43793
|
init_git_worktree();
|
|
43407
43794
|
import { Command as Command12 } from "commander";
|
|
43408
|
-
import { readFile as
|
|
43795
|
+
import { readFile as readFile73 } from "fs/promises";
|
|
43409
43796
|
import { resolve as resolve103 } from "path";
|
|
43410
43797
|
init_fs();
|
|
43411
43798
|
init_paths();
|
|
@@ -43495,7 +43882,7 @@ async function runWorktreeRemove(options, cwd = process.cwd()) {
|
|
|
43495
43882
|
if (!await fileExists(assignmentPath)) {
|
|
43496
43883
|
throw new Error(`Assignment file not found: ${assignmentPath}`);
|
|
43497
43884
|
}
|
|
43498
|
-
const original = await
|
|
43885
|
+
const original = await readFile73(assignmentPath, "utf-8");
|
|
43499
43886
|
const fm = parseAssignmentFrontmatter(original);
|
|
43500
43887
|
const repository = options.repository ?? fm.workspace.repository ?? void 0;
|
|
43501
43888
|
const worktreePath = fm.workspace.worktreePath ?? void 0;
|
|
@@ -43561,7 +43948,7 @@ async function runWorktreeGc(options, cwd = process.cwd()) {
|
|
|
43561
43948
|
const owners = /* @__PURE__ */ new Map();
|
|
43562
43949
|
for (const entry of walk.withAssignmentMd) {
|
|
43563
43950
|
try {
|
|
43564
|
-
const content = await
|
|
43951
|
+
const content = await readFile73(resolve103(entry.assignmentDir, "assignment.md"), "utf-8");
|
|
43565
43952
|
const fm = parseAssignmentFrontmatter(content);
|
|
43566
43953
|
const wp = fm.workspace?.worktreePath;
|
|
43567
43954
|
if (!wp) continue;
|
|
@@ -43802,7 +44189,7 @@ worktreeCommand.command("gc").description(
|
|
|
43802
44189
|
// src/commands/open.ts
|
|
43803
44190
|
init_fs();
|
|
43804
44191
|
import { Command as Command13 } from "commander";
|
|
43805
|
-
import { readFile as
|
|
44192
|
+
import { readFile as readFile74 } from "fs/promises";
|
|
43806
44193
|
import { resolve as resolve104 } from "path";
|
|
43807
44194
|
init_frontmatter();
|
|
43808
44195
|
init_config2();
|
|
@@ -43868,7 +44255,7 @@ async function runOpen(assignmentArg, options) {
|
|
|
43868
44255
|
remediation: "check the assignment slug or --id"
|
|
43869
44256
|
});
|
|
43870
44257
|
}
|
|
43871
|
-
const fm = parseAssignmentFrontmatter(await
|
|
44258
|
+
const fm = parseAssignmentFrontmatter(await readFile74(assignmentPath, "utf-8"));
|
|
43872
44259
|
const worktreePath = fm.workspace?.worktreePath;
|
|
43873
44260
|
if (!worktreePath) {
|
|
43874
44261
|
throw new SyntaurError("No worktree recorded for this assignment.", {
|
|
@@ -43934,12 +44321,12 @@ init_fs();
|
|
|
43934
44321
|
init_slug();
|
|
43935
44322
|
import { Command as Command14 } from "commander";
|
|
43936
44323
|
import { resolve as resolve106 } from "path";
|
|
43937
|
-
import { readFile as
|
|
44324
|
+
import { readFile as readFile76, readdir as readdir38, rm as rm15 } from "fs/promises";
|
|
43938
44325
|
|
|
43939
44326
|
// src/utils/project-indexes.ts
|
|
43940
44327
|
init_parser();
|
|
43941
44328
|
init_fs();
|
|
43942
|
-
import { readdir as
|
|
44329
|
+
import { readdir as readdir37, readFile as readFile75 } from "fs/promises";
|
|
43943
44330
|
import { resolve as resolve105 } from "path";
|
|
43944
44331
|
function nowIso3() {
|
|
43945
44332
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
@@ -43949,7 +44336,7 @@ function readProjectSlug(projectDir) {
|
|
|
43949
44336
|
}
|
|
43950
44337
|
async function listSlugFiles(dir) {
|
|
43951
44338
|
if (!await fileExists(dir)) return [];
|
|
43952
|
-
const entries = await
|
|
44339
|
+
const entries = await readdir37(dir, { withFileTypes: true });
|
|
43953
44340
|
return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && !e.name.startsWith("_")).map((e) => e.name).sort();
|
|
43954
44341
|
}
|
|
43955
44342
|
function escapeCell(value) {
|
|
@@ -43975,7 +44362,7 @@ async function rebuildResourcesIndex(projectDir) {
|
|
|
43975
44362
|
lines.push("| Name | Category | Source | Related Assignments | Updated |");
|
|
43976
44363
|
lines.push("|------|----------|--------|---------------------|---------|");
|
|
43977
44364
|
for (const fileName of files) {
|
|
43978
|
-
const content = await
|
|
44365
|
+
const content = await readFile75(resolve105(dir, fileName), "utf-8");
|
|
43979
44366
|
const parsed = parseResource(content);
|
|
43980
44367
|
const slugBase = fileName.replace(/\.md$/, "");
|
|
43981
44368
|
const name = parsed.name || slugBase;
|
|
@@ -44006,7 +44393,7 @@ async function rebuildMemoriesIndex(projectDir) {
|
|
|
44006
44393
|
lines.push("| Name | Source | Scope | Source Assignment | Updated |");
|
|
44007
44394
|
lines.push("|------|--------|-------|-------------------|---------|");
|
|
44008
44395
|
for (const fileName of files) {
|
|
44009
|
-
const content = await
|
|
44396
|
+
const content = await readFile75(resolve105(dir, fileName), "utf-8");
|
|
44010
44397
|
const parsed = parseMemory(content);
|
|
44011
44398
|
const slugBase = fileName.replace(/\.md$/, "");
|
|
44012
44399
|
const name = parsed.name || slugBase;
|
|
@@ -44113,7 +44500,7 @@ async function runResourceAdd(options) {
|
|
|
44113
44500
|
async function listResourceSlugs(projectDir) {
|
|
44114
44501
|
const dir = resolve106(projectDir, "resources");
|
|
44115
44502
|
if (!await fileExists(dir)) return [];
|
|
44116
|
-
const entries = await
|
|
44503
|
+
const entries = await readdir38(dir, { withFileTypes: true });
|
|
44117
44504
|
return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_index.md").map((e) => e.name.slice(0, -3)).sort();
|
|
44118
44505
|
}
|
|
44119
44506
|
async function runResourceList(project) {
|
|
@@ -44121,7 +44508,7 @@ async function runResourceList(project) {
|
|
|
44121
44508
|
const slugs = await listResourceSlugs(projectDir);
|
|
44122
44509
|
const out = [];
|
|
44123
44510
|
for (const slug of slugs) {
|
|
44124
|
-
const parsed = parseResource(await
|
|
44511
|
+
const parsed = parseResource(await readFile76(resolve106(projectDir, "resources", `${slug}.md`), "utf-8"));
|
|
44125
44512
|
out.push({ slug, name: parsed.name, category: parsed.category, source: parsed.source, updated: parsed.updated });
|
|
44126
44513
|
}
|
|
44127
44514
|
return out;
|
|
@@ -44130,7 +44517,7 @@ async function runResourceShow(project, slug) {
|
|
|
44130
44517
|
const projectDir = await resolveProjectDir(project);
|
|
44131
44518
|
const filePath = resolve106(projectDir, "resources", `${slug}.md`);
|
|
44132
44519
|
if (!await fileExists(filePath)) throw new Error(`Resource "${slug}" not found in project "${project}".`);
|
|
44133
|
-
const parsed = parseResource(await
|
|
44520
|
+
const parsed = parseResource(await readFile76(filePath, "utf-8"));
|
|
44134
44521
|
return {
|
|
44135
44522
|
slug,
|
|
44136
44523
|
name: parsed.name,
|
|
@@ -44151,7 +44538,7 @@ async function runResourceUpdate(slug, options) {
|
|
|
44151
44538
|
if (options.name === void 0 && options.source === void 0 && options.category === void 0 && options.relatedAssignments === void 0) {
|
|
44152
44539
|
throw new Error("Provide at least one of --name, --source, --category, --related-assignments.");
|
|
44153
44540
|
}
|
|
44154
|
-
const original = await
|
|
44541
|
+
const original = await readFile76(filePath, "utf-8");
|
|
44155
44542
|
const content = editResourceFrontmatter(original, {
|
|
44156
44543
|
name: options.name,
|
|
44157
44544
|
category: options.category,
|
|
@@ -44248,7 +44635,7 @@ init_fs();
|
|
|
44248
44635
|
init_slug();
|
|
44249
44636
|
import { Command as Command15 } from "commander";
|
|
44250
44637
|
import { resolve as resolve107 } from "path";
|
|
44251
|
-
import { readFile as
|
|
44638
|
+
import { readFile as readFile77, readdir as readdir39, rm as rm16 } from "fs/promises";
|
|
44252
44639
|
init_parser();
|
|
44253
44640
|
function nowIso5() {
|
|
44254
44641
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
@@ -44346,7 +44733,7 @@ async function runMemoryAdd(options) {
|
|
|
44346
44733
|
async function listMemorySlugs(projectDir) {
|
|
44347
44734
|
const dir = resolve107(projectDir, "memories");
|
|
44348
44735
|
if (!await fileExists(dir)) return [];
|
|
44349
|
-
const entries = await
|
|
44736
|
+
const entries = await readdir39(dir, { withFileTypes: true });
|
|
44350
44737
|
return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "_index.md").map((e) => e.name.slice(0, -3)).sort();
|
|
44351
44738
|
}
|
|
44352
44739
|
async function runMemoryList(project) {
|
|
@@ -44354,7 +44741,7 @@ async function runMemoryList(project) {
|
|
|
44354
44741
|
const slugs = await listMemorySlugs(projectDir);
|
|
44355
44742
|
const out = [];
|
|
44356
44743
|
for (const slug of slugs) {
|
|
44357
|
-
const parsed = parseMemory(await
|
|
44744
|
+
const parsed = parseMemory(await readFile77(resolve107(projectDir, "memories", `${slug}.md`), "utf-8"));
|
|
44358
44745
|
out.push({ slug, name: parsed.name, scope: parsed.scope, source: parsed.source, updated: parsed.updated });
|
|
44359
44746
|
}
|
|
44360
44747
|
return out;
|
|
@@ -44363,7 +44750,7 @@ async function runMemoryShow(project, slug) {
|
|
|
44363
44750
|
const projectDir = await resolveProjectDir2(project);
|
|
44364
44751
|
const filePath = resolve107(projectDir, "memories", `${slug}.md`);
|
|
44365
44752
|
if (!await fileExists(filePath)) throw new Error(`Memory "${slug}" not found in project "${project}".`);
|
|
44366
|
-
const parsed = parseMemory(await
|
|
44753
|
+
const parsed = parseMemory(await readFile77(filePath, "utf-8"));
|
|
44367
44754
|
return {
|
|
44368
44755
|
slug,
|
|
44369
44756
|
name: parsed.name,
|
|
@@ -44387,7 +44774,7 @@ async function runMemoryUpdate(slug, options) {
|
|
|
44387
44774
|
"Provide at least one of --name, --source, --scope, --source-assignment, --related-assignments."
|
|
44388
44775
|
);
|
|
44389
44776
|
}
|
|
44390
|
-
const original = await
|
|
44777
|
+
const original = await readFile77(filePath, "utf-8");
|
|
44391
44778
|
const content = editMemoryFrontmatter(original, {
|
|
44392
44779
|
name: options.name,
|
|
44393
44780
|
source: options.source,
|
|
@@ -44490,7 +44877,7 @@ init_derive();
|
|
|
44490
44877
|
init_recompute();
|
|
44491
44878
|
init_query();
|
|
44492
44879
|
import { Command as Command16 } from "commander";
|
|
44493
|
-
import { readFile as
|
|
44880
|
+
import { readFile as readFile78 } from "fs/promises";
|
|
44494
44881
|
import { dirname as dirname29, resolve as resolve108 } from "path";
|
|
44495
44882
|
var AGE_PATTERN = /^(\d+)([dhwm])$/i;
|
|
44496
44883
|
function parseAgeToCutoff(age) {
|
|
@@ -44524,7 +44911,7 @@ async function loadTags(item) {
|
|
|
44524
44911
|
const path = assignmentMdPath(item);
|
|
44525
44912
|
if (!await fileExists(path)) return [];
|
|
44526
44913
|
try {
|
|
44527
|
-
const content = await
|
|
44914
|
+
const content = await readFile78(path, "utf-8");
|
|
44528
44915
|
return parseAssignmentFrontmatter(content).tags;
|
|
44529
44916
|
} catch {
|
|
44530
44917
|
return [];
|
|
@@ -44588,7 +44975,7 @@ async function loadQueryItem(item, terminalStatuses3, now, declarations) {
|
|
|
44588
44975
|
const path = assignmentMdPath(item);
|
|
44589
44976
|
if (!await fileExists(path)) return null;
|
|
44590
44977
|
try {
|
|
44591
|
-
const content = await
|
|
44978
|
+
const content = await readFile78(path, "utf-8");
|
|
44592
44979
|
const fm = parseAssignmentFrontmatter(content);
|
|
44593
44980
|
const body = content.replace(/^---\n[\s\S]*?\n---/, "");
|
|
44594
44981
|
const assignmentDir = dirname29(path);
|
|
@@ -45367,7 +45754,7 @@ init_fs();
|
|
|
45367
45754
|
init_timestamp();
|
|
45368
45755
|
init_frontmatter();
|
|
45369
45756
|
import { Command as Command21 } from "commander";
|
|
45370
|
-
import { readFile as
|
|
45757
|
+
import { readFile as readFile79 } from "fs/promises";
|
|
45371
45758
|
import { resolve as resolve109 } from "path";
|
|
45372
45759
|
function renameAssignmentStatusRefs(content, id, newId, now) {
|
|
45373
45760
|
const fm = parseAssignmentFrontmatter(content);
|
|
@@ -45394,7 +45781,7 @@ function configPath() {
|
|
|
45394
45781
|
async function readStatusBlock() {
|
|
45395
45782
|
const p = configPath();
|
|
45396
45783
|
if (!await fileExists(p)) return null;
|
|
45397
|
-
const content = await
|
|
45784
|
+
const content = await readFile79(p, "utf-8");
|
|
45398
45785
|
return parseStatusConfig(content);
|
|
45399
45786
|
}
|
|
45400
45787
|
async function requireStatusBlock() {
|
|
@@ -45678,7 +46065,7 @@ async function runStatusRename(id, opts) {
|
|
|
45678
46065
|
printBlockDiff(before, after);
|
|
45679
46066
|
const now2 = nowTimestamp();
|
|
45680
46067
|
for (const a of affected) {
|
|
45681
|
-
const original = await
|
|
46068
|
+
const original = await readFile79(a.path, "utf-8");
|
|
45682
46069
|
const rewritten = renameAssignmentStatusRefs(original, id, newId, now2);
|
|
45683
46070
|
console.log(`
|
|
45684
46071
|
--- ${a.display}/assignment.md`);
|
|
@@ -45689,9 +46076,9 @@ async function runStatusRename(id, opts) {
|
|
|
45689
46076
|
}
|
|
45690
46077
|
const cfgPath = configPath();
|
|
45691
46078
|
const buffers = /* @__PURE__ */ new Map();
|
|
45692
|
-
buffers.set(cfgPath, await fileExists(cfgPath) ? await
|
|
46079
|
+
buffers.set(cfgPath, await fileExists(cfgPath) ? await readFile79(cfgPath, "utf-8") : "");
|
|
45693
46080
|
for (const a of affected) {
|
|
45694
|
-
buffers.set(a.path, await
|
|
46081
|
+
buffers.set(a.path, await readFile79(a.path, "utf-8"));
|
|
45695
46082
|
}
|
|
45696
46083
|
const now = nowTimestamp();
|
|
45697
46084
|
try {
|
|
@@ -45893,7 +46280,7 @@ init_config2();
|
|
|
45893
46280
|
init_timestamp();
|
|
45894
46281
|
init_frontmatter();
|
|
45895
46282
|
import { Command as Command22 } from "commander";
|
|
45896
|
-
import { readFile as
|
|
46283
|
+
import { readFile as readFile80 } from "fs/promises";
|
|
45897
46284
|
import { resolve as resolve110 } from "path";
|
|
45898
46285
|
init_session_id();
|
|
45899
46286
|
async function resolveAssignmentPath3(opts) {
|
|
@@ -45949,7 +46336,7 @@ async function runWorkspaceSet(options, cwd = process.cwd()) {
|
|
|
45949
46336
|
${pre.errors.map((e) => ` - ${e}`).join("\n")}`
|
|
45950
46337
|
);
|
|
45951
46338
|
}
|
|
45952
|
-
const original = await
|
|
46339
|
+
const original = await readFile80(path, "utf-8");
|
|
45953
46340
|
let next = updateAssignmentWorkspace(original, partial);
|
|
45954
46341
|
next = updateAssignmentFile(next, { updated: nowTimestamp() });
|
|
45955
46342
|
await writeFileForce(path, next);
|
|
@@ -45986,7 +46373,7 @@ init_config2();
|
|
|
45986
46373
|
init_timestamp();
|
|
45987
46374
|
init_templates();
|
|
45988
46375
|
import { Command as Command23 } from "commander";
|
|
45989
|
-
import { readFile as
|
|
46376
|
+
import { readFile as readFile81 } from "fs/promises";
|
|
45990
46377
|
import { resolve as resolve111 } from "path";
|
|
45991
46378
|
init_session_id();
|
|
45992
46379
|
async function resolveAssignmentDir2(opts) {
|
|
@@ -46070,7 +46457,7 @@ async function runProgressLog(text, options, cwd = process.cwd()) {
|
|
|
46070
46457
|
}
|
|
46071
46458
|
const path = resolve111(dir, "progress.md");
|
|
46072
46459
|
const now = nowTimestamp();
|
|
46073
|
-
const content = await fileExists(path) ? await
|
|
46460
|
+
const content = await fileExists(path) ? await readFile81(path, "utf-8") : renderProgress({ assignment: slug, timestamp: now });
|
|
46074
46461
|
const next = appendProgressEntry(content, text, now);
|
|
46075
46462
|
await writeFileForce(path, next);
|
|
46076
46463
|
return path;
|
|
@@ -46090,10 +46477,10 @@ progressCommand.command("log").description("Append a timestamped entry to the as
|
|
|
46090
46477
|
|
|
46091
46478
|
// src/cli-default-command.ts
|
|
46092
46479
|
init_config2();
|
|
46093
|
-
import { readdir as
|
|
46480
|
+
import { readdir as readdir40 } from "fs/promises";
|
|
46094
46481
|
async function hasAnyProjectContent(projectsDir2) {
|
|
46095
46482
|
try {
|
|
46096
|
-
const entries = await
|
|
46483
|
+
const entries = await readdir40(projectsDir2, { withFileTypes: true });
|
|
46097
46484
|
return entries.some((entry) => entry.isDirectory());
|
|
46098
46485
|
} catch {
|
|
46099
46486
|
return false;
|