@agentistics/mcp 2.74.2 → 2.76.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.
@@ -171,6 +171,51 @@ var DEFAULT_TEAM = Object.freeze({
171
171
  connections: Object.freeze([])
172
172
  });
173
173
  var SHARE_SOURCE_TYPES = new Set(["repo", "project", "none"]);
174
+ // ../core/src/redact.ts
175
+ var REDACTION = "[REDACTED]";
176
+ var PLACEHOLDER = /^(\*+|x+|\.+|-+|<[^>]*>|\{[^}]*\}|\$\{?[A-Z_][A-Z0-9_]*\}?|your[-_]?\w*|todo|changeme|none|null|nil|empty|redacted|\[redacted\])$/i;
177
+ function looksSecret(value) {
178
+ const v = value.trim().replace(/^["']|["']$/g, "");
179
+ if (v.length < 12)
180
+ return false;
181
+ if (PLACEHOLDER.test(v))
182
+ return false;
183
+ if (/^\d+$/.test(v))
184
+ return false;
185
+ if (/\s/.test(v))
186
+ return false;
187
+ const classes = [/[a-z]/.test(v), /[A-Z]/.test(v), /\d/.test(v), /[^A-Za-z0-9]/.test(v)].filter(Boolean).length;
188
+ return classes >= 2;
189
+ }
190
+ function guarded(whole, prefix, value) {
191
+ return looksSecret(value) ? `${prefix}${REDACTION}` : whole;
192
+ }
193
+ var STRONG = [
194
+ /-----BEGIN[^-]*PRIVATE KEY-----[\s\S]*?-----END[^-]*PRIVATE KEY-----/g,
195
+ /\bgithub_pat_[A-Za-z0-9_]{20,}/g,
196
+ /\bgh[pousr]_[A-Za-z0-9]{20,}/g,
197
+ /\bsk-ant-[A-Za-z0-9\-_]{16,}/g,
198
+ /\bsk-(?:proj-)?[A-Za-z0-9\-_]{20,}/g,
199
+ /\bxox[baprs]-[A-Za-z0-9-]{10,}/g,
200
+ /\bAIza[A-Za-z0-9\-_]{35}/g,
201
+ /\bAKIA[0-9A-Z]{16}\b/g,
202
+ /\beyJ[A-Za-z0-9\-_]{8,}\.eyJ[A-Za-z0-9\-_]{8,}\.[A-Za-z0-9\-_]{8,}/g,
203
+ /\bact1_[A-Za-z0-9\-_]+\.[A-Za-z0-9]{16,}/g
204
+ ];
205
+ var URI_CREDENTIAL = /\b([a-z][a-z0-9+.\-]*:\/\/[^\s:/@"']+:)([^\s@"']+)@/gi;
206
+ var ASSIGNMENT = /(^|[^A-Za-z0-9_])((?:[A-Za-z0-9]+[_-])*(?:pass(?:word|wd)?|pwd|secret|token|auth|credentials?|api[_-]?key|access[_-]?key|private[_-]?key)[a-z0-9_-]*\s*[:=]\s*)(["']?[^\s"',;]+["']?)/gi;
207
+ var BEARER = /\b(Bearer\s+)([A-Za-z0-9\-._~+/]{12,}=*)/g;
208
+ function redactSecrets(text) {
209
+ if (typeof text !== "string" || text === "")
210
+ return "";
211
+ let out = text;
212
+ for (const re of STRONG)
213
+ out = out.replace(re, REDACTION);
214
+ out = out.replace(URI_CREDENTIAL, (whole, prefix, pw) => PLACEHOLDER.test(pw) ? whole : `${prefix}${REDACTION}@`);
215
+ out = out.replace(ASSIGNMENT, (whole, lead, prefix, value) => guarded(whole, `${lead}${prefix}`, value));
216
+ out = out.replace(BEARER, (whole, prefix, value) => guarded(whole, prefix, value));
217
+ return out;
218
+ }
174
219
  // ../core/src/plan-catalog.ts
175
220
  var CLAUDE_PRICING = "https://claude.com/pricing";
176
221
  var COPILOT_PRICING = "https://github.com/features/copilot/plans";
@@ -678,6 +723,81 @@ var ANTHROPIC_EDIT_POLICY = Object.freeze({
678
723
  status: "declared-unverified",
679
724
  source: "CM §7 (docs/superpowers/specs/2026-09-25-runtime-context-manager-design.md), citing " + "Anthropic's documentation that editing earlier turns can invalidate later reasoning blocks " + "(signed signature_delta, R12 §1.3); assistant-text immutability is a product rule (CM §7 line 227)."
680
725
  });
726
+ // ../core/src/agentToolPolicy.ts
727
+ var TASKS = { capability: "localShell", host: true, central: "refuse", allowance: null };
728
+ var GROUPS = TASKS;
729
+ var DATA = { host: false, central: "allow", allowance: null };
730
+ var PREFS = DATA;
731
+ var AGENT_TOOL_POLICY = {
732
+ agentistics_tasks: { ...TASKS, risk: "R", routes: ["GET /api/tasks"], reason: "lists the board; changes nothing" },
733
+ agentistics_task: { ...TASKS, risk: "R", routes: ["GET /api/tasks/:ref"], reason: "reads one task (its comments are untrusted text, §4.8)" },
734
+ agentistics_task_create: { ...TASKS, risk: "W", routes: ["POST /api/tasks"], reason: "adds a card; undone by closing or deleting it" },
735
+ agentistics_task_status: { ...TASKS, risk: "W", routes: ["POST /api/tasks/:ref"], reason: "moves a card between statuses; moved back by the same call" },
736
+ agentistics_task_statuses: { ...TASKS, risk: "R", routes: ["GET /api/tasks/statuses"], reason: "reads the status vocabulary" },
737
+ agentistics_task_status_edit: {
738
+ ...TASKS,
739
+ risk: "W",
740
+ routes: ["DELETE /api/tasks/statuses/:id", "POST /api/tasks/statuses/:id", "POST /api/tasks/statuses"],
741
+ reason: "status vocabulary is configuration; the server refuses to remove a protected status (§3.5)"
742
+ },
743
+ agentistics_task_comment: { ...TASKS, risk: "W", routes: ["POST /api/tasks/:ref/comments"], reason: "appends a note; additive, destroys nothing" },
744
+ agentistics_task_subtask: { ...TASKS, risk: "W", routes: ["POST /api/tasks/:ref/subtasks"], reason: "adds or edits a subtask; reversible by another edit" },
745
+ agentistics_task_link: { ...TASKS, risk: "W", routes: ["POST /api/tasks/:ref/links"], reason: "adds or removes a link; reversible by the inverse call" },
746
+ agentistics_task_blocked_by: { ...TASKS, risk: "W", routes: ["POST /api/tasks/:ref"], reason: "sets a blocker; cleared by the same call" },
747
+ agentistics_task_next: { ...TASKS, risk: "R", routes: ["GET /api/tasks/next"], reason: "asks what is ready; claims nothing" },
748
+ agentistics_task_claim: { ...TASKS, risk: "W", routes: ["POST /api/tasks/:ref/claim"], reason: "a lease that expires on its own and can be released" },
749
+ agentistics_task_activity: { ...TASKS, risk: "R", routes: ["GET /api/tasks/activity"], reason: "reads the board activity log" },
750
+ agentistics_task_edit: { ...TASKS, risk: "W", routes: ["POST /api/tasks/:ref"], reason: "edits task fields; reversible by another edit" },
751
+ agentistics_task_session: {
752
+ ...TASKS,
753
+ risk: "W",
754
+ routes: ["POST /api/tasks/x/sessions", "POST /api/tasks/:ref/sessions"],
755
+ reason: "files or detaches a session under a task; filing is reversible"
756
+ },
757
+ agentistics_task_delete: {
758
+ ...TASKS,
759
+ risk: "D",
760
+ routes: ["DELETE /api/tasks/:ref"],
761
+ reason: "destroys a task with its history; re-classed D by the spec (§3.5), moves behind an intent in P2.6"
762
+ },
763
+ agentistics_session_groups: { ...GROUPS, risk: "R", routes: ["GET /api/session-groups"], reason: "lists the session folders" },
764
+ agentistics_session_group_create: { ...GROUPS, risk: "W", routes: ["POST /api/session-groups"], reason: "creates a folder; removed by delete" },
765
+ agentistics_session_group_edit: {
766
+ ...GROUPS,
767
+ risk: "W",
768
+ routes: [
769
+ "POST /api/session-groups/:group/sessions",
770
+ "POST /api/session-groups/ungroup",
771
+ "POST /api/session-groups/:group",
772
+ "DELETE /api/session-groups/:group"
773
+ ],
774
+ reason: "folders are labels: deleting one ungroups its sessions and touches no session (§5 defect 3: W, not D)"
775
+ },
776
+ agentistics_summary: { ...DATA, risk: "R", routes: ["GET /api/data"], reason: "reads computed metrics" },
777
+ agentistics_harnesses: { ...DATA, risk: "R", routes: ["GET /api/data"], reason: "reads computed metrics per harness" },
778
+ agentistics_projects: { ...DATA, risk: "R", routes: ["GET /api/data"], reason: "reads computed metrics per project" },
779
+ agentistics_sessions: { ...DATA, risk: "R", routes: ["GET /api/data"], reason: "reads session metadata (first_prompt is untrusted text, §4.8)" },
780
+ agentistics_costs: { ...DATA, risk: "R", routes: ["GET /api/data"], reason: "reads computed costs" },
781
+ agentistics_repos: { ...DATA, risk: "R", routes: ["GET /api/data"], reason: "reads computed metrics per repository" },
782
+ agentistics_component_catalog: { ...DATA, risk: "R", routes: [], reason: "returns a static list; calls nothing" },
783
+ agentistics_get_layouts: { ...PREFS, risk: "R", routes: ["GET /api/preferences"], reason: "reads the saved layouts" },
784
+ agentistics_create_layout: { ...PREFS, risk: "W", routes: ["GET /api/preferences", "PUT /api/preferences"], reason: "adds a layout; removed by delete_layout" },
785
+ agentistics_add_component: { ...PREFS, risk: "W", routes: ["GET /api/preferences", "PUT /api/preferences"], reason: "adds a widget; removed by remove_component" },
786
+ agentistics_remove_component: { ...PREFS, risk: "W", routes: ["GET /api/preferences", "PUT /api/preferences"], reason: "removes a widget; re-added by add_component" },
787
+ agentistics_set_active_layout: { ...PREFS, risk: "W", routes: ["GET /api/preferences", "PUT /api/preferences"], reason: "switches the active layout; switched back by the same call" },
788
+ agentistics_delete_layout: {
789
+ ...PREFS,
790
+ risk: "W",
791
+ routes: ["GET /api/preferences", "PUT /api/preferences"],
792
+ reason: "a layout is a saved arrangement of widgets, no data goes with it (§5 defect 3: W, not D)"
793
+ },
794
+ agentistics_build_layout: { ...PREFS, risk: "W", routes: ["GET /api/preferences", "PUT /api/preferences"], reason: "writes a layout; reversible by another build or delete" },
795
+ agentistics_export_pdf: { ...DATA, risk: "R", routes: [], reason: "composes a local dashboard URL; calls nothing and exports nothing itself" },
796
+ agentistics_tags: { ...DATA, risk: "R", routes: ["GET /api/tags"], reason: "reads aggregate-only tag cards" },
797
+ agentistics_tag_detail: { ...DATA, risk: "R", routes: ["GET /api/tags", "GET /api/tags/:id"], reason: "reads one tag aggregate (counts and sums only)" },
798
+ agentistics_team_status: { ...PREFS, risk: "R", routes: ["GET /api/preferences"], reason: "reads mode and connection endpoints; returns no token" },
799
+ agentistics_team_members: { ...DATA, central: "only", risk: "R", routes: ["GET /api/team/members"], reason: "reads the member list; central only" }
800
+ };
681
801
  // session-tokens.ts
682
802
  function sessionHarness(s) {
683
803
  return s.harness ?? "claude";
@@ -740,6 +860,224 @@ function harnessParam() {
740
860
  };
741
861
  }
742
862
 
863
+ // agent-audit.ts
864
+ import { createHash } from "node:crypto";
865
+ import * as nodeFs from "node:fs";
866
+ import { homedir } from "node:os";
867
+ import { dirname, join } from "node:path";
868
+ var AUDIT_ROTATE_BYTES = 10 * 1024 * 1024;
869
+ var AUDIT_KEEP_FILES = 3;
870
+ function defaultAuditPath(env = process.env) {
871
+ return join(env.AGENTISTICS_DIR ?? join(homedir(), ".agentistics"), "agent-audit.jsonl");
872
+ }
873
+ var TARGET_KEYS = [
874
+ "ref",
875
+ "id",
876
+ "taskId",
877
+ "subtaskId",
878
+ "sessionId",
879
+ "session",
880
+ "sessions",
881
+ "group",
882
+ "parentGroupId",
883
+ "blockedBy",
884
+ "componentId",
885
+ "instanceId",
886
+ "tag",
887
+ "remove"
888
+ ];
889
+ var ID_SHAPE = /^[A-Za-z0-9][A-Za-z0-9_.:@-]{0,79}$/;
890
+ var MAX_TARGETS = 20;
891
+ function asId(v) {
892
+ if (typeof v !== "string" || !ID_SHAPE.test(v))
893
+ return null;
894
+ return redactSecrets(v) === v ? v : null;
895
+ }
896
+ function targetsOf(args) {
897
+ const out = [];
898
+ let omitted = 0;
899
+ if (!args || typeof args !== "object")
900
+ return { targets: out, omitted };
901
+ const a = args;
902
+ for (const key of TARGET_KEYS) {
903
+ const raw = a[key];
904
+ if (raw === undefined || raw === null || typeof raw === "boolean")
905
+ continue;
906
+ for (const v of Array.isArray(raw) ? raw : [raw]) {
907
+ const id = asId(v);
908
+ if (id === null) {
909
+ omitted++;
910
+ continue;
911
+ }
912
+ if (out.length >= MAX_TARGETS) {
913
+ omitted++;
914
+ continue;
915
+ }
916
+ if (!out.includes(id))
917
+ out.push(id);
918
+ }
919
+ }
920
+ return { targets: out, omitted };
921
+ }
922
+ function canonical(v) {
923
+ if (Array.isArray(v))
924
+ return `[${v.map(canonical).join(",")}]`;
925
+ if (v && typeof v === "object") {
926
+ const o = v;
927
+ return `{${Object.keys(o).sort().map((k) => `${JSON.stringify(k)}:${canonical(o[k])}`).join(",")}}`;
928
+ }
929
+ return JSON.stringify(v ?? null);
930
+ }
931
+ function argsHash(args) {
932
+ return createHash("sha256").update(canonical(args ?? {})).digest("hex").slice(0, 16);
933
+ }
934
+ function label(v) {
935
+ if (typeof v !== "string")
936
+ return;
937
+ const t = v.trim().slice(0, 64);
938
+ if (!/^[\w.:@/ -]{1,64}$/.test(t))
939
+ return;
940
+ return redactSecrets(t) === t ? t : undefined;
941
+ }
942
+ function actorOf(client, args, naySession) {
943
+ const a = args && typeof args === "object" ? args : {};
944
+ const declared = label(a.actor) ?? label(a.by);
945
+ const nay = naySession !== undefined ? asId(naySession) ?? undefined : undefined;
946
+ return {
947
+ client: label(client?.name) ?? null,
948
+ clientVersion: label(client?.version) ?? null,
949
+ ...declared !== undefined ? { declared } : {},
950
+ ...nay !== undefined ? { naySession: nay } : {}
951
+ };
952
+ }
953
+ function outcomeOf(result) {
954
+ if (result === "unknown_tool")
955
+ return "unknown_tool";
956
+ if (!result.isError)
957
+ return "ok";
958
+ const m = /→ HTTP (\d{3})\b/.exec(result.errorText ?? "");
959
+ return m ? `http_${Number(m[1])}` : "error";
960
+ }
961
+ function isKnownTool(name) {
962
+ return Object.prototype.hasOwnProperty.call(AGENT_TOOL_POLICY, name);
963
+ }
964
+ function riskOf(name) {
965
+ return isKnownTool(name) ? AGENT_TOOL_POLICY[name].risk : null;
966
+ }
967
+ function buildToolAuditRecord(input) {
968
+ const known = isKnownTool(input.name);
969
+ const { targets, omitted } = targetsOf(input.args);
970
+ return {
971
+ v: 1,
972
+ kind: "tool",
973
+ at: input.at.toISOString(),
974
+ actor: actorOf(input.client, input.args, input.naySession),
975
+ tool: known ? input.name : null,
976
+ risk: riskOf(input.name),
977
+ targets,
978
+ ...omitted > 0 ? { targetsOmitted: omitted } : {},
979
+ argsHash: argsHash(input.args),
980
+ outcome: known ? outcomeOf(input.result) : "unknown_tool"
981
+ };
982
+ }
983
+ function hourOf(at) {
984
+ return at.toISOString().slice(0, 13);
985
+ }
986
+ function readCountRecord(hour, counts) {
987
+ return { v: 1, kind: "reads", hour, counts: { ...counts } };
988
+ }
989
+ function rotatedPath(path, n) {
990
+ return n === 0 ? path : `${path}.${n}`;
991
+ }
992
+ function createAgentAuditSink(opts = {}) {
993
+ const path = opts.path ?? defaultAuditPath();
994
+ const maxBytes = opts.maxBytes ?? AUDIT_ROTATE_BYTES;
995
+ const keep = Math.max(1, opts.keep ?? AUDIT_KEEP_FILES);
996
+ const fs = opts.fs ?? nodeFs;
997
+ const now = opts.now ?? (() => new Date);
998
+ let written = 0;
999
+ let writeFailures = 0;
1000
+ let pendingDropped = 0;
1001
+ let modeChecked = false;
1002
+ let readHour = null;
1003
+ let readCounts = {};
1004
+ function sizeOf(p) {
1005
+ try {
1006
+ return fs.statSync(p).size;
1007
+ } catch {
1008
+ return 0;
1009
+ }
1010
+ }
1011
+ function rotate() {
1012
+ fs.rmSync(rotatedPath(path, keep - 1), { force: true });
1013
+ for (let n = keep - 2;n >= 0; n--) {
1014
+ const from = rotatedPath(path, n);
1015
+ try {
1016
+ fs.renameSync(from, rotatedPath(path, n + 1));
1017
+ } catch (e) {
1018
+ if (e?.code !== "ENOENT")
1019
+ throw e;
1020
+ }
1021
+ }
1022
+ modeChecked = false;
1023
+ }
1024
+ function write(rec) {
1025
+ try {
1026
+ const line = `${JSON.stringify(pendingDropped > 0 ? { ...rec, dropped: pendingDropped } : rec)}
1027
+ `;
1028
+ if (!modeChecked)
1029
+ fs.mkdirSync(dirname(path), { recursive: true, mode: 448 });
1030
+ if (keep > 1 && sizeOf(path) + Buffer.byteLength(line) > maxBytes && sizeOf(path) > 0)
1031
+ rotate();
1032
+ else if (keep === 1 && sizeOf(path) + Buffer.byteLength(line) > maxBytes)
1033
+ fs.rmSync(path, { force: true });
1034
+ fs.appendFileSync(path, line, { mode: 384 });
1035
+ if (!modeChecked) {
1036
+ fs.chmodSync(path, 384);
1037
+ modeChecked = true;
1038
+ }
1039
+ written++;
1040
+ pendingDropped = 0;
1041
+ } catch {
1042
+ writeFailures++;
1043
+ pendingDropped++;
1044
+ }
1045
+ }
1046
+ function flushReads() {
1047
+ if (readHour === null || Object.keys(readCounts).length === 0)
1048
+ return;
1049
+ const rec = readCountRecord(readHour, readCounts);
1050
+ readHour = null;
1051
+ readCounts = {};
1052
+ write(rec);
1053
+ }
1054
+ return {
1055
+ recordCall(input) {
1056
+ try {
1057
+ const at = now();
1058
+ const hour = hourOf(at);
1059
+ if (readHour !== null && readHour !== hour)
1060
+ flushReads();
1061
+ if (riskOf(input.name) === "R") {
1062
+ readHour = hour;
1063
+ readCounts[input.name] = (readCounts[input.name] ?? 0) + 1;
1064
+ return;
1065
+ }
1066
+ write(buildToolAuditRecord({ ...input, at }));
1067
+ } catch {
1068
+ writeFailures++;
1069
+ pendingDropped++;
1070
+ }
1071
+ },
1072
+ flush() {
1073
+ flushReads();
1074
+ },
1075
+ stats() {
1076
+ return { written, writeFailures, pendingDropped };
1077
+ }
1078
+ };
1079
+ }
1080
+
743
1081
  // agentistics-mcp.ts
744
1082
  var API = process.env.AGENTISTICS_API ?? "http://localhost:47291";
745
1083
  var HARNESS_PARAM = harnessParam();
@@ -1310,7 +1648,30 @@ var TOOLS = [
1310
1648
  }
1311
1649
  ];
1312
1650
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
1651
+ var audit = createAgentAuditSink();
1652
+ process.on("exit", () => audit.flush());
1653
+ for (const sig of ["SIGINT", "SIGTERM"]) {
1654
+ process.on(sig, () => {
1655
+ audit.flush();
1656
+ process.exit(0);
1657
+ });
1658
+ }
1313
1659
  server.setRequestHandler(CallToolRequestSchema, async (req) => {
1660
+ const result = await callTool(req);
1661
+ const first = result.content?.[0];
1662
+ audit.recordCall({
1663
+ name: req.params.name,
1664
+ args: req.params.arguments,
1665
+ client: server.getClientVersion(),
1666
+ naySession: process.env.AGENTISTICS_NAY_SESSION,
1667
+ result: {
1668
+ isError: result.isError === true,
1669
+ errorText: first && first.type === "text" ? first.text : undefined
1670
+ }
1671
+ });
1672
+ return result;
1673
+ });
1674
+ async function callTool(req) {
1314
1675
  const { name, arguments: args } = req.params;
1315
1676
  try {
1316
1677
  switch (name) {
@@ -1989,6 +2350,6 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
1989
2350
  isError: true
1990
2351
  };
1991
2352
  }
1992
- });
2353
+ }
1993
2354
  var transport = new StdioServerTransport;
1994
2355
  await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentistics/mcp",
3
- "version": "2.74.2",
3
+ "version": "2.76.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",