@agent-plan/server 0.2.19-next.7 → 0.2.19-next.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAiHpC,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,GAAG,KAAK,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC;IACzF,MAAM,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;CACrC;AAwuBD,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,MAAM,OAAO,CAAC,GAAG,SAAS,CAAC;CACtC;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,OAAO,GAAG,KAAK,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,KAAK,CAAC;IACX,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAkFvE"}
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAiHpC,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,GAAG,KAAK,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC;IACzF,MAAM,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;CACrC;AAqyBD,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,MAAM,OAAO,CAAC,GAAG,SAAS,CAAC;CACtC;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,OAAO,GAAG,KAAK,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,KAAK,CAAC;IACX,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAkFvE"}
package/dist/serve.js CHANGED
@@ -644,20 +644,52 @@ function createApiApp(store, hubRef, apiPrefix = "", uiConfig, isBusy) {
644
644
  });
645
645
  // ── Reorder (priority) ───────────────────────────────────────────
646
646
  app.post(route("/reorder"), async (c) => {
647
+ // Midpoint-insert reorder: only the moved item's priority changes (when
648
+ // the gap between its new neighbours allows it). When the gap is exhausted
649
+ // (≤1, e.g. all-zero defaults or tight spacing), the segment is reindexed
650
+ // with GAP. Keeps priority as int (no schema migration) and minimises the
651
+ // set of changed items per drag.
647
652
  const body = await c.req.json();
648
- const { kind, ids } = body;
649
- if (!Array.isArray(ids) || ids.length === 0)
650
- return c.json({ error: "ids required" }, 400);
651
- const gap = 10;
653
+ const { kind, movedId, beforeId, afterId } = body;
654
+ if (!movedId)
655
+ return c.json({ error: "movedId required" }, 400);
656
+ const GAP = 10;
657
+ // Reindex a list in-place: reconstruct the desired order (moved removed +
658
+ // reinserted between beforeId and afterId) then assign (i+1)*GAP.
659
+ const reindexList = (all) => {
660
+ const sorted = [...all].sort((a, b) => a.priority - b.priority || a.number - b.number);
661
+ const moved = sorted.find((x) => x.id === movedId);
662
+ const withoutMoved = sorted.filter((x) => x.id !== movedId);
663
+ let insertIdx;
664
+ if (beforeId) {
665
+ const bi = withoutMoved.findIndex((x) => x.id === beforeId);
666
+ insertIdx = bi === -1 ? withoutMoved.length : bi + 1;
667
+ }
668
+ else {
669
+ insertIdx = 0;
670
+ }
671
+ if (moved)
672
+ withoutMoved.splice(insertIdx, 0, moved);
673
+ withoutMoved.forEach((item, i) => { item.priority = (i + 1) * GAP; });
674
+ };
652
675
  if (kind === "feature") {
653
676
  // Priority-only: suspend status rollup so reordering never flips a
654
677
  // partially-done feature to in-progress (priority ≠ status).
655
678
  await store.runBatch(async () => {
656
679
  await store.updateFeatures((doc) => {
657
- for (const [i, id] of ids.entries()) {
658
- const f = doc.features.find((x) => x.id === id);
659
- if (f)
660
- f.priority = (i + 1) * gap;
680
+ const moved = doc.features.find((x) => x.id === movedId);
681
+ if (!moved)
682
+ return doc;
683
+ const before = beforeId ? doc.features.find((x) => x.id === beforeId) : null;
684
+ const after = afterId ? doc.features.find((x) => x.id === afterId) : null;
685
+ const beforeP = before ? before.priority : 0;
686
+ const maxP = doc.features.reduce((m, f) => Math.max(m, f.priority), 0);
687
+ const afterP = after ? after.priority : (maxP + GAP);
688
+ if (afterP - beforeP > 1) {
689
+ moved.priority = Math.floor((beforeP + afterP) / 2);
690
+ }
691
+ else {
692
+ reindexList(doc.features);
661
693
  }
662
694
  doc.features.sort((a, b) => a.priority - b.priority || a.number - b.number);
663
695
  return doc;
@@ -667,10 +699,36 @@ function createApiApp(store, hubRef, apiPrefix = "", uiConfig, isBusy) {
667
699
  }
668
700
  else if (kind === "phase") {
669
701
  const phases = await store.loadAllPhases();
702
+ const moved = phases.find((p) => p.id === movedId);
703
+ if (!moved)
704
+ return c.json({ error: "moved phase not found" }, 404);
705
+ const siblings = phases.filter((p) => p.featureId === moved.featureId);
706
+ const before = beforeId ? siblings.find((p) => p.id === beforeId) : null;
707
+ const after = afterId ? siblings.find((p) => p.id === afterId) : null;
708
+ const beforeP = before ? before.priority : 0;
709
+ const maxP = siblings.reduce((m, p) => Math.max(m, p.priority), 0);
710
+ const afterP = after ? after.priority : (maxP + GAP);
670
711
  await store.runBatch(async () => {
671
- for (const [i, id] of ids.entries()) {
672
- if (phases.some((x) => x.id === id)) {
673
- await store.updatePhase(id, (entry) => { entry.priority = (i + 1) * gap; return entry; });
712
+ if (afterP - beforeP > 1) {
713
+ await store.updatePhase(movedId, (entry) => { entry.priority = Math.floor((beforeP + afterP) / 2); return entry; });
714
+ }
715
+ else {
716
+ // Reindex all siblings (each phase is a separate file)
717
+ const sorted = [...siblings].sort((a, b) => a.priority - b.priority || a.number - b.number);
718
+ const withoutMoved = sorted.filter((x) => x.id !== movedId);
719
+ let insertIdx;
720
+ if (beforeId) {
721
+ const bi = withoutMoved.findIndex((x) => x.id === beforeId);
722
+ insertIdx = bi === -1 ? withoutMoved.length : bi + 1;
723
+ }
724
+ else {
725
+ insertIdx = 0;
726
+ }
727
+ const movedEntry = sorted.find((x) => x.id === movedId);
728
+ if (movedEntry)
729
+ withoutMoved.splice(insertIdx, 0, movedEntry);
730
+ for (const [i, p] of withoutMoved.entries()) {
731
+ await store.updatePhase(p.id, (entry) => { entry.priority = (i + 1) * GAP; return entry; });
674
732
  }
675
733
  }
676
734
  });
@@ -678,14 +736,23 @@ function createApiApp(store, hubRef, apiPrefix = "", uiConfig, isBusy) {
678
736
  }
679
737
  else if (kind === "task") {
680
738
  const allPhases = await store.loadAllPhases();
681
- const host = allPhases.find((p) => p.tasks.some((t) => ids.includes(t.id)));
739
+ const host = allPhases.find((p) => p.tasks.some((t) => t.id === movedId));
682
740
  if (host) {
683
741
  await store.runBatch(async () => {
684
742
  await store.updatePhase(host.id, (phase) => {
685
- for (const [i, id] of ids.entries()) {
686
- const t = phase.tasks.find((x) => x.id === id);
687
- if (t)
688
- t.priority = (i + 1) * gap;
743
+ const moved = phase.tasks.find((x) => x.id === movedId);
744
+ if (!moved)
745
+ return phase;
746
+ const before = beforeId ? phase.tasks.find((x) => x.id === beforeId) : null;
747
+ const after = afterId ? phase.tasks.find((x) => x.id === afterId) : null;
748
+ const beforeP = before ? before.priority : 0;
749
+ const maxP = phase.tasks.reduce((m, t) => Math.max(m, t.priority), 0);
750
+ const afterP = after ? after.priority : (maxP + GAP);
751
+ if (afterP - beforeP > 1) {
752
+ moved.priority = Math.floor((beforeP + afterP) / 2);
753
+ }
754
+ else {
755
+ reindexList(phase.tasks);
689
756
  }
690
757
  phase.tasks.sort((a, b) => a.priority - b.priority || a.number - b.number);
691
758
  phase.taskIds = phase.tasks.map((t) => t.id);
@@ -700,7 +767,7 @@ function createApiApp(store, hubRef, apiPrefix = "", uiConfig, isBusy) {
700
767
  }
701
768
  await store.writeGenerated();
702
769
  hub()?.broadcast({ type: "plan-rendered", data: {} });
703
- return c.json({ ok: true, kind, count: ids.length });
770
+ return c.json({ ok: true, kind, movedId });
704
771
  });
705
772
  // ── Render ───────────────────────────────────────────────────────
706
773
  app.post(route("/render"), async (c) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-plan/server",
3
- "version": "0.2.19-next.7",
3
+ "version": "0.2.19-next.9",
4
4
  "private": false,
5
5
  "description": "Local HTTP/WebSocket server for Agent Plan dashboards and planner APIs.",
6
6
  "license": "MIT",
@@ -41,7 +41,7 @@
41
41
  "@hono/node-server": "^1.14.0",
42
42
  "hono": "^4.7.0",
43
43
  "ws": "^8.18.0",
44
- "@agent-plan/core": "0.2.19-next.7"
44
+ "@agent-plan/core": "0.2.19-next.9"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/ws": "^8.18.0"