@rubytech/create-maxy-code 0.1.170 → 0.1.171

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.
Files changed (37) hide show
  1. package/dist/__tests__/premium-mcp-discover.test.js +42 -0
  2. package/dist/lib/premium-mcp-discover.js +9 -2
  3. package/package.json +1 -1
  4. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.d.ts +51 -0
  5. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.d.ts.map +1 -0
  6. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.js +196 -0
  7. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.js.map +1 -0
  8. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/package.json +7 -0
  9. package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts +3 -0
  10. package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts.map +1 -0
  11. package/payload/premium-plugins/writer-craft/mcp/dist/index.js +257 -0
  12. package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -0
  13. package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.d.ts +14 -0
  14. package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.d.ts.map +1 -0
  15. package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.js +47 -0
  16. package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.js.map +1 -0
  17. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.d.ts +42 -0
  18. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.d.ts.map +1 -0
  19. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.js +54 -0
  20. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.js.map +1 -0
  21. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts +36 -0
  22. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -0
  23. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js +225 -0
  24. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js.map +1 -0
  25. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts +26 -0
  26. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts.map +1 -0
  27. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js +74 -0
  28. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js.map +1 -0
  29. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts +22 -0
  30. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -0
  31. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js +102 -0
  32. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -0
  33. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.d.ts +14 -0
  34. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.d.ts.map +1 -0
  35. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.js +84 -0
  36. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.js.map +1 -0
  37. package/payload/premium-plugins/writer-craft/mcp/package-lock.json +1327 -0
@@ -83,3 +83,45 @@ test("findPremiumMcpDirs: skips bundle missing plugins/ subdir", () => {
83
83
  rmSync(dir, { recursive: true, force: true });
84
84
  }
85
85
  });
86
+ test("findPremiumMcpDirs: discovers standalone MCP at premium-plugins/<bundle>/mcp/", () => {
87
+ const dir = mkdtempSync(join(tmpdir(), "premium-mcp-"));
88
+ try {
89
+ makeTree(dir, {
90
+ "premium-plugins/writer-craft/mcp/package.json": "{}",
91
+ });
92
+ assert.deepEqual(findPremiumMcpDirs(dir), [
93
+ join(dir, "premium-plugins/writer-craft/mcp"),
94
+ ]);
95
+ }
96
+ finally {
97
+ rmSync(dir, { recursive: true, force: true });
98
+ }
99
+ });
100
+ test("findPremiumMcpDirs: standalone + bundle-sub coexist under different bundles", () => {
101
+ const dir = mkdtempSync(join(tmpdir(), "premium-mcp-"));
102
+ try {
103
+ makeTree(dir, {
104
+ "premium-plugins/writer-craft/mcp/package.json": "{}",
105
+ "premium-plugins/real-agent/plugins/loop/mcp/package.json": "{}",
106
+ });
107
+ assert.deepEqual(findPremiumMcpDirs(dir), [
108
+ join(dir, "premium-plugins/real-agent/plugins/loop/mcp"),
109
+ join(dir, "premium-plugins/writer-craft/mcp"),
110
+ ]);
111
+ }
112
+ finally {
113
+ rmSync(dir, { recursive: true, force: true });
114
+ }
115
+ });
116
+ test("findPremiumMcpDirs: ignores standalone bundle with no mcp/ dir", () => {
117
+ const dir = mkdtempSync(join(tmpdir(), "premium-mcp-"));
118
+ try {
119
+ makeTree(dir, {
120
+ "premium-plugins/teaching/PLUGIN.md": "---\nname: teaching\n---\n",
121
+ });
122
+ assert.deepEqual(findPremiumMcpDirs(dir), []);
123
+ }
124
+ finally {
125
+ rmSync(dir, { recursive: true, force: true });
126
+ }
127
+ });
@@ -1,8 +1,9 @@
1
1
  // Pure premium-plugin MCP directory discovery.
2
2
  //
3
- // Schema (exact, two levels under premium-plugins):
3
+ // Two shapes:
4
4
  //
5
- // <installDir>/premium-plugins/<bundle>/plugins/<plugin>/mcp/package.json
5
+ // Standalone: <installDir>/premium-plugins/<bundle>/mcp/package.json
6
+ // Bundle sub: <installDir>/premium-plugins/<bundle>/plugins/<plugin>/mcp/package.json
6
7
  //
7
8
  // Recursive walks would match nested dirs that aren't real MCP plugins;
8
9
  // the explicit walk eliminates that class of false positive. Each level
@@ -18,6 +19,12 @@ export function findPremiumMcpDirs(installDir) {
18
19
  for (const bundle of readdirSync(root, { withFileTypes: true })) {
19
20
  if (!bundle.isDirectory())
20
21
  continue;
22
+ // Standalone shape: premium-plugins/<bundle>/mcp/
23
+ const standaloneMcp = join(root, bundle.name, "mcp");
24
+ if (existsSync(join(standaloneMcp, "package.json"))) {
25
+ out.push(standaloneMcp);
26
+ }
27
+ // Bundle-sub shape: premium-plugins/<bundle>/plugins/<plugin>/mcp/
21
28
  const pluginsRoot = join(root, bundle.name, "plugins");
22
29
  if (!existsSync(pluginsRoot))
23
30
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy-code",
3
- "version": "0.1.170",
3
+ "version": "0.1.171",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy-code": "./dist/index.js"
@@ -0,0 +1,51 @@
1
+ /**
2
+ * MCP server stderr tee — dual-destination log capture.
3
+ *
4
+ * Claude Code spawns MCP servers as child processes and consumes their stderr
5
+ * internally. The platform cannot intercept at the spawn level. Each server
6
+ * must tee its own stderr so diagnostic output is retrievable.
7
+ *
8
+ * ┌─────────────────────────┐
9
+ * │ MCP server process │
10
+ * │ │
11
+ * │ console.error("[x] ..") │
12
+ * │ │ │
13
+ * │ ▼ │
14
+ * │ patched stderr.write() │
15
+ * │ │ │
16
+ * │ ├──► original stderr (consumed by Claude Code — opaque)
17
+ * │ │
18
+ * │ ├──► mcp-{name}-stderr-{YYYY-MM-DD}.log (raw chunks, per-plugin)
19
+ * │ │
20
+ * │ └──► $STREAM_LOG_PATH (per-line, prefixed)
21
+ * │ "[<iso>] [mcp:{name}] <line>"
22
+ * └─────────────────────────┘
23
+ *
24
+ * $STREAM_LOG_PATH is set by the spawner (`getMcpServers` in `claude-agent.ts`)
25
+ * to the per-conversation stream log file. The MCP server code itself knows
26
+ * nothing about conversations — it just trusts the spawner's path. This is
27
+ * the scope boundary introduced: the tee is attached per spawn,
28
+ * not per MCP-server process lifetime. Servers spawned for conversation A
29
+ * write to conversation A's file; servers for B write to B's file.
30
+ *
31
+ * Every decision is logged via `[mcp-tee-*]` markers on both the target file
32
+ * and the original stderr so an investigator can confirm from the stream log
33
+ * which tees were wired up, which were skipped, and why.
34
+ */
35
+ /**
36
+ * Patch process.stderr.write to tee to:
37
+ * 1. Per-server raw log (`mcp-<serverName>-stderr-<date>.log` under LOG_DIR).
38
+ * 2. The per-conversation stream log at `STREAM_LOG_PATH` — per-line, prefixed.
39
+ * 3. The original stderr (consumed by Claude Code) — always preserved.
40
+ *
41
+ * LOG_DIR absent → skip per-server raw file (dev mode / tool discovery).
42
+ * STREAM_LOG_PATH absent → skip stream-log destination (older spawner or
43
+ * standalone invocation). In both absent cases, stderr works unchanged —
44
+ * a `[mcp-tee-skip]` marker is written to original stderr so the skip is
45
+ * visible to journalctl-level readers.
46
+ *
47
+ * Safe to call once at MCP server module load. Refused on second call to
48
+ * prevent stacking patches.
49
+ */
50
+ export declare function initStderrTee(serverName: string): void;
51
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAeH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CA8ItD"}
@@ -0,0 +1,196 @@
1
+ "use strict";
2
+ /**
3
+ * MCP server stderr tee — dual-destination log capture.
4
+ *
5
+ * Claude Code spawns MCP servers as child processes and consumes their stderr
6
+ * internally. The platform cannot intercept at the spawn level. Each server
7
+ * must tee its own stderr so diagnostic output is retrievable.
8
+ *
9
+ * ┌─────────────────────────┐
10
+ * │ MCP server process │
11
+ * │ │
12
+ * │ console.error("[x] ..") │
13
+ * │ │ │
14
+ * │ ▼ │
15
+ * │ patched stderr.write() │
16
+ * │ │ │
17
+ * │ ├──► original stderr (consumed by Claude Code — opaque)
18
+ * │ │
19
+ * │ ├──► mcp-{name}-stderr-{YYYY-MM-DD}.log (raw chunks, per-plugin)
20
+ * │ │
21
+ * │ └──► $STREAM_LOG_PATH (per-line, prefixed)
22
+ * │ "[<iso>] [mcp:{name}] <line>"
23
+ * └─────────────────────────┘
24
+ *
25
+ * $STREAM_LOG_PATH is set by the spawner (`getMcpServers` in `claude-agent.ts`)
26
+ * to the per-conversation stream log file. The MCP server code itself knows
27
+ * nothing about conversations — it just trusts the spawner's path. This is
28
+ * the scope boundary introduced: the tee is attached per spawn,
29
+ * not per MCP-server process lifetime. Servers spawned for conversation A
30
+ * write to conversation A's file; servers for B write to B's file.
31
+ *
32
+ * Every decision is logged via `[mcp-tee-*]` markers on both the target file
33
+ * and the original stderr so an investigator can confirm from the stream log
34
+ * which tees were wired up, which were skipped, and why.
35
+ */
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.initStderrTee = initStderrTee;
38
+ const node_fs_1 = require("node:fs");
39
+ const node_path_1 = require("node:path");
40
+ const node_string_decoder_1 = require("node:string_decoder");
41
+ // Marker on process.stderr.write so repeat calls to initStderrTee() are
42
+ // detected at runtime, not just warned about in the docstring. A second
43
+ // call would stack patches and double-log every chunk.
44
+ const INIT_MARKER = Symbol.for("maxy.mcpStderrTee.installed");
45
+ /**
46
+ * Patch process.stderr.write to tee to:
47
+ * 1. Per-server raw log (`mcp-<serverName>-stderr-<date>.log` under LOG_DIR).
48
+ * 2. The per-conversation stream log at `STREAM_LOG_PATH` — per-line, prefixed.
49
+ * 3. The original stderr (consumed by Claude Code) — always preserved.
50
+ *
51
+ * LOG_DIR absent → skip per-server raw file (dev mode / tool discovery).
52
+ * STREAM_LOG_PATH absent → skip stream-log destination (older spawner or
53
+ * standalone invocation). In both absent cases, stderr works unchanged —
54
+ * a `[mcp-tee-skip]` marker is written to original stderr so the skip is
55
+ * visible to journalctl-level readers.
56
+ *
57
+ * Safe to call once at MCP server module load. Refused on second call to
58
+ * prevent stacking patches.
59
+ */
60
+ function initStderrTee(serverName) {
61
+ const logDir = process.env.LOG_DIR;
62
+ const streamLogPath = process.env.STREAM_LOG_PATH;
63
+ // Refuse repeat patches — stacking them would double-log every chunk
64
+ // and corrupt the re-entrancy guard (originalWrite would capture the
65
+ // already-patched function on the second call).
66
+ if (process.stderr.write[INIT_MARKER])
67
+ return;
68
+ // Keep a direct reference to the unpatched writer. All diagnostic output
69
+ // from inside this module MUST go through originalWrite to avoid
70
+ // re-entering the patched writer (which would recurse on a tee failure).
71
+ const originalWrite = process.stderr.write.bind(process.stderr);
72
+ const tsPrefix = () => `[${new Date().toISOString()}]`;
73
+ const skipTee = (reason, destination) => {
74
+ originalWrite(`${tsPrefix()} [platform] [mcp-tee-skip] server=${serverName} destination=${destination} reason=${JSON.stringify(reason)}\n`);
75
+ };
76
+ // --- Destination 1: per-server raw file (optional, existing behaviour)
77
+ let perServerStream;
78
+ if (logDir) {
79
+ try {
80
+ (0, node_fs_1.mkdirSync)(logDir, { recursive: true });
81
+ const date = new Date().toISOString().slice(0, 10);
82
+ perServerStream = (0, node_fs_1.createWriteStream)((0, node_path_1.resolve)(logDir, `mcp-${serverName}-stderr-${date}.log`), { flags: "a" });
83
+ perServerStream.on("error", (err) => {
84
+ originalWrite(`${tsPrefix()} [platform] [mcp-tee-error] server=${serverName} destination=per-server reason=${JSON.stringify(err.message)}\n`);
85
+ });
86
+ }
87
+ catch (err) {
88
+ const msg = err instanceof Error ? err.message : String(err);
89
+ skipTee(msg, "per-server");
90
+ perServerStream = undefined;
91
+ }
92
+ }
93
+ else {
94
+ skipTee("LOG_DIR not set", "per-server");
95
+ }
96
+ // --- Destination 2: per-conversation stream log
97
+ let streamLogStream;
98
+ if (streamLogPath) {
99
+ try {
100
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(streamLogPath), { recursive: true });
101
+ const s = (0, node_fs_1.createWriteStream)(streamLogPath, { flags: "a" });
102
+ s.on("error", (err) => {
103
+ originalWrite(`${tsPrefix()} [platform] [mcp-tee-error] server=${serverName} destination=stream-log reason=${JSON.stringify(err.message)}\n`);
104
+ });
105
+ streamLogStream = s;
106
+ // Attach marker lands in the stream log itself so investigators can
107
+ // confirm per-conversation the tee was wired up.
108
+ s.write(`${tsPrefix()} [platform] [mcp-tee-attach] server=${serverName} streamLogPath=${streamLogPath}\n`);
109
+ }
110
+ catch (err) {
111
+ const msg = err instanceof Error ? err.message : String(err);
112
+ skipTee(msg, "stream-log");
113
+ streamLogStream = undefined;
114
+ }
115
+ }
116
+ else {
117
+ skipTee("STREAM_LOG_PATH not set", "stream-log");
118
+ }
119
+ // If neither tee target is available, leave stderr untouched — patching
120
+ // the writer to a no-op tee would still consume event-loop cycles on
121
+ // every write for zero observability gain.
122
+ if (!perServerStream && !streamLogStream) {
123
+ return;
124
+ }
125
+ // Line buffer — accumulates characters written to stderr so complete
126
+ // newline-terminated lines can be prefixed and emitted to the stream log.
127
+ // Partial chunks are held until a newline arrives (or beforeExit flushes).
128
+ let lineBuffer = "";
129
+ // StringDecoder buffers trailing UTF-8 continuation bytes across chunks.
130
+ // Without it, a multi-byte codepoint that straddles a write boundary would
131
+ // render as two U+FFFD replacement characters in the stream log. Only
132
+ // matters when a caller writes Uint8Array chunks directly — console.error
133
+ // produces strings — but plugins piping child-process stderr can hit this.
134
+ const utf8 = new node_string_decoder_1.StringDecoder("utf8");
135
+ const emitCompleteLinesToStreamLog = (chunk) => {
136
+ if (!streamLogStream)
137
+ return;
138
+ lineBuffer += chunk;
139
+ let newlineIndex;
140
+ // eslint-disable-next-line no-cond-assign
141
+ while ((newlineIndex = lineBuffer.indexOf("\n")) !== -1) {
142
+ const line = lineBuffer.slice(0, newlineIndex);
143
+ lineBuffer = lineBuffer.slice(newlineIndex + 1);
144
+ if (line.length === 0)
145
+ continue; // skip blank lines
146
+ if (streamLogStream.destroyed || streamLogStream.writableEnded)
147
+ continue;
148
+ streamLogStream.write(`${tsPrefix()} [mcp:${serverName}] ${line}\n`);
149
+ }
150
+ };
151
+ process.stderr.write = (chunk, ...args) => {
152
+ // 1. Per-server raw file — behaviour (no prefix).
153
+ if (perServerStream && !perServerStream.destroyed) {
154
+ perServerStream.write(chunk);
155
+ }
156
+ // 2. Stream log — per-line, prefixed.
157
+ if (streamLogStream) {
158
+ try {
159
+ const text = typeof chunk === "string"
160
+ ? chunk
161
+ : utf8.write(Buffer.from(chunk));
162
+ emitCompleteLinesToStreamLog(text);
163
+ }
164
+ catch (err) {
165
+ const msg = err instanceof Error ? err.message : String(err);
166
+ originalWrite(`${tsPrefix()} [platform] [mcp-tee-emit-error] server=${serverName} reason=${JSON.stringify(msg)}\n`);
167
+ }
168
+ }
169
+ // 3. Original stderr — Claude Code still gets what it's always got.
170
+ return originalWrite(chunk, ...args);
171
+ };
172
+ // Mark the patch so a second initStderrTee() call is refused at the top.
173
+ process.stderr.write[INIT_MARKER] = true;
174
+ // Flush any trailing unterminated segment on graceful event-loop drain.
175
+ // `beforeExit` can fire repeatedly: each async write to `streamLogStream`
176
+ // schedules I/O that keeps the event loop alive, which drains, which fires
177
+ // `beforeExit` again. With N MCP servers attached, the handler can emit
178
+ // thousands of detach lines per second. The `detached` flag gates the
179
+ // drain+detach emission to a single invocation; subsequent firings are
180
+ // no-ops. Buffer flushing also runs only once — partial-line state at true
181
+ // process exit doesn't change across re-fires.
182
+ let detached = false;
183
+ process.on("beforeExit", () => {
184
+ if (detached)
185
+ return;
186
+ detached = true;
187
+ if (streamLogStream && !streamLogStream.destroyed && !streamLogStream.writableEnded) {
188
+ if (lineBuffer.length > 0) {
189
+ streamLogStream.write(`${tsPrefix()} [mcp:${serverName}] ${lineBuffer}\n`);
190
+ }
191
+ streamLogStream.write(`${tsPrefix()} [platform] [mcp-tee-detach] server=${serverName} reason=process-before-exit\n`);
192
+ }
193
+ lineBuffer = "";
194
+ });
195
+ }
196
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "@maxy/mcp-stderr-tee",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "commonjs",
6
+ "main": "dist/index.js"
7
+ }
@@ -0,0 +1,3 @@
1
+ import { AUTHORSHIP_MODES } from "./tools/voice-tag-content.js";
2
+ export { AUTHORSHIP_MODES };
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAmB,gBAAgB,EAAuB,MAAM,8BAA8B,CAAC;AA0RtG,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,257 @@
1
+ import { initStderrTee } from "../../lib/mcp-stderr-tee/dist/index.js";
2
+ initStderrTee("writer-craft");
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { z } from "zod";
6
+ import { voiceTagContent, AUTHORSHIP_MODES } from "./tools/voice-tag-content.js";
7
+ import { voiceDistilProfile } from "./tools/voice-distil-profile.js";
8
+ import { voiceRetrieveConditioning } from "./tools/voice-retrieve-conditioning.js";
9
+ import { voiceRecordFeedback } from "./tools/voice-record-feedback.js";
10
+ import { closeDriver } from "./lib/neo4j.js";
11
+ const server = new McpServer({
12
+ name: "maxy-writer-craft",
13
+ version: "0.1.0",
14
+ });
15
+ // Plugin-system boot tolerance — module-init must never throw. Per-call
16
+ // refusal preserves account isolation. Mirrors the memory plugin's
17
+ // pattern (Task 202).
18
+ const accountId = process.env.ACCOUNT_ID ?? null;
19
+ const adminUserIdEnv = process.env.ADMIN_USER_ID ?? null;
20
+ process.stderr.write(`[writer-craft] boot accountId=${accountId ?? "null"} adminUserId=${adminUserIdEnv ?? "null"}\n`);
21
+ function refuseNoAccount(toolName) {
22
+ process.stderr.write(`[writer-craft] tool=${toolName} refuse reason=no-account-context\n`);
23
+ return {
24
+ content: [
25
+ {
26
+ type: "text",
27
+ text: `${toolName} cannot execute: this MCP instance was launched without ACCOUNT_ID. Per-account graph access requires ACCOUNT_ID at spawn.`,
28
+ },
29
+ ],
30
+ isError: true,
31
+ };
32
+ }
33
+ function resolveAdminUserId() {
34
+ // ADMIN_USER_ID is stamped by the admin session manager at spawn time.
35
+ // When absent (e.g. specialist subagents), the operator must pass it as
36
+ // a tool argument or the tools refuse rather than orphan a profile.
37
+ return adminUserIdEnv;
38
+ }
39
+ server.tool("voice-tag-content", "Stamp authorshipMode on one or many content nodes (:KnowledgeDocument | :Message | :SocialPost) the operator owns. Email threads live as :KnowledgeDocument {source:'email'} since Task 321. Valid modes: human-only, human-led-agent-assisted, agent-led-human-reviewed, agent-only, unknown.", {
40
+ nodeIds: z.array(z.string()).min(1).describe("Element IDs of nodes to tag"),
41
+ mode: z
42
+ .enum([
43
+ "human-only",
44
+ "human-led-agent-assisted",
45
+ "agent-led-human-reviewed",
46
+ "agent-only",
47
+ "unknown",
48
+ ])
49
+ .describe("Authorship mode to apply"),
50
+ }, async ({ nodeIds, mode }) => {
51
+ if (!accountId)
52
+ return refuseNoAccount("voice-tag-content");
53
+ try {
54
+ const result = await voiceTagContent({
55
+ nodeIds,
56
+ mode: mode,
57
+ accountId,
58
+ });
59
+ return {
60
+ content: [
61
+ {
62
+ type: "text",
63
+ text: `voice-tag: mode=${mode} updated=${result.updated} skipped=${result.skipped}`,
64
+ },
65
+ ],
66
+ };
67
+ }
68
+ catch (err) {
69
+ return {
70
+ content: [
71
+ {
72
+ type: "text",
73
+ text: `voice-tag-content failed: ${err instanceof Error ? err.message : String(err)}`,
74
+ },
75
+ ],
76
+ isError: true,
77
+ };
78
+ }
79
+ });
80
+ server.tool("voice-distil-profile", "Two-mode tool (Task 424). mode='sample' (default) walks the operator's human-only corpus, returns the exemplars + recent operator-edit intents for the agent to read. mode='write' persists the YAML style card the agent composed from the sample-mode response. Cadence-guarded: returns skip in 'write' mode without writing if corpus didn't grow ≥20% AND <30 days passed (pass force=true to override).", {
81
+ adminUserId: z
82
+ .string()
83
+ .optional()
84
+ .describe("Operator AdminUser identifier. Defaults to ADMIN_USER_ID env from spawn context."),
85
+ force: z
86
+ .boolean()
87
+ .optional()
88
+ .describe("Override cadence guard; rebuild even if recent."),
89
+ mode: z
90
+ .enum(["sample", "write"])
91
+ .optional()
92
+ .describe("'sample' returns corpus exemplars + feedback for in-turn distillation; 'write' persists the agent-produced styleCardYaml."),
93
+ styleCardYaml: z
94
+ .string()
95
+ .optional()
96
+ .describe("Required for mode='write'. The YAML style card the agent composed from the sample-mode exemplars + feedback intents."),
97
+ }, async ({ adminUserId, force, mode, styleCardYaml }) => {
98
+ if (!accountId)
99
+ return refuseNoAccount("voice-distil-profile");
100
+ const resolvedAdminUserId = adminUserId ?? resolveAdminUserId();
101
+ if (!resolvedAdminUserId) {
102
+ return {
103
+ content: [
104
+ {
105
+ type: "text",
106
+ text: "voice-distil-profile: adminUserId required (no ADMIN_USER_ID in spawn env).",
107
+ },
108
+ ],
109
+ isError: true,
110
+ };
111
+ }
112
+ try {
113
+ const result = await voiceDistilProfile({
114
+ accountId,
115
+ adminUserId: resolvedAdminUserId,
116
+ force: force === true,
117
+ mode,
118
+ styleCardYaml,
119
+ });
120
+ const summary = result.skipped
121
+ ? (result.exemplars
122
+ ? `voice-distil sample: corpusSize=${result.corpusSize} exemplars=${result.exemplars.length} feedbackEntries=${result.feedbackEntries}\n${JSON.stringify({ exemplars: result.exemplars, feedbackIntents: result.feedbackIntents }, null, 2)}`
123
+ : `voice-distil: skipped reason=${result.skipReason} corpusSize=${result.corpusSize}`)
124
+ : `voice-distil: ok profileId=${result.profileId} corpusSize=${result.corpusSize} feedbackEntries=${result.feedbackEntries} generatedAt=${result.generatedAt}`;
125
+ return { content: [{ type: "text", text: summary }] };
126
+ }
127
+ catch (err) {
128
+ return {
129
+ content: [
130
+ {
131
+ type: "text",
132
+ text: `voice-distil-profile failed: ${err instanceof Error ? err.message : String(err)}`,
133
+ },
134
+ ],
135
+ isError: true,
136
+ };
137
+ }
138
+ });
139
+ server.tool("voice-retrieve-conditioning", "Return the operator's style card and K voice-matched exemplars for a drafting brief. K=5 short-form, K=15 long-form. Token-budget bounded. Returns empty {styleCard:null,exemplars:[]} when no profile exists.", {
140
+ adminUserId: z
141
+ .string()
142
+ .optional()
143
+ .describe("Operator AdminUser identifier. Defaults to ADMIN_USER_ID env."),
144
+ topic: z
145
+ .string()
146
+ .optional()
147
+ .describe("Drafting topic keyword (filters exemplars to relevant ones)"),
148
+ format: z
149
+ .enum(["short", "long"])
150
+ .describe("Short = email/post (K=5, 16k tokens); long = brochure/prospectus (K=15, 96k tokens)"),
151
+ register: z.string().optional().describe("Optional register hint"),
152
+ tokenBudget: z.number().int().positive().optional(),
153
+ }, async ({ adminUserId, topic, format, register, tokenBudget }) => {
154
+ if (!accountId)
155
+ return refuseNoAccount("voice-retrieve-conditioning");
156
+ const resolvedAdminUserId = adminUserId ?? resolveAdminUserId();
157
+ if (!resolvedAdminUserId) {
158
+ return {
159
+ content: [
160
+ {
161
+ type: "text",
162
+ text: JSON.stringify({ styleCard: null, exemplars: [] }),
163
+ },
164
+ ],
165
+ };
166
+ }
167
+ try {
168
+ const result = await voiceRetrieveConditioning({
169
+ accountId,
170
+ adminUserId: resolvedAdminUserId,
171
+ brief: { topic, format, register },
172
+ tokenBudget,
173
+ });
174
+ return {
175
+ content: [
176
+ { type: "text", text: JSON.stringify(result) },
177
+ ],
178
+ };
179
+ }
180
+ catch (err) {
181
+ // Graceful degradation: callers expect {styleCard:null,exemplars:[]}
182
+ // on failure, never an error response.
183
+ process.stderr.write(`[voice-retrieve] tool error: ${err instanceof Error ? err.message : String(err)}\n`);
184
+ return {
185
+ content: [
186
+ {
187
+ type: "text",
188
+ text: JSON.stringify({ styleCard: null, exemplars: [] }),
189
+ },
190
+ ],
191
+ };
192
+ }
193
+ });
194
+ server.tool("voice-record-feedback", "Capture an operator's edit on an agent draft. Writes :VoiceEdit linked to :VoiceProfile via :FEEDBACK_FOR. The calling agent supplies `intent` (one sentence describing what the operator changed and what voice preference it reveals); Task 424 moved the diff-intent summarisation into the agent's turn.", {
195
+ adminUserId: z.string().optional(),
196
+ originalText: z.string().min(1),
197
+ editedText: z.string().min(1),
198
+ intent: z
199
+ .string()
200
+ .min(1)
201
+ .describe("One sentence summarising what changed and what voice preference it reveals — produced by the calling agent in-turn from originalText vs editedText (Task 424)."),
202
+ skill: z.string().optional().describe("Calling skill name, for provenance"),
203
+ brief: z.string().optional().describe("Drafting brief that produced the original"),
204
+ }, async ({ adminUserId, originalText, editedText, intent, skill, brief }) => {
205
+ if (!accountId)
206
+ return refuseNoAccount("voice-record-feedback");
207
+ const resolvedAdminUserId = adminUserId ?? resolveAdminUserId();
208
+ if (!resolvedAdminUserId) {
209
+ return {
210
+ content: [
211
+ {
212
+ type: "text",
213
+ text: "voice-record-feedback: adminUserId required (no ADMIN_USER_ID in spawn env).",
214
+ },
215
+ ],
216
+ isError: true,
217
+ };
218
+ }
219
+ try {
220
+ const result = await voiceRecordFeedback({
221
+ accountId,
222
+ adminUserId: resolvedAdminUserId,
223
+ originalText,
224
+ editedText,
225
+ intent,
226
+ context: { skill, brief },
227
+ });
228
+ return {
229
+ content: [
230
+ {
231
+ type: "text",
232
+ text: `voice-record-feedback: editId=${result.editId} intent="${result.intent}" hadProfile=${result.hadProfile}`,
233
+ },
234
+ ],
235
+ };
236
+ }
237
+ catch (err) {
238
+ return {
239
+ content: [
240
+ {
241
+ type: "text",
242
+ text: `voice-record-feedback failed: ${err instanceof Error ? err.message : String(err)}`,
243
+ },
244
+ ],
245
+ isError: true,
246
+ };
247
+ }
248
+ });
249
+ const transport = new StdioServerTransport();
250
+ await server.connect(transport);
251
+ process.on("SIGTERM", async () => {
252
+ await closeDriver();
253
+ process.exit(0);
254
+ });
255
+ // Surface AUTHORSHIP_MODES for downstream callers / docs.
256
+ export { AUTHORSHIP_MODES };
257
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Minimal neo4j driver wrapper for the writer-craft MCP server.
3
+ *
4
+ * Mirrors the public surface of `platform/plugins/memory/mcp/src/lib/neo4j.ts`:
5
+ * `getSession()` returns a session, `closeDriver()` releases the singleton.
6
+ * Password resolution follows the same `PLATFORM_ROOT/config/.neo4j-password`
7
+ * convention, with an explicit `NEO4J_URI` requirement to avoid silent
8
+ * cross-account orphaning.
9
+ */
10
+ import { Driver, Session } from "neo4j-driver";
11
+ export declare function getDriver(): Driver;
12
+ export declare function getSession(): Session;
13
+ export declare function closeDriver(): Promise<void>;
14
+ //# sourceMappingURL=neo4j.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"neo4j.d.ts","sourceRoot":"","sources":["../../src/lib/neo4j.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAc,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAqBtD,wBAAgB,SAAS,IAAI,MAAM,CAclC;AAED,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAKjD"}