@agentistics/mcp 2.203.0 → 2.204.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.
@@ -23,6 +23,43 @@ function liveDeliveryQuery(a) {
23
23
  return q.toString() ? `?${q}` : "";
24
24
  }
25
25
 
26
+ // delivery-calendar-args.ts
27
+ var CALENDAR_STAGES = ["queue", "blocked", "running", "qa", "adjust", "leader", "merge", "ci", "published"];
28
+ var CALENDAR_PRIORITIES = ["urgent", "high", "medium", "low"];
29
+ function list(v, allowed) {
30
+ const items = (Array.isArray(v) ? v : typeof v === "string" ? v.split(",") : []).filter((x) => typeof x === "string").map((x) => x.trim()).filter(Boolean);
31
+ return (allowed ? items.filter((x) => allowed.includes(x)) : items).join(",");
32
+ }
33
+ function deliveryCalendarQuery(a) {
34
+ const q = new URLSearchParams;
35
+ const task = typeof a?.task === "string" ? a.task.trim() : "";
36
+ if (task)
37
+ q.set("task", task);
38
+ const subtask = typeof a?.subtask === "string" ? a.subtask.trim() : "";
39
+ if (subtask)
40
+ q.set("subtask", subtask);
41
+ for (const [key, value] of [
42
+ ["version", list(a?.version)],
43
+ ["stage", list(a?.stage, CALENDAR_STAGES)],
44
+ ["harness", list(a?.harness)],
45
+ ["priority", list(a?.priority, CALENDAR_PRIORITIES)]
46
+ ])
47
+ if (value)
48
+ q.set(key, value);
49
+ for (const key of ["from", "to"]) {
50
+ const v = a?.[key];
51
+ if (typeof v === "string" && v.trim())
52
+ q.set(key, v.trim());
53
+ }
54
+ if (a?.all === true)
55
+ q.set("all", "1");
56
+ if (a?.confirmedOnly === true)
57
+ q.set("confirmed", "1");
58
+ if (a?.format === "ics")
59
+ q.set("format", "ics");
60
+ return q.toString() ? `?${q}` : "";
61
+ }
62
+
26
63
  // ../core/src/local-models.ts
27
64
  var LOCAL_RUNTIME_PREFIXES = [
28
65
  "ollama",
@@ -967,6 +1004,7 @@ var AGENT_TOOL_POLICY = {
967
1004
  agentistics_task_claim: { ...TASKS, risk: "W", routes: ["POST /api/tasks/:ref/claim"], reason: "a lease that expires on its own and can be released" },
968
1005
  agentistics_task_activity: { ...TASKS, risk: "R", routes: ["GET /api/tasks/activity"], reason: "reads the board activity log" },
969
1006
  agentistics_live_delivery: { ...TASKS, risk: "R", routes: ["GET /api/tasks/live"], reason: "reads the live delivery line and the leaders band; changes nothing" },
1007
+ agentistics_delivery_calendar: { ...TASKS, risk: "R", routes: ["GET /api/deliveries/calendar"], reason: "reads the delivery calendar (dates, versions, ETAs); changes nothing" },
970
1008
  agentistics_task_edit: { ...TASKS, risk: "W", routes: ["POST /api/tasks/:ref"], reason: "edits task fields; reversible by another edit" },
971
1009
  agentistics_task_session: {
972
1010
  ...TASKS,
@@ -1008,7 +1046,7 @@ var AGENT_TOOL_POLICY = {
1008
1046
  agentistics_task_phase: {
1009
1047
  ...TASKS,
1010
1048
  risk: "W",
1011
- routes: ["GET /api/deliveries", "GET /api/deliveries/:subtask", "POST /api/deliveries/:subtask", "POST /api/deliveries/release", "POST /api/deliveries/reconcile"],
1049
+ routes: ["GET /api/deliveries", "GET /api/deliveries/:subtask", "POST /api/deliveries/:subtask", "POST /api/deliveries/release", "POST /api/deliveries/reconcile", "POST /api/deliveries/antigas"],
1012
1050
  reason: "reads or moves a delivery through the fixed phase table; release declares which pieces a release shipped (leader/owner only; the host still reads the green run and the tag); reconcile backfills merged/released pieces (dry run unless apply, leader/owner only); a skipped phase is refused (422 fase_pulada) and every gate is checked by the host from evidence, never from the caller"
1013
1051
  },
1014
1052
  agentistics_task_stage: {
@@ -1224,6 +1262,10 @@ var GO_WINDOW_MS = {
1224
1262
  function isFlowRunId(id) {
1225
1263
  return /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(id);
1226
1264
  }
1265
+ // ../core/src/deliveryCalendar.ts
1266
+ var BRT_OFFSET_MS = -3 * 3600000;
1267
+ var RECENT_ACTIVITY_MS = 24 * 3600000;
1268
+ var BLIP_MS = 15 * 60000;
1227
1269
  // ../core/src/vaultPassword.ts
1228
1270
  var VAULT_PASSWORD_RULES = ["length", "upper", "special", "digit"];
1229
1271
  var VAULT_PASSWORD_MIN_LENGTH = 9;
@@ -1721,6 +1763,7 @@ function planLimitsTool(args, body) {
1721
1763
  const offBySchedule = (body.hiddenFromAgents ?? []).filter((b) => b?.agentUse && !b.agentUse.on).map((b) => ({ harness: b.harness, account: b.account, reason: b.agentUse.reason }));
1722
1764
  return {
1723
1765
  budgets,
1766
+ unmeasured: body.unmeasured ?? [],
1724
1767
  harnesses: body.harnesses ?? {},
1725
1768
  freeSlots: body.freeSlots ?? (budgets.length ? Math.max(...aggregates.map((b) => b.freeSlots)) : 0),
1726
1769
  freeSlotsByHarness: body.freeSlotsByHarness ?? Object.fromEntries(aggregates.map((b) => [b.harness, b.freeSlots])),
@@ -2152,6 +2195,12 @@ var CATALOG = [
2152
2195
  { id: "sessions.highlights", label: "Highlights", category: "sessions", defaultW: 12, defaultH: 6, minW: 6, minH: 3, description: "Record-breaking sessions" },
2153
2196
  { id: "sessions.recent", label: "Recent sessions", category: "sessions", defaultW: 12, defaultH: 7, minW: 6, minH: 4, description: "List of most recent sessions" }
2154
2197
  ];
2198
+ async function apiGetText(path) {
2199
+ const res = await fetch(`${API}${path}`);
2200
+ if (!res.ok)
2201
+ throw new Error(`agentistics API ${path} → HTTP ${res.status}`);
2202
+ return res.text();
2203
+ }
2155
2204
  async function apiGet(path) {
2156
2205
  const res = await fetch(`${API}${path}`);
2157
2206
  if (!res.ok)
@@ -2485,7 +2534,7 @@ var TOOLS = [
2485
2534
  type: "object",
2486
2535
  properties: {
2487
2536
  task: { type: "string", description: "A task id or part of its title." },
2488
- stage: { type: "string", enum: ["queue", "running", "qa", "adjust", "leader", "merge", "published"] },
2537
+ stage: { type: "string", enum: ["queue", "blocked", "running", "qa", "adjust", "leader", "merge", "ci", "completed", "published"] },
2489
2538
  stalledOnly: { type: "boolean", description: "Only deliveries that need a person, lost an agent or are blocked." },
2490
2539
  tab: { type: "string", enum: ["active", "queue", "published", "all"], description: "The screen's tab: active (Em andamento), queue (Na fila), published (Publicado) or all (Tudo). Default all." },
2491
2540
  period: { type: "string", enum: ["24h", "7d", "30d", "all"], description: "How far back Publicado reaches. Default 24h." },
@@ -2550,13 +2599,38 @@ var TOOLS = [
2550
2599
  description: "Delete a task and its comments, subtasks, files and links. The SESSIONS filed under it are kept — deleting a board entry never deletes work.",
2551
2600
  inputSchema: { type: "object", properties: { ref: { type: "string" } }, required: ["ref"] }
2552
2601
  },
2602
+ {
2603
+ name: "agentistics_delivery_calendar",
2604
+ description: "BETA. The DELIVERY CALENDAR — when each piece of work started, when it is expected to ship, which release version it rides and when a version really went out; the same source and rules as the \"Calendário de entregas\" screen (`agentop flow calendario` prints the same). Returns `pieces` (task, subtask, stage, `version`, harness/model, priority, `startedAtMs`, `stageEta` and `publishEta` — `kind: none` means there is NO estimate: say so, never invent a time — `publishedAtMs`, `dueDate`, `confirmed`, `late`), `versions` (each with `state` published|planned, `atMs` = the real publication or the LATEST piece estimate, `basis` published|estimate|partial|none, the pieces and the count per stage) and `marks` (an account's usage window renewing, a task's due day). Times are epoch ms; day arguments are BRT days (America/Sao_Paulo). By default only pieces of tasks being worked on now; pass `all` for the history too. Filters: `task` (id or part of the title), `subtask`, `version` (one or a list), `stage`, `harness`, `priority`, `from`/`to` (yyyy-MM-dd or an ISO instant — keeps what touches the period), `confirmedOnly` (published or a medium/high-confidence estimate). `format: \"ics\"` returns the filtered view as an .ics file instead of JSON.",
2605
+ inputSchema: {
2606
+ type: "object",
2607
+ properties: {
2608
+ task: { type: "string", description: "A task id or part of its title." },
2609
+ subtask: { type: "string", description: "A subtask id." },
2610
+ version: { anyOf: [{ type: "string" }, { type: "array", items: { type: "string" } }], description: "A release version (2.202.0) or a list." },
2611
+ stage: { anyOf: [{ type: "string" }, { type: "array", items: { type: "string" } }], description: "queue, blocked, running, qa, adjust, leader, merge, ci, published — one or a list." },
2612
+ harness: { anyOf: [{ type: "string" }, { type: "array", items: { type: "string" } }] },
2613
+ priority: { anyOf: [{ type: "string" }, { type: "array", items: { type: "string" } }], description: "urgent, high, medium, low." },
2614
+ from: { type: "string", description: "Start of the period: yyyy-MM-dd (BRT) or an ISO instant." },
2615
+ to: { type: "string", description: "End of the period (inclusive)." },
2616
+ all: { type: "boolean", description: "Include pieces of tasks not being worked on now (history)." },
2617
+ confirmedOnly: { type: "boolean", description: "Only published pieces or those with a medium/high-confidence estimate." },
2618
+ format: { type: "string", enum: ["json", "ics"] }
2619
+ },
2620
+ required: []
2621
+ }
2622
+ },
2553
2623
  {
2554
2624
  name: "agentistics_task_phase",
2555
2625
  description: "FLUXO.CICLO-COMPLETO — the minute `tick` also moves a piece in revisao_lider or pr_merge to ci BY ITSELF once its PR is merged (found from the piece's PR number, branch, the PR containing the sha QA approved, or its author worktree's branch; the merge gates `delecoes` + `mergeado` still run, and a refusal leaves the piece where it is with the reason), publishes ci pieces from the FIRST tag that contains the merge, and reminds the LIVE leader of the task (never the owner) of a piece waiting on them for 30 min, then every 2 h, at most 3 times. `get` with a `subtaskId` returns `tickReason`: why the tick has not moved it. `reconcile` (no `subtaskId`; `apply` true to write) is the one-shot BACKFILL: every piece in revisao_lider/pr_merge/ci matched to its merged PR and the first release tag containing it — a report of what moves and what cannot be proven, with the reason. " + "`tick` also enables the mandatory owner-request/placement flows through the official engine switches and reads canonical pedidos; after 10 minutes without complete staging it wakes the current live task leader, including after a handoff or restart, and never asks the owner. " + "Queue actions: `dequeue` withdraws a queued piece with a required free-text `reason` (task leader or owner only), keeps the draft/history, and refuses dispatch until explicitly restaged; `tick` reconciles stale queued pieces against board review/done/abandoned and records a comment. Vacancy counts live backend processes; lost/exited/closed sessions reserve no slots. " + "FLUXO.ENTREGA-DSL — read or move a DELIVERY (one subtask) through its fixed phases: fila → executando → qa → (ajuste ⇄ qa) → revisao_lider → pr_merge → ci → publicado, plus bloqueado (from any phase, back to the stored origin only). Any transition outside that table is REFUSED (422 `fase_pulada`) with a sentence naming what is missing — executando → revisao_lider, ajuste → revisao_lider and every other skip included. The gates each edge needs are run BY THE SERVER from evidence (predispatch, vaga, salvo = sha on origin per ls-remote, qa-modelo = QA model ≠ author model from the registry and never Sonnet over Sonnet, cabeca = the pushed branch is still at the sha QA tested, delecoes = no file deleted outright by the PR, mergeado = gh says the PR is MERGED, the merge commit is on origin/main and the PR head is the sha QA approved — the merge sha is READ FROM THE PR, never from you, release = the batch's version tag exists AND the release.yml run that produced it is green, read in the repository the release recorded); salvo needs every check run on the pushed head to have concluded green (pending or absent refuse); you never pass proof. `action`: `get` (default; omit `subtaskId` to list every delivery) | `phase` (`to` + what that edge reads: `verdict` APROVADO/REPROVADO + `findings` from qa, `reviewedSha` = the sha QA approved for revisao_lider → pr_merge, `detail` for a request for change or a failure reason) | `gate` (`name`: run ONE gate and record its evidence) | `block` (`reason` one of dependencia, pedido_de_bloqueio, limite, maquina, externo, fora_das_autorizacoes; `text`) | `unblock` (`detail`; the leader of the task or the owner — an owner-decision block only the owner) | `step` (`step` 1..9: the step of the current phase, for the Live %. The Live already DERIVES the step from real signals — a session open, a file edit, a test run, a commit, the gates, the PR — so report only when you know better; the card shows the larger of the two and says which it is. Works for a legacy piece with no delivery record too: only the board's `step` event is written, nothing is adopted into the flow) | `configure` (the LEADER of the task or the owner only; `patch`: versionTarget, humanGates [phases needing the owner's approval — skipped and recorded as 'pulado: modo autônomo' while autonomous mode is on], leaderSessionId, pr, tag, allowDeletions {paths, reason}; the QA and author sessions are never settable — the host records them from the sessions it opened and the registry) | `approve` (`phase`, `decision` approve|reject, `note`: answers a human gate the owner was ASKED about; a session identity is deliberately not sent, the owner answers through this same door as the Live card button and `agentop flow approve`) | `stage-run` (predispatch + vaga gates, then start the staged session and move to executando) | `merge` (delecoes gate, squash-merge the PR, move to ci; a failure goes back to revisao_lider) | `release` (the LEADER of the task or the owner DECLARES what a release contains: `version` x.y.z, `mergeSha` = the commit on main carrying it (information only; 40 characters, or a short sha the server resolves), optional `repo` = owner/name (default agentistics/agentistics), `subtaskIds` = every piece in it; no `subtaskId`. Each piece gets its record (a legacy one is adopted), versionTarget/mergeSha/tag/repo, goes to ci and then to publicado as soon as the tag `v<version>` exists and the release.yml run that produced it is green — read by the server from the TAG, not from the sha — with the release's own publish time; a declared piece is never sent back to revisao_lider by the tick (a red tag run keeps it in ci and wakes the leader once); done/abandoned/blocked/unknown/other-task pieces refuse the whole batch, which is written in ONE store write; a second run changes nothing). In autonomous mode nothing here ever asks or waits for the owner.",
2556
2626
  inputSchema: {
2557
2627
  type: "object",
2558
2628
  properties: {
2559
- action: { type: "string", enum: ["get", "phase", "gate", "block", "unblock", "dequeue", "tick", "step", "configure", "approve", "stage-run", "merge", "release", "reconcile"] },
2629
+ action: { type: "string", enum: ["get", "phase", "gate", "block", "unblock", "dequeue", "tick", "step", "configure", "approve", "stage-run", "merge", "release", "reconcile", "antigas"] },
2630
+ antigasAction: { type: "string", enum: ["publish", "archive", "conclude"], description: "antigas: 'conclude' (the screen's one click) completes the pieces with a session and archives the ones without; add `preview` to read the counts without changing anything. 'publish' marks the old record-less pieces published (optional `version`), 'archive' abandons them with an optional `reason`. Targets: `subtaskIds`, or `all` = every piece the reconcile classifies as antiga. Never deletes; a leader or the owner" },
2631
+ preview: { type: "boolean", description: "antigas conclude: only count what the click would do (concluded vs archived); changes nothing" },
2632
+ all: { type: "boolean", description: 'antigas: act on every old piece in the group "Antigas sem registro" (answers from the board at once; a piece the last reconcile proved is left out)' },
2633
+ expect: { type: "number", description: "antigas: the size of the group you saw; a different size refuses (409 count_changed) and nothing changes" },
2560
2634
  apply: { type: "boolean", description: "reconcile: write the moves (a leader of the task, or the owner). Absent/false = dry run: the report only" },
2561
2635
  subtaskId: { type: "string" },
2562
2636
  version: { type: "string", description: "release: the version the pieces shipped in, x.y.z" },
@@ -2572,7 +2646,7 @@ var TOOLS = [
2572
2646
  phase: { type: "string", description: "approve: the phase whose human gate is answered" },
2573
2647
  decision: { type: "string", enum: ["approve", "reject"] },
2574
2648
  note: { type: "string" },
2575
- reason: { type: "string", description: "dequeue: required free-text audit reason (leader only); block: dependencia | pedido_de_bloqueio | limite | maquina | externo | fora_das_autorizacoes" },
2649
+ reason: { type: "string", description: "dequeue: required free-text audit reason (leader only); block: dependencia | pedido_de_bloqueio | limite | maquina | externo | fora_das_autorizacoes; antigas archive: why (kept in the comment)" },
2576
2650
  text: { type: "string" },
2577
2651
  step: { type: "number" },
2578
2652
  patch: { type: "object" }
@@ -3201,6 +3275,13 @@ async function callTool(req) {
3201
3275
  const body = await apiSend("DELETE", `/api/tasks/${encodeURIComponent(ref)}`);
3202
3276
  return { content: [{ type: "text", text: JSON.stringify(body, null, 2) }] };
3203
3277
  }
3278
+ case "agentistics_delivery_calendar": {
3279
+ const q = deliveryCalendarQuery(args);
3280
+ if (args?.format === "ics")
3281
+ return { content: [{ type: "text", text: await apiGetText(`/api/deliveries/calendar${q}`) }] };
3282
+ const body = await apiGet(`/api/deliveries/calendar${q}`);
3283
+ return { content: [{ type: "text", text: JSON.stringify(body, null, 2) }] };
3284
+ }
3204
3285
  case "agentistics_task_phase": {
3205
3286
  const a = args ?? {};
3206
3287
  const action = typeof a.action === "string" ? a.action : "get";
@@ -3222,6 +3303,19 @@ async function callTool(req) {
3222
3303
  const body = await apiSend("POST", "/api/deliveries/reconcile", { apply: a.apply === true, session: sessionProof(process.env) });
3223
3304
  return { content: [{ type: "text", text: JSON.stringify(body, null, 2) }] };
3224
3305
  }
3306
+ if (action === "antigas") {
3307
+ const body = await apiSend("POST", "/api/deliveries/antigas", {
3308
+ action: a.antigasAction,
3309
+ ids: a.subtaskIds,
3310
+ all: a.all === true,
3311
+ preview: a.preview === true,
3312
+ expect: a.expect,
3313
+ version: a.version,
3314
+ reason: a.reason,
3315
+ session: sessionProof(process.env)
3316
+ });
3317
+ return { content: [{ type: "text", text: JSON.stringify(body, null, 2) }] };
3318
+ }
3225
3319
  if (action !== "tick" && (typeof a.subtaskId !== "string" || !a.subtaskId))
3226
3320
  throw new Error("subtaskId is required");
3227
3321
  const { subtaskId: _s, action: _a, ...rest } = a;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentistics/mcp",
3
- "version": "2.203.0",
3
+ "version": "2.204.0",
4
4
  "description": "Agentistics MCP server — Claude Code analytics for Claude Desktop and Claude Code",
5
5
  "type": "module",
6
6
  "main": "./dist/agentistics-mcp.js",