@agent-plan/server 0.2.19-next.20 → 0.2.19-next.22

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;AAyzBD,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;AAuIpC,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;AAo0BD,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
@@ -6,7 +6,7 @@ import { fileURLToPath } from "node:url";
6
6
  import { createAdaptorServer } from "@hono/node-server";
7
7
  import { Hono } from "hono";
8
8
  import { cors } from "hono/cors";
9
- import { ExportService, PlanStore, PlanStoreError, createFeatureId, createPhaseId, createChecklistItemId, createShortId, createTaskId, normalizeSlug, withFeatureLock, needsMotivation } from "@agent-plan/core";
9
+ import { ExportService, PlanStore, PlanStoreError, createFeatureId, createPhaseId, createChecklistItemId, createShortId, createTaskId, findPhaseByRef, normalizeSlug, withFeatureLock, needsMotivation } from "@agent-plan/core";
10
10
  import { WsHub } from "./ws-hub.js";
11
11
  // ─── Watcher ────────────────────────────────────────────────────────────
12
12
  let watcherAbort = null;
@@ -14,6 +14,22 @@ let watcherHubRef = { current: null };
14
14
  function nowISO() {
15
15
  return new Date().toISOString();
16
16
  }
17
+ /** Resolve requirement phase refs before persistence so requirements never dangle. */
18
+ async function resolveRequirementPhaseIds(store, linkedPhaseIds) {
19
+ if (!Array.isArray(linkedPhaseIds) || linkedPhaseIds.length === 0) {
20
+ return { error: "linkedPhaseIds must contain at least one phase" };
21
+ }
22
+ const refs = linkedPhaseIds.map((entry) => typeof entry === "string" ? entry.trim() : "");
23
+ if (refs.some((ref) => !ref)) {
24
+ return { error: "linkedPhaseIds must contain non-empty phase references" };
25
+ }
26
+ const [phases, featuresDocument] = await Promise.all([store.loadAllPhases(), store.loadFeatures()]);
27
+ const resolved = refs.map((ref) => findPhaseByRef(phases, featuresDocument.features, ref));
28
+ const missing = resolved.findIndex((phase) => !phase);
29
+ if (missing !== -1)
30
+ return { error: `linked phase not found: ${refs[missing]}` };
31
+ return { linkedPhaseIds: [...new Set(resolved.map((phase) => phase.id))] };
32
+ }
17
33
  function nextTaskNumber(phase) {
18
34
  const numbers = phase.tasks.map((task) => task.number || 0).filter((n) => Number.isFinite(n));
19
35
  return (numbers.length > 0 ? Math.max(...numbers) : 0) + 1;
@@ -168,21 +184,29 @@ function createApiApp(store, hubRef, apiPrefix = "", uiConfig, isBusy) {
168
184
  app.get(route("/requirements"), async (c) => c.json(await store.loadRequirements()));
169
185
  app.post(route("/requirements"), async (c) => {
170
186
  const body = await c.req.json();
171
- const reqs = await store.updateRequirements((doc) => { doc.requirements.push(body); return doc; });
187
+ const links = await resolveRequirementPhaseIds(store, body.linkedPhaseIds);
188
+ if ("error" in links)
189
+ return c.json({ error: links.error }, 400);
190
+ const requirement = { ...body, linkedPhaseIds: links.linkedPhaseIds };
191
+ const reqs = await store.updateRequirements((doc) => { doc.requirements.push(requirement); return doc; });
172
192
  await store.writeGenerated();
173
193
  hub()?.broadcast({ type: "requirements-updated", data: reqs });
174
194
  hub()?.broadcast({ type: "plan-rendered", data: {} });
175
- return c.json(body, 201);
195
+ return c.json(requirement, 201);
176
196
  });
177
197
  app.put(route("/requirements/:id"), async (c) => {
178
198
  const id = c.req.param("id");
179
199
  const body = await c.req.json();
200
+ const links = await resolveRequirementPhaseIds(store, body.linkedPhaseIds);
201
+ if ("error" in links)
202
+ return c.json({ error: links.error }, 400);
203
+ const requirement = { ...body, linkedPhaseIds: links.linkedPhaseIds };
180
204
  let found = false;
181
205
  const reqs = await store.updateRequirements((doc) => {
182
206
  const idx = doc.requirements.findIndex((r) => r.id === id);
183
207
  if (idx === -1)
184
208
  return doc;
185
- doc.requirements[idx] = body;
209
+ doc.requirements[idx] = requirement;
186
210
  found = true;
187
211
  return doc;
188
212
  });
@@ -191,7 +215,7 @@ function createApiApp(store, hubRef, apiPrefix = "", uiConfig, isBusy) {
191
215
  await store.writeGenerated();
192
216
  hub()?.broadcast({ type: "requirements-updated", data: reqs });
193
217
  hub()?.broadcast({ type: "plan-rendered", data: {} });
194
- return c.json(body);
218
+ return c.json(requirement);
195
219
  });
196
220
  app.delete(route("/requirements/:id"), async (c) => {
197
221
  const id = c.req.param("id");
@@ -800,6 +824,10 @@ function createApiApp(store, hubRef, apiPrefix = "", uiConfig, isBusy) {
800
824
  const list = await store.listHandoffs();
801
825
  return c.json({ handoffs: list });
802
826
  });
827
+ app.get(route("/handoffs/archive"), async (c) => {
828
+ const archived = await store.listArchivedHandoffs();
829
+ return c.json({ archived });
830
+ });
803
831
  app.get(route("/phases/:id/handoff"), async (c) => {
804
832
  const id = c.req.param("id");
805
833
  if (!id)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-plan/server",
3
- "version": "0.2.19-next.20",
3
+ "version": "0.2.19-next.22",
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.20"
44
+ "@agent-plan/core": "0.2.19-next.22"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/ws": "^8.18.0"