@agent-plan/server 0.2.22-next.2 → 0.2.22-next.3
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/dist/serve.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AA8IpC,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;
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AA8IpC,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;AA69BD,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,CA6EvE"}
|
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, createTaskId, findPhaseByRef, normalizeSlug, withFeatureLock, needsMotivation } from "@agent-plan/core";
|
|
9
|
+
import { ExportService, PlanStore, PlanStoreError, createFeatureId, createPhaseId, createChecklistItemId, createTaskId, findPhaseByRef, normalizeSlug, withFeatureLock, needsMotivation, checkExplicitTaskStart, recommendNextTask } from "@agent-plan/core";
|
|
10
10
|
import { WsHub } from "./ws-hub.js";
|
|
11
11
|
// ─── Watcher ────────────────────────────────────────────────────────────
|
|
12
12
|
let watcherAbort = null;
|
|
@@ -634,6 +634,71 @@ function createApiApp(store, hubRef, apiPrefix = "", uiConfig, isBusy) {
|
|
|
634
634
|
});
|
|
635
635
|
return c.json({ active, pendingResume });
|
|
636
636
|
});
|
|
637
|
+
/** Canonical HTTP task-entry path. Generic task updates must never start work,
|
|
638
|
+
* because start/resume is responsible for clearing checkpoints and closing
|
|
639
|
+
* any matching return-stack deviation. */
|
|
640
|
+
app.post(route("/tasks/:id/start"), async (c) => {
|
|
641
|
+
const taskId = c.req.param("id");
|
|
642
|
+
const [phases, featuresDoc, project] = await Promise.all([
|
|
643
|
+
store.loadAllPhases(), store.loadFeatures(), store.loadProject(),
|
|
644
|
+
]);
|
|
645
|
+
const phase = phases.find((entry) => entry.tasks.some((task) => task.id === taskId));
|
|
646
|
+
const existing = phase?.tasks.find((task) => task.id === taskId);
|
|
647
|
+
if (!phase || !existing)
|
|
648
|
+
return c.json({ error: "task not found" }, 404);
|
|
649
|
+
if (existing.status === "in-progress")
|
|
650
|
+
return c.json({ error: "task is already in-progress" }, 400);
|
|
651
|
+
const eligibility = checkExplicitTaskStart(featuresDoc.features, phases, existing.id, project.workDeviations);
|
|
652
|
+
if (!eligibility.eligible)
|
|
653
|
+
return c.json({ error: `Task start denied: ${eligibility.reason}` }, 400);
|
|
654
|
+
const selection = recommendNextTask(featuresDoc.features, phases, project.workDeviations);
|
|
655
|
+
if (selection.kind === "conflict")
|
|
656
|
+
return c.json({ error: selection.reason }, 409);
|
|
657
|
+
if (selection.kind === "active" && selection.candidate?.task.id !== existing.id) {
|
|
658
|
+
return c.json({ error: `Task start denied: another task is active. Use task_switch to checkpoint it before starting this task.` }, 409);
|
|
659
|
+
}
|
|
660
|
+
const now = nowISO();
|
|
661
|
+
let updated;
|
|
662
|
+
if (existing.pauseSnapshot) {
|
|
663
|
+
updated = await store.resumeTask(phase.id, existing.id, now);
|
|
664
|
+
}
|
|
665
|
+
else {
|
|
666
|
+
await store.updatePhase(phase.id, (current) => {
|
|
667
|
+
const task = current.tasks.find((entry) => entry.id === existing.id);
|
|
668
|
+
if (!task)
|
|
669
|
+
return current;
|
|
670
|
+
const previousStatus = task.status;
|
|
671
|
+
applyTaskLifecycleDates(task, "in-progress", now);
|
|
672
|
+
task.statusLog = [...(task.statusLog ?? []), {
|
|
673
|
+
id: createTaskId(),
|
|
674
|
+
date: now,
|
|
675
|
+
fromStatus: previousStatus,
|
|
676
|
+
toStatus: "in-progress",
|
|
677
|
+
title: `${previousStatus} → in-progress`,
|
|
678
|
+
description: "",
|
|
679
|
+
}];
|
|
680
|
+
task.updatedAt = now;
|
|
681
|
+
current.updatedAt = now;
|
|
682
|
+
updated = task;
|
|
683
|
+
return current;
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
const approvedDeviation = project.workDeviations.find((deviation) => deviation.temporaryTaskId === existing.id && deviation.state === "approved");
|
|
687
|
+
if (approvedDeviation)
|
|
688
|
+
await store.setWorkDeviationState(approvedDeviation.id, "active", now);
|
|
689
|
+
const resumedDeviation = project.workDeviations
|
|
690
|
+
.filter((deviation) => deviation.resumeTaskId === existing.id
|
|
691
|
+
&& (deviation.state === "resume-required" || deviation.state === "resolved"))
|
|
692
|
+
.sort((left, right) => right.createdAt.localeCompare(left.createdAt))[0];
|
|
693
|
+
if (resumedDeviation)
|
|
694
|
+
await store.setWorkDeviationState(resumedDeviation.id, "resumed", now);
|
|
695
|
+
await store.syncTaskStatusRollup(phase.id);
|
|
696
|
+
await store.writeGenerated();
|
|
697
|
+
hub()?.broadcast({ type: "phases-updated", data: { action: "task-started", id: phase.id, phaseId: phase.id, featureId: phase.featureId ?? "", taskId } });
|
|
698
|
+
hub()?.broadcast({ type: "plan-rendered", data: {} });
|
|
699
|
+
await store.appendActivity("task_status", existing.id, `Task ${existing.id} → in-progress`);
|
|
700
|
+
return c.json(updated ?? existing);
|
|
701
|
+
});
|
|
637
702
|
app.get(route("/tasks/:id"), async (c) => {
|
|
638
703
|
const taskId = c.req.param("id");
|
|
639
704
|
const phases = await store.loadAllPhases();
|
|
@@ -655,8 +720,8 @@ function createApiApp(store, hubRef, apiPrefix = "", uiConfig, isBusy) {
|
|
|
655
720
|
const existing = phase.tasks.find((t) => t.id === taskId);
|
|
656
721
|
if (!existing)
|
|
657
722
|
return c.json({ error: "task not found" }, 404);
|
|
658
|
-
if (body.status && body.status !== existing.status && (
|
|
659
|
-
return c.json({ error: "
|
|
723
|
+
if (body.status && body.status !== existing.status && (body.status === "in-progress" || body.status === "paused" || existing.status === "paused")) {
|
|
724
|
+
return c.json({ error: "Task start/resume transitions require POST /tasks/:id/start so lifecycle state, checkpoints, and return stacks remain consistent." }, 400);
|
|
660
725
|
}
|
|
661
726
|
// Validate motivation requirement for status transitions. The Web UI is the
|
|
662
727
|
// human supervisor and is exempt (X-Planner-Source: web-ui) — agents calling
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-plan/server",
|
|
3
|
-
"version": "0.2.22-next.
|
|
3
|
+
"version": "0.2.22-next.3",
|
|
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.22-next.
|
|
44
|
+
"@agent-plan/core": "0.2.22-next.3"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@types/ws": "^8.18.0"
|