@agent-plan/mcp 0.4.0 → 0.4.2

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":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AA4BA,KAAK,UAAU,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AA2LrI;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,UAAU,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAUzE;AA83FD,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAItD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AA4BA,KAAK,UAAU,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AA2LrI;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,UAAU,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAUzE;AAi4FD,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAItD"}
package/dist/index.js CHANGED
@@ -1484,7 +1484,7 @@ server.registerTool("planner-task-show", {
1484
1484
  const summary = `${found.task.title} — ${taskCompositeRef(found.task, found.phase, features)}${found.task.shortId ? ` · ${found.task.shortId}` : ""} (${found.task.status}; phase ${formatPhaseRef(found.phase.number, featureNumberOfPhase(found.phase, features))})`;
1485
1485
  if (!full)
1486
1486
  return text(summary);
1487
- const project = await st.loadProject();
1487
+ const project = await st.loadProject(plannerSessionId);
1488
1488
  const pendingDeviation = found.task.status === "done" || found.task.status === "canceled" || found.task.status === "rejected"
1489
1489
  ? undefined
1490
1490
  : project.workDeviations
@@ -1707,7 +1707,8 @@ server.registerTool("planner-task-update", {
1707
1707
  checklist: z.array(z.string()).optional().describe("Replace the task checklist (implementation steps, plain strings). Ticks carry over by exact title match, and by position when the new list is the same length (so renaming an item keeps its tick); an item that cannot be matched loses its tick and that loss is reported. Agents should tick steps via planner-task-checklist-toggle, not write DONE in titles, and use planner-task-checklist-add/remove for granular edits."),
1708
1708
  subtasks: z.array(z.object({ id: z.string().optional(), title: z.string().min(1), description: z.string().optional(), status: z.enum(STATUS_VALUES).optional() })).optional().describe("Replace subtasks; existing IDs must belong to this task and omitted IDs are planner-generated."),
1709
1709
  },
1710
- }, async ({ task: ref, title, status, description, descriptionRef: rawDescriptionRef, notes, decisions, motivation, priority, checklist, subtasks }) => {
1710
+ }, async ({ task: ref, title, status, description, descriptionRef: rawDescriptionRef, notes, decisions, motivation, priority, checklist, subtasks }, extra) => {
1711
+ const plannerSessionId = plannerSessionIdFor(extra);
1711
1712
  const st = await requireStore();
1712
1713
  const found = findTaskByRef(await st.loadAllPhases(), (await st.loadFeatures()).features, ref);
1713
1714
  if (!found)
@@ -1813,7 +1814,7 @@ server.registerTool("planner-task-update", {
1813
1814
  let resumeNotice = "";
1814
1815
  let resumeRequired;
1815
1816
  if (status && status !== "in-progress" && status !== found.task.status) {
1816
- const deviation = (await st.loadProject()).workDeviations
1817
+ const deviation = (await st.loadProject(plannerSessionId)).workDeviations
1817
1818
  .filter((entry) => (entry.state === "approved" || entry.state === "active") && entry.temporaryTaskId === found.task.id)
1818
1819
  .sort((left, right) => right.createdAt.localeCompare(left.createdAt))[0];
1819
1820
  if (deviation) {
@@ -1999,17 +2000,17 @@ server.registerTool("planner-task-delete", {
1999
2000
  server.registerTool("planner-task-recommend", {
2000
2001
  description: "Return the harness-agnostic next-work chain: active task if present, otherwise the lowest-priority ready feature → phase → task, plus bounded typed claims. Only persisted resume-ready handoffs are actionable; Markdown prose and terminal archives are not authority. Does not start or block work.",
2001
2002
  inputSchema: {},
2002
- }, async () => {
2003
+ }, async (_args, extra) => {
2004
+ const plannerSessionId = plannerSessionIdFor(extra);
2003
2005
  const st = await requireStore();
2004
- const [features, phases, project, resume, handoffs, archivedHandoffs] = await Promise.all([
2006
+ const [features, phases, resume, handoffs, archivedHandoffs] = await Promise.all([
2005
2007
  st.loadFeatures(),
2006
2008
  st.loadAllPhases(),
2007
- st.loadProject(),
2008
- st.loadResume(),
2009
+ st.loadResume(plannerSessionId),
2009
2010
  st.listHandoffs(),
2010
2011
  st.listArchivedHandoffs(),
2011
2012
  ]);
2012
- const result = recommendNextWork(features.features, phases, project.workDeviations, resume?.currentPhaseId, "", {
2013
+ const result = recommendNextWork(features.features, phases, await st.listAllWorkDeviations(), resume?.currentPhaseId, plannerSessionId, {
2013
2014
  handoffs: handoffs.map((handoff) => ({
2014
2015
  compositeRef: handoff.compositeRef,
2015
2016
  firstLine: handoff.firstLine,
@@ -2023,13 +2024,14 @@ server.registerTool("planner-task-recommend", {
2023
2024
  server.registerTool("planner-task-deviation", {
2024
2025
  description: "Record a user-approved temporary task deviation. It preserves the recommended/resume task and never starts, pauses, or blocks work; use normal lifecycle tools for those transitions.",
2025
2026
  inputSchema: { temporary_task: z.string().min(1), resume_task: z.string().min(1).optional(), reason: z.string().min(1) },
2026
- }, async ({ temporary_task, resume_task, reason }) => {
2027
+ }, async ({ temporary_task, resume_task, reason }, extra) => {
2028
+ const plannerSessionId = plannerSessionIdFor(extra);
2027
2029
  const st = await requireStore();
2028
- const [features, phases, project, focus] = await Promise.all([st.loadFeatures(), st.loadAllPhases(), st.loadProject(), st.loadResume()]);
2030
+ const [features, phases, focus] = await Promise.all([st.loadFeatures(), st.loadAllPhases(), st.loadResume(plannerSessionId)]);
2029
2031
  const temporary = findTaskByRef(phases, features.features, temporary_task);
2030
2032
  if (!temporary)
2031
2033
  return text(`Task not found: ${temporary_task}`);
2032
- const selected = recommendNextTask(features.features, phases, project.workDeviations, focus?.currentPhaseId);
2034
+ const selected = recommendNextTask(features.features, phases, await st.listAllWorkDeviations(), focus?.currentPhaseId, plannerSessionId);
2033
2035
  const resume = resume_task ? findTaskByRef(phases, features.features, resume_task) : selected.candidate;
2034
2036
  if (!resume)
2035
2037
  return text(`No resume task is available. Provide resume_task explicitly. ${selected.reason}`);
@@ -2044,7 +2046,7 @@ server.registerTool("planner-task-deviation", {
2044
2046
  requestedBy: "user", approvedBy: "user", state: "approved",
2045
2047
  createdAt: timestamp, activatedAt: "", resumeRequiredAt: "", resolvedAt: "", resumedAt: "",
2046
2048
  };
2047
- await st.addWorkDeviation(record);
2049
+ await st.addWorkDeviation(record, plannerSessionId);
2048
2050
  return writeAndSummarize(st, `✅ Approved deviation: ${taskCompositeRef(temporary.task, temporary.phase, features.features)} temporarily overrides ${taskCompositeRef(resume.task, resume.phase, features.features)}. Resume target retained.`, { deviation: record });
2049
2051
  });
2050
2052
  server.registerTool("planner-task-pause", {
@@ -2074,7 +2076,7 @@ server.registerTool("planner-task-pause", {
2074
2076
  invalidateReads(plannerSessionId);
2075
2077
  const checkpointed = await st.pauseTask(found.phase.id, found.task.id, snapshot);
2076
2078
  await st.syncTaskStatusRollup(found.phase.id);
2077
- const activeDeviation = (await st.loadProject()).workDeviations
2079
+ const activeDeviation = (await st.loadProject(plannerSessionId)).workDeviations
2078
2080
  .filter((deviation) => (deviation.state === "approved" || deviation.state === "active")
2079
2081
  && deviation.temporaryTaskId === found.task.id)
2080
2082
  .sort((left, right) => right.createdAt.localeCompare(left.createdAt))[0];
@@ -2108,7 +2110,7 @@ server.registerTool("planner-task-switch", {
2108
2110
  }, async ({ from_task, to_task, reason, what_was_being_done, resume_location, how_to_resume, switched_by }, extra) => {
2109
2111
  const plannerSessionId = plannerSessionIdFor(extra);
2110
2112
  const st = await requireStore();
2111
- const [featuresDoc, phases, project, focus] = await Promise.all([st.loadFeatures(), st.loadAllPhases(), st.loadProject(), st.loadResume()]);
2113
+ const [featuresDoc, phases, project, focus] = await Promise.all([st.loadFeatures(), st.loadAllPhases(), st.loadProject(plannerSessionId), st.loadResume(plannerSessionId)]);
2112
2114
  const features = featuresDoc.features;
2113
2115
  const source = findTaskByRef(phases, features, from_task);
2114
2116
  const target = findTaskByRef(phases, features, to_task);
@@ -2172,7 +2174,7 @@ server.registerTool("planner-task-switch", {
2172
2174
  resumeLocation: resume_location, howToResume: how_to_resume,
2173
2175
  relatedTaskId: target.task.id, pausedAt: timestamp, pausedBy: switched_by?.trim() ?? "",
2174
2176
  };
2175
- const selection = recommendNextTask(features, phases, project.workDeviations, focus?.currentPhaseId, plannerSessionId);
2177
+ const selection = recommendNextTask(features, phases, await st.listAllWorkDeviations(), focus?.currentPhaseId, plannerSessionId);
2176
2178
  const record = {
2177
2179
  id: crypto.randomUUID(), recommendedTaskId: selection.candidate?.task.id ?? source.task.id,
2178
2180
  temporaryTaskId: target.task.id, resumeTaskId: source.task.id, reason, snapshot,
@@ -2222,7 +2224,7 @@ server.registerTool("planner-task-switch", {
2222
2224
  });
2223
2225
  }
2224
2226
  targetStarted = true;
2225
- await st.addWorkDeviation(record);
2227
+ await st.addWorkDeviation(record, plannerSessionId);
2226
2228
  if (target.task.pauseSnapshot) {
2227
2229
  const resumedDeviation = project.workDeviations
2228
2230
  .filter((deviation) => deviation.resumeTaskId === target.task.id
@@ -2306,7 +2308,7 @@ server.registerTool("planner-task-start", {
2306
2308
  const featureRef = parentFeature ? formatFeatureRef(parentFeature.number) : "";
2307
2309
  if (found.task.status === "done")
2308
2310
  return taskStartError(taskStartDenied("TASK_DONE", `Task ${taskRef} is done and was not reopened.`, [`Use planner-task-reopen with task=${taskRef} and confirmed=true after explicit user confirmation.`, `Retry planner-task-start ${taskRef} only if reopening is not the intended operation.`], { taskId: found.task.id }));
2309
- const project = await st.loadProject();
2311
+ const project = await st.loadProject(plannerSessionId);
2310
2312
  // Targeted stale-context refresh (P102(F005)/T404): task-start delivery
2311
2313
  // stays scoped to feature/phase/task context, but a session that already
2312
2314
  // did a full planner-load gets a non-blocking advisory when project-level
@@ -2350,11 +2352,11 @@ server.registerTool("planner-task-start", {
2350
2352
  const phaseOrderAdvisory = higherPriorityOpenPhaseAdvisory(higherPriorityPhase);
2351
2353
  return text(`✅ Task already started: ${taskRef} — ${found.task.title} (in-progress)\nstarted: true${projectContextAdvisory}${phaseOrderAdvisory}`, { ...outcome, task: found.task, projectContextStale: projectContextReadState === "stale", higherPriorityOpenPhase: higherPriorityPhase });
2352
2354
  }
2353
- const [phases, focus] = await Promise.all([st.loadAllPhases(), st.loadResume()]);
2355
+ const [phases, focus] = await Promise.all([st.loadAllPhases(), st.loadResume(plannerSessionId)]);
2354
2356
  const eligibility = checkExplicitTaskStart(features, phases, found.task.id, project.workDeviations);
2355
2357
  if (!eligibility.eligible)
2356
2358
  return taskStartError(taskStartDenied("START_NOT_ALLOWED", eligibility.reason, ["Resolve the reported task readiness condition, then retry planner-task-start."], { taskId: found.task.id }), { eligibility });
2357
- const selection = recommendNextTask(features, phases, project.workDeviations, focus?.currentPhaseId, plannerSessionId);
2359
+ const selection = recommendNextTask(features, phases, await st.listAllWorkDeviations(), focus?.currentPhaseId, plannerSessionId);
2358
2360
  if (selection.kind === "conflict") {
2359
2361
  return taskStartError(taskStartDenied("ACTIVE_TASK_CONFLICT", selection.reason, ["Pause or reconcile the active tasks.", `Retry planner-task-start ${taskRef}.`], { taskId: found.task.id }), { selection });
2360
2362
  }
@@ -2464,7 +2466,8 @@ server.registerTool("planner-task-complete", {
2464
2466
  motivation: z.string().optional().describe("Required when force=true overrides unchecked checklist items: why the checklist no longer matches the work."),
2465
2467
  description_update: z.string().min(10).describe("Required evidence: shipped work, verification level including partial verification, remaining/unverified work, files, decisions, and updated code references."),
2466
2468
  },
2467
- }, async ({ task: ref, force, motivation, description_update }) => {
2469
+ }, async ({ task: ref, force, motivation, description_update }, extra) => {
2470
+ const plannerSessionId = plannerSessionIdFor(extra);
2468
2471
  const st = await requireStore();
2469
2472
  const found = findTaskByRef(await st.loadAllPhases(), (await st.loadFeatures()).features, ref);
2470
2473
  if (!found)
@@ -2510,7 +2513,7 @@ server.registerTool("planner-task-complete", {
2510
2513
  return phase;
2511
2514
  });
2512
2515
  const clearedRef = await st.syncTaskStatusRollup(found.phase.id);
2513
- const completedDeviation = (await st.loadProject()).workDeviations
2516
+ const completedDeviation = (await st.loadProject(plannerSessionId)).workDeviations
2514
2517
  .filter((deviation) => (deviation.state === "approved" || deviation.state === "active") && deviation.temporaryTaskId === found.task.id)
2515
2518
  .sort((left, right) => right.createdAt.localeCompare(left.createdAt))[0];
2516
2519
  if (completedDeviation)
@@ -3167,7 +3170,7 @@ server.registerTool("planner-load", {
3167
3170
  const plannerSkill = await st.syncPlannerSkill();
3168
3171
  await st.syncGrillMeSkill();
3169
3172
  const web = await ensureWebStarted();
3170
- const recap = await buildRecap(st, web, { harness: "mcp" });
3173
+ const recap = await buildRecap(st, web, { harness: "mcp", sessionId: plannerSessionId });
3171
3174
  const plan = await st.loadAll();
3172
3175
  // Explicit planner load must deliver the complete project-level context
3173
3176
  // (P102(F005)/T404), attested through the same lossless contract used
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-plan/mcp",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "private": false,
5
5
  "description": "MCP server for Agent Plan, exposing planner-* tools over stdio.",
6
6
  "license": "MIT",
@@ -43,8 +43,8 @@
43
43
  "dependencies": {
44
44
  "@modelcontextprotocol/sdk": "^1.17.0",
45
45
  "zod": "^3.24.0",
46
- "@agent-plan/server": "0.4.0",
47
- "@agent-plan/core": "0.4.0"
46
+ "@agent-plan/server": "0.4.2",
47
+ "@agent-plan/core": "0.4.2"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "tsc -p tsconfig.json",