syntaur 0.68.0 → 0.70.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.
Files changed (68) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dashboard/dist/assets/{_basePickBy-CE2CIvur.js → _basePickBy-DKk6tHtk.js} +1 -1
  3. package/dashboard/dist/assets/{_baseUniq-BznLQqID.js → _baseUniq-DM-f7DWz.js} +1 -1
  4. package/dashboard/dist/assets/{arc-B6JqtWve.js → arc-ZBlA3YdV.js} +1 -1
  5. package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-P8UCT3rj.js → architectureDiagram-2XIMDMQ5-BUmvtGTF.js} +1 -1
  6. package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-C1ATZKSf.js → blockDiagram-WCTKOSBZ-B3qxWK6s.js} +1 -1
  7. package/dashboard/dist/assets/{c4Diagram-IC4MRINW-AvN1yayQ.js → c4Diagram-IC4MRINW-BEq_UJO-.js} +1 -1
  8. package/dashboard/dist/assets/channel-fypxffzQ.js +1 -0
  9. package/dashboard/dist/assets/{chunk-4BX2VUAB-CyYz6mlJ.js → chunk-4BX2VUAB-C-Y9ryMm.js} +1 -1
  10. package/dashboard/dist/assets/{chunk-55IACEB6-QyOF7ox_.js → chunk-55IACEB6-CGdtbsjw.js} +1 -1
  11. package/dashboard/dist/assets/{chunk-FMBD7UC4-DVTHM99U.js → chunk-FMBD7UC4-DllxJhUp.js} +1 -1
  12. package/dashboard/dist/assets/{chunk-JSJVCQXG-DQfxaQtT.js → chunk-JSJVCQXG-jjMM8O5F.js} +1 -1
  13. package/dashboard/dist/assets/{chunk-KX2RTZJC-4R1oobH6.js → chunk-KX2RTZJC-B_6BPltQ.js} +1 -1
  14. package/dashboard/dist/assets/{chunk-NQ4KR5QH-D8H_7yNS.js → chunk-NQ4KR5QH-D0hJiXHp.js} +1 -1
  15. package/dashboard/dist/assets/{chunk-QZHKN3VN-DLxDUSuo.js → chunk-QZHKN3VN-BCWo4hLS.js} +1 -1
  16. package/dashboard/dist/assets/{chunk-WL4C6EOR-CWuFDkVp.js → chunk-WL4C6EOR-DH_jEAwg.js} +1 -1
  17. package/dashboard/dist/assets/classDiagram-VBA2DB6C-1KnjQvtL.js +1 -0
  18. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-1KnjQvtL.js +1 -0
  19. package/dashboard/dist/assets/clone-CKMabBhS.js +1 -0
  20. package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-D23Dy_Za.js → cose-bilkent-S5V4N54A-5ld00TOH.js} +1 -1
  21. package/dashboard/dist/assets/{dagre-KLK3FWXG-CaKBk8eh.js → dagre-KLK3FWXG-Cnu6eQWy.js} +1 -1
  22. package/dashboard/dist/assets/{diagram-E7M64L7V-BAPQPki-.js → diagram-E7M64L7V-_CBBKNP-.js} +1 -1
  23. package/dashboard/dist/assets/{diagram-IFDJBPK2-Cla6qyvn.js → diagram-IFDJBPK2-DE6WjIb1.js} +1 -1
  24. package/dashboard/dist/assets/{diagram-P4PSJMXO-DnTZq_y6.js → diagram-P4PSJMXO-DpW7UzNK.js} +1 -1
  25. package/dashboard/dist/assets/{erDiagram-INFDFZHY-yc1_7ebn.js → erDiagram-INFDFZHY-BD2409fE.js} +1 -1
  26. package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-CMt2tF6O.js → flowDiagram-PKNHOUZH-1p0khhFI.js} +1 -1
  27. package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-CXiK-5Gp.js → ganttDiagram-A5KZAMGK-B2zFyA4s.js} +1 -1
  28. package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-B4PbW06T.js → gitGraphDiagram-K3NZZRJ6-bH-4YH7h.js} +1 -1
  29. package/dashboard/dist/assets/{graph-CjdFy-q-.js → graph-BT24B6iQ.js} +1 -1
  30. package/dashboard/dist/assets/{index-DlUgV5eO.css → index-BZwPAi8K.css} +1 -1
  31. package/dashboard/dist/assets/index-Cxqr3rQB.js +670 -0
  32. package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-BeOWVt7p.js → infoDiagram-LFFYTUFH-CMzP4Hcg.js} +1 -1
  33. package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-LE7swZOH.js → ishikawaDiagram-PHBUUO56-DMEmFC7M.js} +1 -1
  34. package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-DG9-sksf.js → journeyDiagram-4ABVD52K-CAtzYQUm.js} +1 -1
  35. package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-7CKAw6eI.js → kanban-definition-K7BYSVSG-d1JVbtvX.js} +1 -1
  36. package/dashboard/dist/assets/{layout-CHChKPuz.js → layout-BVuI38I_.js} +1 -1
  37. package/dashboard/dist/assets/{linear-BWSj4au4.js → linear-Bc8PGMbp.js} +1 -1
  38. package/dashboard/dist/assets/{mermaid.core-CAwQaPqG.js → mermaid.core-UtwFYLNj.js} +4 -4
  39. package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-CtZWMkVN.js → mindmap-definition-YRQLILUH-DHc5RCDj.js} +1 -1
  40. package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-CstCoaK7.js → pieDiagram-SKSYHLDU-9anIsdIA.js} +1 -1
  41. package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-DD8zRtaB.js → quadrantDiagram-337W2JSQ-FZ0D9HnU.js} +1 -1
  42. package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-BWpKIK3b.js → requirementDiagram-Z7DCOOCP-BkjCvH_u.js} +1 -1
  43. package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-08gqQtFM.js → sankeyDiagram-WA2Y5GQK-DzqwYHDo.js} +1 -1
  44. package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-DsfIDBUH.js → sequenceDiagram-2WXFIKYE-BW4g5Ao-.js} +1 -1
  45. package/dashboard/dist/assets/{stateDiagram-RAJIS63D-Dqzfk_yy.js → stateDiagram-RAJIS63D-D0tKU3Z0.js} +1 -1
  46. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-DxWQhjNO.js +1 -0
  47. package/dashboard/dist/assets/{timeline-definition-YZTLITO2-DgH_p9jR.js → timeline-definition-YZTLITO2-Bu269QDX.js} +1 -1
  48. package/dashboard/dist/assets/{treemap-KZPCXAKY-7XKqMhq9.js → treemap-KZPCXAKY-BGu_rrva.js} +1 -1
  49. package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-BFtNLBWM.js → vennDiagram-LZ73GAT5-Cx_n5FRZ.js} +1 -1
  50. package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-CQPevMNl.js → xychartDiagram-JWTSCODW-BOJsKV_W.js} +1 -1
  51. package/dashboard/dist/index.html +2 -2
  52. package/dist/dashboard/server.js +83 -46
  53. package/dist/dashboard/server.js.map +1 -1
  54. package/dist/index.js +353 -326
  55. package/dist/index.js.map +1 -1
  56. package/dist/launch/index.js +328 -37
  57. package/dist/launch/index.js.map +1 -1
  58. package/package.json +1 -1
  59. package/platforms/claude-code/.claude-plugin/plugin.json +1 -1
  60. package/platforms/codex/.codex-plugin/plugin.json +1 -1
  61. package/platforms/hermes/plugins/syntaur/__pycache__/__init__.cpython-312.pyc +0 -0
  62. package/platforms/hermes/plugins/syntaur/__pycache__/boundary.cpython-312.pyc +0 -0
  63. package/dashboard/dist/assets/channel-IZujZyS6.js +0 -1
  64. package/dashboard/dist/assets/classDiagram-VBA2DB6C-ChnJofe3.js +0 -1
  65. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-ChnJofe3.js +0 -1
  66. package/dashboard/dist/assets/clone-JjIbzsqJ.js +0 -1
  67. package/dashboard/dist/assets/index-COOcebN7.js +0 -659
  68. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-D542UPiR.js +0 -1
@@ -122,7 +122,7 @@ function getTargetStatus(_from, command, table) {
122
122
  if (!table) {
123
123
  return DEFAULT_COMMAND_TARGETS.get(command) ?? null;
124
124
  }
125
- return table.get(command) ?? table.get(`${_from}:${command}`) ?? null;
125
+ return table.get(`${_from}:${command}`) ?? table.get(command) ?? null;
126
126
  }
127
127
  var DEFAULT_COMMAND_TARGETS, DEFAULT_TRANSITION_TABLE;
128
128
  var init_state_machine = __esm({
@@ -6322,8 +6322,7 @@ async function areDependenciesSatisfied(projectDir, dependsOn, terminalStatuses)
6322
6322
  if (!await fileExists(depPath)) return false;
6323
6323
  try {
6324
6324
  const content = await readFile9(depPath, "utf-8");
6325
- const m = content.match(/^status:\s*(.+)$/m);
6326
- const status = m ? m[1].trim() : "";
6325
+ const { status } = parseAssignmentFrontmatter(content);
6327
6326
  if (!terminalStatuses.has(status)) return false;
6328
6327
  } catch {
6329
6328
  return false;
@@ -6438,6 +6437,7 @@ var init_facts = __esm({
6438
6437
  init_fs();
6439
6438
  init_git_worktree();
6440
6439
  init_derive();
6440
+ init_frontmatter();
6441
6441
  HTML_COMMENT_RE = /<!--[\s\S]*?-->/g;
6442
6442
  PLAN_FILE_RE = /^plan(?:-v(\d+))?\.md$/;
6443
6443
  }
@@ -8175,8 +8175,8 @@ function scanKey(serversDir2, projectsDir, assignmentsDir2) {
8175
8175
  return `${serversDir2}\0${projectsDir}\0${assignmentsDir2 ?? ""}`;
8176
8176
  }
8177
8177
  function delay(ms) {
8178
- return new Promise((resolve47) => {
8179
- const timer3 = setTimeout(resolve47, ms);
8178
+ return new Promise((resolve48) => {
8179
+ const timer3 = setTimeout(resolve48, ms);
8180
8180
  if (typeof timer3.unref === "function") {
8181
8181
  timer3.unref();
8182
8182
  }
@@ -11991,6 +11991,22 @@ var init_assignment_todos = __esm({
11991
11991
  }
11992
11992
  });
11993
11993
 
11994
+ // src/utils/path-canon.ts
11995
+ import { realpathSync as realpathSync2 } from "fs";
11996
+ import { resolve as resolve43 } from "path";
11997
+ function canonicalPath(p) {
11998
+ try {
11999
+ return realpathSync2(resolve43(p));
12000
+ } catch {
12001
+ return resolve43(p).replace(/\/+$/, "");
12002
+ }
12003
+ }
12004
+ var init_path_canon = __esm({
12005
+ "src/utils/path-canon.ts"() {
12006
+ "use strict";
12007
+ }
12008
+ });
12009
+
11994
12010
  // src/targets/renderers.ts
11995
12011
  var RENDERERS;
11996
12012
  var init_renderers = __esm({
@@ -12011,7 +12027,7 @@ var init_renderers = __esm({
12011
12027
  });
12012
12028
 
12013
12029
  // src/targets/user-descriptors.ts
12014
- import { resolve as resolve43 } from "path";
12030
+ import { resolve as resolve44 } from "path";
12015
12031
  import { readFile as readFile30, readdir as readdir18 } from "fs/promises";
12016
12032
  var VALID_RENDERER_KEYS;
12017
12033
  var init_user_descriptors = __esm({
@@ -12026,20 +12042,20 @@ var init_user_descriptors = __esm({
12026
12042
 
12027
12043
  // src/targets/registry.ts
12028
12044
  import { homedir as homedir7 } from "os";
12029
- import { join as join10, resolve as resolve44 } from "path";
12045
+ import { join as join10, resolve as resolve45 } from "path";
12030
12046
  function home(...segments) {
12031
- return resolve44(homedir7(), ...segments);
12047
+ return resolve45(homedir7(), ...segments);
12032
12048
  }
12033
12049
  function hermesHome() {
12034
12050
  const env = process.env.HERMES_HOME;
12035
- return env && env.length > 0 ? resolve44(env) : home(".hermes");
12051
+ return env && env.length > 0 ? resolve45(env) : home(".hermes");
12036
12052
  }
12037
12053
  function hermesSkillsDir() {
12038
- return resolve44(hermesHome(), "skills");
12054
+ return resolve45(hermesHome(), "skills");
12039
12055
  }
12040
12056
  function codexHome() {
12041
12057
  const env = process.env.CODEX_HOME;
12042
- return env && env.length > 0 ? resolve44(env) : home(".codex");
12058
+ return env && env.length > 0 ? resolve45(env) : home(".codex");
12043
12059
  }
12044
12060
  function toDiscovered(meta) {
12045
12061
  if (!meta) return null;
@@ -12110,7 +12126,7 @@ var init_registry = __esm({
12110
12126
  skillsShAgentId: "codex",
12111
12127
  nativePlugin: "codex",
12112
12128
  detect: detectDir(codexHome()),
12113
- skillsDir: { global: resolve44(codexHome(), "skills") },
12129
+ skillsDir: { global: resolve45(codexHome(), "skills") },
12114
12130
  instructions: { files: [{ path: "AGENTS.md", renderer: "codexAgents" }] },
12115
12131
  sessions: codexSessions
12116
12132
  },
@@ -12179,7 +12195,7 @@ var init_registry = __esm({
12179
12195
  tier3: {
12180
12196
  kind: "hermes-plugin",
12181
12197
  source: "platforms/hermes/plugins/syntaur",
12182
- installDir: () => resolve44(hermesHome(), "plugins", "syntaur"),
12198
+ installDir: () => resolve45(hermesHome(), "plugins", "syntaur"),
12183
12199
  entry: "plugin.yaml"
12184
12200
  }
12185
12201
  }
@@ -12199,7 +12215,7 @@ import { execFile as execFile3, execFileSync as execFileSync4 } from "child_proc
12199
12215
  import { promisify as promisify3 } from "util";
12200
12216
  import { statSync as statSync4 } from "fs";
12201
12217
  import { readFile as readFile31 } from "fs/promises";
12202
- import { resolve as resolve45 } from "path";
12218
+ import { resolve as resolve46 } from "path";
12203
12219
  function emptySummary() {
12204
12220
  return { discovered: 0, inserted: 0, revived: 0, swept: 0, skipped: 0, changed: false };
12205
12221
  }
@@ -12252,10 +12268,15 @@ async function defaultOpenFiles(files) {
12252
12268
  }
12253
12269
  return open6;
12254
12270
  }
12271
+ function canonicalizeOpenSet(open6) {
12272
+ const out = /* @__PURE__ */ new Set();
12273
+ for (const p of open6) out.add(canonicalPath(p));
12274
+ return out;
12275
+ }
12255
12276
  async function readContextLink(cwd, cache3) {
12256
12277
  if (cache3.has(cwd)) return cache3.get(cwd);
12257
12278
  let link = null;
12258
- const path = resolve45(cwd, ".syntaur", "context.json");
12279
+ const path = resolve46(cwd, ".syntaur", "context.json");
12259
12280
  if (await fileExists(path)) {
12260
12281
  try {
12261
12282
  const parsed = JSON.parse(await readFile31(path, "utf-8"));
@@ -12307,7 +12328,9 @@ async function scanSessions(opts = {}, deps = {}) {
12307
12328
  }
12308
12329
  }
12309
12330
  summary.discovered = discovered.length;
12310
- const openSet = await openFiles(discovered.map((d) => d.transcriptPath));
12331
+ const openSet = canonicalizeOpenSet(
12332
+ await openFiles(discovered.map((d) => d.transcriptPath))
12333
+ );
12311
12334
  const contextCache = /* @__PURE__ */ new Map();
12312
12335
  for (const d of discovered) {
12313
12336
  const link = await readContextLink(d.cwd, contextCache);
@@ -12316,7 +12339,7 @@ async function scanSessions(opts = {}, deps = {}) {
12316
12339
  continue;
12317
12340
  }
12318
12341
  const mtime = statMtimeMs(d.transcriptPath);
12319
- const heldOpen = openSet.has(d.transcriptPath);
12342
+ const heldOpen = openSet.has(canonicalPath(d.transcriptPath));
12320
12343
  const isLive = heldOpen || mtime !== null && now() - mtime < FRESH_MTIME_MS;
12321
12344
  const prev = getSessionById(d.sessionId);
12322
12345
  const status = isLive ? "active" : prev?.status ?? "stopped";
@@ -12378,12 +12401,14 @@ async function scanSessions(opts = {}, deps = {}) {
12378
12401
  sweepCandidates.push({ sessionId: row.session_id, transcriptPath: null });
12379
12402
  }
12380
12403
  }
12381
- const sweepOpenSet = await openFiles(
12382
- sweepCandidates.map((c) => c.transcriptPath).filter((p) => p !== null)
12404
+ const sweepOpenSet = canonicalizeOpenSet(
12405
+ await openFiles(
12406
+ sweepCandidates.map((c) => c.transcriptPath).filter((p) => p !== null)
12407
+ )
12383
12408
  );
12384
12409
  for (const candidate of sweepCandidates) {
12385
12410
  if (candidate.transcriptPath) {
12386
- if (sweepOpenSet.has(candidate.transcriptPath)) continue;
12411
+ if (sweepOpenSet.has(canonicalPath(candidate.transcriptPath))) continue;
12387
12412
  const mtime = statMtimeMs(candidate.transcriptPath);
12388
12413
  if (mtime !== null && now() - mtime < FRESH_MTIME_MS) continue;
12389
12414
  const endedAt = mtime !== null ? new Date(mtime).toISOString() : void 0;
@@ -12404,6 +12429,7 @@ var init_scanner2 = __esm({
12404
12429
  "src/sessions/scanner.ts"() {
12405
12430
  "use strict";
12406
12431
  init_fs();
12432
+ init_path_canon();
12407
12433
  init_config2();
12408
12434
  init_session_id();
12409
12435
  init_registry();
@@ -12457,7 +12483,7 @@ init_assignment_resolver();
12457
12483
  init_agent_sessions();
12458
12484
  import express from "express";
12459
12485
  import { createServer } from "http";
12460
- import { resolve as resolve46 } from "path";
12486
+ import { resolve as resolve47 } from "path";
12461
12487
  import { writeFile as writeFile8, unlink as unlink9 } from "fs/promises";
12462
12488
  import { WebSocketServer, WebSocket } from "ws";
12463
12489
 
@@ -18165,25 +18191,29 @@ async function resolveSessionPlan(input, terminal) {
18165
18191
  }
18166
18192
  let cwd = session.path;
18167
18193
  let fallbackWarning = null;
18168
- if (session.projectSlug && session.assignmentSlug) {
18169
- const detail = await getAssignmentDetail(
18194
+ if (!isExistingDir(session.path)) {
18195
+ const detail = session.projectSlug && session.assignmentSlug ? await getAssignmentDetail(
18170
18196
  input.projectsDir,
18171
18197
  session.projectSlug,
18172
18198
  session.assignmentSlug
18173
- );
18199
+ ) : session.assignmentSlug ? await getAssignmentDetailById(
18200
+ input.projectsDir,
18201
+ input.assignmentsDir,
18202
+ session.assignmentSlug
18203
+ ) : null;
18174
18204
  if (detail) {
18175
18205
  const picked = resolveWorkspaceCwd({
18176
18206
  worktreePath: detail.workspace.worktreePath,
18177
18207
  repository: detail.workspace.repository,
18178
18208
  branch: detail.workspace.branch,
18179
- assignmentSlug: session.assignmentSlug
18209
+ assignmentSlug: detail.slug
18180
18210
  });
18181
18211
  if (picked.cwd !== null) {
18182
18212
  cwd = picked.cwd;
18183
18213
  fallbackWarning = picked.fallbackWarning;
18184
18214
  } else {
18185
18215
  fallbackWarning = formatFallbackCwdWarning({
18186
- assignmentSlug: session.assignmentSlug,
18216
+ assignmentSlug: detail.slug,
18187
18217
  workspaceDir: session.path,
18188
18218
  worktreePath: detail.workspace.worktreePath,
18189
18219
  branch: detail.workspace.branch
@@ -18191,6 +18221,12 @@ async function resolveSessionPlan(input, terminal) {
18191
18221
  }
18192
18222
  }
18193
18223
  }
18224
+ if (!cwd.trim()) {
18225
+ throw new LaunchError(
18226
+ "workspace-path-invalid",
18227
+ `Session ${input.id} has no recorded working directory and no linked assignment workspace resolved \u2014 refusing to launch in an unknown directory.`
18228
+ );
18229
+ }
18194
18230
  const agent = getAgents(input.config).find((a) => a.id === session.agent);
18195
18231
  if (!agent) {
18196
18232
  throw new LaunchError(
@@ -18267,7 +18303,7 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
18267
18303
  `Spawn failed: ${msg}. Verify the terminal is installed and on PATH.`
18268
18304
  );
18269
18305
  }
18270
- await new Promise((resolve47, reject) => {
18306
+ await new Promise((resolve48, reject) => {
18271
18307
  let settled = false;
18272
18308
  let stderr = "";
18273
18309
  const finishOk = () => {
@@ -18277,7 +18313,7 @@ async function executeLaunchPlan(plan, spawnFn = realSpawn) {
18277
18313
  child.unref();
18278
18314
  } catch {
18279
18315
  }
18280
- resolve47();
18316
+ resolve48();
18281
18317
  };
18282
18318
  const finishErr = (remediation) => {
18283
18319
  if (settled) return;
@@ -20040,8 +20076,7 @@ function predictReset(_provider, anchor) {
20040
20076
  }
20041
20077
  function verifyReset(provider, anchor, now) {
20042
20078
  const reset = predictReset(provider, anchor);
20043
- if (now.getTime() >= Date.parse(reset)) return { eligible: true };
20044
- return { eligible: false, rescheduleToIso: reset };
20079
+ return { eligible: now.getTime() >= Date.parse(reset) };
20045
20080
  }
20046
20081
 
20047
20082
  // src/schedules/triggers.ts
@@ -20065,13 +20100,15 @@ function evaluateKind(trigger, job, ctx) {
20065
20100
  switch (trigger.kind) {
20066
20101
  case "at": {
20067
20102
  const at = Date.parse(trigger.at);
20068
- const due = !Number.isNaN(at) && ctx.now.getTime() >= at;
20103
+ const beforeCreation = !Number.isNaN(createdAtMs) && at < createdAtMs;
20104
+ const due = !Number.isNaN(at) && ctx.now.getTime() >= at && !beforeCreation;
20069
20105
  return { due, dedupeKey: `at:${trigger.at}`, nextFireIso: trigger.at };
20070
20106
  }
20071
20107
  case "in": {
20072
20108
  const anchor = Date.parse(trigger.anchorIso);
20073
20109
  const fireAt = anchor + trigger.durationMs;
20074
- const due = !Number.isNaN(anchor) && ctx.now.getTime() >= fireAt;
20110
+ const beforeCreation = !Number.isNaN(createdAtMs) && fireAt < createdAtMs;
20111
+ const due = !Number.isNaN(anchor) && ctx.now.getTime() >= fireAt && !beforeCreation;
20075
20112
  const fireIso = Number.isNaN(anchor) ? null : iso(new Date(fireAt));
20076
20113
  return { due, dedupeKey: `in:${fireAt}`, nextFireIso: fireIso };
20077
20114
  }
@@ -20105,7 +20142,7 @@ function evaluateAfterReset(trigger, now) {
20105
20142
  if (v.eligible) {
20106
20143
  return { due: true, dedupeKey: `after-reset:${trigger.anchor.windowStartIso}`, nextFireIso: predicted };
20107
20144
  }
20108
- return { due: false, nextFireIso: predicted, rescheduleToIso: v.rescheduleToIso };
20145
+ return { due: false, nextFireIso: predicted };
20109
20146
  }
20110
20147
  function evaluateWhenStatus(trigger, job, ctx, createdAtMs) {
20111
20148
  const fm = ctx.assignment;
@@ -22805,7 +22842,7 @@ function createTodosRouter(todosDir2, broadcast, projectsDir) {
22805
22842
  router.post("/:workspace/archive", async (req2, res) => {
22806
22843
  try {
22807
22844
  const { archivePath: archivePath2 } = await Promise.resolve().then(() => (init_parser2(), parser_exports));
22808
- const { resolve: resolve47 } = await import("path");
22845
+ const { resolve: resolve48 } = await import("path");
22809
22846
  const { readFile: readFile32 } = await import("fs/promises");
22810
22847
  const { writeFileForce: writeFileForce2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
22811
22848
  const workspace = getWorkspaceParam(req2.params.workspace);
@@ -22822,7 +22859,7 @@ function createTodosRouter(todosDir2, broadcast, projectsDir) {
22822
22859
  (e) => e.itemIds.every((id) => completedIds.has(id))
22823
22860
  );
22824
22861
  const archFile = archivePath2(todosDir2, workspace, checklist.archiveInterval);
22825
- await ensureDir(resolve47(todosDir2, "archive"));
22862
+ await ensureDir(resolve48(todosDir2, "archive"));
22826
22863
  let archContent = "";
22827
22864
  if (await fileExists(archFile)) {
22828
22865
  archContent = await readFile32(archFile, "utf-8");
@@ -25301,7 +25338,7 @@ async function runCcusage(opts = {}) {
25301
25338
  };
25302
25339
  }
25303
25340
  function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
25304
- return new Promise((resolve47) => {
25341
+ return new Promise((resolve48) => {
25305
25342
  const child = spawn4(binary, args, {
25306
25343
  env: env ?? process.env,
25307
25344
  stdio: ["ignore", "pipe", "pipe"]
@@ -25315,7 +25352,7 @@ function runOnce(binary, args, env, timeoutMs, maxOutputBytes) {
25315
25352
  if (settled) return;
25316
25353
  settled = true;
25317
25354
  clearTimeout(timer3);
25318
- resolve47(result);
25355
+ resolve48(result);
25319
25356
  };
25320
25357
  const timer3 = setTimeout(() => {
25321
25358
  timedOut = true;
@@ -25719,7 +25756,7 @@ function createDashboardServer(options) {
25719
25756
  (async () => {
25720
25757
  try {
25721
25758
  const configResult = await migrateLegacyConfig(
25722
- resolve46(syntaurRoot(), "config.md")
25759
+ resolve47(syntaurRoot(), "config.md")
25723
25760
  );
25724
25761
  const projectResult = await migrateLegacyProjectFiles(projectsDir);
25725
25762
  const summary = summarizeMigration(projectResult, configResult);
@@ -26242,14 +26279,14 @@ function createDashboardServer(options) {
26242
26279
  app.use("/api/backup", createBackupRouter());
26243
26280
  if (serveStaticUi && dashboardDistPath) {
26244
26281
  const sendOpts = { dotfiles: "allow" };
26245
- app.use("/assets", express.static(resolve46(dashboardDistPath, "assets"), sendOpts));
26282
+ app.use("/assets", express.static(resolve47(dashboardDistPath, "assets"), sendOpts));
26246
26283
  app.use(express.static(dashboardDistPath, { ...sendOpts, index: false, fallthrough: true }));
26247
26284
  app.get("{*path}", async (req2, res) => {
26248
26285
  if (req2.path.startsWith("/api") || req2.path === "/ws" || req2.path.startsWith("/assets")) {
26249
26286
  res.status(404).json({ error: "Not Found" });
26250
26287
  return;
26251
26288
  }
26252
- const indexPath = resolve46(dashboardDistPath, "index.html");
26289
+ const indexPath = resolve47(dashboardDistPath, "index.html");
26253
26290
  if (!await fileExists(indexPath)) {
26254
26291
  res.status(503).send(
26255
26292
  'Dashboard not built. Run "npm run build:dashboard" first.'
@@ -26285,8 +26322,8 @@ function createDashboardServer(options) {
26285
26322
  if (!await migrationGate()) return;
26286
26323
  try {
26287
26324
  const context = await resolveDeriveContext2();
26288
- const projectDir = projectSlug ? resolve46(projectsDir, projectSlug) : null;
26289
- const path = projectDir ? resolve46(projectDir, "assignments", assignmentSlug, "assignment.md") : resolve46(assignmentsDir2, assignmentSlug, "assignment.md");
26325
+ const projectDir = projectSlug ? resolve47(projectsDir, projectSlug) : null;
26326
+ const path = projectDir ? resolve47(projectDir, "assignments", assignmentSlug, "assignment.md") : resolve47(assignmentsDir2, assignmentSlug, "assignment.md");
26290
26327
  if (!await fileExists(path)) return;
26291
26328
  const result = await recomputeAndWrite2(path, {
26292
26329
  cause: "derive",
@@ -26339,8 +26376,8 @@ function createDashboardServer(options) {
26339
26376
  serversDir: serversDir2,
26340
26377
  playbooksDir: playbooksDir2,
26341
26378
  todosDir: todosDir2,
26342
- dbPath: resolve46(syntaurRoot(), "syntaur.db"),
26343
- configPath: resolve46(syntaurRoot(), "config.md"),
26379
+ dbPath: resolve47(syntaurRoot(), "syntaur.db"),
26380
+ configPath: resolve47(syntaurRoot(), "config.md"),
26344
26381
  onMessage: broadcast,
26345
26382
  onAssignmentChanged: (projectSlug, assignmentSlug) => {
26346
26383
  void recomputeOne(projectSlug, assignmentSlug);
@@ -26408,7 +26445,7 @@ function createDashboardServer(options) {
26408
26445
  }
26409
26446
  });
26410
26447
  server.listen(port, () => {
26411
- const portFile = resolve46(syntaurRoot(), "dashboard-port");
26448
+ const portFile = resolve47(syntaurRoot(), "dashboard-port");
26412
26449
  writeFile8(portFile, String(port), "utf-8").catch(() => {
26413
26450
  });
26414
26451
  resolvePromise();
@@ -26432,7 +26469,7 @@ function createDashboardServer(options) {
26432
26469
  client.terminate();
26433
26470
  }
26434
26471
  clients.clear();
26435
- const portFile = resolve46(syntaurRoot(), "dashboard-port");
26472
+ const portFile = resolve47(syntaurRoot(), "dashboard-port");
26436
26473
  await unlink9(portFile).catch(() => {
26437
26474
  });
26438
26475
  server.closeAllConnections?.();