@rubytech/create-maxy 1.0.881 → 1.0.884
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/package.json +1 -1
- package/payload/platform/lib/graph-mcp/dist/index.js +45 -0
- package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-mcp/src/index.ts +47 -0
- package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js +57 -9
- package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js.map +1 -1
- package/payload/platform/lib/graph-write/dist/conversation-provenance.d.ts +26 -0
- package/payload/platform/lib/graph-write/dist/conversation-provenance.d.ts.map +1 -0
- package/payload/platform/lib/graph-write/dist/conversation-provenance.js +81 -0
- package/payload/platform/lib/graph-write/dist/conversation-provenance.js.map +1 -0
- package/payload/platform/lib/graph-write/dist/index.d.ts +38 -16
- package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-write/dist/index.js +75 -35
- package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-write/src/__tests__/action-provenance-gate.test.ts +59 -9
- package/payload/platform/lib/graph-write/src/conversation-provenance.ts +140 -0
- package/payload/platform/lib/graph-write/src/index.ts +76 -35
- package/payload/platform/lib/mcp-eager/dist/index.d.ts +61 -0
- package/payload/platform/lib/mcp-eager/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/mcp-eager/dist/index.js +49 -0
- package/payload/platform/lib/mcp-eager/dist/index.js.map +1 -0
- package/payload/platform/lib/mcp-eager/src/index.ts +78 -0
- package/payload/platform/lib/mcp-eager/tsconfig.json +8 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/mcp/dist/__tests__/plugin-read-skill-resolution.test.js +26 -2
- package/payload/platform/plugins/admin/mcp/dist/__tests__/plugin-read-skill-resolution.test.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +36 -33
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts +5 -1
- package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js +24 -8
- package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js.map +1 -1
- package/payload/platform/plugins/contacts/PLUGIN.md +8 -0
- package/payload/platform/plugins/contacts/mcp/dist/index.js +10 -9
- package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js +17 -2
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js.map +1 -1
- package/payload/platform/plugins/docs/references/internals.md +15 -2
- package/payload/platform/plugins/docs/references/plugins-guide.md +2 -0
- package/payload/platform/plugins/email/mcp/dist/index.js +10 -9
- package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/PLUGIN.md +5 -3
- package/payload/platform/plugins/memory/mcp/dist/index.js +10 -9
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +18 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +9 -8
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/tasks/mcp/dist/index.js +15 -14
- package/payload/platform/plugins/tasks/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/index.js +4 -3
- package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/index.js +9 -8
- package/payload/platform/plugins/workflows/mcp/dist/index.js.map +1 -1
- package/payload/platform/scripts/__tests__/logs-read-prefix.sh +341 -0
- package/payload/platform/scripts/logs-read.sh +108 -41
- package/payload/platform/scripts/logs-read.test.sh +6 -2
- package/payload/platform/templates/agents/admin/IDENTITY.md +1 -1
- package/payload/premium-plugins/real-agency/BUNDLE.md +1 -1
- package/payload/server/chunk-5PQU2HW2.js +11672 -0
- package/payload/server/chunk-ECAQVMRA.js +759 -0
- package/payload/server/chunk-K7S5T4VG.js +11534 -0
- package/payload/server/cloudflare-task-tracker-JNZXLW32.js +22 -0
- package/payload/server/maxy-edge.js +2 -2
- package/payload/server/server.js +38 -6
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { initStderrTee } from "../../../../lib/mcp-stderr-tee/dist/index.js";
|
|
2
2
|
initStderrTee("admin");
|
|
3
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { eagerTool } from "../../../../lib/mcp-eager/dist/index.js";
|
|
4
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
6
|
import { z } from "zod";
|
|
6
7
|
import { readFile, writeFile } from "node:fs/promises";
|
|
@@ -217,7 +218,7 @@ function checkPort(port, timeoutMs = 1000) {
|
|
|
217
218
|
socket.once("timeout", () => { socket.destroy(); res(false); });
|
|
218
219
|
});
|
|
219
220
|
}
|
|
220
|
-
server
|
|
221
|
+
eagerTool(server, "system-status", "Check health of all Maxy platform services: Neo4j, Ollama, Cloudflare tunnel, crontab (Maxy cron entries), VNC, Chrome (CDP), specialist agents, and deployed brand identity.", {}, async () => {
|
|
221
222
|
const checks = {};
|
|
222
223
|
try {
|
|
223
224
|
// Task 580: NEO4J_URI must be explicit. The outer try/catch surfaces the
|
|
@@ -403,7 +404,7 @@ server.tool("system-status", "Check health of all Maxy platform services: Neo4j,
|
|
|
403
404
|
.join("\n");
|
|
404
405
|
return { content: [{ type: "text", text: formatted }] };
|
|
405
406
|
});
|
|
406
|
-
server
|
|
407
|
+
eagerTool(server, "public-hostname", "Resolve this account's canonical public hostname. Reads cloudflared ingress + alias-domains.json — the same files the platform server trusts to route. Returns a single deterministic answer; use this immediately after publish-site to construct the full URL.", {}, async () => {
|
|
407
408
|
const TAG = "[admin:public-hostname]";
|
|
408
409
|
try {
|
|
409
410
|
const result = resolvePublicHostname(CONFIG_DIR);
|
|
@@ -433,7 +434,7 @@ server.tool("public-hostname", "Resolve this account's canonical public hostname
|
|
|
433
434
|
};
|
|
434
435
|
}
|
|
435
436
|
});
|
|
436
|
-
server
|
|
437
|
+
eagerTool(server, "remote-auth-status", "Check whether the remote access password is configured. When not configured, emits a device-bound URL affordance (maxy-device-url fenced block) pointing at the password setup page — this URL opens on the device's own screen when the operator clicks it. The agent never constructs the password file path or runs shell commands — this tool is the single authority.", {}, async () => {
|
|
437
438
|
const TAG = "[remote-auth-status]";
|
|
438
439
|
const platformPort = parseInt(PLATFORM_PORT, 10);
|
|
439
440
|
const setupUrl = `http://${osHostname()}.local:${platformPort}/__remote-auth/setup`;
|
|
@@ -469,7 +470,7 @@ server.tool("remote-auth-status", "Check whether the remote access password is c
|
|
|
469
470
|
};
|
|
470
471
|
}
|
|
471
472
|
});
|
|
472
|
-
server
|
|
473
|
+
eagerTool(server, "brand-settings", "Read the brand/styling configuration (name, tagline, colours, fonts, plugin sets). Reads from config/brand.json (stamped by the bundler at install time).", {}, async () => {
|
|
473
474
|
try {
|
|
474
475
|
const brandPath = resolve(PLATFORM_ROOT, "config", "brand.json");
|
|
475
476
|
if (!existsSync(brandPath)) {
|
|
@@ -549,7 +550,7 @@ server.tool("onboarding-plugin-options", "Return the fully-assembled multi-selec
|
|
|
549
550
|
return { content: [{ type: "text", text: `Failed: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
550
551
|
}
|
|
551
552
|
});
|
|
552
|
-
server
|
|
553
|
+
eagerTool(server, "account-manage", "Read the account configuration (tier, domains, settings).", {}, async () => {
|
|
553
554
|
try {
|
|
554
555
|
const config = await readAccountConfig();
|
|
555
556
|
return {
|
|
@@ -563,7 +564,7 @@ server.tool("account-manage", "Read the account configuration (tier, domains, se
|
|
|
563
564
|
};
|
|
564
565
|
}
|
|
565
566
|
});
|
|
566
|
-
server
|
|
567
|
+
eagerTool(server, "account-update", "Update a user-configurable setting in account.json. Valid fields: outputStyle (default|explanatory), thinkingView (default|expanded|collapsed), effort (low|medium|high|max|auto), adminModel (any Anthropic model ID), publicModel (any Anthropic model ID), defaultAgent (slug of an existing public agent, or empty string to clear). Changes take effect on the next session.", {
|
|
567
568
|
field: z.enum(["outputStyle", "thinkingView", "effort", "adminModel", "publicModel", "defaultAgent"]),
|
|
568
569
|
value: z.string(),
|
|
569
570
|
}, async ({ field, value }) => {
|
|
@@ -686,7 +687,7 @@ server.tool("plugin-toggle-enabled", "Enable or disable a plugin in this account
|
|
|
686
687
|
// ===================================================================
|
|
687
688
|
// Admin user management tools
|
|
688
689
|
// ===================================================================
|
|
689
|
-
server
|
|
690
|
+
eagerTool(server, "admin-add", "Add a new admin user to this account. Creates a device-level user entry (users.json) and adds them to this account's admins list (account.json). PIN must be at least 4 digits. If no PIN is provided, a unique 4-digit PIN is generated. Returns the userId and PIN to share with the new admin.\n\nIMPORTANT — retry behaviour: if the user already stated a specific PIN earlier in the conversation and a first admin-add call failed (e.g. tier cap reached, PIN collision), every retry MUST re-pass that PIN as the `pin` parameter. Omitting `pin` on the retry auto-generates a different 4-digit PIN, silently substituting what the user asked for.", {
|
|
690
691
|
name: z.string().describe("Display name for the new admin (stored on the AdminUser node in Neo4j)."),
|
|
691
692
|
pin: z.string().optional().describe("Optional PIN (minimum 4 digits). If omitted, a unique 4-digit PIN is generated."),
|
|
692
693
|
}, async ({ name, pin: rawPin }) => {
|
|
@@ -873,7 +874,7 @@ server.tool("admin-add", "Add a new admin user to this account. Creates a device
|
|
|
873
874
|
}],
|
|
874
875
|
};
|
|
875
876
|
});
|
|
876
|
-
server
|
|
877
|
+
eagerTool(server, "admin-remove", "Remove an admin from this account. Removes them from the account's admins list (account.json) and deletes the ADMIN_OF relationship in Neo4j. Does NOT remove the device-level user entry (they may admin other accounts). Cannot remove the last admin on the account.", {
|
|
877
878
|
userId: z.string().describe("The userId of the admin to remove (use admin-list to find userIds)"),
|
|
878
879
|
}, async ({ userId }) => {
|
|
879
880
|
const TAG = "[admin]";
|
|
@@ -949,7 +950,7 @@ server.tool("admin-remove", "Remove an admin from this account. Removes them fro
|
|
|
949
950
|
}],
|
|
950
951
|
};
|
|
951
952
|
});
|
|
952
|
-
server
|
|
953
|
+
eagerTool(server, "admin-list", "List all admins for this account with their names and roles.", {}, async () => {
|
|
953
954
|
const TAG = "[admin]";
|
|
954
955
|
let admins;
|
|
955
956
|
try {
|
|
@@ -991,7 +992,7 @@ server.tool("admin-list", "List all admins for this account with their names and
|
|
|
991
992
|
content: [{ type: "text", text: `Admins for this account:\n\n${lines.join("\n")}` }],
|
|
992
993
|
};
|
|
993
994
|
});
|
|
994
|
-
server
|
|
995
|
+
eagerTool(server, "admin-update-pin", "Update an existing admin user's PIN. Defaults to the calling admin if no userId is given. PIN must be at least 4 digits and unique across all users on the device. PINs are device-level: updating another admin's PIN does not require shared account membership — any admin on the device can rotate any other admin's PIN, matching the existing trust model used by admin-remove.", {
|
|
995
996
|
userId: z.string().optional().describe("The userId of the admin whose PIN to update. Defaults to the caller (the admin invoking this tool)."),
|
|
996
997
|
newPin: z.string().describe("The new PIN. Minimum 4 digits, no upper bound."),
|
|
997
998
|
}, async ({ userId: targetUserId, newPin }) => {
|
|
@@ -1254,7 +1255,7 @@ server.tool("agent-list", "List all public (non-admin) agents with their full co
|
|
|
1254
1255
|
};
|
|
1255
1256
|
}
|
|
1256
1257
|
});
|
|
1257
|
-
server
|
|
1258
|
+
eagerTool(server, "logs-read", "Read recent logs. Stream logs (type=agent-stream/error/session/public) are per-conversation — pass `conversationId` to retrieve a single conversation's log from first [spawn] to final [process-exit]. type=agent-stream: per-conversation tool-use/tool-result archive (every `[tool-use]` and `[tool-result]` pair with full input + output JSON, plus raw Claude stream-json, agent events, and MCP server stderr via tee). USE THIS when investigating what an agent ACTUALLY did with its tools — server.log only carries `[persist] tool-call persisted` markers, not bodies. (`type=system` is a backwards-compatible alias for the same archive.) type=session: SSE events sent to client. type=error: Claude subprocess stderr (raw — NODE_DEBUG HTTP/NET/UNDICI traces land in agent-stream via the stream tee, not here). type=heartbeat: platform event dispatcher (check-due-events cron). type=public: public agent diagnostic log. type=server: platform server log. type=mcp: MCP server stderr (per-plugin raw). type=vnc: VNC browser viewer lifecycle. sessionKey: grep legacy sessionKey-tagged lines across all logs (useful for pre-per-conversation artefacts). When conversationId is provided, reads the single per-conversation file for the requested type (or dumps all type files for that conversationId if type is omitted).", {
|
|
1258
1259
|
type: z.enum(["agent-stream", "system", "session", "error", "heartbeat", "public", "server", "mcp", "vnc"]).optional(),
|
|
1259
1260
|
lines: z.number().optional(),
|
|
1260
1261
|
sessionKey: z.string().optional(),
|
|
@@ -1491,7 +1492,7 @@ server.tool("logs-read", "Read recent logs. Stream logs (type=agent-stream/error
|
|
|
1491
1492
|
// autoDeliverUserPlugins. The agent supplies pluginName/skillName/body —
|
|
1492
1493
|
// path is computed by this tool from ACCOUNT_ID. Symmetric write counterpart
|
|
1493
1494
|
// to plugin-read (Task 916).
|
|
1494
|
-
server
|
|
1495
|
+
eagerTool(server, "store-skill", "Save an operator-authored skill on disk as part of an admin-managed plugin. " +
|
|
1495
1496
|
"The skill becomes immediately discoverable by the admin agent (and the public agent if publicEmbed=true). " +
|
|
1496
1497
|
"Path is computed internally from the active account; the agent supplies content + names only. " +
|
|
1497
1498
|
"Re-running for the same skillName overwrites in place (drops orphan reference files).", {
|
|
@@ -1614,7 +1615,7 @@ ${body}
|
|
|
1614
1615
|
return { content: [{ type: "text", text: `Failed to write skill: ${msg}` }], isError: true };
|
|
1615
1616
|
}
|
|
1616
1617
|
});
|
|
1617
|
-
server
|
|
1618
|
+
eagerTool(server, "plugin-read", "Read a plugin definition (PLUGIN.md) or one of its reference files.", {
|
|
1618
1619
|
pluginName: z.string().describe("Name of the plugin directory (e.g. 'sales', 'business-assistant')"),
|
|
1619
1620
|
file: z.string().optional().describe("Specific file to read (e.g. 'references/pricing.md'). Defaults to PLUGIN.md."),
|
|
1620
1621
|
}, async ({ pluginName, file }) => {
|
|
@@ -1622,12 +1623,14 @@ server.tool("plugin-read", "Read a plugin definition (PLUGIN.md) or one of its r
|
|
|
1622
1623
|
const resolvedFile = file ?? "PLUGIN.md";
|
|
1623
1624
|
const pluginPath = resolve(PLATFORM_ROOT, "plugins", pluginName, resolvedFile);
|
|
1624
1625
|
if (!existsSync(pluginPath)) {
|
|
1625
|
-
// Task 964 — when the agent
|
|
1626
|
-
//
|
|
1627
|
-
// the
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1626
|
+
// Task 964/1000 — when the agent's pluginName/file combination misses
|
|
1627
|
+
// a skill that DOES live under `plugins/*/skills/<slug>/SKILL.md`,
|
|
1628
|
+
// surface the corrected pluginName AND the canonical file path so
|
|
1629
|
+
// the next call is deterministic. Both wrong-`file` and wrong-`pluginName`
|
|
1630
|
+
// shapes feed through `computePluginReadHint`.
|
|
1631
|
+
const hint = computePluginReadHint(PLATFORM_ROOT, pluginName, resolvedFile);
|
|
1632
|
+
const hintText = hint ? ` Did you mean pluginName="${hint.pluginName}", file="${hint.file}"?` : "";
|
|
1633
|
+
console.log(`[plugin-read] ${pluginName}/${resolvedFile} not-found hint=${hint ? hint.pluginName : "none"}`);
|
|
1631
1634
|
return {
|
|
1632
1635
|
content: [{ type: "text", text: `Plugin file not found: ${pluginPath}.${hintText}` }],
|
|
1633
1636
|
isError: true,
|
|
@@ -1739,7 +1742,7 @@ server.tool("skill-find", "Find which plugin owns a skill by name. Walks plugins
|
|
|
1739
1742
|
// returns richer JSON so the doctrine grep
|
|
1740
1743
|
// `render-component.*"rendered"` resolves to a persistence-aware handler
|
|
1741
1744
|
// rather than a bare stub.
|
|
1742
|
-
server
|
|
1745
|
+
eagerTool(server, "render-component", "Render a pre-built UI component inline in the conversation. " +
|
|
1743
1746
|
"Call this instead of describing a UI — the component handles input collection. " +
|
|
1744
1747
|
"Wait for the user's response before continuing.", {
|
|
1745
1748
|
name: z.string().describe("Component name from the UI suite (e.g. single-select, confirm, info-card, form, progress)"),
|
|
@@ -1766,10 +1769,10 @@ server.tool("render-component", "Render a pre-built UI component inline in the c
|
|
|
1766
1769
|
}
|
|
1767
1770
|
return { content: [{ type: "text", text: "rendered" }] };
|
|
1768
1771
|
});
|
|
1769
|
-
server
|
|
1772
|
+
eagerTool(server, "session-reset", "Reset the current session. Compacts conversation history to memory, clears the visible conversation, " +
|
|
1770
1773
|
"and starts a fresh session with a new greeting. Call when the user asks to start a new session, " +
|
|
1771
1774
|
"clear the conversation, or start fresh.", {}, async () => ({ content: [{ type: "text", text: "reset" }] }));
|
|
1772
|
-
server
|
|
1775
|
+
eagerTool(server, "session-resume", "Resume a previous session. Loads the selected session's message history into the chat timeline " +
|
|
1773
1776
|
"and routes new messages to that conversation. Call after the user selects a session from the " +
|
|
1774
1777
|
"session-list results. Pass the conversationId from the selected session.", { conversationId: z.string().uuid().describe("The conversationId of the session to resume") }, async () => ({ content: [{ type: "text", text: "resumed" }] }));
|
|
1775
1778
|
server.tool("remote-auth-set-password", "Set the remote access password. Hashes with scrypt and writes to the platform's brand-specific config directory with mode 0600. " +
|
|
@@ -1813,7 +1816,7 @@ server.tool("remote-auth-set-password", "Set the remote access password. Hashes
|
|
|
1813
1816
|
};
|
|
1814
1817
|
}
|
|
1815
1818
|
});
|
|
1816
|
-
server
|
|
1819
|
+
eagerTool(server, "api-key-store", "Validate and store an Anthropic API key. Key must start with sk-ant- and be at least 90 characters. " +
|
|
1817
1820
|
"Writes to the platform's brand-specific config directory. Takes effect immediately for the public agent.", { apiKey: z.string() }, async ({ apiKey }) => {
|
|
1818
1821
|
try {
|
|
1819
1822
|
writeKey(apiKey);
|
|
@@ -1826,7 +1829,7 @@ server.tool("api-key-store", "Validate and store an Anthropic API key. Key must
|
|
|
1826
1829
|
};
|
|
1827
1830
|
}
|
|
1828
1831
|
});
|
|
1829
|
-
server
|
|
1832
|
+
eagerTool(server, "api-key-verify", "Verify the stored Anthropic API key works by making a minimal probe call. " +
|
|
1830
1833
|
"Returns one of: valid (key works, credits available), billing (key valid but credit balance too low — " +
|
|
1831
1834
|
"user must add credits at console.anthropic.com/settings/billing), auth_error (key rejected — invalid or revoked), " +
|
|
1832
1835
|
"missing (no key file found), error (could not verify — network issue or Anthropic outage). " +
|
|
@@ -1970,7 +1973,7 @@ function hasPublicEndpointConfigured() {
|
|
|
1970
1973
|
reason: "no entries in alias-domains.json and no public.* hostname in cloudflared/config.yml",
|
|
1971
1974
|
};
|
|
1972
1975
|
}
|
|
1973
|
-
server
|
|
1976
|
+
eagerTool(server, "anthropic-setup", "Deterministic state machine for Anthropic API key acquisition. " +
|
|
1974
1977
|
"Checks current state, advances as far as possible, and returns a structured JSON result. " +
|
|
1975
1978
|
"On first call (no consoleResult): first verifies a public-facing endpoint is configured " +
|
|
1976
1979
|
"(the key only powers the public agent); if not, returns status 'not_needed'. Otherwise " +
|
|
@@ -2309,7 +2312,7 @@ server.tool("onboarding-step9-mode", "Step 9 onboarding fork: record the operato
|
|
|
2309
2312
|
// ===================================================================
|
|
2310
2313
|
// Utility tools
|
|
2311
2314
|
// ===================================================================
|
|
2312
|
-
server
|
|
2315
|
+
eagerTool(server, "qr-generate", "Generate a QR code from text or a URL. Returns the QR code as a data URI (PNG) or saves to a file path.", {
|
|
2313
2316
|
data: z.string().describe("The text or URL to encode in the QR code"),
|
|
2314
2317
|
outputPath: z
|
|
2315
2318
|
.string()
|
|
@@ -2360,7 +2363,7 @@ server.tool("qr-generate", "Generate a QR code from text or a URL. Returns the Q
|
|
|
2360
2363
|
// ===================================================================
|
|
2361
2364
|
// WiFi management (Task 429)
|
|
2362
2365
|
// ===================================================================
|
|
2363
|
-
server
|
|
2366
|
+
eagerTool(server, "wifi", "Manage WiFi connections on this device. Actions: " +
|
|
2364
2367
|
"scan (list visible networks with signal strength and security), " +
|
|
2365
2368
|
"connect (join a network by SSID and password — warn user first if signal is below 30%), " +
|
|
2366
2369
|
"status (current WiFi connection details), " +
|
|
@@ -2936,7 +2939,7 @@ server.tool("premium-deliver", "Deliver a purchased premium plugin. Copies plugi
|
|
|
2936
2939
|
// ---------------------------------------------------------------------------
|
|
2937
2940
|
// file-attach — copy a generated file into the attachment store for download
|
|
2938
2941
|
// ---------------------------------------------------------------------------
|
|
2939
|
-
server
|
|
2942
|
+
eagerTool(server, "file-attach", "Attach a file from the account directory for delivery to the user. " +
|
|
2940
2943
|
"Copies the file into the attachment store and returns metadata for rendering " +
|
|
2941
2944
|
"a download component. The file must be within the account directory tree. " +
|
|
2942
2945
|
"After calling this tool, call render-component with name 'file-attachment' " +
|
|
@@ -3226,7 +3229,7 @@ async function dispatchApprovedAction(plugin, tool, args, timeoutMs = 30_000) {
|
|
|
3226
3229
|
await client.close().catch(() => { });
|
|
3227
3230
|
}
|
|
3228
3231
|
}
|
|
3229
|
-
server
|
|
3232
|
+
eagerTool(server, "action-pending", "List actions that are queued for human approval. Returns each pending action's ID, " +
|
|
3230
3233
|
"tool name, input summary, and when it was queued. Use this to review what the agent " +
|
|
3231
3234
|
"wanted to do before approving or rejecting.", {}, async () => {
|
|
3232
3235
|
const actions = readPendingActions();
|
|
@@ -3243,7 +3246,7 @@ server.tool("action-pending", "List actions that are queued for human approval.
|
|
|
3243
3246
|
content: [{ type: "text", text: `## Pending Actions (${actions.length})\n\n${lines.join("\n\n")}` }],
|
|
3244
3247
|
};
|
|
3245
3248
|
});
|
|
3246
|
-
server
|
|
3249
|
+
eagerTool(server, "action-approve", "Approve a pending action and execute it immediately. The original tool call is " +
|
|
3247
3250
|
"executed via the target plugin's MCP server. The result is returned and an audit " +
|
|
3248
3251
|
"record is written to Neo4j with approvalState: approved.", {
|
|
3249
3252
|
actionId: z.string().describe("The action ID to approve (from action-pending)"),
|
|
@@ -3313,7 +3316,7 @@ server.tool("action-approve", "Approve a pending action and execute it immediate
|
|
|
3313
3316
|
};
|
|
3314
3317
|
}
|
|
3315
3318
|
});
|
|
3316
|
-
server
|
|
3319
|
+
eagerTool(server, "action-reject", "Reject a pending action. The action is not executed. An audit record is written " +
|
|
3317
3320
|
"to Neo4j with approvalState: rejected.", {
|
|
3318
3321
|
actionId: z.string().describe("The action ID to reject (from action-pending)"),
|
|
3319
3322
|
reason: z.string().optional().describe("Optional reason for rejection"),
|
|
@@ -3354,7 +3357,7 @@ server.tool("action-reject", "Reject a pending action. The action is not execute
|
|
|
3354
3357
|
content: [{ type: "text", text: `Action rejected. ${action.toolName} will not be executed.${reasonSuffix}` }],
|
|
3355
3358
|
};
|
|
3356
3359
|
});
|
|
3357
|
-
server
|
|
3360
|
+
eagerTool(server, "action-edit", "Edit a pending action's input and then execute the modified version. The original " +
|
|
3358
3361
|
"input is preserved in the audit trail. Use this when the admin wants to modify the " +
|
|
3359
3362
|
"action (e.g., change the email subject) before approving.", {
|
|
3360
3363
|
actionId: z.string().describe("The action ID to edit (from action-pending)"),
|
|
@@ -3442,7 +3445,7 @@ server.tool("action-edit", "Edit a pending action's input and then execute the m
|
|
|
3442
3445
|
// so the returned score matches the on-disk state byte-for-byte. File-only
|
|
3443
3446
|
// access keeps the answer authoritative even if the Hono server is down.
|
|
3444
3447
|
// ---------------------------------------------------------------------------
|
|
3445
|
-
server
|
|
3448
|
+
eagerTool(server, "adherence-read", "Read the attention-weighted adherence ledger for an agent in this account. Returns the ledger JSON (rules with counts, rolling_7d, samples, streaks) and the score. Reads the file on every call — the value is authoritative and matches `{accountDir}/agents/<agent>/adherence-ledger.json` on disk. Use to answer 'what is my adherence score' or to surface the top offenders. Defaults to the admin agent when no name is supplied.", {
|
|
3446
3449
|
agent: z.string().optional().describe("Agent name to query. Defaults to 'admin'."),
|
|
3447
3450
|
}, async ({ agent }) => {
|
|
3448
3451
|
const TAG = "[adherence-read]";
|