@agentistics/mcp 2.104.4 → 2.105.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.
@@ -787,6 +787,8 @@ var HARNESS_MODELS = {
787
787
  opencode: []
788
788
  };
789
789
  var SPAWN_SPECS_MODEL_IDS = Object.fromEntries(Object.entries(HARNESS_MODELS).map(([h, opts]) => [h, opts.map((o) => o.id)]));
790
+ // ../core/src/taskThreads.ts
791
+ var LIVE = new Set(["working", "waiting", "waiting-approval"]);
790
792
  // ../core/src/attachments.ts
791
793
  var IMAGE_EXTENSIONS = new Set(["png", "jpg", "jpeg", "gif", "webp", "bmp", "svg", "avif"]);
792
794
  // ../core/src/pasteSanitize.ts
@@ -1314,20 +1316,50 @@ function createAgentAuditSink(opts = {}) {
1314
1316
  }
1315
1317
 
1316
1318
  // task-comment-args.ts
1317
- function taskCommentRequest(args) {
1319
+ function taskCommentRequest(args, session) {
1318
1320
  const a = args ?? {};
1319
1321
  const subtaskId = typeof a.subtaskId === "string" && a.subtaskId.trim() ? a.subtaskId.trim() : undefined;
1322
+ const threadId = typeof a.threadId === "string" && a.threadId.trim() ? a.threadId.trim() : undefined;
1323
+ const threadTitle = typeof a.threadTitle === "string" && a.threadTitle.trim() ? a.threadTitle.trim() : undefined;
1324
+ const threadKind = a.threadKind === "handback" || a.threadKind === "block" ? a.threadKind : undefined;
1325
+ const kind = a.kind === "handback" || a.kind === "block" ? a.kind : undefined;
1320
1326
  return {
1321
1327
  path: `/api/tasks/${encodeURIComponent(String(a.ref))}/comments`,
1322
1328
  payload: {
1323
1329
  body: typeof a.body === "string" ? a.body : "",
1324
1330
  author: typeof a.author === "string" && a.author ? a.author : "assistant",
1325
1331
  ...subtaskId ? { subtaskId } : {},
1326
- ...Array.isArray(a.attachments) && a.attachments.length > 0 ? { attachments: a.attachments } : {}
1332
+ ...Array.isArray(a.attachments) && a.attachments.length > 0 ? { attachments: a.attachments } : {},
1333
+ ...threadId ? { threadId } : threadTitle ? { newThread: { title: threadTitle, kind: threadKind ?? "handback" } } : {},
1334
+ ...session ? { session } : {},
1335
+ ...kind ? { kind } : {}
1327
1336
  }
1328
1337
  };
1329
1338
  }
1330
1339
 
1340
+ // session-proof.ts
1341
+ import { createHmac } from "node:crypto";
1342
+ import { readFileSync } from "node:fs";
1343
+ import { homedir as homedir2 } from "node:os";
1344
+ import { join as join2 } from "node:path";
1345
+ function sessionProofToken(key, id) {
1346
+ return createHmac("sha256", key).update(`agentop-session:${id}`).digest("hex");
1347
+ }
1348
+ function sessionProof(env, readKey = (p) => readFileSync(p, "utf8")) {
1349
+ const id = env.AGENTOP_MANAGED_ID;
1350
+ if (!id)
1351
+ return;
1352
+ const dir = env.AGENTISTICS_DIR || join2(env.HOME || homedir2(), ".agentistics");
1353
+ try {
1354
+ const key = Buffer.from(readKey(join2(dir, "session-identity.key")).trim(), "hex");
1355
+ if (key.length !== 32)
1356
+ return;
1357
+ return { id, token: sessionProofToken(key, id) };
1358
+ } catch {
1359
+ return;
1360
+ }
1361
+ }
1362
+
1331
1363
  // legacy-analytics.ts
1332
1364
  function legacySummary(data, harness) {
1333
1365
  const unified = !harness || harness === "all";
@@ -1875,7 +1907,7 @@ var TOOLS = [
1875
1907
  },
1876
1908
  {
1877
1909
  name: "agentistics_task_comment",
1878
- description: "BETA — Agentask (the task board) is new and still changing; its shapes may move between releases. Leave a comment on a task — or on ONE of its subtasks or subtask GROUPS by passing `subtaskId` (a group's own id is allowed; omit it to comment on the task itself). `body` may be empty when `attachments` is given. Comments carry attachments as REFERENCES into the chat's own attachment store (`{name, path}`; agentistics_task returns them on each comment with a `url` that serves the file) — there is no second store. Use it to tell the person and the other assistants what you did, what you found, or what you are blocked on; comment where the work is (the subtask you are on) rather than on the whole task. An unknown, deleted or other task's `subtaskId` is REFUSED with a sentence (422, `no_such_subtask` / `wrong_delivery`) — never silently filed on the task. Threads read downward: a subtask's thread is its own comments, a group's thread is its own plus its members', the task's is everything. The activity log names the target. `author` is free text — say who you are (e.g. 'claude:3f5f').",
1910
+ description: "BETA — Agentask (the task board) is new and still changing; its shapes may move between releases. Leave a comment on a task — or on ONE of its subtasks or subtask GROUPS by passing `subtaskId` (a group's own id is allowed; omit it to comment on the task itself). `body` may be empty when `attachments` is given. Comments carry attachments as REFERENCES into the chat's own attachment store (`{name, path}`; agentistics_task returns them on each comment with a `url` that serves the file) — there is no second store. Use it to tell the person and the other assistants what you did, what you found, or what you are blocked on; comment where the work is (the subtask you are on) rather than on the whole task. An unknown, deleted or other task's `subtaskId` is REFUSED with a sentence (422, `no_such_subtask` / `wrong_delivery`) — never silently filed on the task. Threads read downward: a subtask's thread is its own comments, a group's thread is its own plus its members', the task's is everything. The activity log names the target. `author` is free text — say who you are (e.g. 'claude:3f5f'). THREADS: a thread is a topic on the task; post into one with `threadId`, or open one with `threadTitle` (sessions: handbacks and blocks only). A thread is a RECORD, not a chat: a comment there reaches nobody by itself, so never wait for an answer in a thread. When you post in a thread you join it; the person may explicitly SEND a message from it, which arrives in your own chat starting `[Agentask · … · sent by the owner]` — answer there, in your chat, which is where conversations live. If you need something from the person, ask in your own chat as always.",
1879
1911
  inputSchema: {
1880
1912
  type: "object",
1881
1913
  properties: {
@@ -1886,6 +1918,24 @@ var TOOLS = [
1886
1918
  type: "string",
1887
1919
  description: "Optional target: a subtask or subtask GROUP id of this task (from agentistics_task's `subtasks`). Omit for the task itself."
1888
1920
  },
1921
+ threadId: {
1922
+ type: "string",
1923
+ description: "Optional: post INTO this thread (an id from agentistics_task's `threads`). Reply in the thread the person or another session already opened about this."
1924
+ },
1925
+ threadTitle: {
1926
+ type: "string",
1927
+ description: "Optional: OPEN a new thread with this title and post the comment as its first message. Sessions may open threads ONLY for a handback or a block (`threadKind`)."
1928
+ },
1929
+ threadKind: {
1930
+ type: "string",
1931
+ enum: ["handback", "block"],
1932
+ description: "The kind of the thread opened with `threadTitle`. Default handback."
1933
+ },
1934
+ kind: {
1935
+ type: "string",
1936
+ enum: ["handback", "block"],
1937
+ description: "Optional tag on THIS comment: a handback (you delivered something) or a block (you are stuck on something). Omit for a plain note."
1938
+ },
1889
1939
  attachments: {
1890
1940
  type: "array",
1891
1941
  description: "Optional files left with the comment, as {name, path} references to files already in agentop's attachments directory (the path the chat upload returns). Paths outside it are dropped. At most 10.",
@@ -2385,7 +2435,7 @@ async function callTool(req) {
2385
2435
  return { content: [{ type: "text", text: JSON.stringify(body, null, 2) }] };
2386
2436
  }
2387
2437
  case "agentistics_task_comment": {
2388
- const body = await apiSend("POST", `/api/tasks/${encodeURIComponent(String(args?.ref))}/comments`, taskCommentRequest(args).payload);
2438
+ const body = await apiSend("POST", `/api/tasks/${encodeURIComponent(String(args?.ref))}/comments`, taskCommentRequest(args, sessionProof(process.env)).payload);
2389
2439
  return { content: [{ type: "text", text: JSON.stringify(body, null, 2) }] };
2390
2440
  }
2391
2441
  case "agentistics_task_subtask": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentistics/mcp",
3
- "version": "2.104.4",
3
+ "version": "2.105.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",