@rubytech/create-sitedesk-code 0.1.511 → 0.1.513
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/docs/superpowers/plans/2026-07-27-task-2028-declared-file-write-deny.md +303 -0
- package/payload/platform/docs/superpowers/specs/2026-07-27-task-2028-declared-file-write-deny-design.md +126 -0
- package/payload/platform/lib/account-schema-regions/dist/index.d.ts +5 -0
- package/payload/platform/lib/account-schema-regions/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/account-schema-regions/dist/index.js +5 -0
- package/payload/platform/lib/account-schema-regions/dist/index.js.map +1 -1
- package/payload/platform/lib/account-schema-regions/src/index.ts +5 -0
- package/payload/platform/package.json +3 -0
- package/payload/platform/plugins/admin/hooks/__tests__/fs-schema-guard-bash.test.sh +14 -0
- package/payload/platform/plugins/admin/hooks/__tests__/fs-schema-guard.test.sh +38 -0
- package/payload/platform/plugins/admin/hooks/fs-schema-guard-bash-post.sh +11 -0
- package/payload/platform/plugins/admin/hooks/fs-schema-guard.sh +25 -1
- package/payload/platform/plugins/admin/skills/deck-pages/SKILL.md +2 -2
- package/payload/platform/plugins/admin/skills/skill-builder/SKILL.md +1 -1
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +12 -0
- package/payload/platform/plugins/business-assistant/skills/e-sign/SKILL.md +15 -34
- package/payload/platform/plugins/business-assistant/skills/e-sign/stamp.mjs +269 -0
- package/payload/platform/plugins/cloudflare/PLUGIN.md +1 -1
- package/payload/platform/plugins/cloudflare/bin/schema-exposed-dirs.mjs +1 -1
- package/payload/platform/plugins/linkedin-import/skills/linkedin-import/references/profile.md +5 -5
- package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +2 -2
- package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +1 -1
- package/payload/platform/plugins/scheduling/PLUGIN.md +1 -1
- package/payload/platform/plugins/x-import/skills/x-import/SKILL.md +1 -1
- package/payload/platform/scripts/__tests__/account-schema-owned-dirs.test.sh +26 -0
- package/payload/platform/scripts/check-no-esm-require.mjs +6 -0
- package/payload/platform/scripts/lib/account-schema-owned-dirs.py +40 -4
- package/payload/platform/scripts/logs-read.sh +154 -50
- package/payload/platform/scripts/logs-read.test.sh +276 -0
- package/payload/platform/scripts/provision-worktree.sh +80 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +13 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts +7 -3
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +17 -11
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
- package/payload/server/{chunk-2WAXM5N2.js → chunk-S6HYTIU3.js} +2 -3
- package/payload/server/maxy-edge.js +7 -3
- package/payload/server/public/assets/admin-6QN-k3zQ.js +1 -0
- package/payload/server/public/assets/admin-6QN-k3zQ.js.br +0 -0
- package/payload/server/public/assets/admin-6QN-k3zQ.js.gz +0 -0
- package/payload/server/public/index.html +1 -1
- package/payload/server/server.js +860 -384
- package/payload/server/public/assets/admin-Do53K90C.js +0 -1
- package/payload/server/public/assets/admin-Do53K90C.js.br +0 -0
- package/payload/server/public/assets/admin-Do53K90C.js.gz +0 -0
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
# For per-session types (agent-stream/system/session/error/public): sessionKey
|
|
27
27
|
# is required in the first mode. For platform-scoped types (server/vnc/
|
|
28
28
|
# heartbeat/mem): the id is ignored. chat-attempts is --tail-only:
|
|
29
|
-
# cross-grep of edge.log + server.log for the chat-ingress
|
|
29
|
+
# cross-grep of edge.log + server.log for the chat-ingress checkpoints within
|
|
30
30
|
# the most recent N minutes.
|
|
31
31
|
#
|
|
32
32
|
# Every invocation writes a one-line trailer describing files searched,
|
|
@@ -154,11 +154,21 @@ is_per_conversation_type() {
|
|
|
154
154
|
SEARCH_TYPES="agent-stream error session public server mcp vnc"
|
|
155
155
|
VALID_TYPES="agent-stream, system, session, error, heartbeat, public, server, mcp, vnc, mem, chat-attempts"
|
|
156
156
|
|
|
157
|
-
# chat-attempts cross-grep prefixes.
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
#
|
|
161
|
-
|
|
157
|
+
# chat-attempts cross-grep prefixes. Four checkpoint patterns across
|
|
158
|
+
# edge.log + server.log: edge-side inbound/outcome, admin-auth gate verdict,
|
|
159
|
+
# chat-route handler entry. Any one chat emits THREE of the four, and which
|
|
160
|
+
# three depends on the surface: the admin webchat (POST /api/webchat/send)
|
|
161
|
+
# carries an admin-auth row and no chat-route row, public chat
|
|
162
|
+
# (POST /api/chat) carries a chat-route row and no admin-auth row. Absence of
|
|
163
|
+
# a row the surface does emit localises the failure to one ingress stage.
|
|
164
|
+
#
|
|
165
|
+
# The `ts=` group is optional and sits between the tag and the keyword because
|
|
166
|
+
# that is where Task 2024 put it: the shipped line is
|
|
167
|
+
# `[edge-admin] ts=<ISO> inbound …` (edge.ts:188, 199; edge-admin.ts:48, 52).
|
|
168
|
+
# Requiring tag and keyword adjacent matched zero lines and reported the
|
|
169
|
+
# absence as an edge-side silence (Task 2032). Optional rather than required,
|
|
170
|
+
# so the pattern is not pinned to one format version a second time.
|
|
171
|
+
CHAT_ATTEMPT_GREP='\[edge-admin\] (ts=[^ ]+ )?(inbound|outcome)|\[admin-auth\] outcome|\[chat-route\] entered'
|
|
162
172
|
|
|
163
173
|
# Authoritative sessionKey character set.
|
|
164
174
|
# Writer-side emits `sk_<hex16>` filenames; the underscore must
|
|
@@ -179,7 +189,7 @@ Usage:
|
|
|
179
189
|
is_error result (silent-failure audit)
|
|
180
190
|
logs-read.sh --tail [type] [lines] Tail most recent log of type
|
|
181
191
|
logs-read.sh --tail chat-attempts [min] Cross-grep edge.log + server.log
|
|
182
|
-
for the chat-ingress
|
|
192
|
+
for the chat-ingress checkpoints
|
|
183
193
|
logs-read.sh --grep <sessionKey> [type] Legacy grep across log files
|
|
184
194
|
|
|
185
195
|
Types: $VALID_TYPES
|
|
@@ -193,9 +203,12 @@ transcript, flagging subagent is_error results inline. An explicit <type>
|
|
|
193
203
|
keeps the legacy per-account stream-log read.
|
|
194
204
|
Per-session stream-log types (agent-stream, system, session, error, public)
|
|
195
205
|
require sessionKey; platform-scoped types (server, vnc, heartbeat, mem) ignore the id.
|
|
196
|
-
chat-attempts is --tail-only — it aggregates
|
|
197
|
-
([edge-admin] inbound, [admin-auth] outcome, [chat-route] entered,
|
|
198
|
-
[edge-admin] outcome) into one timeline.
|
|
206
|
+
chat-attempts is --tail-only — it aggregates four ingress checkpoint patterns
|
|
207
|
+
([edge-admin] ts=<ISO> inbound, [admin-auth] outcome, [chat-route] entered,
|
|
208
|
+
[edge-admin] ts=<ISO> outcome) into one timeline. Any one chat emits three of
|
|
209
|
+
them: the admin webchat (POST /api/webchat/send) emits the two edge rows plus
|
|
210
|
+
[admin-auth] outcome and no [chat-route] row; public chat (POST /api/chat)
|
|
211
|
+
emits the two edge rows plus [chat-route] entered and no [admin-auth] row.
|
|
199
212
|
EOF
|
|
200
213
|
exit 2
|
|
201
214
|
}
|
|
@@ -209,25 +222,48 @@ validate_type() {
|
|
|
209
222
|
}
|
|
210
223
|
|
|
211
224
|
# chat-attempts cross-grep mode. Combines edge.log + server.log
|
|
212
|
-
# lines matching the chat-ingress
|
|
225
|
+
# lines matching the chat-ingress checkpoints, filtered to the last N minutes,
|
|
213
226
|
# sorted chronologically. Default window: 5 minutes (matches the typical
|
|
214
227
|
# "agent doesn't respond" report window — operator sees the silence,
|
|
215
228
|
# screenshots the chat, then runs this within a few minutes).
|
|
216
229
|
#
|
|
217
230
|
# Output preserves source-file prefix so operators can see whether the line
|
|
218
231
|
# came from the edge process (edge.log) or maxy-ui (server.log). On a
|
|
219
|
-
# successful chat POST the timeline reads
|
|
232
|
+
# successful chat POST the timeline reads THREE rows, and which three depends
|
|
233
|
+
# on the surface.
|
|
234
|
+
#
|
|
235
|
+
# admin webchat, POST /api/webchat/send:
|
|
236
|
+
# [edge-admin] ts=… inbound method=POST path=/api/webchat/send … (edge.log)
|
|
237
|
+
# [admin-auth] outcome=accept path=/api/webchat/send cacheKey=… (server.log)
|
|
238
|
+
# [edge-admin] ts=… outcome method=POST path=… status=200 … (edge.log)
|
|
239
|
+
#
|
|
240
|
+
# public chat, POST /api/chat:
|
|
241
|
+
# [edge-admin] ts=… inbound method=POST path=/api/chat … (edge.log)
|
|
242
|
+
# [chat-route] entered route=public method=POST (server.log)
|
|
243
|
+
# [edge-admin] ts=… outcome method=POST path=… status=200 … (edge.log)
|
|
244
|
+
#
|
|
245
|
+
# Nothing emits [chat-route] on the admin surface and nothing emits
|
|
246
|
+
# [admin-auth] on the public one, so the row the OTHER surface would have
|
|
247
|
+
# shown is not evidence of anything. Reading admin against a four-row
|
|
248
|
+
# sequence is what made every healthy admin chat look like a routing
|
|
249
|
+
# regression (Task 2042).
|
|
220
250
|
#
|
|
221
|
-
#
|
|
222
|
-
#
|
|
223
|
-
#
|
|
224
|
-
#
|
|
251
|
+
# A row missing from the surface's OWN sequence is diagnostic.
|
|
252
|
+
# Both surfaces: zero edge inbound = browser/network problem; edge outcome
|
|
253
|
+
# missing = upstream proxy crash.
|
|
254
|
+
# Admin: [admin-auth] outcome is the handler-side checkpoint. Missing against
|
|
255
|
+
# a present inbound = handler unreachable; outcome=reject = auth failure;
|
|
256
|
+
# outcome=accept already proves the route matched, because requireAdminSession
|
|
257
|
+
# is middleware mounted on /send (webchat.ts), so no further handler-side row
|
|
258
|
+
# is expected.
|
|
259
|
+
# Public: [chat-route] entered is the handler-side checkpoint. Missing against
|
|
260
|
+
# a present inbound for /api/chat = public-route routing regression.
|
|
225
261
|
#
|
|
226
|
-
#
|
|
227
|
-
#
|
|
228
|
-
#
|
|
229
|
-
#
|
|
230
|
-
#
|
|
262
|
+
# The two log families are stamped differently and neither is negotiable here:
|
|
263
|
+
# edge.log self-stamps `ts=` inside the line (Task 2024), server.log is stamped
|
|
264
|
+
# at the line start by server-init-line-stamper.cjs. Reading only the leading
|
|
265
|
+
# 19 characters yielded `[edge-admin] ts=202` on every edge line, so the window
|
|
266
|
+
# filter and the sort both have to read whichever form the line carries.
|
|
231
267
|
chat_attempts_mode() {
|
|
232
268
|
local minutes="${1:-5}"
|
|
233
269
|
if ! [[ "$minutes" =~ ^[0-9]+$ ]]; then
|
|
@@ -236,57 +272,125 @@ chat_attempts_mode() {
|
|
|
236
272
|
fi
|
|
237
273
|
|
|
238
274
|
local EDGE_LOG="$CONFIG_DIR/logs/edge.log"
|
|
239
|
-
local
|
|
240
|
-
|
|
241
|
-
if [[ -z "$
|
|
275
|
+
local since_iso
|
|
276
|
+
since_iso=$(date -u -v-"${minutes}"M +%Y-%m-%dT%H:%M:%S 2>/dev/null || date -u -d "${minutes} minutes ago" +%Y-%m-%dT%H:%M:%S 2>/dev/null || true)
|
|
277
|
+
if [[ -z "$since_iso" ]]; then
|
|
242
278
|
echo "Error: could not compute time window — neither BSD nor GNU date available" >&2
|
|
243
279
|
exit 2
|
|
244
280
|
fi
|
|
245
281
|
|
|
246
|
-
#
|
|
247
|
-
#
|
|
248
|
-
#
|
|
249
|
-
# the
|
|
250
|
-
#
|
|
282
|
+
# Emits `<ts>\t<source>\t<line>` into $tmp, where <ts> is the line's own
|
|
283
|
+
# timestamp to millisecond precision, or `-` when the line carries none.
|
|
284
|
+
# ISO-8601 UTC strings compare lexicographically in time order, which is why
|
|
285
|
+
# the window test is a string comparison and not a `date` subprocess per
|
|
286
|
+
# matched line, which is what the previous form spawned on both dialects.
|
|
287
|
+
#
|
|
288
|
+
# Milliseconds are load-bearing, not decoration. Both families emit
|
|
289
|
+
# `toISOString()`, and a chat's three checkpoints normally complete inside
|
|
290
|
+
# one wall-clock second, so a key truncated to seconds collides on every row
|
|
291
|
+
# and the sort falls back to file-append order — which puts the edge rows
|
|
292
|
+
# first and reproduces the clustering this mode was fixed to stop.
|
|
293
|
+
#
|
|
294
|
+
# An undated line reaches $tmp with `-` as its key. It cannot be placed in
|
|
295
|
+
# the window or in the sequence, so it is listed separately below rather
|
|
296
|
+
# than merged into the timeline. It is never discarded: a matched line
|
|
297
|
+
# dropped in silence is the exact fault this mode was fixed for.
|
|
251
298
|
local filter_awk='
|
|
252
|
-
BEGIN { since = '"$since_epoch"' }
|
|
253
299
|
{
|
|
254
|
-
ts =
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
300
|
+
ts = "-"
|
|
301
|
+
if (match($0, /ts=[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9][0-9][0-9]/)) {
|
|
302
|
+
ts = substr($0, RSTART + 3, 23)
|
|
303
|
+
} else if ($0 ~ /^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9][0-9][0-9]/) {
|
|
304
|
+
ts = substr($0, 1, 23)
|
|
305
|
+
}
|
|
306
|
+
if (ts == "-" || ts >= since) print ts "\t" src "\t" $0
|
|
260
307
|
}
|
|
261
308
|
'
|
|
262
309
|
|
|
263
|
-
local hits=0
|
|
264
310
|
local tmp
|
|
265
311
|
tmp=$(mktemp -t chat-attempts.XXXXXX)
|
|
266
312
|
trap 'rm -f "$tmp"' EXIT
|
|
267
313
|
|
|
268
314
|
if [[ -f "$EDGE_LOG" ]]; then
|
|
269
|
-
grep -E "$CHAT_ATTEMPT_GREP" "$EDGE_LOG" 2>/dev/null
|
|
315
|
+
grep -E "$CHAT_ATTEMPT_GREP" "$EDGE_LOG" 2>/dev/null \
|
|
316
|
+
| awk -v since="$since_iso" -v src="edge.log" "$filter_awk" >> "$tmp" || true
|
|
270
317
|
fi
|
|
271
318
|
if [[ -f "$SERVER_LOG" ]]; then
|
|
272
|
-
grep -E "$CHAT_ATTEMPT_GREP" "$SERVER_LOG" 2>/dev/null
|
|
319
|
+
grep -E "$CHAT_ATTEMPT_GREP" "$SERVER_LOG" 2>/dev/null \
|
|
320
|
+
| awk -v since="$since_iso" -v src="server.log" "$filter_awk" >> "$tmp" || true
|
|
273
321
|
fi
|
|
274
322
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
323
|
+
# Per-source tallies. One aggregate count is what made the miss silent:
|
|
324
|
+
# `edge=0` folded into the same "no events" line as a genuinely quiet window,
|
|
325
|
+
# so a reader that could not see the edge read as an edge that said nothing.
|
|
326
|
+
local counts edge_hits edge_undated server_hits server_undated hits undated
|
|
327
|
+
counts=$(awk -F'\t' '
|
|
328
|
+
{ if ($1 == "-") u[$2]++; else m[$2]++ }
|
|
329
|
+
END { printf "%d %d %d %d", m["edge.log"], u["edge.log"], m["server.log"], u["server.log"] }
|
|
330
|
+
' "$tmp")
|
|
331
|
+
read -r edge_hits edge_undated server_hits server_undated <<< "$counts"
|
|
332
|
+
hits=$((edge_hits + server_hits))
|
|
333
|
+
undated=$((edge_undated + server_undated))
|
|
334
|
+
|
|
335
|
+
local edge_state="present"
|
|
336
|
+
[[ -f "$EDGE_LOG" ]] || edge_state="absent:$EDGE_LOG"
|
|
337
|
+
local server_state="present"
|
|
338
|
+
[[ -f "$SERVER_LOG" ]] || server_state="absent:$SERVER_LOG"
|
|
339
|
+
|
|
340
|
+
local trailer="-- trailer: type=chat-attempts window_min=${minutes} matches=${hits} edge=${edge_hits} server=${server_hits} undated=${undated} searched=edge.log,server.log"
|
|
341
|
+
|
|
342
|
+
# Nothing matched at all, dated or not. Only here can the mode say anything
|
|
343
|
+
# about whether a request arrived, and even here only if it could read the
|
|
344
|
+
# edge log — a file it never opened proves nothing about the traffic.
|
|
345
|
+
if [[ "$hits" -eq 0 && "$undated" -eq 0 ]]; then
|
|
346
|
+
echo "# chat-attempts (last ${minutes} min) — no ingress checkpoints matched" >&2
|
|
347
|
+
echo "# edge.log=${edge_state} server.log=${server_state}" >&2
|
|
348
|
+
if [[ -f "$EDGE_LOG" ]]; then
|
|
349
|
+
# What a genuine zero means, now that the patterns track the shipped
|
|
350
|
+
# lines: the first checkpoint is the edge accepting a connection, so its
|
|
351
|
+
# absence places the fault before this device. Saying it here is the
|
|
352
|
+
# point of the fix — the reader used to produce this same output when it
|
|
353
|
+
# simply could not see the edge lines.
|
|
354
|
+
echo "# The edge patterns track the shipped \`[edge-admin] ts=<ISO> …\` shape, so this" >&2
|
|
355
|
+
echo "# is an absence in the logs, not in the reader: no request reached the edge in" >&2
|
|
356
|
+
echo "# this window. Look at the browser, DNS, or the tunnel — the admin server is" >&2
|
|
357
|
+
echo "# never in the path of a request that never arrived." >&2
|
|
358
|
+
else
|
|
359
|
+
echo "# edge.log is not on disk, so the edge checkpoints could not be read at all." >&2
|
|
360
|
+
echo "# This says nothing about whether a request arrived. Check that the edge service" >&2
|
|
361
|
+
echo "# is running and writing to the path above before drawing any conclusion." >&2
|
|
362
|
+
fi
|
|
363
|
+
echo "$trailer" >&2
|
|
279
364
|
exit 1
|
|
280
365
|
fi
|
|
281
366
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
367
|
+
if [[ "$hits" -gt 0 ]]; then
|
|
368
|
+
echo "# chat-attempts (last ${minutes} min — chronological)"
|
|
369
|
+
echo ""
|
|
370
|
+
# Sort on the extracted timestamp column, then drop it. The previous form
|
|
371
|
+
# sorted on a fixed byte offset that only landed on a timestamp for
|
|
372
|
+
# server.log lines, so edge rows clustered rather than interleaved. `-s`
|
|
373
|
+
# keeps edge before server on an exact millisecond tie; LC_ALL=C makes the
|
|
374
|
+
# byte ordering deterministic across locales.
|
|
375
|
+
LC_ALL=C sort -t$'\t' -k1,1 -s "$tmp" \
|
|
376
|
+
| awk -F'\t' '$1 != "-" { printf "%-10s %s\n", $2, $3 }'
|
|
377
|
+
else
|
|
378
|
+
echo "# chat-attempts (last ${minutes} min) — no datable checkpoint in the window"
|
|
379
|
+
fi
|
|
380
|
+
|
|
381
|
+
# Matched but undatable. Shown, because a matched edge line is evidence that
|
|
382
|
+
# a request DID arrive, and suppressing it while reporting silence is how
|
|
383
|
+
# this mode misread the edge in the first place. Listed in file order and
|
|
384
|
+
# outside the timeline, because an undated line has no position in it.
|
|
385
|
+
if [[ "$undated" -gt 0 ]]; then
|
|
386
|
+
echo ""
|
|
387
|
+
echo "# ${undated} matched line(s) carry no timestamp and cannot be placed in the window."
|
|
388
|
+
echo "# An edge line written before the \`ts=\` stamp carries no clock. File order:"
|
|
389
|
+
awk -F'\t' '$1 == "-" { printf "%-10s %s\n", $2, $3 }' "$tmp"
|
|
390
|
+
fi
|
|
391
|
+
|
|
288
392
|
echo "" >&2
|
|
289
|
-
echo "
|
|
393
|
+
echo "$trailer" >&2
|
|
290
394
|
exit 0
|
|
291
395
|
}
|
|
292
396
|
|
|
@@ -188,11 +188,287 @@ case_mem_absent() {
|
|
|
188
188
|
return 0
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
# --- chat-attempts helpers (Task 2032) ---
|
|
192
|
+
# The fixtures are dated off the same clock the script computes its window
|
|
193
|
+
# from, so no case depends on a literal timestamp ageing out.
|
|
194
|
+
iso_minutes_ago() {
|
|
195
|
+
local m="$1"
|
|
196
|
+
date -u -v-"${m}"M +%Y-%m-%dT%H:%M:%S 2>/dev/null \
|
|
197
|
+
|| date -u -d "${m} minutes ago" +%Y-%m-%dT%H:%M:%S 2>/dev/null
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
# --- Case 6 (Task 2032): all four patterns match, interleaved by time ---
|
|
201
|
+
case_chat_attempts_both_surfaces() {
|
|
202
|
+
local root="/tmp/maxy-logs-read-test-6-$$"
|
|
203
|
+
local script
|
|
204
|
+
script=$(setup_install_tree "$root")
|
|
205
|
+
local logs="$HOME/.$(basename "$root")/logs"
|
|
206
|
+
# Four checkpoint patterns in one window takes TWO chats, not one: no single
|
|
207
|
+
# surface emits four (Task 2042). A public chat then an admin chat, three
|
|
208
|
+
# rows each. Distinct milliseconds inside two minute-slots, so the ordering
|
|
209
|
+
# assertion below is strict and exercises the millisecond sort key.
|
|
210
|
+
local tp ta
|
|
211
|
+
tp=$(iso_minutes_ago 4); ta=$(iso_minutes_ago 2)
|
|
212
|
+
|
|
213
|
+
# Shipped shapes: edge.log self-stamps `ts=` after the tag (edge.ts:188,199);
|
|
214
|
+
# server.log is stamped at the line start by server-init-line-stamper.cjs.
|
|
215
|
+
# Both edge rows fire for any /api/ path (lib/proxy-log-path.ts:28-30).
|
|
216
|
+
{
|
|
217
|
+
echo "[edge-admin] ts=${tp}.100Z inbound method=POST path=/api/chat token=absent allowlist-branch=passthrough"
|
|
218
|
+
echo "[edge-admin] ts=${tp}.300Z outcome method=POST path=/api/chat status=200 duration_ms=200"
|
|
219
|
+
echo "[edge-admin] ts=${ta}.100Z inbound method=POST path=/api/webchat/send token=present allowlist-branch=passthrough"
|
|
220
|
+
echo "[edge-admin] ts=${ta}.300Z outcome method=POST path=/api/webchat/send status=200 duration_ms=200"
|
|
221
|
+
} > "$logs/edge.log"
|
|
222
|
+
{
|
|
223
|
+
echo "${tp}.200Z [chat-route] entered route=public method=POST"
|
|
224
|
+
echo "${ta}.200Z [admin-auth] outcome=accept path=/api/webchat/send cacheKey=deadbeef…"
|
|
225
|
+
} > "$logs/server.log"
|
|
226
|
+
|
|
227
|
+
local stdout stderr rc=0
|
|
228
|
+
stdout=$("$script" --tail chat-attempts 5 2>/tmp/maxy-logs-read-stderr-6-$$) || rc=$?
|
|
229
|
+
stderr=$(cat /tmp/maxy-logs-read-stderr-6-$$)
|
|
230
|
+
rm -f /tmp/maxy-logs-read-stderr-6-$$
|
|
231
|
+
|
|
232
|
+
cleanup_install_tree "$root"
|
|
233
|
+
|
|
234
|
+
if [[ $rc -ne 0 ]]; then echo " expected exit 0, got $rc"; return 1; fi
|
|
235
|
+
if [[ "$stdout" != *"inbound"* ]]; then echo " timeline missing edge inbound"; return 1; fi
|
|
236
|
+
if [[ "$stdout" != *"[edge-admin]"*"outcome"* ]]; then echo " timeline missing edge outcome"; return 1; fi
|
|
237
|
+
if [[ "$stdout" != *"[admin-auth] outcome=accept"* ]]; then echo " timeline missing admin-auth"; return 1; fi
|
|
238
|
+
if [[ "$stdout" != *"[chat-route] entered route=public"* ]]; then echo " timeline missing chat-route"; return 1; fi
|
|
239
|
+
if [[ "$stderr" != *"edge=4"* ]]; then echo " trailer missing edge=4: $stderr"; return 1; fi
|
|
240
|
+
if [[ "$stderr" != *"server=2"* ]]; then echo " trailer missing server=2: $stderr"; return 1; fi
|
|
241
|
+
if [[ "$stderr" != *"undated=0"* ]]; then echo " trailer missing undated=0: $stderr"; return 1; fi
|
|
242
|
+
|
|
243
|
+
# Chronological across the two log families: the public chat's edge inbound
|
|
244
|
+
# precedes its chat-route row, which precedes its edge outcome. A fixed-column
|
|
245
|
+
# sort put the two edge rows adjacent instead, which is the ordering defect
|
|
246
|
+
# this pins.
|
|
247
|
+
local first mid last
|
|
248
|
+
first=$(echo "$stdout" | grep -n 'inbound' | head -1 | cut -d: -f1)
|
|
249
|
+
mid=$(echo "$stdout" | grep -n '\[chat-route\] entered' | head -1 | cut -d: -f1)
|
|
250
|
+
last=$(echo "$stdout" | grep -n '\[edge-admin\].*outcome' | head -1 | cut -d: -f1)
|
|
251
|
+
if [[ -z "$first" || -z "$mid" || -z "$last" ]]; then
|
|
252
|
+
echo " could not locate rows: inbound=$first chat-route=$mid outcome=$last"; return 1
|
|
253
|
+
fi
|
|
254
|
+
if [[ "$first" -ge "$mid" || "$mid" -ge "$last" ]]; then
|
|
255
|
+
echo " rows not in chronological order: inbound=$first chat-route=$mid outcome=$last"
|
|
256
|
+
return 1
|
|
257
|
+
fi
|
|
258
|
+
return 0
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
# --- Case 7 (Task 2032): genuine zero says so distinctly ---
|
|
262
|
+
case_chat_attempts_genuine_zero() {
|
|
263
|
+
local root="/tmp/maxy-logs-read-test-7-$$"
|
|
264
|
+
local script
|
|
265
|
+
script=$(setup_install_tree "$root")
|
|
266
|
+
local logs="$HOME/.$(basename "$root")/logs"
|
|
267
|
+
local t0
|
|
268
|
+
t0=$(iso_minutes_ago 1)
|
|
269
|
+
# Both files exist and hold traffic; none of it is a chat-ingress checkpoint.
|
|
270
|
+
echo "[edge] ts=${t0}.000Z upstream http error path=/api/whatsapp err=ECONNREFUSED err-class=econnrefused-coldstart upstream=127.0.0.1:19201" > "$logs/edge.log"
|
|
271
|
+
echo "${t0}.000Z [server-init] watchdog enabled (ping-interval-ms=15000 deadline-ms=30000)" > "$logs/server.log"
|
|
272
|
+
|
|
273
|
+
local stderr rc=0
|
|
274
|
+
"$script" --tail chat-attempts 5 >/dev/null 2>/tmp/maxy-logs-read-stderr-7-$$ || rc=$?
|
|
275
|
+
stderr=$(cat /tmp/maxy-logs-read-stderr-7-$$)
|
|
276
|
+
rm -f /tmp/maxy-logs-read-stderr-7-$$
|
|
277
|
+
|
|
278
|
+
cleanup_install_tree "$root"
|
|
279
|
+
|
|
280
|
+
if [[ $rc -ne 1 ]]; then echo " expected exit 1, got $rc"; return 1; fi
|
|
281
|
+
if [[ "$stderr" != *"edge=0"* || "$stderr" != *"server=0"* ]]; then
|
|
282
|
+
echo " trailer missing per-source zeroes: $stderr"; return 1
|
|
283
|
+
fi
|
|
284
|
+
if [[ "$stderr" != *"no request reached the edge"* ]]; then
|
|
285
|
+
echo " zero-hit message does not state what a genuine zero means: $stderr"; return 1
|
|
286
|
+
fi
|
|
287
|
+
return 0
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
# --- Case 8 (Task 2032): the window excludes an older edge line ---
|
|
291
|
+
case_chat_attempts_window() {
|
|
292
|
+
local root="/tmp/maxy-logs-read-test-8-$$"
|
|
293
|
+
local script
|
|
294
|
+
script=$(setup_install_tree "$root")
|
|
295
|
+
local logs="$HOME/.$(basename "$root")/logs"
|
|
296
|
+
local recent old
|
|
297
|
+
recent=$(iso_minutes_ago 1)
|
|
298
|
+
old=$(iso_minutes_ago 90)
|
|
299
|
+
{
|
|
300
|
+
echo "[edge-admin] ts=${old}.000Z inbound method=POST path=/api/webchat/send token=present allowlist-branch=passthrough"
|
|
301
|
+
echo "[edge-admin] ts=${recent}.000Z inbound method=GET path=/api/admin/version token=absent allowlist-branch=passthrough"
|
|
302
|
+
} > "$logs/edge.log"
|
|
303
|
+
: > "$logs/server.log"
|
|
304
|
+
|
|
305
|
+
local stdout stderr rc=0
|
|
306
|
+
stdout=$("$script" --tail chat-attempts 5 2>/tmp/maxy-logs-read-stderr-8-$$) || rc=$?
|
|
307
|
+
stderr=$(cat /tmp/maxy-logs-read-stderr-8-$$)
|
|
308
|
+
rm -f /tmp/maxy-logs-read-stderr-8-$$
|
|
309
|
+
|
|
310
|
+
cleanup_install_tree "$root"
|
|
311
|
+
|
|
312
|
+
if [[ $rc -ne 0 ]]; then echo " expected exit 0, got $rc"; return 1; fi
|
|
313
|
+
if [[ "$stdout" == *"$old"* ]]; then echo " out-of-window line was not filtered"; return 1; fi
|
|
314
|
+
if [[ "$stdout" != *"$recent"* ]]; then echo " in-window line missing"; return 1; fi
|
|
315
|
+
if [[ "$stderr" != *"edge=1"* ]]; then echo " trailer edge count wrong: $stderr"; return 1; fi
|
|
316
|
+
return 0
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
# --- Case 9 (Task 2032): all four patterns inside one second still order ---
|
|
320
|
+
# A chat POST completes in a few hundred milliseconds, so its checkpoints share
|
|
321
|
+
# a wall-clock second; an admin chat and a public chat overlapping in that same
|
|
322
|
+
# second put all four patterns there at once. A sort key truncated to seconds
|
|
323
|
+
# collides on every row and falls back to file-append order, which puts the edge
|
|
324
|
+
# rows first — the clustering this mode was fixed to stop. Six rows, because no
|
|
325
|
+
# single surface emits four checkpoints (Task 2042).
|
|
326
|
+
case_chat_attempts_subsecond_order() {
|
|
327
|
+
local root="/tmp/maxy-logs-read-test-9-$$"
|
|
328
|
+
local script
|
|
329
|
+
script=$(setup_install_tree "$root")
|
|
330
|
+
local logs="$HOME/.$(basename "$root")/logs"
|
|
331
|
+
local s
|
|
332
|
+
s=$(iso_minutes_ago 1)
|
|
333
|
+
{
|
|
334
|
+
echo "[edge-admin] ts=${s}.010Z inbound method=POST path=/api/webchat/send token=present allowlist-branch=passthrough"
|
|
335
|
+
echo "[edge-admin] ts=${s}.060Z inbound method=POST path=/api/chat token=absent allowlist-branch=passthrough"
|
|
336
|
+
echo "[edge-admin] ts=${s}.090Z outcome method=POST path=/api/chat status=200 duration_ms=30"
|
|
337
|
+
echo "[edge-admin] ts=${s}.230Z outcome method=POST path=/api/webchat/send status=200 duration_ms=220"
|
|
338
|
+
} > "$logs/edge.log"
|
|
339
|
+
{
|
|
340
|
+
echo "${s}.050Z [admin-auth] outcome=accept path=/api/webchat/send cacheKey=deadbeef"
|
|
341
|
+
echo "${s}.070Z [chat-route] entered route=public method=POST"
|
|
342
|
+
} > "$logs/server.log"
|
|
343
|
+
|
|
344
|
+
local stdout rc=0
|
|
345
|
+
stdout=$("$script" --tail chat-attempts 5 2>/dev/null) || rc=$?
|
|
346
|
+
|
|
347
|
+
cleanup_install_tree "$root"
|
|
348
|
+
|
|
349
|
+
if [[ $rc -ne 0 ]]; then echo " expected exit 0, got $rc"; return 1; fi
|
|
350
|
+
local n_in n_auth n_route n_out
|
|
351
|
+
n_in=$(echo "$stdout" | grep -n 'inbound' | head -1 | cut -d: -f1)
|
|
352
|
+
n_auth=$(echo "$stdout" | grep -n '\[admin-auth\]' | head -1 | cut -d: -f1)
|
|
353
|
+
n_route=$(echo "$stdout" | grep -n '\[chat-route\]' | head -1 | cut -d: -f1)
|
|
354
|
+
n_out=$(echo "$stdout" | grep -n '\[edge-admin\].*outcome' | head -1 | cut -d: -f1)
|
|
355
|
+
if [[ -z "$n_in" || -z "$n_auth" || -z "$n_route" || -z "$n_out" ]]; then
|
|
356
|
+
echo " missing a row: in=$n_in auth=$n_auth route=$n_route out=$n_out"; return 1
|
|
357
|
+
fi
|
|
358
|
+
if [[ "$n_in" -ge "$n_auth" || "$n_auth" -ge "$n_route" || "$n_route" -ge "$n_out" ]]; then
|
|
359
|
+
echo " sub-second rows out of order: in=$n_in auth=$n_auth route=$n_route out=$n_out"
|
|
360
|
+
echo "$stdout"
|
|
361
|
+
return 1
|
|
362
|
+
fi
|
|
363
|
+
return 0
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
# --- Case 10 (Task 2032): an undated match is never narrated as edge silence ---
|
|
367
|
+
# The grep matches the `[edge-admin] inbound` shape written before the `ts=`
|
|
368
|
+
# no timestamp. Such a line cannot be placed in the window, but it is evidence
|
|
369
|
+
# that a request DID reach the edge, so the mode must not answer with the
|
|
370
|
+
# genuine-zero verdict.
|
|
371
|
+
case_chat_attempts_undated_not_silence() {
|
|
372
|
+
local root="/tmp/maxy-logs-read-test-10-$$"
|
|
373
|
+
local script
|
|
374
|
+
script=$(setup_install_tree "$root")
|
|
375
|
+
local logs="$HOME/.$(basename "$root")/logs"
|
|
376
|
+
echo "[edge-admin] inbound method=POST path=/api/webchat/send token=present allowlist-branch=passthrough" > "$logs/edge.log"
|
|
377
|
+
: > "$logs/server.log"
|
|
378
|
+
|
|
379
|
+
local stdout stderr rc=0
|
|
380
|
+
stdout=$("$script" --tail chat-attempts 5 2>/tmp/maxy-logs-read-stderr-10-$$) || rc=$?
|
|
381
|
+
stderr=$(cat /tmp/maxy-logs-read-stderr-10-$$)
|
|
382
|
+
rm -f /tmp/maxy-logs-read-stderr-10-$$
|
|
383
|
+
|
|
384
|
+
cleanup_install_tree "$root"
|
|
385
|
+
|
|
386
|
+
if [[ $rc -ne 0 ]]; then echo " expected exit 0 (a match is a match), got $rc"; return 1; fi
|
|
387
|
+
if [[ "$stderr" == *"no request reached the edge"* || "$stdout" == *"no request reached the edge"* ]]; then
|
|
388
|
+
echo " matched an edge line and still claimed no request reached the edge"; return 1
|
|
389
|
+
fi
|
|
390
|
+
if [[ "$stdout" != *"carry no timestamp"* ]]; then
|
|
391
|
+
echo " undated match not surfaced in the output: $stdout"; return 1
|
|
392
|
+
fi
|
|
393
|
+
if [[ "$stdout" != *"[edge-admin] inbound"* ]]; then
|
|
394
|
+
echo " undated line itself not printed"; return 1
|
|
395
|
+
fi
|
|
396
|
+
if [[ "$stderr" != *"undated=1"* ]]; then echo " trailer undated count wrong: $stderr"; return 1; fi
|
|
397
|
+
return 0
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
# --- Case 11 (Task 2032): a missing edge.log is reader blindness, not silence ---
|
|
401
|
+
case_chat_attempts_edge_log_absent() {
|
|
402
|
+
local root="/tmp/maxy-logs-read-test-11-$$"
|
|
403
|
+
local script
|
|
404
|
+
script=$(setup_install_tree "$root")
|
|
405
|
+
local logs="$HOME/.$(basename "$root")/logs"
|
|
406
|
+
# server.log exists, edge.log does not.
|
|
407
|
+
: > "$logs/server.log"
|
|
408
|
+
rm -f "$logs/edge.log"
|
|
409
|
+
|
|
410
|
+
local stderr rc=0
|
|
411
|
+
"$script" --tail chat-attempts 5 >/dev/null 2>/tmp/maxy-logs-read-stderr-11-$$ || rc=$?
|
|
412
|
+
stderr=$(cat /tmp/maxy-logs-read-stderr-11-$$)
|
|
413
|
+
rm -f /tmp/maxy-logs-read-stderr-11-$$
|
|
414
|
+
|
|
415
|
+
cleanup_install_tree "$root"
|
|
416
|
+
|
|
417
|
+
if [[ $rc -ne 1 ]]; then echo " expected exit 1, got $rc"; return 1; fi
|
|
418
|
+
if [[ "$stderr" == *"no request reached the edge"* ]]; then
|
|
419
|
+
echo " claimed no request arrived while edge.log was unreadable"; return 1
|
|
420
|
+
fi
|
|
421
|
+
if [[ "$stderr" != *"edge.log is not on disk"* ]]; then
|
|
422
|
+
echo " did not state that the edge checkpoints were unreadable: $stderr"; return 1
|
|
423
|
+
fi
|
|
424
|
+
return 0
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
# --- Case 12 (Task 2042): usage names each surface, not four rows per chat ---
|
|
428
|
+
# The mode greps four checkpoint patterns, but no single chat emits four: the
|
|
429
|
+
# admin webchat has no [chat-route] row and public chat has no [admin-auth]
|
|
430
|
+
# row. Usage that promised four made every healthy admin chat read as a
|
|
431
|
+
# routing regression, so the count and both surface paths are pinned here.
|
|
432
|
+
case_usage_checkpoints_per_surface() {
|
|
433
|
+
local root="/tmp/maxy-logs-read-test-12-$$"
|
|
434
|
+
local script
|
|
435
|
+
script=$(setup_install_tree "$root")
|
|
436
|
+
|
|
437
|
+
local stderr rc=0
|
|
438
|
+
"$script" >/dev/null 2>/tmp/maxy-logs-read-stderr-12-$$ || rc=$?
|
|
439
|
+
stderr=$(cat /tmp/maxy-logs-read-stderr-12-$$)
|
|
440
|
+
rm -f /tmp/maxy-logs-read-stderr-12-$$
|
|
441
|
+
|
|
442
|
+
cleanup_install_tree "$root"
|
|
443
|
+
|
|
444
|
+
if [[ $rc -ne 2 ]]; then echo " expected usage exit 2, got $rc"; return 1; fi
|
|
445
|
+
if [[ "$stderr" == *"four ingress checkpoints"* ]]; then
|
|
446
|
+
echo " usage still claims four checkpoints per chat"; return 1
|
|
447
|
+
fi
|
|
448
|
+
if [[ "$stderr" == *"quartet"* ]]; then
|
|
449
|
+
echo " usage still calls the checkpoints a quartet"; return 1
|
|
450
|
+
fi
|
|
451
|
+
if [[ "$stderr" != *"/api/webchat/send"* ]]; then
|
|
452
|
+
echo " usage does not name the admin surface path"; return 1
|
|
453
|
+
fi
|
|
454
|
+
if [[ "$stderr" != *"/api/chat"* ]]; then
|
|
455
|
+
echo " usage does not name the public surface path"; return 1
|
|
456
|
+
fi
|
|
457
|
+
return 0
|
|
458
|
+
}
|
|
459
|
+
|
|
191
460
|
run_case "sessionKey file present → exit 0" case_file_present
|
|
192
461
|
run_case "no file → exit 1 + missing-on-resolve" case_missing
|
|
193
462
|
run_case "ambiguous prefix → exit 1, refuses to pick" case_ambiguous
|
|
194
463
|
run_case "--tail mem present → exit 0 + sampler lines" case_mem_present
|
|
195
464
|
run_case "--tail mem absent → exit 1 + not-found message" case_mem_absent
|
|
465
|
+
run_case "chat-attempts matches both surfaces and interleaves" case_chat_attempts_both_surfaces
|
|
466
|
+
run_case "chat-attempts genuine zero states what it means" case_chat_attempts_genuine_zero
|
|
467
|
+
run_case "chat-attempts window excludes an older line" case_chat_attempts_window
|
|
468
|
+
run_case "chat-attempts orders all four patterns inside one second" case_chat_attempts_subsecond_order
|
|
469
|
+
run_case "chat-attempts undated match is not edge silence" case_chat_attempts_undated_not_silence
|
|
470
|
+
run_case "chat-attempts absent edge.log is reader blindness" case_chat_attempts_edge_log_absent
|
|
471
|
+
run_case "usage names each surface's checkpoints" case_usage_checkpoints_per_surface
|
|
196
472
|
|
|
197
473
|
echo ""
|
|
198
474
|
echo "================================================"
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# The one documented action that makes a fresh worktree able to run the
|
|
3
|
+
# platform/ui suite. Task 2034.
|
|
4
|
+
#
|
|
5
|
+
# A git worktree carries tracked files only. platform/node_modules,
|
|
6
|
+
# platform/ui/node_modules and platform/lib/*/dist are gitignored build output, so
|
|
7
|
+
# a fresh worktree has none of them, and `npm install` inside platform/ui creates
|
|
8
|
+
# neither the hoisted platform/node_modules nor any lib dist. Without this, the
|
|
9
|
+
# suite fails on absent artifacts in a way that reads as flaky tests.
|
|
10
|
+
#
|
|
11
|
+
# Two things here are not obvious and are the reason this is a script:
|
|
12
|
+
#
|
|
13
|
+
# 1. tsc is called as platform/node_modules/.bin/tsc, never bare. platform's
|
|
14
|
+
# own package.json declares no typescript; it hoists one from 28 workspace
|
|
15
|
+
# members. Inside an npm script npm prepends node_modules/.bin to PATH and a
|
|
16
|
+
# bare `tsc` resolves; from a bare shell it does not, and the tsc on PATH is
|
|
17
|
+
# an unrelated program that refuses to run.
|
|
18
|
+
#
|
|
19
|
+
# 2. The libs are built in a loop, not through `npm run build:lib`. build:lib
|
|
20
|
+
# chains its 27 compiler runs with &&, and one lib emits its output while
|
|
21
|
+
# still reporting type errors, which would abort every run after it. So each
|
|
22
|
+
# lib is built independently and the final gate is artifact presence, not
|
|
23
|
+
# compiler exit status — the only check that separates "emitted with type
|
|
24
|
+
# errors" from "emitted nothing".
|
|
25
|
+
|
|
26
|
+
set -uo pipefail
|
|
27
|
+
|
|
28
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
|
|
29
|
+
PLATFORM="$(cd "$SCRIPT_DIR/.." && pwd -P)"
|
|
30
|
+
TSC="$PLATFORM/node_modules/.bin/tsc"
|
|
31
|
+
GATE="$PLATFORM/ui/scripts/check-worktree-provisioned.mjs"
|
|
32
|
+
|
|
33
|
+
echo "[provision] platform: $PLATFORM"
|
|
34
|
+
|
|
35
|
+
echo "[provision] stage 1/3: npm install in platform/"
|
|
36
|
+
if ! (cd "$PLATFORM" && npm install); then
|
|
37
|
+
echo "[provision] FAILED at stage 1: npm install in platform/" >&2
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
echo "[provision] stage 2/3: npm install in platform/ui"
|
|
42
|
+
if ! (cd "$PLATFORM/ui" && npm install); then
|
|
43
|
+
echo "[provision] FAILED at stage 2: npm install in platform/ui" >&2
|
|
44
|
+
exit 1
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
if [ ! -x "$TSC" ]; then
|
|
48
|
+
echo "[provision] FAILED: $TSC absent after stage 1." >&2
|
|
49
|
+
echo "[provision] typescript hoists to platform/node_modules from the workspace" >&2
|
|
50
|
+
echo "[provision] members; if it is missing, stage 1 did not complete." >&2
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
echo "[provision] stage 3/3: building platform/lib/*/dist"
|
|
55
|
+
emitted_with_errors=()
|
|
56
|
+
for tsconfig in "$PLATFORM"/lib/*/tsconfig.json; do
|
|
57
|
+
lib="$(basename "$(dirname "$tsconfig")")"
|
|
58
|
+
if "$TSC" -p "$tsconfig" >/dev/null 2>&1; then
|
|
59
|
+
printf ' %-32s ok\n' "$lib"
|
|
60
|
+
elif [ -f "$PLATFORM/lib/$lib/dist/index.js" ]; then
|
|
61
|
+
printf ' %-32s emitted, with type errors\n' "$lib"
|
|
62
|
+
emitted_with_errors+=("$lib")
|
|
63
|
+
else
|
|
64
|
+
printf ' %-32s FAILED, emitted nothing\n' "$lib"
|
|
65
|
+
fi
|
|
66
|
+
done
|
|
67
|
+
|
|
68
|
+
if [ ${#emitted_with_errors[@]} -gt 0 ]; then
|
|
69
|
+
echo "[provision] ${#emitted_with_errors[@]} lib(s) emitted output while reporting type"
|
|
70
|
+
echo "[provision] errors: ${emitted_with_errors[*]}. Their dist is present, so the suite"
|
|
71
|
+
echo "[provision] can run. The type errors themselves are out of scope for provisioning."
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
echo "[provision] verifying against the gate"
|
|
75
|
+
if ! node "$GATE"; then
|
|
76
|
+
echo "[provision] FAILED: the tree is still unprovisioned after all three stages." >&2
|
|
77
|
+
exit 1
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
echo "[provision] done. platform/ui is ready: cd platform/ui && npm test"
|