@rubytech/create-maxy-code 0.1.172 → 0.1.174
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/dist/index.js +12 -1
- package/package.json +1 -1
- package/payload/platform/scripts/verify-skill-tool-surface.sh +98 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js.map +1 -1
- package/payload/platform/templates/specialists/agents/content-producer.md +4 -4
- package/payload/platform/templates/specialists/agents/librarian.md +2 -2
- package/payload/platform/templates/specialists/agents/personal-assistant.md +4 -4
- package/payload/platform/templates/specialists/agents/project-manager.md +2 -2
- package/payload/platform/templates/specialists/agents/research-assistant.md +2 -2
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js +21 -21
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js +17 -17
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js +9 -9
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js +4 -4
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/src/index.ts +21 -21
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-distil-profile.ts +18 -18
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-record-feedback.ts +10 -10
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-retrieve-conditioning.ts +5 -5
- package/payload/server/server.js +12 -3
package/dist/index.js
CHANGED
|
@@ -3781,7 +3781,18 @@ try {
|
|
|
3781
3781
|
console.log("");
|
|
3782
3782
|
console.log("================================================================");
|
|
3783
3783
|
console.log("");
|
|
3784
|
-
|
|
3784
|
+
if (isLinux()) {
|
|
3785
|
+
console.log(` Same network (Pi / LAN): http://${DEVICE_HOSTNAME}.local:${PORT}`);
|
|
3786
|
+
console.log("");
|
|
3787
|
+
console.log(` Remote access (Hetzner / cloud) — on your local machine run:`);
|
|
3788
|
+
console.log(` ssh -L ${PORT}:localhost:${PORT} -L ${BRAND.websockifyPort}:localhost:${BRAND.websockifyPort} admin@<server-ipv4>`);
|
|
3789
|
+
console.log(` Then open:`);
|
|
3790
|
+
console.log(` Dashboard: http://localhost:${PORT}`);
|
|
3791
|
+
console.log(` VNC browser (Claude OAuth + Cloudflare): http://localhost:${BRAND.websockifyPort}/vnc.html`);
|
|
3792
|
+
}
|
|
3793
|
+
else {
|
|
3794
|
+
console.log(` Open in your browser: http://${DEVICE_HOSTNAME}.local:${PORT}`);
|
|
3795
|
+
}
|
|
3785
3796
|
console.log("");
|
|
3786
3797
|
console.log("================================================================");
|
|
3787
3798
|
}
|
package/package.json
CHANGED
|
@@ -68,6 +68,13 @@ ADMIN_OWNED_SKILLS = {
|
|
|
68
68
|
"memory/conversational-memory",
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
# Regex for skill-name tokens in the prompt body that require `Skill` in tools:
|
|
72
|
+
# 1. `skill-load skillName=<name>` pattern (how templates reference Skill calls)
|
|
73
|
+
# 2. `Skill <name>` pattern (explicit Skill tool invocation in enforcement directives)
|
|
74
|
+
# Only hyphenated lowercase names are skill names.
|
|
75
|
+
SKILL_LOAD_RE = re.compile(r"skillName=([a-z][a-z0-9-]+)")
|
|
76
|
+
SKILL_INVOKE_RE = re.compile(r"`Skill\s+([a-z][a-z0-9-]+)`")
|
|
77
|
+
|
|
71
78
|
TOKEN_RE = re.compile(r"`(mcp__[a-z][a-z0-9_-]*__[a-z][a-z0-9_-]*)`")
|
|
72
79
|
FENCED_BLOCK_RE = re.compile(r"```(?P<lang>[a-zA-Z]*)\n(?P<body>.*?)\n```", re.S)
|
|
73
80
|
PROSE_CYPHER_RE = re.compile(
|
|
@@ -170,6 +177,73 @@ def aggregate_skill_text(skill_dir: str) -> str:
|
|
|
170
177
|
return "\n".join(out)
|
|
171
178
|
|
|
172
179
|
|
|
180
|
+
def collect_skill_names() -> set[str]:
|
|
181
|
+
"""Enumerate all installed skill directory names from platform/plugins/*/skills/."""
|
|
182
|
+
names: set[str] = set()
|
|
183
|
+
if not os.path.isdir(PLUGINS_DIR):
|
|
184
|
+
return names
|
|
185
|
+
for plugin in os.listdir(PLUGINS_DIR):
|
|
186
|
+
skills_dir = os.path.join(PLUGINS_DIR, plugin, "skills")
|
|
187
|
+
if not os.path.isdir(skills_dir):
|
|
188
|
+
continue
|
|
189
|
+
for entry in os.listdir(skills_dir):
|
|
190
|
+
if os.path.isdir(os.path.join(skills_dir, entry)):
|
|
191
|
+
names.add(entry)
|
|
192
|
+
return names
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def specialist_body(specialist_path: str) -> str:
|
|
196
|
+
"""Return the prompt body of a specialist template (content below frontmatter)."""
|
|
197
|
+
try:
|
|
198
|
+
text = open(specialist_path, encoding="utf-8").read()
|
|
199
|
+
except FileNotFoundError:
|
|
200
|
+
return ""
|
|
201
|
+
m = re.match(r"^---\n.*?\n---\n(.*)", text, re.S)
|
|
202
|
+
return m.group(1) if m else text
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def check_builtin_tool_rule(
|
|
206
|
+
specialist: str,
|
|
207
|
+
body: str,
|
|
208
|
+
tools: set[str],
|
|
209
|
+
known_skills: set[str],
|
|
210
|
+
) -> list[str]:
|
|
211
|
+
"""Built-in-tool rule: if the specialist prompt references a skill load that
|
|
212
|
+
matches an installed skill directory, `Skill` must appear in tools:."""
|
|
213
|
+
referenced: set[str] = set()
|
|
214
|
+
# Pattern 1: skill-load skillName=<name> (template invocation form)
|
|
215
|
+
referenced |= set(SKILL_LOAD_RE.findall(body)) & known_skills
|
|
216
|
+
# Pattern 2: `Skill <name>` (enforcement directive form)
|
|
217
|
+
referenced |= set(SKILL_INVOKE_RE.findall(body)) & known_skills
|
|
218
|
+
if not referenced or "Skill" in tools:
|
|
219
|
+
return []
|
|
220
|
+
return [
|
|
221
|
+
f"[verify] specialist={specialist} claims-loads={name} "
|
|
222
|
+
f"but Skill missing from tools"
|
|
223
|
+
for name in sorted(referenced)
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def check_webfetch_rule(
|
|
228
|
+
specialist: str,
|
|
229
|
+
body: str,
|
|
230
|
+
tools: set[str],
|
|
231
|
+
) -> list[str]:
|
|
232
|
+
"""WebFetch rule: if the specialist prompt names WebFetch explicitly or
|
|
233
|
+
directs dereferencing an operator-provided URL, WebFetch must be in tools:."""
|
|
234
|
+
if "WebFetch" in tools:
|
|
235
|
+
return []
|
|
236
|
+
has_webfetch = bool(re.search(r"\bWebFetch\b", body))
|
|
237
|
+
has_fetch_url = bool(re.search(r"\bfetch\b.*\bURL\b", body, re.IGNORECASE))
|
|
238
|
+
if not (has_webfetch or has_fetch_url):
|
|
239
|
+
return []
|
|
240
|
+
reason = "WebFetch" if has_webfetch else r"\bfetch\b.*\bURL\b"
|
|
241
|
+
return [
|
|
242
|
+
f"[verify] specialist={specialist} directs WebFetch but tool missing "
|
|
243
|
+
f"(matched: {reason})"
|
|
244
|
+
]
|
|
245
|
+
|
|
246
|
+
|
|
173
247
|
def main() -> int:
|
|
174
248
|
if not os.path.isdir(PLUGINS_DIR):
|
|
175
249
|
print(f"[verify] PLUGINS_DIR not found: {PLUGINS_DIR}", file=sys.stderr)
|
|
@@ -252,6 +326,30 @@ def main() -> int:
|
|
|
252
326
|
)
|
|
253
327
|
pairs_checked += 1
|
|
254
328
|
|
|
329
|
+
# Built-in-tool rule + WebFetch rule: sweep all specialist templates directly.
|
|
330
|
+
# These rules are orthogonal to the skill-pairing loop above — they check the
|
|
331
|
+
# specialist's own prompt body for directives that require built-in CC tools.
|
|
332
|
+
known_skills = collect_skill_names()
|
|
333
|
+
builtin_checked = 0
|
|
334
|
+
if os.path.isdir(SPECIALISTS_DIR):
|
|
335
|
+
for fname in sorted(os.listdir(SPECIALISTS_DIR)):
|
|
336
|
+
if not fname.endswith(".md"):
|
|
337
|
+
continue
|
|
338
|
+
specialist = fname[:-3]
|
|
339
|
+
spath = os.path.join(SPECIALISTS_DIR, fname)
|
|
340
|
+
tools = specialist_tools(specialist)
|
|
341
|
+
if tools is None:
|
|
342
|
+
continue
|
|
343
|
+
body = specialist_body(spath)
|
|
344
|
+
for err in check_builtin_tool_rule(specialist, body, tools, known_skills):
|
|
345
|
+
errors.append(err)
|
|
346
|
+
for err in check_webfetch_rule(specialist, body, tools):
|
|
347
|
+
errors.append(err)
|
|
348
|
+
builtin_checked += 1
|
|
349
|
+
summary.append(
|
|
350
|
+
f"[verify] builtin-tool-check specialists_checked={builtin_checked}"
|
|
351
|
+
)
|
|
352
|
+
|
|
255
353
|
for line in summary:
|
|
256
354
|
print(line)
|
|
257
355
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"specialist-drift.d.ts","sourceRoot":"","sources":["../src/specialist-drift.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"specialist-drift.d.ts","sourceRoot":"","sources":["../src/specialist-drift.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAoCpD,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EACF,0BAA0B,GAC1B,wBAAwB,GACxB,gBAAgB,GAChB,uBAAuB,CAAA;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC;;;yCAGqC;IACrC,EAAE,EAAE,OAAO,CAAA;IACX;;wCAEoC;IACpC,OAAO,EAAE,qBAAqB,EAAE,CAAA;IAChC,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAA;IACjB;;;;6CAIyC;IACzC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAA;CACpD;AAED;;;kEAGkE;AAClE,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI3E;AAmCD;;;;;;;;;wDASwD;AACxD,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,WAAW,EAAE,WAAW,EACxB,eAAe,GAAE,WAAW,CAAC,MAAM,CAAa,GAC/C,qBAAqB,CAgDvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"specialist-drift.js","sourceRoot":"","sources":["../src/specialist-drift.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"specialist-drift.js","sourceRoot":"","sources":["../src/specialist-drift.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ name: content-producer
|
|
|
3
3
|
description: "Visual production and static-site hosting. Reads from the populated graph to produce visual artifacts (image generation, PDF rendering, component delivery) and hosts already-prepared static sites by extracting attached archives via unzip-attachment then placing the tree under <accountDir>/sites/<slug>/ via publish-site. Delegate for: generating images, saving rendered pages as PDF, or any 'host this website' / 'publish this site' / 'put this online' intent carrying an HTML+assets archive. Not document ingestion: graph ingestion of any kind routes to specialists:database-operator. Static-site zips are extracted to disk for publication, never written to the graph."
|
|
4
4
|
summary: "Produces visual output from your graph: generates images, renders pages to PDF, and hosts static websites you upload as a zip."
|
|
5
5
|
model: claude-sonnet-4-6
|
|
6
|
-
tools: Bash, mcp__memory__memory-search, mcp__replicate__image-generate, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_take_screenshot, mcp__plugin_playwright_playwright__browser_pdf_save, mcp__admin__file-attach, mcp__admin__plugin-read, mcp__admin__public-hostname, mcp__admin__publish-site
|
|
6
|
+
tools: Bash, Skill, mcp__memory__memory-search, mcp__replicate__image-generate, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_take_screenshot, mcp__plugin_playwright_playwright__browser_pdf_save, mcp__admin__file-attach, mcp__admin__plugin-read, mcp__admin__public-hostname, mcp__admin__publish-site
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Content Producer
|
|
@@ -32,13 +32,13 @@ Three models via `image-generate`. Pick by output need: `recraft-v4` for design-
|
|
|
32
32
|
|
|
33
33
|
## PDF output
|
|
34
34
|
|
|
35
|
-
Generate the HTML, navigate the Playwright browser to it, and capture with `browser_pdf_save`. For A4 print,
|
|
35
|
+
Generate the HTML, navigate the Playwright browser to it, and capture with `browser_pdf_save`. For A4 print, **the first tool call of this workflow branch MUST be `Skill a4-print-documents`. Any browser tool call before the skill content is loaded into context is a contract violation.** Load `skill-load skillName=a4-print-documents`: the skill carries the print-CSS constraints (page margins, glassmorphism fallback, page-break rules, dark-background colour-adjust). Do not paraphrase those rules; load and follow.
|
|
36
36
|
|
|
37
37
|
`file://` URLs are rewritten transparently by the `playwright-file-guard` PreToolUse hook. Pass them directly to `browser_navigate`.
|
|
38
38
|
|
|
39
39
|
## Hosting websites
|
|
40
40
|
|
|
41
|
-
When a brief carries a "host this website" / "publish this site" / "put this online" intent with a `.zip` of HTML and assets,
|
|
41
|
+
When a brief carries a "host this website" / "publish this site" / "put this online" intent with a `.zip` of HTML and assets, **the first tool call of this workflow branch MUST be `Skill unzip-attachment`. Any publish tool call before the skill content is loaded into context is a contract violation.** Run `skill-load skillName=unzip-attachment` to extract, then call `mcp__admin__publish-site` directly. The tool owns slug validation, the symlink scan, the `mv`, the refusal taxonomy, and the post-publish llms.txt refresh — load `skill-load skillName=publish-site` only if you need the intent-router context. Do not improvise a fallback server.
|
|
42
42
|
|
|
43
43
|
Confirm the slug with the operator before publishing. The slug is one or more `/`-separated segments under `<accountDir>/sites/`. Refusals are loud-fail; relay the tool's `Operator action:` line verbatim and stop. On success, take the `pathSlug` from the tool response, call `mcp__admin__public-hostname`, and surface `https://<hostname><pathSlug>` to the operator as one line.
|
|
44
44
|
|
|
@@ -60,4 +60,4 @@ Return to the admin agent: what you did (images generated, PDFs produced, compon
|
|
|
60
60
|
|
|
61
61
|
## Plain English
|
|
62
62
|
|
|
63
|
-
Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin (captions, brochure prose, summaries, the "What you did" lines). It does not apply to `image-generate` prompts: those are agent-to-machine payloads where technical descriptors are required vocabulary, not jargon to strip.
|
|
63
|
+
**The first tool call MUST be `Skill plainly`. Any prose tool call before the skill content is loaded into context is a contract violation.** Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin (captions, brochure prose, summaries, the "What you did" lines). It does not apply to `image-generate` prompts: those are agent-to-machine payloads where technical descriptors are required vocabulary, not jargon to strip.
|
|
@@ -3,7 +3,7 @@ name: librarian
|
|
|
3
3
|
description: "Foreground ingester for the memory graph. Owns external-archive and document ingestion — PDFs, web pages, plain text, conversation transcripts (WhatsApp / Telegram / Signal / iMessage / Slack / LinkedIn DMs / Zoom / meeting minutes), LinkedIn Basic Data Exports, and post-unzip trees the admin agent forwards. Loads `document-ingest`, `conversation-archive`, `conversation-archive-enrich`, and `linkedin-import` skills. Returns to the admin agent with a structured outcome line; never interacts with the operator directly except through the dispatching agent."
|
|
4
4
|
summary: "Owns foreground ingest of documents, conversation transcripts, and external archives into the memory graph."
|
|
5
5
|
model: claude-sonnet-4-5
|
|
6
|
-
tools: mcp__plugin_memory_memory__memory-ingest-extract, mcp__plugin_memory_memory__memory-ingest, mcp__plugin_memory_memory__memory-ingest-web, mcp__plugin_memory_memory__memory-archive-write, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__conversation-archive-list-chunks, mcp__plugin_memory_memory__conversation-archive-derive-insights, mcp__plugin_memory_memory__conversation-archive-enrich-rejection, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_work_work__work-create, Read, Bash
|
|
6
|
+
tools: mcp__plugin_memory_memory__memory-ingest-extract, mcp__plugin_memory_memory__memory-ingest, mcp__plugin_memory_memory__memory-ingest-web, mcp__plugin_memory_memory__memory-archive-write, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__conversation-archive-list-chunks, mcp__plugin_memory_memory__conversation-archive-derive-insights, mcp__plugin_memory_memory__conversation-archive-enrich-rejection, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_work_work__work-create, Read, Bash, Skill, WebFetch
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Librarian
|
|
@@ -28,7 +28,7 @@ These three rules win when anything else in this prompt conflicts with them.
|
|
|
28
28
|
|
|
29
29
|
## Skill routing
|
|
30
30
|
|
|
31
|
-
The dispatch brief from the admin agent names the input class. Map it to one skill
|
|
31
|
+
The dispatch brief from the admin agent names the input class. Map it to one skill. **After routing, the first tool call MUST be `Skill <skill-name>`. Any `memory-*` write tool called before the skill content is loaded into context is a contract violation.**
|
|
32
32
|
|
|
33
33
|
| Input | Skill | Parent label |
|
|
34
34
|
|---|---|---|
|
|
@@ -3,7 +3,7 @@ name: personal-assistant
|
|
|
3
3
|
description: "Your personal assistant. Scheduling, platform administration, messaging channels (Telegram, WhatsApp, email, Outlook), system health, Cloudflare tunnel setup, and browser automation. Delegate when a task involves managing your calendar, configuring the platform, operating messaging channels, setting up a tunnel or domain, or completing interactive browser tasks."
|
|
4
4
|
summary: "Handles the operational tasks you'd give a personal assistant: scheduling meetings, managing your platform settings, connecting messaging channels, and completing browser-based tasks on your behalf."
|
|
5
5
|
model: claude-sonnet-4-6
|
|
6
|
-
tools: mcp__admin__system-status, mcp__admin__brand-settings, mcp__admin__account-manage, mcp__admin__account-update, mcp__admin__logs-read, mcp__admin__plugin-read, mcp__admin__file-attach, mcp__admin__wifi, mcp__contacts__contact-create, mcp__contacts__contact-lookup, mcp__contacts__contact-update, mcp__contacts__contact-delete, mcp__contacts__contact-list, mcp__contacts__contact-export, mcp__contacts__contact-erase, mcp__contacts__group-create, mcp__contacts__group-manage, mcp__telegram__message, mcp__telegram__message-history, mcp__telegram__telegram-webhook-register, mcp__whatsapp__whatsapp-login-start, mcp__whatsapp__whatsapp-login-wait, mcp__whatsapp__whatsapp-status, mcp__whatsapp__whatsapp-disconnect, mcp__whatsapp__whatsapp-send, mcp__whatsapp__whatsapp-send-document, mcp__whatsapp__whatsapp-config, mcp__whatsapp__whatsapp-activity, mcp__whatsapp__whatsapp-conversations, mcp__whatsapp__whatsapp-messages, mcp__whatsapp__whatsapp-conversation-graph-state, mcp__whatsapp__whatsapp-group-info, mcp__email__email-setup, mcp__email__email-read, mcp__email__email-send, mcp__email__email-reply, mcp__email__email-search, mcp__email__email-graph-query, mcp__email__email-otp-extract, mcp__email__email-status, mcp__email__email-fetch, mcp__email__email-ingest, mcp__outlook__outlook-account-register, mcp__outlook__outlook-mail-list, mcp__outlook__outlook-mail-search, mcp__outlook__outlook-calendar-list, mcp__outlook__outlook-calendar-event, mcp__outlook__outlook-contacts-list, mcp__outlook__outlook-mailbox-info, mcp__scheduling__schedule-event, mcp__scheduling__schedule-list, mcp__scheduling__schedule-get, mcp__scheduling__schedule-update, mcp__scheduling__schedule-cancel, mcp__scheduling__schedule-export-ics, mcp__scheduling__schedule-import-ics, mcp__scheduling__time-resolve, mcp__memory__memory-search, mcp__memory__profile-update, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_navigate_back, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_click, mcp__plugin_playwright_playwright__browser_fill, mcp__plugin_playwright_playwright__browser_fill_form, mcp__plugin_playwright_playwright__browser_type, mcp__plugin_playwright_playwright__browser_press_key, mcp__plugin_playwright_playwright__browser_hover, mcp__plugin_playwright_playwright__browser_select_option, mcp__plugin_playwright_playwright__browser_wait_for, mcp__plugin_playwright_playwright__browser_handle_dialog, mcp__plugin_playwright_playwright__browser_evaluate, mcp__plugin_playwright_playwright__browser_console_messages, mcp__plugin_playwright_playwright__browser_resize, mcp__plugin_playwright_playwright__browser_tabs, mcp__plugin_playwright_playwright__browser_close
|
|
6
|
+
tools: Skill, mcp__admin__system-status, mcp__admin__brand-settings, mcp__admin__account-manage, mcp__admin__account-update, mcp__admin__logs-read, mcp__admin__plugin-read, mcp__admin__file-attach, mcp__admin__wifi, mcp__contacts__contact-create, mcp__contacts__contact-lookup, mcp__contacts__contact-update, mcp__contacts__contact-delete, mcp__contacts__contact-list, mcp__contacts__contact-export, mcp__contacts__contact-erase, mcp__contacts__group-create, mcp__contacts__group-manage, mcp__telegram__message, mcp__telegram__message-history, mcp__telegram__telegram-webhook-register, mcp__whatsapp__whatsapp-login-start, mcp__whatsapp__whatsapp-login-wait, mcp__whatsapp__whatsapp-status, mcp__whatsapp__whatsapp-disconnect, mcp__whatsapp__whatsapp-send, mcp__whatsapp__whatsapp-send-document, mcp__whatsapp__whatsapp-config, mcp__whatsapp__whatsapp-activity, mcp__whatsapp__whatsapp-conversations, mcp__whatsapp__whatsapp-messages, mcp__whatsapp__whatsapp-conversation-graph-state, mcp__whatsapp__whatsapp-group-info, mcp__email__email-setup, mcp__email__email-read, mcp__email__email-send, mcp__email__email-reply, mcp__email__email-search, mcp__email__email-graph-query, mcp__email__email-otp-extract, mcp__email__email-status, mcp__email__email-fetch, mcp__email__email-ingest, mcp__outlook__outlook-account-register, mcp__outlook__outlook-mail-list, mcp__outlook__outlook-mail-search, mcp__outlook__outlook-calendar-list, mcp__outlook__outlook-calendar-event, mcp__outlook__outlook-contacts-list, mcp__outlook__outlook-mailbox-info, mcp__scheduling__schedule-event, mcp__scheduling__schedule-list, mcp__scheduling__schedule-get, mcp__scheduling__schedule-update, mcp__scheduling__schedule-cancel, mcp__scheduling__schedule-export-ics, mcp__scheduling__schedule-import-ics, mcp__scheduling__time-resolve, mcp__memory__memory-search, mcp__memory__profile-update, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_navigate_back, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_click, mcp__plugin_playwright_playwright__browser_fill, mcp__plugin_playwright_playwright__browser_fill_form, mcp__plugin_playwright_playwright__browser_type, mcp__plugin_playwright_playwright__browser_press_key, mcp__plugin_playwright_playwright__browser_hover, mcp__plugin_playwright_playwright__browser_select_option, mcp__plugin_playwright_playwright__browser_wait_for, mcp__plugin_playwright_playwright__browser_handle_dialog, mcp__plugin_playwright_playwright__browser_evaluate, mcp__plugin_playwright_playwright__browser_console_messages, mcp__plugin_playwright_playwright__browser_resize, mcp__plugin_playwright_playwright__browser_tabs, mcp__plugin_playwright_playwright__browser_close
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Personal Assistant
|
|
@@ -22,8 +22,8 @@ These three rules win when anything else in this prompt conflicts with them.
|
|
|
22
22
|
|
|
23
23
|
Each domain has a small set of tools and, where it exists, a skill that drives the multi-step flow. Match the brief to the domain, load the skill if one is named, and run the tools the skill prescribes.
|
|
24
24
|
|
|
25
|
-
- **WhatsApp setup or config:**
|
|
26
|
-
- **Cloudflare tunnel:**
|
|
25
|
+
- **WhatsApp setup or config:** **After routing, the first tool call MUST be `Skill connect-whatsapp` (for QR pairing and admin-phone setup) or `Skill manage-whatsapp-config` (for DM/group policies). Any channel tool call before the routed skill's content is loaded into context is a contract violation.** Load `skill-load skillName=connect-whatsapp` for QR pairing and admin-phone setup; load `skill-load skillName=manage-whatsapp-config` for DM/group policies and admin-phone management. The skills carry the per-phase flow.
|
|
26
|
+
- **Cloudflare tunnel:** **After routing, the first tool call MUST be `Skill setup-tunnel`. Any Bash call before the skill content is loaded into context is a contract violation.** Load `skill-load skillName=setup-tunnel`. The skill drives `cloudflared` directly via Bash following `references/manual-setup.md`, `references/reset-guide.md`, and `references/dashboard-guide.md`. There is no shell-script wrapper; PTY stdout is the only surface.
|
|
27
27
|
- **Every other domain** (scheduling, Telegram, email, Outlook, contacts, browser, platform admin) runs through the tool descriptions injected into your system prompt. The rules below apply across these domains regardless of which tool is invoked.
|
|
28
28
|
|
|
29
29
|
## Cross-domain rules
|
|
@@ -56,4 +56,4 @@ Name the tool, what you tried, and what the `[tool-failure-diag]` line shows. Do
|
|
|
56
56
|
|
|
57
57
|
## Plain English
|
|
58
58
|
|
|
59
|
-
Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin and to every message body destined for a human reader (email bodies, WhatsApp text, status summaries). It does not apply to structured tool arguments (cron expressions, scheduling enums, browser selectors).
|
|
59
|
+
**The first tool call MUST be `Skill plainly`. Any prose tool call before the skill content is loaded into context is a contract violation.** Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin and to every message body destined for a human reader (email bodies, WhatsApp text, status summaries). It does not apply to structured tool arguments (cron expressions, scheduling enums, browser selectors).
|
|
@@ -3,7 +3,7 @@ name: project-manager
|
|
|
3
3
|
description: "Project and task management. Creating, tracking, and completing tasks and projects, naming sessions, building and running workflows, and linking work to people and entities. Delegate when a task involves organising work, tracking progress, or composing multi-step workflows."
|
|
4
4
|
summary: "Manages your tasks, projects, sessions, and workflows: linking work to people and goals, and keeping everything organised."
|
|
5
5
|
model: claude-sonnet-4-6
|
|
6
|
-
tools: mcp__work__work-create, mcp__work__work-update, mcp__work__work-list, mcp__work__work-get, mcp__work__work-relate, mcp__work__work-complete, mcp__work__work-ready, mcp__work__project-create, mcp__work__project-list, mcp__work__project-get, mcp__work__project-update, mcp__work__project-complete, mcp__work__session-list, mcp__work__session-name, mcp__workflows__workflow-create, mcp__workflows__workflow-list, mcp__workflows__workflow-get, mcp__workflows__workflow-update, mcp__workflows__workflow-delete, mcp__workflows__workflow-validate, mcp__workflows__workflow-execute, mcp__workflows__workflow-runs, mcp__memory__memory-search
|
|
6
|
+
tools: mcp__work__work-create, mcp__work__work-update, mcp__work__work-list, mcp__work__work-get, mcp__work__work-relate, mcp__work__work-complete, mcp__work__work-ready, mcp__work__project-create, mcp__work__project-list, mcp__work__project-get, mcp__work__project-update, mcp__work__project-complete, mcp__work__session-list, mcp__work__session-name, mcp__workflows__workflow-create, mcp__workflows__workflow-list, mcp__workflows__workflow-get, mcp__workflows__workflow-update, mcp__workflows__workflow-delete, mcp__workflows__workflow-validate, mcp__workflows__workflow-execute, mcp__workflows__workflow-runs, mcp__memory__memory-search, Skill
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Project Manager
|
|
@@ -60,4 +60,4 @@ Name the tool, what you tried, and what the `[tool-failure-diag]` line shows. Do
|
|
|
60
60
|
|
|
61
61
|
## Plain English
|
|
62
62
|
|
|
63
|
-
Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin (status updates, sprint summaries, project digests) and to task title/description fields a human will read. It does not apply to structured arguments (state enums, IDs, JSON-shaped relationship payloads).
|
|
63
|
+
**The first tool call MUST be `Skill plainly`. Any prose tool call before the skill content is loaded into context is a contract violation.** Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin (status updates, sprint summaries, project digests) and to task title/description fields a human will read. It does not apply to structured arguments (state enums, IDs, JSON-shaped relationship payloads).
|
|
@@ -3,7 +3,7 @@ name: research-assistant
|
|
|
3
3
|
description: "Deep research, information gathering, knowledge management, and supporting visuals. Delegate when a task requires searching the web, reading web pages, combining findings from multiple sources into a structured summary with citations, reorganising stored knowledge, or generating supporting images."
|
|
4
4
|
summary: "Researches topics online, manages your knowledge graph, and produces supporting visuals."
|
|
5
5
|
model: claude-opus-4-7
|
|
6
|
-
tools: WebSearch, WebFetch, mcp__memory__memory-search, mcp__memory__memory-write, mcp__memory__memory-reindex, mcp__replicate__image-generate, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_evaluate
|
|
6
|
+
tools: WebSearch, WebFetch, Skill, mcp__memory__memory-search, mcp__memory__memory-write, mcp__memory__memory-reindex, mcp__replicate__image-generate, mcp__plugin_playwright_playwright__browser_navigate, mcp__plugin_playwright_playwright__browser_snapshot, mcp__plugin_playwright_playwright__browser_evaluate
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Research Assistant
|
|
@@ -70,4 +70,4 @@ Name the tool, the target URL, and the `[tool-failure-diag]` block if present. S
|
|
|
70
70
|
|
|
71
71
|
## Plain English
|
|
72
72
|
|
|
73
|
-
Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin (research summaries, the "Key findings" section). It does not apply to `WebSearch` queries, `WebFetch` URLs, or quoted source titles and URLs in the Sources list: those pass through verbatim.
|
|
73
|
+
**The first tool call MUST be `Skill plainly`. Any prose tool call before the skill content is loaded into context is a contract violation.** Load `skill-load skillName=plainly` on the first turn and apply it to every prose payload returned to admin (research summaries, the "Key findings" section). It does not apply to `WebSearch` queries, `WebFetch` URLs, or quoted source titles and URLs in the Sources list: those pass through verbatim.
|
|
@@ -16,8 +16,8 @@ const server = new McpServer({
|
|
|
16
16
|
// refusal preserves account isolation. Mirrors the memory plugin's
|
|
17
17
|
// pattern (Task 202).
|
|
18
18
|
const accountId = process.env.ACCOUNT_ID ?? null;
|
|
19
|
-
const
|
|
20
|
-
process.stderr.write(`[writer-craft] boot accountId=${accountId ?? "null"}
|
|
19
|
+
const userIdEnv = process.env.ADMIN_USER_ID ?? null;
|
|
20
|
+
process.stderr.write(`[writer-craft] boot accountId=${accountId ?? "null"} userId=${userIdEnv ?? "null"}\n`);
|
|
21
21
|
function refuseNoAccount(toolName) {
|
|
22
22
|
process.stderr.write(`[writer-craft] tool=${toolName} refuse reason=no-account-context\n`);
|
|
23
23
|
return {
|
|
@@ -30,11 +30,11 @@ function refuseNoAccount(toolName) {
|
|
|
30
30
|
isError: true,
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
-
function
|
|
33
|
+
function resolveUserId() {
|
|
34
34
|
// ADMIN_USER_ID is stamped by the admin session manager at spawn time.
|
|
35
35
|
// When absent (e.g. specialist subagents), the operator must pass it as
|
|
36
36
|
// a tool argument or the tools refuse rather than orphan a profile.
|
|
37
|
-
return
|
|
37
|
+
return userIdEnv;
|
|
38
38
|
}
|
|
39
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
40
|
nodeIds: z.array(z.string()).min(1).describe("Element IDs of nodes to tag"),
|
|
@@ -78,7 +78,7 @@ server.tool("voice-tag-content", "Stamp authorshipMode on one or many content no
|
|
|
78
78
|
}
|
|
79
79
|
});
|
|
80
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
|
-
|
|
81
|
+
userId: z
|
|
82
82
|
.string()
|
|
83
83
|
.optional()
|
|
84
84
|
.describe("Operator AdminUser identifier. Defaults to ADMIN_USER_ID env from spawn context."),
|
|
@@ -94,16 +94,16 @@ server.tool("voice-distil-profile", "Two-mode tool (Task 424). mode='sample' (de
|
|
|
94
94
|
.string()
|
|
95
95
|
.optional()
|
|
96
96
|
.describe("Required for mode='write'. The YAML style card the agent composed from the sample-mode exemplars + feedback intents."),
|
|
97
|
-
}, async ({
|
|
97
|
+
}, async ({ userId, force, mode, styleCardYaml }) => {
|
|
98
98
|
if (!accountId)
|
|
99
99
|
return refuseNoAccount("voice-distil-profile");
|
|
100
|
-
const
|
|
101
|
-
if (!
|
|
100
|
+
const resolvedUserId = userId ?? resolveUserId();
|
|
101
|
+
if (!resolvedUserId) {
|
|
102
102
|
return {
|
|
103
103
|
content: [
|
|
104
104
|
{
|
|
105
105
|
type: "text",
|
|
106
|
-
text: "voice-distil-profile:
|
|
106
|
+
text: "voice-distil-profile: userId required (no ADMIN_USER_ID in spawn env).",
|
|
107
107
|
},
|
|
108
108
|
],
|
|
109
109
|
isError: true,
|
|
@@ -112,7 +112,7 @@ server.tool("voice-distil-profile", "Two-mode tool (Task 424). mode='sample' (de
|
|
|
112
112
|
try {
|
|
113
113
|
const result = await voiceDistilProfile({
|
|
114
114
|
accountId,
|
|
115
|
-
|
|
115
|
+
userId: resolvedUserId,
|
|
116
116
|
force: force === true,
|
|
117
117
|
mode,
|
|
118
118
|
styleCardYaml,
|
|
@@ -137,7 +137,7 @@ server.tool("voice-distil-profile", "Two-mode tool (Task 424). mode='sample' (de
|
|
|
137
137
|
}
|
|
138
138
|
});
|
|
139
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
|
-
|
|
140
|
+
userId: z
|
|
141
141
|
.string()
|
|
142
142
|
.optional()
|
|
143
143
|
.describe("Operator AdminUser identifier. Defaults to ADMIN_USER_ID env."),
|
|
@@ -150,11 +150,11 @@ server.tool("voice-retrieve-conditioning", "Return the operator's style card and
|
|
|
150
150
|
.describe("Short = email/post (K=5, 16k tokens); long = brochure/prospectus (K=15, 96k tokens)"),
|
|
151
151
|
register: z.string().optional().describe("Optional register hint"),
|
|
152
152
|
tokenBudget: z.number().int().positive().optional(),
|
|
153
|
-
}, async ({
|
|
153
|
+
}, async ({ userId, topic, format, register, tokenBudget }) => {
|
|
154
154
|
if (!accountId)
|
|
155
155
|
return refuseNoAccount("voice-retrieve-conditioning");
|
|
156
|
-
const
|
|
157
|
-
if (!
|
|
156
|
+
const resolvedUserId = userId ?? resolveUserId();
|
|
157
|
+
if (!resolvedUserId) {
|
|
158
158
|
return {
|
|
159
159
|
content: [
|
|
160
160
|
{
|
|
@@ -167,7 +167,7 @@ server.tool("voice-retrieve-conditioning", "Return the operator's style card and
|
|
|
167
167
|
try {
|
|
168
168
|
const result = await voiceRetrieveConditioning({
|
|
169
169
|
accountId,
|
|
170
|
-
|
|
170
|
+
userId: resolvedUserId,
|
|
171
171
|
brief: { topic, format, register },
|
|
172
172
|
tokenBudget,
|
|
173
173
|
});
|
|
@@ -192,7 +192,7 @@ server.tool("voice-retrieve-conditioning", "Return the operator's style card and
|
|
|
192
192
|
}
|
|
193
193
|
});
|
|
194
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
|
-
|
|
195
|
+
userId: z.string().optional(),
|
|
196
196
|
originalText: z.string().min(1),
|
|
197
197
|
editedText: z.string().min(1),
|
|
198
198
|
intent: z
|
|
@@ -201,16 +201,16 @@ server.tool("voice-record-feedback", "Capture an operator's edit on an agent dra
|
|
|
201
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
202
|
skill: z.string().optional().describe("Calling skill name, for provenance"),
|
|
203
203
|
brief: z.string().optional().describe("Drafting brief that produced the original"),
|
|
204
|
-
}, async ({
|
|
204
|
+
}, async ({ userId, originalText, editedText, intent, skill, brief }) => {
|
|
205
205
|
if (!accountId)
|
|
206
206
|
return refuseNoAccount("voice-record-feedback");
|
|
207
|
-
const
|
|
208
|
-
if (!
|
|
207
|
+
const resolvedUserId = userId ?? resolveUserId();
|
|
208
|
+
if (!resolvedUserId) {
|
|
209
209
|
return {
|
|
210
210
|
content: [
|
|
211
211
|
{
|
|
212
212
|
type: "text",
|
|
213
|
-
text: "voice-record-feedback:
|
|
213
|
+
text: "voice-record-feedback: userId required (no ADMIN_USER_ID in spawn env).",
|
|
214
214
|
},
|
|
215
215
|
],
|
|
216
216
|
isError: true,
|
|
@@ -219,7 +219,7 @@ server.tool("voice-record-feedback", "Capture an operator's edit on an agent dra
|
|
|
219
219
|
try {
|
|
220
220
|
const result = await voiceRecordFeedback({
|
|
221
221
|
accountId,
|
|
222
|
-
|
|
222
|
+
userId: resolvedUserId,
|
|
223
223
|
originalText,
|
|
224
224
|
editedText,
|
|
225
225
|
intent,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,uDAAuD,CAAC;AACtF,aAAa,CAAC,cAAc,CAAC,CAAC;AAE9B,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAuB,MAAM,8BAA8B,CAAC;AACtG,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,mBAAmB;IACzB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,wEAAwE;AACxE,mEAAmE;AACnE,sBAAsB;AACtB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC;AACjD,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-distil-profile.d.ts","sourceRoot":"","sources":["../../src/tools/voice-distil-profile.ts"],"names":[],"mappings":"AA4CA,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,
|
|
1
|
+
{"version":3,"file":"voice-distil-profile.d.ts","sourceRoot":"","sources":["../../src/tools/voice-distil-profile.ts"],"names":[],"mappings":"AA4CA,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC1B,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,iBAAiB,GAAG,QAAQ,GAAG,cAAc,GAAG,oBAAoB,CAAC;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAClC,uFAAuF;IACvF,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAOD,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,wBAAwB,CAAC,CAsNnC"}
|
|
@@ -46,19 +46,19 @@ const RE_RUN_AGE_DAYS = 30;
|
|
|
46
46
|
// openingPattern, closingPattern, exemplarSentences
|
|
47
47
|
// Exemplar sentences should be quoted verbatim from the returned corpus.
|
|
48
48
|
export async function voiceDistilProfile(params) {
|
|
49
|
-
const { accountId,
|
|
50
|
-
if (!accountId || !
|
|
51
|
-
throw new Error("voice-distil-profile: accountId and
|
|
49
|
+
const { accountId, userId, force = false } = params;
|
|
50
|
+
if (!accountId || !userId) {
|
|
51
|
+
throw new Error("voice-distil-profile: accountId and userId required");
|
|
52
52
|
}
|
|
53
53
|
const session = getSession();
|
|
54
54
|
const now = new Date();
|
|
55
55
|
const nowIso = now.toISOString();
|
|
56
56
|
try {
|
|
57
57
|
// 1. Read existing profile (if any) for cadence-guard comparison.
|
|
58
|
-
const existing = await session.run(`MATCH (a:AdminUser {accountId: $accountId,
|
|
58
|
+
const existing = await session.run(`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
59
59
|
OPTIONAL MATCH (a)-[:HAS_VOICE_PROFILE]->(p:VoiceProfile)
|
|
60
60
|
RETURN elementId(p) AS profileId, p.corpusSize AS corpusSize,
|
|
61
|
-
p.generatedAt AS generatedAt`, { accountId,
|
|
61
|
+
p.generatedAt AS generatedAt`, { accountId, userId });
|
|
62
62
|
const existingRow = existing.records[0];
|
|
63
63
|
const prevProfileId = existingRow?.get("profileId") ?? null;
|
|
64
64
|
const prevCorpusSize = toJsNumber(existingRow?.get("corpusSize"));
|
|
@@ -72,7 +72,7 @@ export async function voiceDistilProfile(params) {
|
|
|
72
72
|
RETURN count(n) AS c`, { accountId });
|
|
73
73
|
const corpusSize = toJsNumber(countResult.records[0]?.get("c")) ?? 0;
|
|
74
74
|
if (corpusSize === 0) {
|
|
75
|
-
process.stderr.write(`[voice-distil] adminUser=${
|
|
75
|
+
process.stderr.write(`[voice-distil] adminUser=${userId} skip reason=empty-corpus\n`);
|
|
76
76
|
return {
|
|
77
77
|
profileId: prevProfileId,
|
|
78
78
|
corpusSize: 0,
|
|
@@ -96,7 +96,7 @@ export async function voiceDistilProfile(params) {
|
|
|
96
96
|
const growthTrigger = growth >= RE_RUN_GROWTH_FRACTION;
|
|
97
97
|
if (!ageTrigger && !growthTrigger) {
|
|
98
98
|
const reason = ageDays < 1 ? "recent" : "below-threshold";
|
|
99
|
-
process.stderr.write(`[voice-distil] adminUser=${
|
|
99
|
+
process.stderr.write(`[voice-distil] adminUser=${userId} skip reason=${reason} corpusSize=${corpusSize} prevCorpus=${prevCorpusSize} ageDays=${ageDays.toFixed(1)}\n`);
|
|
100
100
|
return {
|
|
101
101
|
profileId: prevProfileId,
|
|
102
102
|
corpusSize,
|
|
@@ -145,9 +145,9 @@ export async function voiceDistilProfile(params) {
|
|
|
145
145
|
break;
|
|
146
146
|
}
|
|
147
147
|
// 5. Pull feedback intents from existing :VoiceEdit nodes for this operator.
|
|
148
|
-
const feedback = await session.run(`MATCH (a:AdminUser {accountId: $accountId,
|
|
149
|
-
MATCH (e:VoiceEdit {
|
|
150
|
-
RETURN e.intent AS intent ORDER BY e.occurredAt DESC LIMIT 50`, { accountId,
|
|
148
|
+
const feedback = await session.run(`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
149
|
+
MATCH (e:VoiceEdit {userId: $userId, accountId: $accountId})
|
|
150
|
+
RETURN e.intent AS intent ORDER BY e.occurredAt DESC LIMIT 50`, { accountId, userId });
|
|
151
151
|
const feedbackIntents = feedback.records
|
|
152
152
|
.map((r) => r.get("intent"))
|
|
153
153
|
.filter((x) => typeof x === "string" && x.length > 0);
|
|
@@ -158,7 +158,7 @@ export async function voiceDistilProfile(params) {
|
|
|
158
158
|
// - `write`: persist the agent-produced style card.
|
|
159
159
|
const mode = params.mode ?? "sample";
|
|
160
160
|
if (mode === "sample") {
|
|
161
|
-
process.stderr.write(`[voice-distil] adminUser=${
|
|
161
|
+
process.stderr.write(`[voice-distil] adminUser=${userId} mode=sample corpusSize=${corpusSize} ` +
|
|
162
162
|
`exemplars=${samples.length} feedbackEntries=${feedbackIntents.length}\n`);
|
|
163
163
|
return {
|
|
164
164
|
profileId: prevProfileId,
|
|
@@ -179,11 +179,11 @@ export async function voiceDistilProfile(params) {
|
|
|
179
179
|
//
|
|
180
180
|
// The :AdminUser must already exist (onboarding/auth is the only
|
|
181
181
|
// legitimate origin for :AdminUser). MATCH not MERGE: a typo in
|
|
182
|
-
//
|
|
182
|
+
// userId, an env mismatch, or a dropped credential surfaces
|
|
183
183
|
// here as a typed error rather than silently minting an orphan
|
|
184
184
|
// AdminUser that bypasses the platform's label-origin protection.
|
|
185
|
-
const writeResult = await session.run(`MATCH (a:AdminUser {accountId: $accountId,
|
|
186
|
-
MERGE (a)-[:HAS_VOICE_PROFILE]->(p:VoiceProfile {accountId: $accountId,
|
|
185
|
+
const writeResult = await session.run(`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
186
|
+
MERGE (a)-[:HAS_VOICE_PROFILE]->(p:VoiceProfile {accountId: $accountId, userId: $userId})
|
|
187
187
|
ON CREATE SET p.createdAt = $now
|
|
188
188
|
SET p.styleCard = $styleCard,
|
|
189
189
|
p.generatedAt = $now,
|
|
@@ -196,7 +196,7 @@ export async function voiceDistilProfile(params) {
|
|
|
196
196
|
MERGE (p)-[:LEARNED_FROM]->(s)
|
|
197
197
|
RETURN elementId(p) AS profileId`, {
|
|
198
198
|
accountId,
|
|
199
|
-
|
|
199
|
+
userId,
|
|
200
200
|
styleCard: styleCardYaml,
|
|
201
201
|
now: nowIso,
|
|
202
202
|
corpusSize,
|
|
@@ -206,10 +206,10 @@ export async function voiceDistilProfile(params) {
|
|
|
206
206
|
// MATCH-on-:AdminUser failure yields zero records. Throw the typed
|
|
207
207
|
// error here rather than returning a half-baked result.
|
|
208
208
|
if (writeResult.records.length === 0) {
|
|
209
|
-
throw new Error(`voice-mirror: :AdminUser {accountId='${accountId}',
|
|
209
|
+
throw new Error(`voice-mirror: :AdminUser {accountId='${accountId}', userId='${userId}'} not found. Onboarding must promote the operator to :AdminUser before distillation.`);
|
|
210
210
|
}
|
|
211
211
|
const profileId = writeResult.records[0].get("profileId");
|
|
212
|
-
process.stderr.write(`[voice-distil] adminUser=${
|
|
212
|
+
process.stderr.write(`[voice-distil] adminUser=${userId} mode=write corpusSize=${corpusSize} generatedAt=${nowIso} feedbackEntries=${feedbackIntents.length}\n`);
|
|
213
213
|
return {
|
|
214
214
|
profileId,
|
|
215
215
|
corpusSize,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-distil-profile.js","sourceRoot":"","sources":["../../src/tools/voice-distil-profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,MAAM,cAAc,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,6EAA6E;AAC7E,6EAA6E;AAC7E,gFAAgF;AAChF,wEAAwE;AAExE;;;;;;;;GAQG;AACH,SAAS,UAAU,CAAC,KAAc;IAChC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACvD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAQ,KAAoC,CAAC,QAAQ,EAAE,CAAC;IAChF,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7B,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IACjD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,eAAe,GAAG,OAAO,CAAC;AAChC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AACnC,MAAM,eAAe,GAAG,EAAE,CAAC;AAuC3B,mEAAmE;AACnE,qEAAqE;AACrE,sDAAsD;AACtD,yEAAyE;AAEzE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAgC;IAEhC,MAAM,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"voice-distil-profile.js","sourceRoot":"","sources":["../../src/tools/voice-distil-profile.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-record-feedback.d.ts","sourceRoot":"","sources":["../../src/tools/voice-record-feedback.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,
|
|
1
|
+
{"version":3,"file":"voice-record-feedback.d.ts","sourceRoot":"","sources":["../../src/tools/voice-record-feedback.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,yBAAyB,CAAC,CAoEpC"}
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
import { randomUUID } from "node:crypto";
|
|
16
16
|
import { getSession } from "../lib/neo4j.js";
|
|
17
17
|
export async function voiceRecordFeedback(params) {
|
|
18
|
-
const { accountId,
|
|
19
|
-
if (!accountId || !
|
|
20
|
-
throw new Error("voice-record-feedback: accountId and
|
|
18
|
+
const { accountId, userId, originalText, editedText, intent: rawIntent, context } = params;
|
|
19
|
+
if (!accountId || !userId) {
|
|
20
|
+
throw new Error("voice-record-feedback: accountId and userId required");
|
|
21
21
|
}
|
|
22
22
|
if (!originalText || !editedText) {
|
|
23
23
|
throw new Error("voice-record-feedback: originalText and editedText required");
|
|
@@ -31,11 +31,11 @@ export async function voiceRecordFeedback(params) {
|
|
|
31
31
|
const cappedIntent = intent.slice(0, 500);
|
|
32
32
|
const session = getSession();
|
|
33
33
|
try {
|
|
34
|
-
const result = await session.run(`MATCH (a:AdminUser {accountId: $accountId,
|
|
34
|
+
const result = await session.run(`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
35
35
|
CREATE (e:VoiceEdit {
|
|
36
36
|
editId: $editId,
|
|
37
37
|
accountId: $accountId,
|
|
38
|
-
|
|
38
|
+
userId: $userId,
|
|
39
39
|
originalText: $originalText,
|
|
40
40
|
editedText: $editedText,
|
|
41
41
|
intent: $intent,
|
|
@@ -45,13 +45,13 @@ export async function voiceRecordFeedback(params) {
|
|
|
45
45
|
})
|
|
46
46
|
CREATE (a)-[:AUTHORED]->(e)
|
|
47
47
|
WITH e
|
|
48
|
-
OPTIONAL MATCH (:AdminUser {accountId: $accountId,
|
|
48
|
+
OPTIONAL MATCH (:AdminUser {accountId: $accountId, userId: $userId})-[:HAS_VOICE_PROFILE]->(p:VoiceProfile)
|
|
49
49
|
FOREACH (_ IN CASE WHEN p IS NULL THEN [] ELSE [1] END |
|
|
50
50
|
MERGE (e)-[:FEEDBACK_FOR]->(p)
|
|
51
51
|
)
|
|
52
52
|
RETURN elementId(e) AS editId, (p IS NOT NULL) AS hadProfile`, {
|
|
53
53
|
accountId,
|
|
54
|
-
|
|
54
|
+
userId,
|
|
55
55
|
editId,
|
|
56
56
|
originalText,
|
|
57
57
|
editedText,
|
|
@@ -61,10 +61,10 @@ export async function voiceRecordFeedback(params) {
|
|
|
61
61
|
brief: context?.brief ?? null,
|
|
62
62
|
});
|
|
63
63
|
if (result.records.length === 0) {
|
|
64
|
-
throw new Error(`voice-mirror: :AdminUser {accountId='${accountId}',
|
|
64
|
+
throw new Error(`voice-mirror: :AdminUser {accountId='${accountId}', userId='${userId}'} not found. Onboarding must promote the operator to :AdminUser before feedback can be recorded.`);
|
|
65
65
|
}
|
|
66
66
|
const hadProfile = result.records[0].get("hadProfile") === true;
|
|
67
|
-
process.stderr.write(`[voice-record-feedback] adminUser=${
|
|
67
|
+
process.stderr.write(`[voice-record-feedback] adminUser=${userId} intent="${cappedIntent.replace(/"/g, "'")}" diffBytes=${editedText.length - originalText.length}\n`);
|
|
68
68
|
return { editId, intent: cappedIntent, occurredAt, hadProfile };
|
|
69
69
|
}
|
|
70
70
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-record-feedback.js","sourceRoot":"","sources":["../../src/tools/voice-record-feedback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AA4B7C,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAiC;IAEjC,MAAM,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"voice-record-feedback.js","sourceRoot":"","sources":["../../src/tools/voice-record-feedback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AA4B7C,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAiC;IAEjC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;IAC3F,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,CAAC,YAAY,IAAI,CAAC,UAAU,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,8HAA8H,CAC/H,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5C,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAE1C,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B;;;;;;;;;;;;;;;;;;oEAkB8D,EAC9D;YACE,SAAS;YACT,MAAM;YACN,MAAM;YACN,YAAY;YACZ,UAAU;YACV,MAAM,EAAE,YAAY;YACpB,UAAU;YACV,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,IAAI;YAC7B,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,IAAI;SAC9B,CACF,CAAC;QACF,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,wCAAwC,SAAS,cAAc,MAAM,mGAAmG,CACzK,CAAC;QACJ,CAAC;QACD,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;QAEhE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,qCAAqC,MAAM,YAAY,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,eAAe,UAAU,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM,IAAI,CACjJ,CAAC;QAEF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;IAClE,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;AACH,CAAC"}
|
package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-retrieve-conditioning.d.ts","sourceRoot":"","sources":["../../src/tools/voice-retrieve-conditioning.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,+BAA+B;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,
|
|
1
|
+
{"version":3,"file":"voice-retrieve-conditioning.d.ts","sourceRoot":"","sources":["../../src/tools/voice-retrieve-conditioning.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,+BAA+B;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE;QACL,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,+BAA+B;IAC9C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,aAAa,EAAE,CAAC;CAC5B;AAID,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,+BAA+B,GACtC,OAAO,CAAC,+BAA+B,CAAC,CA2F1C"}
|
|
@@ -24,8 +24,8 @@ const DEFAULT_TOKEN_BUDGET_LONG = 96_000;
|
|
|
24
24
|
const CHARS_PER_TOKEN = 4;
|
|
25
25
|
const EMPTY = { styleCard: null, exemplars: [] };
|
|
26
26
|
export async function voiceRetrieveConditioning(params) {
|
|
27
|
-
const { accountId,
|
|
28
|
-
if (!accountId || !
|
|
27
|
+
const { accountId, userId, brief } = params;
|
|
28
|
+
if (!accountId || !userId)
|
|
29
29
|
return EMPTY;
|
|
30
30
|
const k = brief.format === "long" ? 15 : 5;
|
|
31
31
|
const tokenBudget = params.tokenBudget ??
|
|
@@ -34,9 +34,9 @@ export async function voiceRetrieveConditioning(params) {
|
|
|
34
34
|
const session = getSession();
|
|
35
35
|
try {
|
|
36
36
|
// 1. Style card.
|
|
37
|
-
const profile = await session.run(`MATCH (a:AdminUser {accountId: $accountId,
|
|
37
|
+
const profile = await session.run(`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
38
38
|
OPTIONAL MATCH (a)-[:HAS_VOICE_PROFILE]->(p:VoiceProfile)
|
|
39
|
-
RETURN p.styleCard AS styleCard`, { accountId,
|
|
39
|
+
RETURN p.styleCard AS styleCard`, { accountId, userId });
|
|
40
40
|
const styleCard = profile.records[0]?.get("styleCard") ?? null;
|
|
41
41
|
// 2. Exemplars. Keyword-aware filter when brief.topic is set.
|
|
42
42
|
const topic = (brief.topic ?? "").trim();
|
package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-retrieve-conditioning.js","sourceRoot":"","sources":["../../src/tools/voice-retrieve-conditioning.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,MAAM,0BAA0B,GAAG,MAAM,CAAC;AAC1C,MAAM,yBAAyB,GAAG,MAAM,CAAC;AACzC,MAAM,eAAe,GAAG,CAAC,CAAC;AAyB1B,MAAM,KAAK,GAAoC,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;AAElF,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAuC;IAEvC,MAAM,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"voice-retrieve-conditioning.js","sourceRoot":"","sources":["../../src/tools/voice-retrieve-conditioning.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,9 +19,9 @@ const server = new McpServer({
|
|
|
19
19
|
// refusal preserves account isolation. Mirrors the memory plugin's
|
|
20
20
|
// pattern (Task 202).
|
|
21
21
|
const accountId = process.env.ACCOUNT_ID ?? null;
|
|
22
|
-
const
|
|
22
|
+
const userIdEnv = process.env.ADMIN_USER_ID ?? null;
|
|
23
23
|
process.stderr.write(
|
|
24
|
-
`[writer-craft] boot accountId=${accountId ?? "null"}
|
|
24
|
+
`[writer-craft] boot accountId=${accountId ?? "null"} userId=${userIdEnv ?? "null"}\n`,
|
|
25
25
|
);
|
|
26
26
|
|
|
27
27
|
function refuseNoAccount(toolName: string) {
|
|
@@ -39,11 +39,11 @@ function refuseNoAccount(toolName: string) {
|
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
function
|
|
42
|
+
function resolveUserId(): string | null {
|
|
43
43
|
// ADMIN_USER_ID is stamped by the admin session manager at spawn time.
|
|
44
44
|
// When absent (e.g. specialist subagents), the operator must pass it as
|
|
45
45
|
// a tool argument or the tools refuse rather than orphan a profile.
|
|
46
|
-
return
|
|
46
|
+
return userIdEnv;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
server.tool(
|
|
@@ -95,7 +95,7 @@ server.tool(
|
|
|
95
95
|
"voice-distil-profile",
|
|
96
96
|
"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).",
|
|
97
97
|
{
|
|
98
|
-
|
|
98
|
+
userId: z
|
|
99
99
|
.string()
|
|
100
100
|
.optional()
|
|
101
101
|
.describe(
|
|
@@ -114,16 +114,16 @@ server.tool(
|
|
|
114
114
|
.optional()
|
|
115
115
|
.describe("Required for mode='write'. The YAML style card the agent composed from the sample-mode exemplars + feedback intents."),
|
|
116
116
|
},
|
|
117
|
-
async ({
|
|
117
|
+
async ({ userId, force, mode, styleCardYaml }) => {
|
|
118
118
|
if (!accountId) return refuseNoAccount("voice-distil-profile");
|
|
119
|
-
const
|
|
120
|
-
if (!
|
|
119
|
+
const resolvedUserId = userId ?? resolveUserId();
|
|
120
|
+
if (!resolvedUserId) {
|
|
121
121
|
return {
|
|
122
122
|
content: [
|
|
123
123
|
{
|
|
124
124
|
type: "text" as const,
|
|
125
125
|
text:
|
|
126
|
-
"voice-distil-profile:
|
|
126
|
+
"voice-distil-profile: userId required (no ADMIN_USER_ID in spawn env).",
|
|
127
127
|
},
|
|
128
128
|
],
|
|
129
129
|
isError: true,
|
|
@@ -132,7 +132,7 @@ server.tool(
|
|
|
132
132
|
try {
|
|
133
133
|
const result = await voiceDistilProfile({
|
|
134
134
|
accountId,
|
|
135
|
-
|
|
135
|
+
userId: resolvedUserId,
|
|
136
136
|
force: force === true,
|
|
137
137
|
mode,
|
|
138
138
|
styleCardYaml,
|
|
@@ -161,7 +161,7 @@ server.tool(
|
|
|
161
161
|
"voice-retrieve-conditioning",
|
|
162
162
|
"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.",
|
|
163
163
|
{
|
|
164
|
-
|
|
164
|
+
userId: z
|
|
165
165
|
.string()
|
|
166
166
|
.optional()
|
|
167
167
|
.describe("Operator AdminUser identifier. Defaults to ADMIN_USER_ID env."),
|
|
@@ -175,10 +175,10 @@ server.tool(
|
|
|
175
175
|
register: z.string().optional().describe("Optional register hint"),
|
|
176
176
|
tokenBudget: z.number().int().positive().optional(),
|
|
177
177
|
},
|
|
178
|
-
async ({
|
|
178
|
+
async ({ userId, topic, format, register, tokenBudget }) => {
|
|
179
179
|
if (!accountId) return refuseNoAccount("voice-retrieve-conditioning");
|
|
180
|
-
const
|
|
181
|
-
if (!
|
|
180
|
+
const resolvedUserId = userId ?? resolveUserId();
|
|
181
|
+
if (!resolvedUserId) {
|
|
182
182
|
return {
|
|
183
183
|
content: [
|
|
184
184
|
{
|
|
@@ -191,7 +191,7 @@ server.tool(
|
|
|
191
191
|
try {
|
|
192
192
|
const result = await voiceRetrieveConditioning({
|
|
193
193
|
accountId,
|
|
194
|
-
|
|
194
|
+
userId: resolvedUserId,
|
|
195
195
|
brief: { topic, format, register },
|
|
196
196
|
tokenBudget,
|
|
197
197
|
});
|
|
@@ -222,7 +222,7 @@ server.tool(
|
|
|
222
222
|
"voice-record-feedback",
|
|
223
223
|
"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.",
|
|
224
224
|
{
|
|
225
|
-
|
|
225
|
+
userId: z.string().optional(),
|
|
226
226
|
originalText: z.string().min(1),
|
|
227
227
|
editedText: z.string().min(1),
|
|
228
228
|
intent: z
|
|
@@ -232,15 +232,15 @@ server.tool(
|
|
|
232
232
|
skill: z.string().optional().describe("Calling skill name, for provenance"),
|
|
233
233
|
brief: z.string().optional().describe("Drafting brief that produced the original"),
|
|
234
234
|
},
|
|
235
|
-
async ({
|
|
235
|
+
async ({ userId, originalText, editedText, intent, skill, brief }) => {
|
|
236
236
|
if (!accountId) return refuseNoAccount("voice-record-feedback");
|
|
237
|
-
const
|
|
238
|
-
if (!
|
|
237
|
+
const resolvedUserId = userId ?? resolveUserId();
|
|
238
|
+
if (!resolvedUserId) {
|
|
239
239
|
return {
|
|
240
240
|
content: [
|
|
241
241
|
{
|
|
242
242
|
type: "text" as const,
|
|
243
|
-
text: "voice-record-feedback:
|
|
243
|
+
text: "voice-record-feedback: userId required (no ADMIN_USER_ID in spawn env).",
|
|
244
244
|
},
|
|
245
245
|
],
|
|
246
246
|
isError: true,
|
|
@@ -249,7 +249,7 @@ server.tool(
|
|
|
249
249
|
try {
|
|
250
250
|
const result = await voiceRecordFeedback({
|
|
251
251
|
accountId,
|
|
252
|
-
|
|
252
|
+
userId: resolvedUserId,
|
|
253
253
|
originalText,
|
|
254
254
|
editedText,
|
|
255
255
|
intent,
|
|
@@ -44,7 +44,7 @@ const RE_RUN_AGE_DAYS = 30;
|
|
|
44
44
|
|
|
45
45
|
export interface VoiceDistilProfileParams {
|
|
46
46
|
accountId: string;
|
|
47
|
-
|
|
47
|
+
userId: string;
|
|
48
48
|
force?: boolean;
|
|
49
49
|
/**
|
|
50
50
|
* Operation mode (Task 424):
|
|
@@ -87,9 +87,9 @@ export interface VoiceDistilProfileResult {
|
|
|
87
87
|
export async function voiceDistilProfile(
|
|
88
88
|
params: VoiceDistilProfileParams,
|
|
89
89
|
): Promise<VoiceDistilProfileResult> {
|
|
90
|
-
const { accountId,
|
|
91
|
-
if (!accountId || !
|
|
92
|
-
throw new Error("voice-distil-profile: accountId and
|
|
90
|
+
const { accountId, userId, force = false } = params;
|
|
91
|
+
if (!accountId || !userId) {
|
|
92
|
+
throw new Error("voice-distil-profile: accountId and userId required");
|
|
93
93
|
}
|
|
94
94
|
const session = getSession();
|
|
95
95
|
const now = new Date();
|
|
@@ -98,11 +98,11 @@ export async function voiceDistilProfile(
|
|
|
98
98
|
try {
|
|
99
99
|
// 1. Read existing profile (if any) for cadence-guard comparison.
|
|
100
100
|
const existing = await session.run(
|
|
101
|
-
`MATCH (a:AdminUser {accountId: $accountId,
|
|
101
|
+
`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
102
102
|
OPTIONAL MATCH (a)-[:HAS_VOICE_PROFILE]->(p:VoiceProfile)
|
|
103
103
|
RETURN elementId(p) AS profileId, p.corpusSize AS corpusSize,
|
|
104
104
|
p.generatedAt AS generatedAt`,
|
|
105
|
-
{ accountId,
|
|
105
|
+
{ accountId, userId },
|
|
106
106
|
);
|
|
107
107
|
const existingRow = existing.records[0];
|
|
108
108
|
const prevProfileId = (existingRow?.get("profileId") as string | null) ?? null;
|
|
@@ -123,7 +123,7 @@ export async function voiceDistilProfile(
|
|
|
123
123
|
|
|
124
124
|
if (corpusSize === 0) {
|
|
125
125
|
process.stderr.write(
|
|
126
|
-
`[voice-distil] adminUser=${
|
|
126
|
+
`[voice-distil] adminUser=${userId} skip reason=empty-corpus\n`,
|
|
127
127
|
);
|
|
128
128
|
return {
|
|
129
129
|
profileId: prevProfileId,
|
|
@@ -151,7 +151,7 @@ export async function voiceDistilProfile(
|
|
|
151
151
|
if (!ageTrigger && !growthTrigger) {
|
|
152
152
|
const reason = ageDays < 1 ? "recent" : "below-threshold";
|
|
153
153
|
process.stderr.write(
|
|
154
|
-
`[voice-distil] adminUser=${
|
|
154
|
+
`[voice-distil] adminUser=${userId} skip reason=${reason} corpusSize=${corpusSize} prevCorpus=${prevCorpusSize} ageDays=${ageDays.toFixed(1)}\n`,
|
|
155
155
|
);
|
|
156
156
|
return {
|
|
157
157
|
profileId: prevProfileId,
|
|
@@ -207,10 +207,10 @@ export async function voiceDistilProfile(
|
|
|
207
207
|
|
|
208
208
|
// 5. Pull feedback intents from existing :VoiceEdit nodes for this operator.
|
|
209
209
|
const feedback = await session.run(
|
|
210
|
-
`MATCH (a:AdminUser {accountId: $accountId,
|
|
211
|
-
MATCH (e:VoiceEdit {
|
|
210
|
+
`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
211
|
+
MATCH (e:VoiceEdit {userId: $userId, accountId: $accountId})
|
|
212
212
|
RETURN e.intent AS intent ORDER BY e.occurredAt DESC LIMIT 50`,
|
|
213
|
-
{ accountId,
|
|
213
|
+
{ accountId, userId },
|
|
214
214
|
);
|
|
215
215
|
const feedbackIntents = feedback.records
|
|
216
216
|
.map((r) => r.get("intent") as string | null)
|
|
@@ -224,7 +224,7 @@ export async function voiceDistilProfile(
|
|
|
224
224
|
const mode = params.mode ?? "sample";
|
|
225
225
|
if (mode === "sample") {
|
|
226
226
|
process.stderr.write(
|
|
227
|
-
`[voice-distil] adminUser=${
|
|
227
|
+
`[voice-distil] adminUser=${userId} mode=sample corpusSize=${corpusSize} ` +
|
|
228
228
|
`exemplars=${samples.length} feedbackEntries=${feedbackIntents.length}\n`,
|
|
229
229
|
);
|
|
230
230
|
return {
|
|
@@ -250,12 +250,12 @@ export async function voiceDistilProfile(
|
|
|
250
250
|
//
|
|
251
251
|
// The :AdminUser must already exist (onboarding/auth is the only
|
|
252
252
|
// legitimate origin for :AdminUser). MATCH not MERGE: a typo in
|
|
253
|
-
//
|
|
253
|
+
// userId, an env mismatch, or a dropped credential surfaces
|
|
254
254
|
// here as a typed error rather than silently minting an orphan
|
|
255
255
|
// AdminUser that bypasses the platform's label-origin protection.
|
|
256
256
|
const writeResult = await session.run(
|
|
257
|
-
`MATCH (a:AdminUser {accountId: $accountId,
|
|
258
|
-
MERGE (a)-[:HAS_VOICE_PROFILE]->(p:VoiceProfile {accountId: $accountId,
|
|
257
|
+
`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
258
|
+
MERGE (a)-[:HAS_VOICE_PROFILE]->(p:VoiceProfile {accountId: $accountId, userId: $userId})
|
|
259
259
|
ON CREATE SET p.createdAt = $now
|
|
260
260
|
SET p.styleCard = $styleCard,
|
|
261
261
|
p.generatedAt = $now,
|
|
@@ -269,7 +269,7 @@ export async function voiceDistilProfile(
|
|
|
269
269
|
RETURN elementId(p) AS profileId`,
|
|
270
270
|
{
|
|
271
271
|
accountId,
|
|
272
|
-
|
|
272
|
+
userId,
|
|
273
273
|
styleCard: styleCardYaml,
|
|
274
274
|
now: nowIso,
|
|
275
275
|
corpusSize,
|
|
@@ -281,13 +281,13 @@ export async function voiceDistilProfile(
|
|
|
281
281
|
// error here rather than returning a half-baked result.
|
|
282
282
|
if (writeResult.records.length === 0) {
|
|
283
283
|
throw new Error(
|
|
284
|
-
`voice-mirror: :AdminUser {accountId='${accountId}',
|
|
284
|
+
`voice-mirror: :AdminUser {accountId='${accountId}', userId='${userId}'} not found. Onboarding must promote the operator to :AdminUser before distillation.`,
|
|
285
285
|
);
|
|
286
286
|
}
|
|
287
287
|
const profileId = writeResult.records[0].get("profileId") as string;
|
|
288
288
|
|
|
289
289
|
process.stderr.write(
|
|
290
|
-
`[voice-distil] adminUser=${
|
|
290
|
+
`[voice-distil] adminUser=${userId} mode=write corpusSize=${corpusSize} generatedAt=${nowIso} feedbackEntries=${feedbackIntents.length}\n`,
|
|
291
291
|
);
|
|
292
292
|
|
|
293
293
|
return {
|
|
@@ -17,7 +17,7 @@ import { getSession } from "../lib/neo4j.js";
|
|
|
17
17
|
|
|
18
18
|
export interface VoiceRecordFeedbackParams {
|
|
19
19
|
accountId: string;
|
|
20
|
-
|
|
20
|
+
userId: string;
|
|
21
21
|
originalText: string;
|
|
22
22
|
editedText: string;
|
|
23
23
|
/**
|
|
@@ -44,9 +44,9 @@ export interface VoiceRecordFeedbackResult {
|
|
|
44
44
|
export async function voiceRecordFeedback(
|
|
45
45
|
params: VoiceRecordFeedbackParams,
|
|
46
46
|
): Promise<VoiceRecordFeedbackResult> {
|
|
47
|
-
const { accountId,
|
|
48
|
-
if (!accountId || !
|
|
49
|
-
throw new Error("voice-record-feedback: accountId and
|
|
47
|
+
const { accountId, userId, originalText, editedText, intent: rawIntent, context } = params;
|
|
48
|
+
if (!accountId || !userId) {
|
|
49
|
+
throw new Error("voice-record-feedback: accountId and userId required");
|
|
50
50
|
}
|
|
51
51
|
if (!originalText || !editedText) {
|
|
52
52
|
throw new Error("voice-record-feedback: originalText and editedText required");
|
|
@@ -65,11 +65,11 @@ export async function voiceRecordFeedback(
|
|
|
65
65
|
const session = getSession();
|
|
66
66
|
try {
|
|
67
67
|
const result = await session.run(
|
|
68
|
-
`MATCH (a:AdminUser {accountId: $accountId,
|
|
68
|
+
`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
69
69
|
CREATE (e:VoiceEdit {
|
|
70
70
|
editId: $editId,
|
|
71
71
|
accountId: $accountId,
|
|
72
|
-
|
|
72
|
+
userId: $userId,
|
|
73
73
|
originalText: $originalText,
|
|
74
74
|
editedText: $editedText,
|
|
75
75
|
intent: $intent,
|
|
@@ -79,14 +79,14 @@ export async function voiceRecordFeedback(
|
|
|
79
79
|
})
|
|
80
80
|
CREATE (a)-[:AUTHORED]->(e)
|
|
81
81
|
WITH e
|
|
82
|
-
OPTIONAL MATCH (:AdminUser {accountId: $accountId,
|
|
82
|
+
OPTIONAL MATCH (:AdminUser {accountId: $accountId, userId: $userId})-[:HAS_VOICE_PROFILE]->(p:VoiceProfile)
|
|
83
83
|
FOREACH (_ IN CASE WHEN p IS NULL THEN [] ELSE [1] END |
|
|
84
84
|
MERGE (e)-[:FEEDBACK_FOR]->(p)
|
|
85
85
|
)
|
|
86
86
|
RETURN elementId(e) AS editId, (p IS NOT NULL) AS hadProfile`,
|
|
87
87
|
{
|
|
88
88
|
accountId,
|
|
89
|
-
|
|
89
|
+
userId,
|
|
90
90
|
editId,
|
|
91
91
|
originalText,
|
|
92
92
|
editedText,
|
|
@@ -98,13 +98,13 @@ export async function voiceRecordFeedback(
|
|
|
98
98
|
);
|
|
99
99
|
if (result.records.length === 0) {
|
|
100
100
|
throw new Error(
|
|
101
|
-
`voice-mirror: :AdminUser {accountId='${accountId}',
|
|
101
|
+
`voice-mirror: :AdminUser {accountId='${accountId}', userId='${userId}'} not found. Onboarding must promote the operator to :AdminUser before feedback can be recorded.`,
|
|
102
102
|
);
|
|
103
103
|
}
|
|
104
104
|
const hadProfile = result.records[0].get("hadProfile") === true;
|
|
105
105
|
|
|
106
106
|
process.stderr.write(
|
|
107
|
-
`[voice-record-feedback] adminUser=${
|
|
107
|
+
`[voice-record-feedback] adminUser=${userId} intent="${cappedIntent.replace(/"/g, "'")}" diffBytes=${editedText.length - originalText.length}\n`,
|
|
108
108
|
);
|
|
109
109
|
|
|
110
110
|
return { editId, intent: cappedIntent, occurredAt, hadProfile };
|
|
@@ -26,7 +26,7 @@ const CHARS_PER_TOKEN = 4;
|
|
|
26
26
|
|
|
27
27
|
export interface VoiceRetrieveConditioningParams {
|
|
28
28
|
accountId: string;
|
|
29
|
-
|
|
29
|
+
userId: string;
|
|
30
30
|
brief: {
|
|
31
31
|
topic?: string;
|
|
32
32
|
format: "short" | "long";
|
|
@@ -52,8 +52,8 @@ const EMPTY: VoiceRetrieveConditioningResult = { styleCard: null, exemplars: []
|
|
|
52
52
|
export async function voiceRetrieveConditioning(
|
|
53
53
|
params: VoiceRetrieveConditioningParams,
|
|
54
54
|
): Promise<VoiceRetrieveConditioningResult> {
|
|
55
|
-
const { accountId,
|
|
56
|
-
if (!accountId || !
|
|
55
|
+
const { accountId, userId, brief } = params;
|
|
56
|
+
if (!accountId || !userId) return EMPTY;
|
|
57
57
|
|
|
58
58
|
const k = brief.format === "long" ? 15 : 5;
|
|
59
59
|
const tokenBudget =
|
|
@@ -65,10 +65,10 @@ export async function voiceRetrieveConditioning(
|
|
|
65
65
|
try {
|
|
66
66
|
// 1. Style card.
|
|
67
67
|
const profile = await session.run(
|
|
68
|
-
`MATCH (a:AdminUser {accountId: $accountId,
|
|
68
|
+
`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
69
69
|
OPTIONAL MATCH (a)-[:HAS_VOICE_PROFILE]->(p:VoiceProfile)
|
|
70
70
|
RETURN p.styleCard AS styleCard`,
|
|
71
|
-
{ accountId,
|
|
71
|
+
{ accountId, userId },
|
|
72
72
|
);
|
|
73
73
|
const styleCard = (profile.records[0]?.get("styleCard") as string | null) ?? null;
|
|
74
74
|
|
package/payload/server/server.js
CHANGED
|
@@ -4093,6 +4093,13 @@ function managerBase() {
|
|
|
4093
4093
|
return `http://127.0.0.1:${port2}`;
|
|
4094
4094
|
}
|
|
4095
4095
|
async function managerSpawn(opts) {
|
|
4096
|
+
const auth = await ensureAuth();
|
|
4097
|
+
if (auth.status === "dead" || auth.status === "missing") {
|
|
4098
|
+
console.log(
|
|
4099
|
+
`[channel-pty-bridge] spawn-refused reason=auth-${auth.status} channel=${opts.channel} senderId=${opts.senderId}`
|
|
4100
|
+
);
|
|
4101
|
+
return { error: "claude-auth-dead", status: 503 };
|
|
4102
|
+
}
|
|
4096
4103
|
const res = await fetch(`${managerBase()}/spawn`, {
|
|
4097
4104
|
method: "POST",
|
|
4098
4105
|
headers: { "content-type": "application/json" },
|
|
@@ -4260,9 +4267,11 @@ async function ensureEntry(input) {
|
|
|
4260
4267
|
attachmentDir
|
|
4261
4268
|
});
|
|
4262
4269
|
if ("error" in spawned) {
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4270
|
+
if (spawned.error !== "claude-auth-dead") {
|
|
4271
|
+
console.error(
|
|
4272
|
+
`${tag} reject reason=spawn-failed senderId=${input.senderId} status=${spawned.status} message=${spawned.error}`
|
|
4273
|
+
);
|
|
4274
|
+
}
|
|
4266
4275
|
return null;
|
|
4267
4276
|
}
|
|
4268
4277
|
const entry = {
|