@rubytech/create-maxy-code 0.1.185 → 0.1.187

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 (61) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-directive.test.sh +70 -0
  3. package/payload/platform/plugins/admin/hooks/prompt-optimiser-directive.sh +52 -0
  4. package/payload/platform/plugins/admin/skills/a4-print-documents/SKILL.md +14 -14
  5. package/payload/platform/plugins/admin/skills/deck-pages/SKILL.md +9 -23
  6. package/payload/platform/plugins/admin/skills/professional-document/SKILL.md +1 -1
  7. package/payload/platform/plugins/admin/skills/skill-builder/SKILL.md +1 -1
  8. package/payload/platform/plugins/admin/skills/skill-builder/references/pdf-generation.md +4 -4
  9. package/payload/platform/plugins/browser/.claude-plugin/plugin.json +1 -1
  10. package/payload/platform/plugins/browser/PLUGIN.md +78 -8
  11. package/payload/platform/plugins/browser/mcp/dist/index.js +111 -7
  12. package/payload/platform/plugins/browser/mcp/dist/index.js.map +1 -1
  13. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.d.ts +98 -0
  14. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.d.ts.map +1 -0
  15. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.js +455 -0
  16. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.js.map +1 -0
  17. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.d.ts +9 -31
  18. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.d.ts.map +1 -1
  19. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.js +6 -165
  20. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.js.map +1 -1
  21. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.d.ts +153 -0
  22. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.d.ts.map +1 -0
  23. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.js +401 -0
  24. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.js.map +1 -0
  25. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
  26. package/payload/platform/plugins/email/.claude-plugin/plugin.json +1 -1
  27. package/payload/platform/plugins/email/PLUGIN.md +6 -2
  28. package/payload/platform/plugins/email/mcp/dist/index.js +38 -0
  29. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
  30. package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts +28 -0
  31. package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts.map +1 -1
  32. package/payload/platform/plugins/email/mcp/dist/lib/providers.js +106 -0
  33. package/payload/platform/plugins/email/mcp/dist/lib/providers.js.map +1 -1
  34. package/payload/platform/plugins/email/references/email-reference.md +19 -15
  35. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.d.ts.map +1 -1
  36. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.js +3 -2
  37. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.js.map +1 -1
  38. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.d.ts.map +1 -1
  39. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js +2 -1
  40. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js.map +1 -1
  41. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.d.ts.map +1 -1
  42. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.js +2 -1
  43. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.js.map +1 -1
  44. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.d.ts +1 -1
  45. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.d.ts.map +1 -1
  46. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.js +3 -2
  47. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.js.map +1 -1
  48. package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +15 -0
  49. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js +1 -1
  50. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js.map +1 -1
  51. package/payload/platform/scripts/check-cypher-int-params.mjs +277 -0
  52. package/payload/platform/scripts/setup-account.sh +2 -1
  53. package/payload/platform/templates/specialists/agents/content-producer.md +2 -2
  54. package/payload/platform/templates/specialists/agents/personal-assistant.md +6 -2
  55. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -1
  56. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js +33 -1
  57. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -1
  58. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-retrieve-conditioning.ts +5 -2
  59. package/payload/server/{chunk-L2YK2VK3.js → chunk-EFJ2EXZK.js} +3 -1
  60. package/payload/server/maxy-edge.js +1 -1
  61. package/payload/server/server.js +1 -1
@@ -0,0 +1,277 @@
1
+ #!/usr/bin/env node
2
+ // Build-time gate: rejects raw JS numbers bound into Cypher integer positions.
3
+ //
4
+ // The neo4j-driver serializes a plain JS `number` as a Cypher FLOAT (15 -> 15.0).
5
+ // Cypher `LIMIT`/`SKIP` reject non-integers: "Invalid input. '15.0' is not a
6
+ // valid value. Must be a non-negative integer." A `LIMIT $p` / `SKIP $p` bound a
7
+ // raw number therefore THROWS on every call — and the throw is usually swallowed
8
+ // by a tool's catch and returned as empty data, so it presents as "no results"
9
+ // rather than an error. The fix at every call site is `neo4j.int(p)` (or the
10
+ // package's `int(...)` alias). Live repro: writer-craft voice-retrieve returned an
11
+ // empty voice profile in production because `LIMIT $k` was bound k=15.
12
+ //
13
+ // Posture: TARGETED, FAIL-OPEN. The gate fails the build only on a DEFINITE
14
+ // unwrapped binding — a `LIMIT $p`/`SKIP $p` param bound as object shorthand
15
+ // (`{ p }`) or as `p: <expr>` where <expr> contains no `int(`. When the params
16
+ // object cannot be statically resolved (built across multiple statements, spread
17
+ // from `...rest`, or passed through a helper), the site is skipped rather than
18
+ // flagged — zero false positives is the priority for a gate that must stay
19
+ // trusted. A novel unparseable offender would still surface at runtime via the
20
+ // existing per-tool error logging.
21
+ //
22
+ // Detection model:
23
+ // 1. Tokenize once into two newline-preserving masked views: comments blanked
24
+ // in both; string/template CONTENTS kept in `keepStr` (so `LIMIT $p` inside a
25
+ // query template is visible) and blanked in `noStr` (so braces/parens/commas
26
+ // inside queries and string values never confuse structural scanning).
27
+ // 2. Collect integer-position param names from `keepStr`: `LIMIT $p` / `SKIP $p`.
28
+ // 3. For each `.run(` call, resolve its params argument from `noStr` — an inline
29
+ // `{...}` object, or a bare identifier traced back to its `const/let/var X = {`
30
+ // object literal in the same file.
31
+ // 4. Within that object, flag each integer-position param bound shorthand or
32
+ // without an `int(` wrap.
33
+
34
+ import { readFileSync, readdirSync, statSync } from 'node:fs'
35
+ import { dirname, join, relative, basename } from 'node:path'
36
+ import { fileURLToPath } from 'node:url'
37
+
38
+ const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url))
39
+ const REPO_ROOT = join(SCRIPT_DIR, '..', '..')
40
+
41
+ const SCAN_ROOTS = [
42
+ join(REPO_ROOT, 'premium-plugins'),
43
+ join(REPO_ROOT, 'platform', 'plugins'),
44
+ join(REPO_ROOT, 'platform', 'ui', 'server'),
45
+ join(REPO_ROOT, 'platform', 'ui', 'app'),
46
+ ]
47
+
48
+ const ALLOWED_EXTS = new Set(['.ts', '.tsx'])
49
+ const SKIP_DIR_NAMES = new Set([
50
+ 'node_modules', 'dist', 'build', '.next', 'payload', '__tests__',
51
+ ])
52
+
53
+ function shouldScanFile(filePath) {
54
+ const name = basename(filePath)
55
+ if (name.endsWith('.test.ts') || name.endsWith('.test.tsx')) return false
56
+ const ext = name.includes('.') ? '.' + name.split('.').pop() : ''
57
+ return ALLOWED_EXTS.has(ext)
58
+ }
59
+
60
+ function* walk(root) {
61
+ let entries
62
+ try { entries = readdirSync(root) } catch { return }
63
+ for (const name of entries) {
64
+ if (SKIP_DIR_NAMES.has(name)) continue
65
+ const full = join(root, name)
66
+ let st
67
+ try { st = statSync(full) } catch { continue }
68
+ if (st.isDirectory()) yield* walk(full)
69
+ else if (st.isFile()) yield full
70
+ }
71
+ }
72
+
73
+ // Single tokenizer pass. Returns two strings of identical length to `src`, with
74
+ // newlines preserved so character offsets map back to line numbers:
75
+ // keepStr — comment characters replaced by spaces; string/template contents kept.
76
+ // noStr — comment characters AND string/template contents replaced by spaces.
77
+ // Delimiters (quotes, backticks, comment markers) become spaces in both.
78
+ function mask(src) {
79
+ const keep = new Array(src.length)
80
+ const no = new Array(src.length)
81
+ // states: code, line (//), block (/* */), sq ('), dq ("), tpl (`)
82
+ let state = 'code'
83
+ for (let i = 0; i < src.length; i++) {
84
+ const c = src[i]
85
+ const n = src[i + 1]
86
+ const blank = c === '\n' ? '\n' : ' '
87
+ if (state === 'code') {
88
+ if (c === '/' && n === '/') { keep[i] = no[i] = blank; state = 'line'; continue }
89
+ if (c === '/' && n === '*') { keep[i] = no[i] = blank; state = 'block'; continue }
90
+ if (c === "'") { keep[i] = no[i] = blank; state = 'sq'; continue }
91
+ if (c === '"') { keep[i] = no[i] = blank; state = 'dq'; continue }
92
+ if (c === '`') { keep[i] = no[i] = blank; state = 'tpl'; continue }
93
+ keep[i] = no[i] = c
94
+ continue
95
+ }
96
+ if (state === 'line') {
97
+ keep[i] = no[i] = blank
98
+ if (c === '\n') state = 'code'
99
+ continue
100
+ }
101
+ if (state === 'block') {
102
+ keep[i] = no[i] = blank
103
+ if (c === '*' && n === '/') {
104
+ // blank the closing slash too on the next iteration
105
+ no[i + 1] = keep[i + 1] = ' '
106
+ i++
107
+ state = 'code'
108
+ }
109
+ continue
110
+ }
111
+ // inside a string/template: keep content in `keep`, blank it in `no`.
112
+ if (state === 'sq' || state === 'dq' || state === 'tpl') {
113
+ const closer = state === 'sq' ? "'" : state === 'dq' ? '"' : '`'
114
+ if (c === '\\') {
115
+ // escape: consume this and the next char as string content
116
+ keep[i] = c === '\n' ? '\n' : (c)
117
+ no[i] = blank
118
+ if (i + 1 < src.length) {
119
+ keep[i + 1] = src[i + 1] === '\n' ? '\n' : src[i + 1]
120
+ no[i + 1] = src[i + 1] === '\n' ? '\n' : ' '
121
+ i++
122
+ }
123
+ continue
124
+ }
125
+ if (c === closer) { keep[i] = no[i] = blank; state = 'code'; continue }
126
+ keep[i] = c
127
+ no[i] = blank
128
+ continue
129
+ }
130
+ }
131
+ return { keep: keep.join(''), no: no.join('') }
132
+ }
133
+
134
+ function lineAt(text, index) {
135
+ let line = 1
136
+ for (let i = 0; i < index && i < text.length; i++) if (text[i] === '\n') line++
137
+ return line
138
+ }
139
+
140
+ const IDENT_RE = /^[A-Za-z_$][\w$]*$/
141
+
142
+ // Capture a balanced {...} starting at `noStr[start]` (which must be '{').
143
+ // Returns [objTextInNoStr, endIndexExclusive] or null.
144
+ function captureBraces(noStr, start) {
145
+ if (noStr[start] !== '{') return null
146
+ let depth = 0
147
+ for (let i = start; i < noStr.length; i++) {
148
+ if (noStr[i] === '{') depth++
149
+ else if (noStr[i] === '}') { depth--; if (depth === 0) return [noStr.slice(start, i + 1), i + 1] }
150
+ }
151
+ return null
152
+ }
153
+
154
+ // Capture a balanced (...) starting at `noStr[start]` (which must be '(').
155
+ // Returns [argsTextInNoStr, endIndexExclusive] or null.
156
+ function captureParens(noStr, start) {
157
+ if (noStr[start] !== '(') return null
158
+ let depth = 0
159
+ for (let i = start; i < noStr.length; i++) {
160
+ if (noStr[i] === '(') depth++
161
+ else if (noStr[i] === ')') { depth--; if (depth === 0) return [noStr.slice(start, i + 1), i + 1] }
162
+ }
163
+ return null
164
+ }
165
+
166
+ // Split args text (without the outer parens) on TOP-LEVEL commas only.
167
+ function splitTopLevelArgs(argsInner) {
168
+ const parts = []
169
+ let depth = 0
170
+ let cur = ''
171
+ for (const ch of argsInner) {
172
+ if (ch === '(' || ch === '{' || ch === '[') depth++
173
+ else if (ch === ')' || ch === '}' || ch === ']') depth--
174
+ if (ch === ',' && depth === 0) { parts.push(cur); cur = ''; continue }
175
+ cur += ch
176
+ }
177
+ if (cur.trim() !== '') parts.push(cur)
178
+ return parts
179
+ }
180
+
181
+ // Given a params object's text (from noStr) and the set of integer-position
182
+ // param names, return the names that are bound shorthand or without an int() wrap.
183
+ function findUnwrapped(objText, intParams) {
184
+ const offenders = []
185
+ for (const name of intParams) {
186
+ const esc = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
187
+ // Explicit binding `name : value`
188
+ const explicit = new RegExp(`\\b${esc}\\s*:\\s*([^,}]+)`)
189
+ const m = objText.match(explicit)
190
+ if (m) {
191
+ if (!/\bint\s*\(/.test(m[1])) offenders.push(name)
192
+ continue
193
+ }
194
+ // Shorthand `{ name }` / `, name ,` / `, name }` — bare identifier, never wrapped.
195
+ const shorthand = new RegExp(`[{,]\\s*${esc}\\s*[,}]`)
196
+ if (shorthand.test(objText)) offenders.push(name)
197
+ }
198
+ return offenders
199
+ }
200
+
201
+ const violations = []
202
+
203
+ for (const root of SCAN_ROOTS) {
204
+ for (const file of walk(root)) {
205
+ if (!shouldScanFile(file)) continue
206
+ let src
207
+ try { src = readFileSync(file, 'utf-8') } catch { continue }
208
+ if (!/\.run\s*\(/.test(src)) continue
209
+
210
+ const { keep, no } = mask(src)
211
+
212
+ // 1. Integer-position param names from the query strings (kept in `keep`).
213
+ const intParams = new Set()
214
+ for (const mm of keep.matchAll(/\b(?:LIMIT|SKIP)\s+\$(\w+)/gi)) intParams.add(mm[1])
215
+ if (intParams.size === 0) continue
216
+
217
+ // 2. Walk each `.run(` call.
218
+ for (const rm of no.matchAll(/\.run\s*\(/g)) {
219
+ const parenStart = rm.index + rm[0].length - 1
220
+ const cap = captureParens(no, parenStart)
221
+ if (!cap) continue
222
+ const inner = cap[0].slice(1, -1)
223
+ const args = splitTopLevelArgs(inner)
224
+ if (args.length < 2) continue
225
+ const paramArg = args[1].trim()
226
+
227
+ let objText = null
228
+ if (paramArg.startsWith('{')) {
229
+ // Inline object literal: re-capture against `no` for balanced braces.
230
+ const objStart = no.indexOf('{', parenStart)
231
+ const objCap = objStart >= 0 ? captureBraces(no, objStart) : null
232
+ if (objCap) objText = objCap[0]
233
+ } else if (IDENT_RE.test(paramArg)) {
234
+ // Single-variable params object: trace back to its declaration.
235
+ const esc = paramArg.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
236
+ const declRe = new RegExp(`(?:const|let|var)\\s+${esc}\\b[^=]*=\\s*\\{`)
237
+ const dm = no.match(declRe)
238
+ if (dm) {
239
+ const braceIdx = no.indexOf('{', dm.index)
240
+ const objCap = braceIdx >= 0 ? captureBraces(no, braceIdx) : null
241
+ if (objCap) objText = objCap[0]
242
+ }
243
+ }
244
+ // Unresolved params shape -> fail open (skip).
245
+ if (!objText) continue
246
+
247
+ for (const name of findUnwrapped(objText, intParams)) {
248
+ violations.push({
249
+ file: relative(REPO_ROOT, file),
250
+ line: lineAt(no, parenStart),
251
+ name,
252
+ })
253
+ }
254
+ }
255
+ }
256
+ }
257
+
258
+ if (violations.length > 0) {
259
+ // De-duplicate identical (file, line, name) tuples.
260
+ const seen = new Set()
261
+ const unique = violations.filter((v) => {
262
+ const k = `${v.file}:${v.line}:${v.name}`
263
+ if (seen.has(k)) return false
264
+ seen.add(k)
265
+ return true
266
+ })
267
+ console.error(`check-cypher-int-params: ${unique.length} raw-number Cypher integer binding(s):`)
268
+ for (const v of unique) {
269
+ console.error(` ${v.file}:${v.line}: LIMIT/SKIP $${v.name} is bound a raw JS number — wrap with int(${v.name})`)
270
+ }
271
+ console.error('')
272
+ console.error('neo4j-driver serializes a JS number as a Cypher float (15 -> 15.0); LIMIT/SKIP')
273
+ console.error('reject non-integers. Bind neo4j.int(p) (or the package int() alias) instead.')
274
+ process.exit(1)
275
+ }
276
+
277
+ console.log('check-cypher-int-params: ok (0 raw-number integer-position bindings)')
@@ -143,7 +143,8 @@ cat > "$ACCOUNT_SETTINGS" << SETTINGS_EOF
143
143
  "UserPromptSubmit": [
144
144
  {
145
145
  "hooks": [
146
- { "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
146
+ { "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" },
147
+ { "type": "command", "command": "bash $HOOKS_PATH/prompt-optimiser-directive.sh" }
147
148
  ]
148
149
  }
149
150
  ],
@@ -3,7 +3,7 @@ name: content-producer
3
3
  description: "Author professional business documents (proposal, report, brief, memo, plan, case study, brochure), render PDFs, generate images, and publish static websites. Delegate when the operator asks for a written document, a PDF render, a generated image, or to publish a prepared website."
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, Skill, mcp__memory__memory-search, mcp__replicate__image-generate, mcp__browser__browser-render, 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__browser__browser-render, mcp__browser__browser-navigate, mcp__browser__browser-evaluate, mcp__browser__browser-resize, mcp__browser__browser-screenshot, mcp__browser__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
@@ -34,7 +34,7 @@ Three models via `image-generate`. Pick by output need: `recraft-v4` for design-
34
34
 
35
35
  Generate the HTML to the print-CSS constraints. For A4 print, **the first tool call of this workflow branch MUST be `Skill a4-print-documents`. Any rendering step 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
- On-device PDF capture (the print-to-PDF tool that turns the generated HTML into a PDF file) is tracked in Task 496 and is not yet available; until it lands, deliver the HTML and state that the PDF save step is pending. Use `browser-render` only to read back a rendered page's content, not to produce a PDF.
37
+ Render the PDF on device with `browser-pdf-save`: serve or open the HTML, `browser-navigate` to it, then `browser-pdf-save` to the output path it uses Chromium's print pipeline (honours `@page`/print CSS, prints backgrounds). For glassmorphism cover/back pages that do not survive print, `a4-print-documents` directs you to capture print-fallback images with `browser-screenshot` (element clip) after `browser-resize`; use `browser-evaluate` to hide on-screen chrome before the capture. Do not write or run Playwright scripts — these on-device tools are the rendering path.
38
38
 
39
39
  When the brief is to author a generic business document (proposal / report / brief / memo / white paper / plan / case study), **the first tool call MUST be `Skill professional-document`. Any browser tool call before the skill is loaded into context is a contract violation.** Load `skill-load skillName=professional-document`: it carries the document-type catalogue, the refusal taxonomy for briefs owned by other composers (fundraise → `venture-studio:investor-data-room`; property → `real-agent:property-brochure` or `:property-preval`; decks → `admin:deck-pages`), the brand-token resolution, and the outline-approve-draft-render-save-deliver workflow. The skill loads `a4-print-documents` itself at the render phase — do not load it earlier. Format-only briefs ("create a PDF of this HTML", "save this as a one-pager", "render this brochure") stay on the existing `a4-print-documents` route above.
40
40
 
@@ -3,7 +3,7 @@ name: personal-assistant
3
3
  description: "Scheduling, platform settings, messaging channels (Telegram, WhatsApp, email, Outlook), tunnel and domain setup, and browser automation. Delegate when the work is on your calendar, configuring the platform, sending or reading messages, or driving a browser."
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: 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__url-get__url-get, mcp__browser__browser-render
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-provider-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__url-get__url-get, mcp__browser__browser-render, mcp__browser__browser-navigate, mcp__browser__browser-snapshot, mcp__browser__browser-click, mcp__browser__browser-fill, mcp__browser__browser-fill-form, mcp__browser__browser-type, mcp__browser__browser-press-key, mcp__browser__browser-hover, mcp__browser__browser-select-option, mcp__browser__browser-wait-for, mcp__browser__browser-handle-dialog, mcp__browser__browser-evaluate, mcp__browser__browser-console-messages, mcp__browser__browser-tabs, mcp__browser__browser-pdf-save, mcp__browser__browser-screenshot, mcp__browser__browser-resize
7
7
  ---
8
8
 
9
9
  # Personal Assistant
@@ -40,7 +40,11 @@ Each domain has a small set of tools and, where it exists, a skill that drives t
40
40
 
41
41
  **Cloudflare lives in the operator's browser.** Cloudflare exposes zero MCP tools. The operator's logged-in dashboard is the single source of truth. Do not drive the dashboard with a browser tool. Do not synthesise `cloudflared` flag combinations. Do not call the Cloudflare API or SDK. Do not edit `cert.pem`, `tunnel.state`, `config.yml`, or `alias-domains.json` directly. When a sanctioned surface fails, report with evidence and cite `plugins/cloudflare/references/reset-guide.md`. User-facing language: "Cloudflare account", "domain", "address", "sign in", "browser". Never say "zone", "CNAME", "account ID", "API", "SDK", or any hexadecimal identifier. After a tunnel script finishes, verify with `curl -I https://<hostname>`; a non-530 response means the tunnel is live.
42
42
 
43
- **Reading JavaScript-rendered pages.** When a page needs JavaScript to show its content and `url-get` comes back empty or as a shell use `browser-render` with the page URL. It renders the page in the device's Chromium and returns the rendered HTML plus the visible text. It is read-only: it does not click, fill, or navigate within a page, and it does not save PDFs or screenshots (an interactive automation surface is tracked in Task 496). Report CAPTCHA or bot detection as a blocker; do not try to solve it.
43
+ **Reading JavaScript-rendered pages.** When you only need to *read* a JS page and `url-get` comes back empty or as a shell, use `browser-render` with the URL. It renders the page in the device's Chromium and returns the rendered HTML plus visible text in one stateless call it does not keep the page open.
44
+
45
+ **Automating a page.** When a task needs to *act* on a page (log in, fill a form, click through a flow, drive a web app), use the persistent automation tools. Start with `browser-navigate` to open the page and keep it alive, then `browser-snapshot` to see what is on the page — it returns each interactive element as a role, a name, and a unique CSS selector. Pass those selectors verbatim to `browser-click`, `browser-fill`, `browser-fill-form`, `browser-hover`, and `browser-select-option`. Use `browser-type` / `browser-press-key` for real keyboard input (e.g. Enter to submit), `browser-wait-for` after anything that loads asynchronously, `browser-evaluate` to read page state, and `browser-console-messages` to debug. Arm `browser-handle-dialog` *before* the action that triggers an alert/confirm/prompt, because dialogs block the page. `browser-tabs` opens or switches to a fresh page so stale state from a prior task does not leak in. If an action returns `session-lost`, the page closed — call `browser-navigate` again. Element targeting is by CSS selector (always from a fresh `browser-snapshot`), not by Playwright-style refs. Report CAPTCHA or bot detection as a blocker; do not try to solve it.
46
+
47
+ **Saving PDFs and screenshots.** `browser-pdf-save` renders the current page to a PDF on device (Chromium's print pipeline — honours `@page`/print CSS). `browser-screenshot` saves a PNG of the page or one element (CSS selector clip); `browser-resize` sets the viewport first when you need exact dimensions. For A4 print documents, follow the `a4-print-documents` skill rather than driving these directly.
44
48
 
45
49
  ## Optional capabilities
46
50
 
@@ -1 +1 @@
1
- {"version":3,"file":"voice-retrieve-conditioning.d.ts","sourceRoot":"","sources":["../../src/tools/voice-retrieve-conditioning.ts"],"names":[],"mappings":"AA+BA,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,wBAAwB,CAAC;AAMhC,MAAM,WAAW,+BAA+B;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE;QACL,KAAK,CAAC,EAAE,MAAM,CAAC;QACf;;;WAGG;QACH,MAAM,EAAE,WAAW,CAAC;QACpB;;;;WAIG;QACH,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;QAC1B,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;;;;;;;;;;GAUG;AACH,MAAM,MAAM,mBAAmB,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC;AAE7D,MAAM,WAAW,+BAA+B;IAC9C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,+BAA+B,GACtC,OAAO,CAAC,+BAA+B,CAAC,CAuI1C"}
1
+ {"version":3,"file":"voice-retrieve-conditioning.d.ts","sourceRoot":"","sources":["../../src/tools/voice-retrieve-conditioning.ts"],"names":[],"mappings":"AA+BA,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,wBAAwB,CAAC;AAMhC,MAAM,WAAW,+BAA+B;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE;QACL,KAAK,CAAC,EAAE,MAAM,CAAC;QACf;;;WAGG;QACH,MAAM,EAAE,WAAW,CAAC;QACpB;;;;WAIG;QACH,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;QAC1B,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;;;;;;;;;;GAUG;AACH,MAAM,MAAM,mBAAmB,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC;AAE7D,MAAM,WAAW,+BAA+B;IAC9C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,+BAA+B,GACtC,OAAO,CAAC,+BAA+B,CAAC,CA0I1C"}
@@ -1,3 +1,32 @@
1
+ /**
2
+ * voice-retrieve-conditioning — return the operator's style card plus K
3
+ * voice-matched exemplars for a drafting brief.
4
+ *
5
+ * Task 462 changes:
6
+ * - `brief.format` (K-selector: 'short'|'long') renamed to `brief.length`
7
+ * to free the name for the new `brief.format: VoiceFormat` axis.
8
+ * - `brief.format: VoiceFormat` (required) — corpus exemplars are filtered
9
+ * to this writing format; the `:VoiceProfile` is the per-format profile.
10
+ * - All callers updated in the same commit.
11
+ *
12
+ * Retrieval order (best to worst):
13
+ * 1. If brief.topic is provided AND keyword search on the per-format corpus
14
+ * returns ≥K matches → use those (ordered by recency).
15
+ * 2. Otherwise, return the K most-recent per-format corpus nodes.
16
+ *
17
+ * Embeddings are not used in v1: the corpus is small (single operator's
18
+ * personal writing — typically <500 docs), and recency-with-keyword-filter
19
+ * is both faster and more predictable than vector ANN at that scale.
20
+ * Vector-search is a Task 365-follow-up if the corpus grows beyond the
21
+ * 500-doc breakeven point.
22
+ *
23
+ * Graceful degradation, discriminated (Task 493): the function never throws.
24
+ * Missing profile / empty corpus returns status "no-data"; a failed lookup
25
+ * (blank identity, driver/connection fault, Cypher error) returns status
26
+ * "error" with the message. The calling drafting skill falls back to its
27
+ * default register on both, but only "no-data" means "you have no profile".
28
+ */
29
+ import neo4j from "neo4j-driver";
1
30
  import { getSession } from "../lib/neo4j.js";
2
31
  import { notTrashed } from "../lib/voice-corpus.js";
3
32
  import { voiceCorpusWhereWithFormat, } from "../lib/voice-corpus.js";
@@ -85,7 +114,10 @@ export async function voiceRetrieveConditioning(params) {
85
114
  accountId,
86
115
  format,
87
116
  topic,
88
- k,
117
+ // neo4j-driver serializes a plain JS number as a Cypher float (15 → 15.0),
118
+ // which LIMIT rejects ("not a valid value. Must be a non-negative integer").
119
+ // Send it as a Neo4j integer.
120
+ k: neo4j.int(k),
89
121
  });
90
122
  let charsUsed = 0;
91
123
  const exemplars = [];
@@ -1 +1 @@
1
- {"version":3,"file":"voice-retrieve-conditioning.js","sourceRoot":"","sources":["../../src/tools/voice-retrieve-conditioning.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"voice-retrieve-conditioning.js","sourceRoot":"","sources":["../../src/tools/voice-retrieve-conditioning.ts"],"names":[],"mappings":"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"}
@@ -26,7 +26,7 @@
26
26
  * "error" with the message. The calling drafting skill falls back to its
27
27
  * default register on both, but only "no-data" means "you have no profile".
28
28
  */
29
- import type { Session } from "neo4j-driver";
29
+ import neo4j, { type Session } from "neo4j-driver";
30
30
  import { getSession } from "../lib/neo4j.js";
31
31
  import { notTrashed } from "../lib/voice-corpus.js";
32
32
  import {
@@ -183,7 +183,10 @@ export async function voiceRetrieveConditioning(
183
183
  accountId,
184
184
  format,
185
185
  topic,
186
- k,
186
+ // neo4j-driver serializes a plain JS number as a Cypher float (15 → 15.0),
187
+ // which LIMIT rejects ("not a valid value. Must be a non-negative integer").
188
+ // Send it as a Neo4j integer.
189
+ k: neo4j.int(k),
187
190
  });
188
191
 
189
192
  let charsUsed = 0;
@@ -5042,7 +5042,9 @@ async function loadUserProfile(accountId, userId, sessionId) {
5042
5042
  WITH up, p, collect(pref) AS allPrefs
5043
5043
  WITH up, p, allPrefs[0..$limit] AS prefs
5044
5044
  RETURN up, p AS person, prefs`,
5045
- { accountId, userId, threshold: INJECTION_THRESHOLD, limit: MAX_SUMMARY_PREFERENCES }
5045
+ // List-range slice bounds are an integer position; a raw JS number
5046
+ // serializes as a Cypher float. Bind a Neo4j integer.
5047
+ { accountId, userId, threshold: INJECTION_THRESHOLD, limit: neo4j.int(MAX_SUMMARY_PREFERENCES) }
5046
5048
  );
5047
5049
  if (result.records.length === 0 || !result.records[0].get("up")) {
5048
5050
  return null;
@@ -14,7 +14,7 @@ import {
14
14
  sanitizeClientCorrId,
15
15
  vncLog,
16
16
  websockifyLog
17
- } from "./chunk-L2YK2VK3.js";
17
+ } from "./chunk-EFJ2EXZK.js";
18
18
  import "./chunk-PFF6I7KP.js";
19
19
 
20
20
  // server/edge.ts
@@ -84,7 +84,7 @@ import {
84
84
  vncLog,
85
85
  walkPremiumBundles,
86
86
  writeAdminUserAndPerson
87
- } from "./chunk-L2YK2VK3.js";
87
+ } from "./chunk-EFJ2EXZK.js";
88
88
  import {
89
89
  __commonJS,
90
90
  __toESM