@meridiona/meridian-darwin-arm64 1.23.11 → 1.24.0

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/VERSION CHANGED
@@ -1 +1 @@
1
- 1.23.11
1
+ 1.24.0
package/bin/meridian CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meridiona/meridian-darwin-arm64",
3
- "version": "1.23.11",
3
+ "version": "1.24.0",
4
4
  "description": "Prebuilt Meridian app for macOS arm64 (daemon binary + dashboard + Python services). Installed via @meridiona/meridian.",
5
5
  "homepage": "https://github.com/Meridiona/meridian",
6
6
  "repository": {
@@ -563,6 +563,15 @@ _final_ui_hash="${_new_ui_hash:-${_OLD_UI_HASH}}"
563
563
 
564
564
  ok "all daemons installed"
565
565
 
566
+ # Pipeline smoke test — verify both LLM stages return valid output (no DB writes).
567
+ echo ""
568
+ info "Running pipeline smoke test (this exercises the model — may take ~30s)…"
569
+ if bash "${APP_ROOT}/scripts/meridian-cli.sh" smoke; then
570
+ ok "pipeline smoke passed — classification and worklog synthesis are working"
571
+ else
572
+ warn "pipeline smoke found issues — run 'meridian doctor' for remedies"
573
+ fi
574
+
566
575
  echo ""
567
576
  echo "✓ Meridian installed at ${APP_ROOT}"
568
577
  echo " meridian status # check the daemons"
@@ -43,7 +43,8 @@ Commands:
43
43
  target: daemon|daemon-error|screenpipe|screenpipe-error|ui|ui-error|mlx-server|mlx-server-error
44
44
  -f Follow (stream)
45
45
  -n N Last N lines (default 100)
46
- doctor Run environment health checks
46
+ doctor Run environment health checks (includes pipeline smoke)
47
+ smoke Dry-run both LLM pipeline stages — no DB writes
47
48
  worklog-status Show today's PM worklogs (done/pending/drafted/posted + comments)
48
49
  [--day YYYY-MM-DD]
49
50
  config edit Open the repo-root .env in $EDITOR
@@ -227,26 +228,34 @@ _daemon_bin() {
227
228
  }
228
229
 
229
230
  cmd_doctor() {
230
- local bin
231
+ local bin rc=0
231
232
  if bin="$(_daemon_bin)"; then
232
233
  set +e
233
234
  if [[ "$*" == *--fix* ]]; then
234
235
  # --fix has interactive guided prompts — the user is present, so run
235
236
  # without the alarm (which would kill a prompt waiting for input).
236
237
  "$bin" doctor "$@"
238
+ rc=$?
237
239
  else
238
240
  # Guard with a perl alarm so a stale binary (one that predates
239
241
  # `doctor` and would fall through to starting the daemon) can never
240
242
  # hang the terminal. The Rust report colourises itself on a tty.
241
243
  perl -e 'alarm shift @ARGV; exec @ARGV' 30 "$bin" doctor "$@"
244
+ rc=$?
242
245
  fi
243
- local rc=$?
244
246
  set -e
245
247
  # 0 = healthy, 1 = critical issues found — both are real doctor runs.
246
- if [[ $rc -eq 0 || $rc -eq 1 ]]; then return $rc; fi
248
+ if [[ $rc -eq 0 || $rc -eq 1 ]]; then
249
+ # Append classification smoke (fast path, ~30s max). Failures are
250
+ # informational — they don't override the doctor exit code, since the
251
+ # doctor already surfaces the MLX health state.
252
+ cmd_smoke --classify-only || true
253
+ return $rc
254
+ fi
247
255
  warn "health engine timed out or is stale — rebuild: cargo build --release"
248
256
  fi
249
257
  _doctor_fallback
258
+ cmd_smoke --classify-only || true
250
259
  }
251
260
 
252
261
  # Minimal bash-only checks for when the daemon binary is unavailable.
@@ -270,6 +279,161 @@ _doctor_fallback() {
270
279
  [[ $DOCTOR_FAILURES -eq 0 ]]
271
280
  }
272
281
 
282
+ # --- smoke (pipeline dry run) ---
283
+ # Sends synthetic requests (no DB writes) to both LLM stages:
284
+ # --classify-only fast path (~30s max) called automatically from cmd_doctor
285
+ # (no flag) full run: classification + worklog synthesis
286
+
287
+ _smoke_read_env() {
288
+ local key="$1" env_file="${REPO_ROOT}/.env"
289
+ [[ -f "$env_file" ]] || return 0
290
+ grep -E "^${key}=" "$env_file" 2>/dev/null | tail -1 | cut -d= -f2- || true
291
+ }
292
+
293
+ _smoke_row() { # glyph ansi-color label detail
294
+ local glyph="$1" color="$2" label="$3" detail="${4:-}"
295
+ if [[ -t 1 ]]; then
296
+ printf " \033[%sm%s\033[0m %-26s \033[2m%s\033[0m\n" "$color" "$glyph" "$label" "$detail"
297
+ else
298
+ printf " %s %-26s %s\n" "$glyph" "$label" "$detail"
299
+ fi
300
+ }
301
+
302
+ _smoke_remedy() {
303
+ local msg="$1"
304
+ if [[ -t 1 ]]; then printf " \033[2m→ %s\033[0m\n" "$msg"
305
+ else printf " → %s\n" "$msg"; fi
306
+ }
307
+
308
+ cmd_smoke() {
309
+ local classify_only=0
310
+ [[ "${1:-}" == "--classify-only" ]] && classify_only=1
311
+
312
+ local mlx_port
313
+ mlx_port="$(_smoke_read_env MLX_SERVER_PORT)"
314
+ mlx_port="${mlx_port:-7823}"
315
+ local base="http://127.0.0.1:${mlx_port}"
316
+ local classify_timeout=60
317
+ [[ $classify_only -eq 1 ]] && classify_timeout=30
318
+ local all_ok=1
319
+
320
+ if [[ -t 1 ]]; then
321
+ printf "\n \033[36m▸ smoke (pipeline dry run)\033[0m\n"
322
+ printf " \033[2m%s\033[0m\n" "════════════════════════════════════════════════════════"
323
+ else
324
+ printf "\n ▸ smoke (pipeline dry run)\n"
325
+ printf " %s\n" "════════════════════════════════════════════════════════"
326
+ fi
327
+
328
+ # Quick reachability probe — if the server isn't up, nothing else can run.
329
+ local reach_ok=0
330
+ set +e
331
+ curl -sf --max-time 5 "${base}/health" >/dev/null 2>&1 && reach_ok=1
332
+ set -e
333
+ if [[ $reach_ok -eq 0 ]]; then
334
+ _smoke_row "✗" "31" "mlx reachable" "server not responding at ${base}"
335
+ _smoke_remedy "meridian start (or: meridian logs mlx-server)"
336
+ echo ""
337
+ return 1
338
+ fi
339
+
340
+ # Stage 1: classification smoke.
341
+ # POST /classify takes {"input":"..."} — pure model inference, zero DB access.
342
+ local t0 classify_resp classify_ok=0
343
+ t0=$SECONDS
344
+ set +e
345
+ classify_resp="$(curl -sf --max-time "${classify_timeout}" \
346
+ -X POST "${base}/classify" \
347
+ -H "Content-Type: application/json" \
348
+ -d '{"input":"App: Xcode\nWindow: ContentView.swift — MyApp\nOCR: func body: some View { Text(\"Hello World\") }\nDuration: 600s"}' \
349
+ 2>/dev/null)"
350
+ local classify_curl_rc=$?
351
+ set -e
352
+ local classify_elapsed=$(( SECONDS - t0 ))
353
+
354
+ if [[ $classify_curl_rc -ne 0 || -z "$classify_resp" ]]; then
355
+ _smoke_row "✗" "31" "classification" "no response from /classify (timeout or error)"
356
+ _smoke_remedy "check: meridian logs mlx-server"
357
+ all_ok=0
358
+ else
359
+ local stype conf
360
+ stype="$(printf '%s' "$classify_resp" | grep -o '"session_type":"[^"]*"' | cut -d'"' -f4)" || stype=""
361
+ conf="$(printf '%s' "$classify_resp" | grep -o '"confidence":[0-9.]*' | cut -d: -f2)" || conf="?"
362
+ if [[ -n "$stype" ]]; then
363
+ _smoke_row "✓" "32" "classification" "${classify_elapsed}s session_type=${stype} conf=${conf}"
364
+ classify_ok=1
365
+ else
366
+ _smoke_row "✗" "31" "classification" "response did not parse — got: ${classify_resp:0:80}"
367
+ _smoke_remedy "restart MLX server: meridian dev mlx (or: meridian restart)"
368
+ all_ok=0
369
+ fi
370
+ fi
371
+
372
+ # Fast path (called from cmd_doctor): stop here.
373
+ if [[ $classify_only -eq 1 ]]; then
374
+ echo ""
375
+ [[ $classify_ok -eq 1 ]]
376
+ return
377
+ fi
378
+
379
+ # Stage 2: worklog synthesis smoke.
380
+ # POST /synthesise_worklog with a synthetic bundle — the agno agent runs the model
381
+ # and returns a JiraUpdate. Nothing is written to the DB; Rust never sees this call.
382
+ local jira_url jira_token linear_key github_token has_pm=0
383
+ jira_url="$(_smoke_read_env JIRA_BASE_URL)"
384
+ [[ -z "$jira_url" ]] && jira_url="$(_smoke_read_env JIRA_URL)"
385
+ jira_token="$(_smoke_read_env JIRA_API_TOKEN)"
386
+ linear_key="$(_smoke_read_env LINEAR_API_KEY)"
387
+ github_token="$(_smoke_read_env GITHUB_TOKEN)"
388
+ [[ -n "$jira_url" && -n "$jira_token" ]] && has_pm=1
389
+ [[ -n "$linear_key" ]] && has_pm=1
390
+ [[ -n "$github_token" ]] && has_pm=1
391
+
392
+ if [[ $has_pm -eq 0 ]]; then
393
+ _smoke_row "·" "2" "worklog synthesis" "skipped — no PM credentials in .env"
394
+ echo ""
395
+ [[ $all_ok -eq 1 ]]
396
+ return
397
+ fi
398
+
399
+ # Dates are fixed to 2024-01-01 so the output is obviously synthetic.
400
+ local synth_bundle
401
+ synth_bundle='{"bundle":{"task_key":"SMOKE-1","window_start":"2024-01-01T09:00:00","window_end":"2024-01-01T09:30:00","cycle_index":0,"sessions":[{"id":1,"app_name":"Xcode","started_at":"2024-01-01T09:00:00","ended_at":"2024-01-01T09:30:00","duration_s":1800,"idle_frame_s":0,"top_titles":["ContentView.swift — MyApp"],"excerpt":"Implementing SwiftUI body layout. func body: some View { Text(\"Hello World\") }","category":"coding"}],"total_seconds":1800,"real_seconds":1800,"pm_task_title":"Implement ContentView layout"}}'
402
+
403
+ local t1 synth_resp synth_ok=0
404
+ t1=$SECONDS
405
+ set +e
406
+ synth_resp="$(curl -sf --max-time 120 \
407
+ -X POST "${base}/synthesise_worklog" \
408
+ -H "Content-Type: application/json" \
409
+ -d "$synth_bundle" \
410
+ 2>/dev/null)"
411
+ local synth_curl_rc=$?
412
+ set -e
413
+ local synth_elapsed=$(( SECONDS - t1 ))
414
+
415
+ if [[ $synth_curl_rc -ne 0 || -z "$synth_resp" ]]; then
416
+ _smoke_row "✗" "31" "worklog synthesis" "no response from /synthesise_worklog (timeout or error)"
417
+ _smoke_remedy "check: meridian logs mlx-server"
418
+ all_ok=0
419
+ elif printf '%s' "$synth_resp" | grep -q '"summary"'; then
420
+ local bullets conf2
421
+ bullets="$(printf '%s' "$synth_resp" | grep -o '"text":' | wc -l | tr -d ' ')" || bullets="?"
422
+ conf2="$(printf '%s' "$synth_resp" | grep -o '"confidence":[0-9.]*' | cut -d: -f2)" || conf2="?"
423
+ _smoke_row "✓" "32" "worklog synthesis" "${synth_elapsed}s bullets=${bullets} conf=${conf2}"
424
+ synth_ok=1
425
+ else
426
+ _smoke_row "✗" "31" "worklog synthesis" "response missing summary — got: ${synth_resp:0:80}"
427
+ _smoke_remedy "restart MLX server: meridian dev mlx (or: meridian restart)"
428
+ all_ok=0
429
+ synth_ok=0 # explicitly mark unused var for clarity
430
+ : "$synth_ok"
431
+ fi
432
+
433
+ echo ""
434
+ [[ $all_ok -eq 1 ]]
435
+ }
436
+
273
437
  # --- config ---
274
438
  cmd_config() {
275
439
  local subcmd="${1:-}"
@@ -478,6 +642,7 @@ case "$CMD" in
478
642
  status) cmd_status ;;
479
643
  logs) cmd_logs "$@" ;;
480
644
  doctor) cmd_doctor "$@" ;;
645
+ smoke) cmd_smoke "$@" ;;
481
646
  config) cmd_config "$@" ;;
482
647
  dev) cmd_dev "$@" ;;
483
648
  uninstall) cmd_uninstall ;;
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meridian-agents"
7
- version = "1.23.11"
7
+ version = "1.24.0"
8
8
  description = "Meridian agents — hermes task linking and Jira progress updates for meridian.db"
9
9
  requires-python = ">=3.11"
10
10
  authors = [{ name = "Meridiona" }]
package/ui.tar.gz DELETED
Binary file