@rubytech/create-realagent 1.0.852 → 1.0.854

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 (41) hide show
  1. package/dist/__tests__/preflight-port-classifier.test.js +240 -73
  2. package/dist/index.js +59 -11
  3. package/dist/preflight-port-classifier.js +176 -41
  4. package/package.json +1 -1
  5. package/payload/platform/config/brand-registry.json +44 -0
  6. package/payload/platform/lib/persistent-components/dist/index.d.ts +21 -0
  7. package/payload/platform/lib/persistent-components/dist/index.d.ts.map +1 -0
  8. package/payload/platform/lib/persistent-components/dist/index.js +32 -0
  9. package/payload/platform/lib/persistent-components/dist/index.js.map +1 -0
  10. package/payload/platform/lib/persistent-components/src/index.ts +28 -0
  11. package/payload/platform/lib/persistent-components/tsconfig.json +8 -0
  12. package/payload/platform/package.json +2 -2
  13. package/payload/platform/plugins/admin/PLUGIN.md +1 -1
  14. package/payload/platform/plugins/admin/hooks/__tests__/playwright-file-guard.test.sh +278 -0
  15. package/payload/platform/plugins/admin/hooks/playwright-file-guard.sh +204 -20
  16. package/payload/platform/plugins/admin/mcp/dist/index.js +40 -1
  17. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  18. package/payload/platform/plugins/docs/references/deployment.md +2 -0
  19. package/payload/platform/plugins/docs/references/getting-started.md +2 -0
  20. package/payload/platform/plugins/docs/references/platform.md +1 -1
  21. package/payload/platform/plugins/docs/references/troubleshooting.md +10 -0
  22. package/payload/platform/scripts/admin-persist-audit.ts +191 -0
  23. package/payload/platform/scripts/component-knowledgedoc-backfill.ts +214 -0
  24. package/payload/platform/scripts/installer-device-verify.sh +249 -0
  25. package/payload/platform/templates/specialists/agents/content-producer.md +2 -2
  26. package/payload/server/chunk-CFNSKDGA.js +667 -0
  27. package/payload/server/chunk-DC6DWYZJ.js +1603 -0
  28. package/payload/server/chunk-LTB5SSQW.js +10889 -0
  29. package/payload/server/chunk-MN2LGNUB.js +2143 -0
  30. package/payload/server/client-pool-AMT2W3II.js +34 -0
  31. package/payload/server/cloudflare-task-tracker-LJ4SMK2D.js +20 -0
  32. package/payload/server/maxy-edge.js +3 -3
  33. package/payload/server/public/assets/admin-DZ8Ke7t3.js +352 -0
  34. package/payload/server/public/assets/public-DApUXgoq.js +5 -0
  35. package/payload/server/public/assets/useVoiceRecorder-CI8GpxfU.js +36 -0
  36. package/payload/server/public/index.html +2 -2
  37. package/payload/server/public/public.html +2 -2
  38. package/payload/server/server.js +535 -351
  39. package/payload/server/public/assets/admin-Dyl8uNxX.js +0 -352
  40. package/payload/server/public/assets/public-B_PNZUph.js +0 -5
  41. package/payload/server/public/assets/useVoiceRecorder-fD0IWzJj.js +0 -36
@@ -0,0 +1,249 @@
1
+ #!/usr/bin/env bash
2
+ # Task 939 — post-publish device-side verification harness.
3
+ #
4
+ # Closes the verification gap that let Task 938 archive on source-diff alone:
5
+ # without a device run, neither (a) the classifier-extension fix nor (b) the
6
+ # CDP probe brand-aware fix shipped to actual hardware. This script SSHes to
7
+ # every device in a manifest, runs the published installer for that brand,
8
+ # then greps the install log for the canonical CDP success banner.
9
+ #
10
+ # Exit zero ↔ every device's installer reached "Browser automation ready
11
+ # (CDP connected)". Any other state — ssh failure, npx non-zero, missing
12
+ # banner — is a non-zero exit with the failing device named on stderr.
13
+ #
14
+ # CONTRACT
15
+ # Archival of any task that touches packages/create-maxy/** is contingent
16
+ # on this script exiting zero against the published version. The exit code
17
+ # and the per-device summary are quoted in the close commit body.
18
+ #
19
+ # USAGE
20
+ # $ installer-device-verify.sh <published-version>
21
+ #
22
+ # <published-version> e.g. 1.0.853 — appended to `npx -y @rubytech/create-<brand>@<version>`.
23
+ #
24
+ # MANIFEST
25
+ # Path: $MAXY_VERIFY_MANIFEST (default $HOME/.maxy-verify-devices.json).
26
+ # Format: JSON array of devices; each entry:
27
+ # {
28
+ # "name": "maxy-pi-test", // free-form display name
29
+ # "brand": "maxy", // npm package suffix (@rubytech/create-<brand>)
30
+ # "configDir": ".maxy", // brand configDir; logs live in $HOME/<configDir>/logs/
31
+ # "sshTarget": "admin@maxytest.local", // user@host for ssh
32
+ # "sshPass": "password" // optional; uses sshpass if present
33
+ # }
34
+ # sshTarget supports inline port via "user@host:port" — script splits if present.
35
+ # sshPass omission → relies on existing ssh keys / agent.
36
+ #
37
+ # OUTPUT
38
+ # Per-device summary line on stdout.
39
+ # Detailed log: $HOME/.maxy/logs/installer-verify-<runId>.log (created if absent).
40
+ #
41
+ # DEPENDENCIES
42
+ # ssh (always), sshpass (only if any device uses sshPass), jq (always — the
43
+ # manifest is JSON; bash-only parse would be a CVE waiting to happen).
44
+
45
+ set -euo pipefail
46
+
47
+ if [[ $# -ne 1 ]]; then
48
+ echo "ERROR: missing argument <published-version>" >&2
49
+ echo "Usage: $0 <published-version>" >&2
50
+ echo "Example: $0 1.0.853" >&2
51
+ exit 2
52
+ fi
53
+
54
+ VERSION="$1"
55
+ # Pattern-validate version before any remote-shell interpolation. The version
56
+ # flows into `npx -y @rubytech/create-<brand>@$VERSION` over SSH; a stray
57
+ # semicolon or backtick would land inside the remote shell. Operator-owned
58
+ # input but the principle is validate-at-boundary.
59
+ if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
60
+ echo "ERROR: invalid version '$VERSION' — expected semver (e.g. 1.0.853 or 1.0.853-rc.1)" >&2
61
+ exit 2
62
+ fi
63
+
64
+ MANIFEST="${MAXY_VERIFY_MANIFEST:-$HOME/.maxy-verify-devices.json}"
65
+ RUN_ID="$(date +%Y%m%dT%H%M%SZ)-$$"
66
+ SUMMARY_DIR="$HOME/.maxy/logs"
67
+ SUMMARY_LOG="$SUMMARY_DIR/installer-verify-$RUN_ID.log"
68
+
69
+ if [[ ! -f "$MANIFEST" ]]; then
70
+ cat >&2 <<EOF
71
+ ERROR: device manifest not found at $MANIFEST.
72
+
73
+ Create one with this shape (JSON array, one entry per device):
74
+ [
75
+ {
76
+ "name": "maxy-pi-test",
77
+ "brand": "maxy",
78
+ "configDir": ".maxy",
79
+ "sshTarget": "admin@maxytest.local",
80
+ "sshPass": "password"
81
+ }
82
+ ]
83
+
84
+ Or set \$MAXY_VERIFY_MANIFEST to point elsewhere.
85
+ Device list reference: ~/.claude/projects/-Users-neo-getmaxy/memory/reference_device_ssh.md
86
+ EOF
87
+ exit 2
88
+ fi
89
+
90
+ if ! command -v jq >/dev/null 2>&1; then
91
+ echo "ERROR: jq is required (manifest is JSON)." >&2
92
+ echo " macOS: brew install jq" >&2
93
+ echo " Ubuntu: sudo apt-get install -y jq" >&2
94
+ exit 2
95
+ fi
96
+
97
+ mkdir -p "$SUMMARY_DIR"
98
+ : > "$SUMMARY_LOG"
99
+
100
+ # Resolve sshpass once: required only if any manifest entry has sshPass set.
101
+ NEEDS_SSHPASS=$(jq -r 'any(.[]; .sshPass != null and .sshPass != "")' "$MANIFEST")
102
+ if [[ "$NEEDS_SSHPASS" == "true" ]] && ! command -v sshpass >/dev/null 2>&1; then
103
+ echo "ERROR: manifest references sshPass but sshpass is not installed." >&2
104
+ echo " macOS: brew install hudochenkov/sshpass/sshpass" >&2
105
+ echo " Ubuntu: sudo apt-get install -y sshpass" >&2
106
+ exit 2
107
+ fi
108
+
109
+ DEVICE_COUNT=$(jq 'length' "$MANIFEST")
110
+ FAILED=0
111
+
112
+ # Common ssh hardening: short timeouts, no host-key prompt that would block
113
+ # when adding a new Pi to the fleet, and StrictHostKeyChecking=accept-new so
114
+ # fingerprints are recorded the first time but rejected on mismatch after.
115
+ SSH_OPTS=(
116
+ -o "ConnectTimeout=10"
117
+ -o "ServerAliveInterval=15"
118
+ -o "ServerAliveCountMax=2"
119
+ -o "StrictHostKeyChecking=accept-new"
120
+ -o "BatchMode=no"
121
+ )
122
+
123
+ run_ssh() {
124
+ local target="$1" pass="$2"
125
+ shift 2
126
+ if [[ -n "$pass" ]]; then
127
+ SSHPASS="$pass" sshpass -e ssh "${SSH_OPTS[@]}" "$target" "$@"
128
+ else
129
+ ssh "${SSH_OPTS[@]}" "$target" "$@"
130
+ fi
131
+ }
132
+
133
+ # Allowed brand pattern matches what bundle.js validates: lowercase
134
+ # alphanumeric, hyphens. Reject anything else before interpolating into
135
+ # remote shell commands. configDir mirrors the brand convention (a leading
136
+ # dot then the same character class), so the same shape passes through.
137
+ # `$NAME` is interpolated into `--hostname "$NAME"` over SSH — same boundary
138
+ # discipline applies; allow dots so it can carry mDNS hostnames like
139
+ # `maxytest.local`, but never quote characters or shell metacharacters.
140
+ ALLOWED='^[a-z0-9][a-z0-9-]*$'
141
+ ALLOWED_HOSTNAME='^[a-zA-Z0-9][a-zA-Z0-9.-]*$'
142
+
143
+ echo "installer-device-verify run=$RUN_ID version=$VERSION devices=$DEVICE_COUNT" | tee -a "$SUMMARY_LOG"
144
+
145
+ for i in $(seq 0 $((DEVICE_COUNT - 1))); do
146
+ NAME=$(jq -r ".[$i].name" "$MANIFEST")
147
+ BRAND=$(jq -r ".[$i].brand" "$MANIFEST")
148
+ CONFIGDIR=$(jq -r ".[$i].configDir" "$MANIFEST")
149
+ TARGET=$(jq -r ".[$i].sshTarget" "$MANIFEST")
150
+ PASS=$(jq -r ".[$i].sshPass // \"\"" "$MANIFEST")
151
+
152
+ if [[ ! "$BRAND" =~ $ALLOWED ]]; then
153
+ echo "FAIL $NAME — invalid brand '$BRAND' (must match $ALLOWED)" | tee -a "$SUMMARY_LOG"
154
+ FAILED=1
155
+ continue
156
+ fi
157
+
158
+ if [[ ! "$NAME" =~ $ALLOWED_HOSTNAME ]]; then
159
+ echo "FAIL device name '$NAME' rejected — must match $ALLOWED_HOSTNAME" | tee -a "$SUMMARY_LOG"
160
+ FAILED=1
161
+ continue
162
+ fi
163
+
164
+ # configDir always begins with '.' (e.g. .maxy); strip the dot and validate
165
+ # the remainder with the same allowed-character class.
166
+ CD_TAIL="${CONFIGDIR#.}"
167
+ if [[ "$CD_TAIL" == "$CONFIGDIR" || ! "$CD_TAIL" =~ $ALLOWED ]]; then
168
+ echo "FAIL $NAME — invalid configDir '$CONFIGDIR' (must be a leading dot + $ALLOWED)" | tee -a "$SUMMARY_LOG"
169
+ FAILED=1
170
+ continue
171
+ fi
172
+
173
+ echo "" | tee -a "$SUMMARY_LOG"
174
+ echo "[$NAME] brand=$BRAND target=$TARGET version=$VERSION" | tee -a "$SUMMARY_LOG"
175
+
176
+ # Step 1 — install. Run npx with auto-yes; redirect to the device's own
177
+ # install log path so the summary log on the operator side stays clean,
178
+ # and so the device-side log matches what reference_device_ssh.md would
179
+ # tail.
180
+ set +e
181
+ run_ssh "$TARGET" "$PASS" "npx -y @rubytech/create-$BRAND@$VERSION --hostname \"$NAME\"" >>"$SUMMARY_LOG" 2>&1
182
+ INSTALL_RC=$?
183
+ set -e
184
+
185
+ if [[ $INSTALL_RC -ne 0 ]]; then
186
+ echo "FAIL $NAME — install exited $INSTALL_RC (see $SUMMARY_LOG)" | tee -a "$SUMMARY_LOG"
187
+ FAILED=1
188
+ continue
189
+ fi
190
+
191
+ # Step 2 — confirm a terminal-success banner in the latest install log.
192
+ # Pick the newest install-*.log by mtime (`ls -t`) and grep for either of
193
+ # the installer's two terminal-success markers emitted by
194
+ # packages/create-maxy/src/index.ts:
195
+ # • DISPLAY_MODE=virtual (Pi, headless VNC) →
196
+ # "Browser automation ready (CDP connected)" (index.ts:3012)
197
+ # • DISPLAY_MODE=native (laptop, on-demand Chromium) →
198
+ # "[cdp-check] skipped reason=native-display" (index.ts:3004)
199
+ # Both terminate the install successfully; either is a pass. Hard-coding
200
+ # only the virtual-mode banner would mark every laptop install FAIL even
201
+ # though the laptop install correctly skips CDP probing because there is
202
+ # no persistent Chromium running for CDP to talk to.
203
+ REMOTE_CHECK=$(cat <<'REMOTE'
204
+ set -euo pipefail
205
+ LOG_DIR="$HOME/__CONFIGDIR__/logs"
206
+ LATEST=$(ls -t "$LOG_DIR"/install-*.log 2>/dev/null | head -n1 || true)
207
+ if [[ -z "${LATEST:-}" ]]; then
208
+ echo "no-install-log"
209
+ exit 1
210
+ fi
211
+ echo "log=$LATEST"
212
+ if grep -F -q "Browser automation ready (CDP connected)" "$LATEST"; then
213
+ echo "marker=cdp-connected"
214
+ exit 0
215
+ fi
216
+ if grep -F -q "[cdp-check] skipped reason=native-display" "$LATEST"; then
217
+ echo "marker=native-display-skip"
218
+ exit 0
219
+ fi
220
+ echo "banner-not-found"
221
+ tail -n 30 "$LATEST"
222
+ exit 1
223
+ REMOTE
224
+ )
225
+ REMOTE_CHECK="${REMOTE_CHECK//__CONFIGDIR__/$CONFIGDIR}"
226
+
227
+ set +e
228
+ run_ssh "$TARGET" "$PASS" "$REMOTE_CHECK" >>"$SUMMARY_LOG" 2>&1
229
+ CHECK_RC=$?
230
+ set -e
231
+
232
+ if [[ $CHECK_RC -eq 0 ]]; then
233
+ echo "OK $NAME — CDP banner present" | tee -a "$SUMMARY_LOG"
234
+ else
235
+ echo "FAIL $NAME — CDP banner missing (rc=$CHECK_RC, see $SUMMARY_LOG)" | tee -a "$SUMMARY_LOG"
236
+ FAILED=1
237
+ fi
238
+ done
239
+
240
+ echo "" | tee -a "$SUMMARY_LOG"
241
+ if [[ $FAILED -eq 0 ]]; then
242
+ echo "PASS — all $DEVICE_COUNT devices installed and reported CDP banner" | tee -a "$SUMMARY_LOG"
243
+ echo "summary: $SUMMARY_LOG"
244
+ exit 0
245
+ else
246
+ echo "FAIL — at least one device did not reach CDP banner; details in $SUMMARY_LOG" | tee -a "$SUMMARY_LOG"
247
+ echo "summary: $SUMMARY_LOG"
248
+ exit 1
249
+ fi
@@ -64,9 +64,9 @@ Generate PDFs from rendered HTML pages using the browser tools.
64
64
  - **Document structure:** Cover (full-bleed, print image fallback, `page-break-after: always`) > Optional TOC > Content (flowing) > Back page (mandatory for multi-page, `page-break-before: always`).
65
65
  - **Single-pager:** Fixed `width: 210mm`, `min-height: 297mm`, `margin: 0 auto` on screen. In print add `height: 297mm`, `page-break-after: always`.
66
66
 
67
- **Print image capture:** For cover and back page: start a local HTTP server, set viewport to element size, hide UI chrome, take screenshot of element, save PNG. These images replace glassmorphism effects in print mode.
67
+ **Print image capture:** For cover and back page: navigate to the rendered HTML, set viewport to element size, hide UI chrome, take screenshot of element, save PNG. These images replace glassmorphism effects in print mode.
68
68
 
69
- **Local files:** `file://` URLs are blocked by Playwright. Start a local HTTP server and navigate to `http://localhost:8080/filename.html`.
69
+ **Local files:** `file://` URLs are rewritten transparently by the `playwright-file-guard` PreToolUse hook pass them directly to `browser_navigate` and the hook will spawn a loopback `python3 -m http.server` on a free port and rewrite the URL before Playwright sees it. No agent-side server management needed.
70
70
 
71
71
  ## File delivery
72
72