dev3000 0.0.113 → 0.0.115
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +32 -2
- package/dist/cli.js.map +1 -1
- package/dist/dev-environment.d.ts.map +1 -1
- package/dist/dev-environment.js +25 -4
- package/dist/dev-environment.js.map +1 -1
- package/dist/src/tui-interface-impl.tsx +175 -127
- package/dist/tui-interface-impl.d.ts.map +1 -1
- package/dist/tui-interface-impl.js +113 -74
- package/dist/tui-interface-impl.js.map +1 -1
- package/mcp-server/.next/BUILD_ID +1 -1
- package/mcp-server/.next/build-manifest.json +2 -2
- package/mcp-server/.next/fallback-build-manifest.json +2 -2
- package/mcp-server/.next/next-minimal-server.js.nft.json +1 -1
- package/mcp-server/.next/next-server.js.nft.json +1 -1
- package/mcp-server/.next/prerender-manifest.json +3 -3
- package/mcp-server/.next/required-server-files.json +4 -4
- package/mcp-server/.next/server/app/.well-known/workflow/v1/flow/route.js +2 -2
- package/mcp-server/.next/server/app/.well-known/workflow/v1/flow/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/.well-known/workflow/v1/step/route.js +2 -2
- package/mcp-server/.next/server/app/.well-known/workflow/v1/step/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/.well-known/workflow/v1/webhook/[token]/route.js +2 -2
- package/mcp-server/.next/server/app/.well-known/workflow/v1/webhook/[token]/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/_global-error.html +2 -2
- package/mcp-server/.next/server/app/_global-error.rsc +1 -1
- package/mcp-server/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/_not-found.html +1 -1
- package/mcp-server/.next/server/app/_not-found.rsc +2 -2
- package/mcp-server/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/mcp-server/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/mcp-server/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/mcp-server/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/mcp-server/.next/server/app/api/auth/authorize/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/auth/callback/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/auth/signout/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/auth/token/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/cloud/check-pr/route.js +2 -2
- package/mcp-server/.next/server/app/api/cloud/check-pr/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/cloud/fix-workflow/health/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/cloud/fix-workflow/route.js +2 -2
- package/mcp-server/.next/server/app/api/cloud/fix-workflow/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/cloud/start-fix/route.js +2 -2
- package/mcp-server/.next/server/app/api/cloud/start-fix/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/integration/webhook/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/jank/[session]/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/logs/append/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/logs/head/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/logs/list/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/logs/rotate/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/logs/stream/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/logs/tail/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/orchestrator/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/projects/[projectId]/bypass-token/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/projects/branches/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/projects/check-protection/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/screenshots/[filename]/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/screenshots/list/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/teams/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/tools/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/api/workflows/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/auth/error/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/auth/error/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/auth/error.html +1 -1
- package/mcp-server/.next/server/app/auth/error.rsc +2 -2
- package/mcp-server/.next/server/app/auth/error.segments/_full.segment.rsc +2 -2
- package/mcp-server/.next/server/app/auth/error.segments/_head.segment.rsc +1 -1
- package/mcp-server/.next/server/app/auth/error.segments/_index.segment.rsc +2 -2
- package/mcp-server/.next/server/app/auth/error.segments/_tree.segment.rsc +2 -2
- package/mcp-server/.next/server/app/auth/error.segments/auth/error/__PAGE__.segment.rsc +1 -1
- package/mcp-server/.next/server/app/auth/error.segments/auth/error.segment.rsc +1 -1
- package/mcp-server/.next/server/app/auth/error.segments/auth.segment.rsc +1 -1
- package/mcp-server/.next/server/app/index.html +1 -1
- package/mcp-server/.next/server/app/index.rsc +3 -3
- package/mcp-server/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/mcp-server/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/mcp-server/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/mcp-server/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/mcp-server/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/mcp-server/.next/server/app/logs/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/logs/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/mcp/route.js.nft.json +1 -1
- package/mcp-server/.next/server/app/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/signin/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/signin/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/video/[session]/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/video/[session]/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/workflows/[id]/report/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/workflows/[id]/report/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/workflows/new/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/workflows/new/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/app/workflows/page.js.nft.json +1 -1
- package/mcp-server/.next/server/app/workflows/page_client-reference-manifest.js +1 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__157de66b._.js +101 -36
- package/mcp-server/.next/server/chunks/[root-of-the-server]__157de66b._.js.map +1 -1
- package/mcp-server/.next/server/chunks/{[root-of-the-server]__f99bd75f._.js → [root-of-the-server]__2920484d._.js} +2 -2
- package/mcp-server/.next/server/chunks/{[root-of-the-server]__f99bd75f._.js.map → [root-of-the-server]__2920484d._.js.map} +1 -1
- package/mcp-server/.next/server/chunks/{[root-of-the-server]__d6a224bc._.js → [root-of-the-server]__71b44a42._.js} +14 -14
- package/mcp-server/.next/server/chunks/[root-of-the-server]__71b44a42._.js.map +1 -0
- package/mcp-server/.next/server/chunks/[root-of-the-server]__730a8fd0._.js +1 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__730a8fd0._.js.map +1 -1
- package/mcp-server/.next/server/chunks/{[root-of-the-server]__c86876f8._.js → [root-of-the-server]__76031cfc._.js} +2 -2
- package/mcp-server/.next/server/chunks/{[root-of-the-server]__c86876f8._.js.map → [root-of-the-server]__76031cfc._.js.map} +1 -1
- package/mcp-server/.next/server/chunks/{[root-of-the-server]__c5e6aa23._.js → [root-of-the-server]__832ec618._.js} +2 -2
- package/mcp-server/.next/server/chunks/{[root-of-the-server]__c5e6aa23._.js.map → [root-of-the-server]__832ec618._.js.map} +1 -1
- package/mcp-server/.next/server/chunks/{[root-of-the-server]__41aa7b20._.js → [root-of-the-server]__b194d4eb._.js} +13 -13
- package/mcp-server/.next/server/chunks/[root-of-the-server]__b194d4eb._.js.map +1 -0
- package/mcp-server/.next/server/chunks/[root-of-the-server]__c1681338._.js +3 -0
- package/mcp-server/.next/server/chunks/[root-of-the-server]__c1681338._.js.map +1 -0
- package/mcp-server/.next/server/chunks/{[root-of-the-server]__d37c38d3._.js → [root-of-the-server]__e6808c21._.js} +2 -2
- package/mcp-server/.next/server/chunks/{[root-of-the-server]__d37c38d3._.js.map → [root-of-the-server]__e6808c21._.js.map} +1 -1
- package/mcp-server/.next/server/chunks/{[root-of-the-server]__446f0436._.js → [root-of-the-server]__ec6a1335._.js} +2 -2
- package/mcp-server/.next/server/chunks/[root-of-the-server]__ec6a1335._.js.map +1 -0
- package/mcp-server/.next/server/chunks/bee4f_next_dist_esm_build_templates_app-route_1ece9366.js +5 -5
- package/mcp-server/.next/server/chunks/bee4f_next_dist_esm_build_templates_app-route_1ece9366.js.map +1 -1
- package/mcp-server/.next/server/chunks/mcp-server_app_api_cloud_fix-workflow_steps_ts_b65f3271._.js +30 -16
- package/mcp-server/.next/server/chunks/mcp-server_app_api_cloud_fix-workflow_steps_ts_b65f3271._.js.map +1 -1
- package/mcp-server/.next/server/chunks/node_modules__pnpm_85ddbe9c._.js +2 -2
- package/mcp-server/.next/server/chunks/node_modules__pnpm_85ddbe9c._.js.map +1 -1
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__2e44f0db._.js +3 -0
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__2e44f0db._.js.map +1 -0
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__3585c949._.js +3 -0
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__3585c949._.js.map +1 -0
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__477c3bbb._.js +3 -0
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__477c3bbb._.js.map +1 -0
- package/mcp-server/.next/server/chunks/ssr/{[root-of-the-server]__570677dc._.js → [root-of-the-server]__880839a0._.js} +2 -2
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__880839a0._.js.map +1 -0
- package/mcp-server/.next/server/chunks/ssr/_41b8f993._.js +3 -0
- package/mcp-server/.next/server/chunks/ssr/_41b8f993._.js.map +1 -0
- package/mcp-server/.next/server/chunks/ssr/_9ba0ef29._.js +3 -0
- package/mcp-server/.next/server/chunks/ssr/_9ba0ef29._.js.map +1 -0
- package/mcp-server/.next/server/chunks/ssr/_cd4dc25e._.js.map +1 -1
- package/mcp-server/.next/server/chunks/ssr/mcp-server_app_workflows_new_new-workflow-client_tsx_1312c046._.js +2 -2
- package/mcp-server/.next/server/chunks/ssr/mcp-server_app_workflows_new_new-workflow-client_tsx_1312c046._.js.map +1 -1
- package/mcp-server/.next/server/chunks/ssr/mcp-server_app_workflows_workflows-client_tsx_268cfd4a._.js +7 -0
- package/mcp-server/.next/server/chunks/ssr/mcp-server_app_workflows_workflows-client_tsx_268cfd4a._.js.map +1 -0
- package/mcp-server/.next/server/chunks/ssr/node_modules__pnpm_961f21c4._.js +3 -0
- package/mcp-server/.next/server/chunks/ssr/node_modules__pnpm_961f21c4._.js.map +1 -0
- package/mcp-server/.next/server/chunks/ssr/node_modules__pnpm_a82244bf._.js +3 -0
- package/mcp-server/.next/server/chunks/ssr/node_modules__pnpm_a82244bf._.js.map +1 -0
- package/mcp-server/.next/server/chunks/ssr/{node_modules__pnpm_07527699._.js → node_modules__pnpm_eb98e511._.js} +2 -2
- package/mcp-server/.next/server/chunks/ssr/node_modules__pnpm_eb98e511._.js.map +1 -0
- package/mcp-server/.next/server/middleware.js.nft.json +1 -1
- package/mcp-server/.next/server/server-reference-manifest.js +1 -1
- package/mcp-server/.next/server/server-reference-manifest.json +1 -1
- package/mcp-server/.next/static/chunks/000849a6a897f531.css +1 -0
- package/mcp-server/.next/static/chunks/048cee2510ddb1a0.js +1 -0
- package/mcp-server/.next/static/chunks/0622bd0e093adee7.js +3 -0
- package/mcp-server/.next/static/chunks/{46f60efee5f19794.js → 16359f64918a93f3.js} +1 -1
- package/mcp-server/.next/static/chunks/1851a3e70d7efc10.js +1 -0
- package/mcp-server/.next/static/chunks/{cc6addc4bb10fa11.js → 2ad16eeb719786f1.js} +1 -1
- package/mcp-server/.next/static/chunks/57feca7a4e06545e.js +7 -0
- package/mcp-server/.next/static/chunks/93db5737a327ab0c.js +6 -0
- package/mcp-server/.next/static/chunks/9fd3c715ecfb4d05.js +1 -0
- package/mcp-server/.next/static/chunks/b4b1ec6435790587.js +1 -0
- package/mcp-server/.next/static/chunks/cfe150cb2048b7e8.js +1 -0
- package/mcp-server/app/api/cloud/fix-workflow/steps.ts +267 -28
- package/mcp-server/app/api/cloud/fix-workflow/workflow.ts +16 -8
- package/mcp-server/app/api/cloud/start-fix/route.ts +2 -2
- package/mcp-server/app/api/workflows/route.ts +45 -1
- package/mcp-server/app/workflows/workflows-client.tsx +259 -100
- package/mcp-server/package.json +1 -1
- package/package.json +3 -3
- package/src/tui-interface-impl.tsx +175 -127
- package/mcp-server/.next/server/chunks/[root-of-the-server]__41aa7b20._.js.map +0 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__446f0436._.js.map +0 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__c508da18._.js +0 -3
- package/mcp-server/.next/server/chunks/[root-of-the-server]__c508da18._.js.map +0 -1
- package/mcp-server/.next/server/chunks/[root-of-the-server]__d6a224bc._.js.map +0 -1
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__0ff05d72._.js +0 -3
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__0ff05d72._.js.map +0 -1
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__27cc5956._.js +0 -3
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__27cc5956._.js.map +0 -1
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__570677dc._.js.map +0 -1
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__ef510343._.js +0 -3
- package/mcp-server/.next/server/chunks/ssr/[root-of-the-server]__ef510343._.js.map +0 -1
- package/mcp-server/.next/server/chunks/ssr/node_modules__pnpm_07527699._.js.map +0 -1
- package/mcp-server/.next/server/chunks/ssr/node_modules__pnpm_7cc36047._.js +0 -3
- package/mcp-server/.next/server/chunks/ssr/node_modules__pnpm_7cc36047._.js.map +0 -1
- package/mcp-server/.next/static/chunks/07848f6bd2a7e5f6.js +0 -3
- package/mcp-server/.next/static/chunks/637a66565f27572f.js +0 -6
- package/mcp-server/.next/static/chunks/aed4fb5252a4bc95.js +0 -3
- package/mcp-server/.next/static/chunks/e8d521464b0c96ca.css +0 -1
- package/mcp-server/.next/static/chunks/ff53279afa939907.js +0 -1
- package/mcp-server/.next/static/chunks/ffa2ecb6845be49c.js +0 -1
- /package/mcp-server/.next/static/{UcmWUkU-l9iLeWRnSUybj → 5zfTZk2QSS7WLdL1K8Q5I}/_buildManifest.js +0 -0
- /package/mcp-server/.next/static/{UcmWUkU-l9iLeWRnSUybj → 5zfTZk2QSS7WLdL1K8Q5I}/_clientMiddlewareManifest.json +0 -0
- /package/mcp-server/.next/static/{UcmWUkU-l9iLeWRnSUybj → 5zfTZk2QSS7WLdL1K8Q5I}/_ssgManifest.js +0 -0
|
@@ -2,7 +2,7 @@ import chalk from "chalk"
|
|
|
2
2
|
import { createReadStream, unwatchFile, watchFile } from "fs"
|
|
3
3
|
import { Box, render, Text, useInput, useStdout } from "ink"
|
|
4
4
|
import Spinner from "ink-spinner"
|
|
5
|
-
import { useEffect, useRef, useState } from "react"
|
|
5
|
+
import { memo, useEffect, useRef, useState } from "react"
|
|
6
6
|
import type { Readable } from "stream"
|
|
7
7
|
import { LOG_COLORS } from "./constants/log-colors.js"
|
|
8
8
|
|
|
@@ -29,6 +29,117 @@ const COMPACT_LOGO = "d3k"
|
|
|
29
29
|
// Full ASCII logo lines as array for easier rendering
|
|
30
30
|
const FULL_LOGO = [" ▐▌▄▄▄▄ █ ▄ ", " ▐▌ █ █▄▀ ", "▗▞▀▜▌▀▀▀█ █ ▀▄ ", "▝▚▄▟▌▄▄▄█ █ █ "]
|
|
31
31
|
|
|
32
|
+
// Type colors map - defined outside component to avoid recreation
|
|
33
|
+
const TYPE_COLORS: Record<string, string> = {
|
|
34
|
+
NETWORK: LOG_COLORS.NETWORK,
|
|
35
|
+
ERROR: LOG_COLORS.ERROR,
|
|
36
|
+
WARNING: LOG_COLORS.WARNING,
|
|
37
|
+
INFO: LOG_COLORS.INFO,
|
|
38
|
+
LOG: LOG_COLORS.LOG,
|
|
39
|
+
DEBUG: LOG_COLORS.DEBUG,
|
|
40
|
+
SCREENSHOT: LOG_COLORS.SCREENSHOT,
|
|
41
|
+
DOM: LOG_COLORS.DOM,
|
|
42
|
+
CDP: LOG_COLORS.CDP,
|
|
43
|
+
CHROME: LOG_COLORS.CHROME,
|
|
44
|
+
CRASH: LOG_COLORS.CRASH,
|
|
45
|
+
REPLAY: LOG_COLORS.REPLAY,
|
|
46
|
+
NAVIGATION: LOG_COLORS.NAVIGATION,
|
|
47
|
+
INTERACTION: LOG_COLORS.INTERACTION,
|
|
48
|
+
GET: LOG_COLORS.SERVER,
|
|
49
|
+
POST: LOG_COLORS.SERVER,
|
|
50
|
+
PUT: LOG_COLORS.SERVER,
|
|
51
|
+
DELETE: LOG_COLORS.SERVER,
|
|
52
|
+
PATCH: LOG_COLORS.SERVER,
|
|
53
|
+
HEAD: LOG_COLORS.SERVER,
|
|
54
|
+
OPTIONS: LOG_COLORS.SERVER
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Memoized log line component to prevent re-parsing on every render
|
|
58
|
+
const LogLine = memo(
|
|
59
|
+
({ log, isCompact, isVeryCompact }: { log: LogEntry; isCompact: boolean; isVeryCompact: boolean }) => {
|
|
60
|
+
// Parse log line to colorize different parts
|
|
61
|
+
const parts = log.content.match(/^\[(.*?)\] \[(.*?)\] (?:\[(.*?)\] )?(.*)$/)
|
|
62
|
+
|
|
63
|
+
if (parts) {
|
|
64
|
+
let [, timestamp, source, type, message] = parts
|
|
65
|
+
|
|
66
|
+
// Extract HTTP method from SERVER logs as a secondary tag
|
|
67
|
+
if (source === "SERVER" && !type && message) {
|
|
68
|
+
const methodMatch = message.match(/^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s/)
|
|
69
|
+
if (methodMatch) {
|
|
70
|
+
type = methodMatch[1]
|
|
71
|
+
message = message.slice(type.length + 1) // Remove method from message
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Replace warning emoji in ERROR/WARNING messages for consistent terminal rendering
|
|
76
|
+
if (message && (type === "ERROR" || type === "WARNING")) {
|
|
77
|
+
message = message.replace(/⚠/g, "[!]")
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// In very compact mode, simplify the output
|
|
81
|
+
if (isVeryCompact) {
|
|
82
|
+
const shortSource = source === "BROWSER" ? "B" : "S"
|
|
83
|
+
const shortType = type ? type.split(".")[0].charAt(0) : ""
|
|
84
|
+
return (
|
|
85
|
+
<Text wrap="truncate-end">
|
|
86
|
+
<Text dimColor>[{shortSource}]</Text>
|
|
87
|
+
{shortType && <Text dimColor>[{shortType}]</Text>}
|
|
88
|
+
<Text> {message}</Text>
|
|
89
|
+
</Text>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Use shared color constants
|
|
94
|
+
const sourceColor = source === "BROWSER" ? LOG_COLORS.BROWSER : LOG_COLORS.SERVER
|
|
95
|
+
|
|
96
|
+
// In compact mode, skip padding
|
|
97
|
+
if (isCompact) {
|
|
98
|
+
return (
|
|
99
|
+
<Text wrap="truncate-end">
|
|
100
|
+
<Text dimColor>[{timestamp}]</Text>
|
|
101
|
+
<Text> </Text>
|
|
102
|
+
<Text color={sourceColor} bold>
|
|
103
|
+
[{source.charAt(0)}]
|
|
104
|
+
</Text>
|
|
105
|
+
{type && (
|
|
106
|
+
<>
|
|
107
|
+
<Text> </Text>
|
|
108
|
+
<Text color={TYPE_COLORS[type] || "#A0A0A0"}>[{type}]</Text>
|
|
109
|
+
</>
|
|
110
|
+
)}
|
|
111
|
+
<Text> {message}</Text>
|
|
112
|
+
</Text>
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Normal mode with minimal padding
|
|
117
|
+
return (
|
|
118
|
+
<Text wrap="truncate-end">
|
|
119
|
+
<Text dimColor>[{timestamp}]</Text>
|
|
120
|
+
<Text> </Text>
|
|
121
|
+
<Text color={sourceColor} bold>
|
|
122
|
+
[{source}]
|
|
123
|
+
</Text>
|
|
124
|
+
{type ? (
|
|
125
|
+
<>
|
|
126
|
+
<Text> </Text>
|
|
127
|
+
<Text color={TYPE_COLORS[type] || "#A0A0A0"}>[{type}]</Text>
|
|
128
|
+
<Text> </Text>
|
|
129
|
+
</>
|
|
130
|
+
) : (
|
|
131
|
+
<Text> </Text>
|
|
132
|
+
)}
|
|
133
|
+
<Text>{message}</Text>
|
|
134
|
+
</Text>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Fallback for unparsed lines
|
|
139
|
+
return <Text wrap="truncate-end">{log.content}</Text>
|
|
140
|
+
}
|
|
141
|
+
)
|
|
142
|
+
|
|
32
143
|
const TUIApp = ({
|
|
33
144
|
appPort: initialAppPort,
|
|
34
145
|
mcpPort,
|
|
@@ -155,19 +266,19 @@ const TUIApp = ({
|
|
|
155
266
|
useEffect(() => {
|
|
156
267
|
let logStream: Readable | undefined
|
|
157
268
|
let buffer = ""
|
|
269
|
+
let pendingLogs: LogEntry[] = []
|
|
270
|
+
let flushTimeout: NodeJS.Timeout | null = null
|
|
158
271
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
272
|
+
// Batch log updates to prevent excessive renders
|
|
273
|
+
const flushPendingLogs = () => {
|
|
274
|
+
if (pendingLogs.length === 0) return
|
|
163
275
|
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
276
|
+
const logsToAdd = pendingLogs
|
|
277
|
+
pendingLogs = []
|
|
278
|
+
flushTimeout = null
|
|
168
279
|
|
|
169
280
|
setLogs((prevLogs) => {
|
|
170
|
-
const updated = [...prevLogs,
|
|
281
|
+
const updated = [...prevLogs, ...logsToAdd]
|
|
171
282
|
// Keep only last N logs to prevent memory issues
|
|
172
283
|
if (updated.length > maxLogs) {
|
|
173
284
|
return updated.slice(-maxLogs)
|
|
@@ -176,12 +287,32 @@ const TUIApp = ({
|
|
|
176
287
|
})
|
|
177
288
|
|
|
178
289
|
// Auto-scroll to bottom only if user is already at the bottom
|
|
179
|
-
// Otherwise, increment scroll offset by
|
|
290
|
+
// Otherwise, increment scroll offset by count of new logs
|
|
180
291
|
setScrollOffset((currentOffset) => {
|
|
181
|
-
return currentOffset === 0 ? 0 : Math.min(maxScrollOffsetRef.current, currentOffset +
|
|
292
|
+
return currentOffset === 0 ? 0 : Math.min(maxScrollOffsetRef.current, currentOffset + logsToAdd.length)
|
|
182
293
|
})
|
|
183
294
|
}
|
|
184
295
|
|
|
296
|
+
const appendLog = (line: string) => {
|
|
297
|
+
if (NEXTJS_MCP_404_REGEX.test(line)) {
|
|
298
|
+
return
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const newLog: LogEntry = {
|
|
302
|
+
id: logIdCounter.current++,
|
|
303
|
+
content: line
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
pendingLogs.push(newLog)
|
|
307
|
+
|
|
308
|
+
// Debounce: flush after 50ms of no new logs
|
|
309
|
+
// Terminal synchronized updates prevent flicker, so we can be more responsive
|
|
310
|
+
if (flushTimeout) {
|
|
311
|
+
clearTimeout(flushTimeout)
|
|
312
|
+
}
|
|
313
|
+
flushTimeout = setTimeout(flushPendingLogs, 50)
|
|
314
|
+
}
|
|
315
|
+
|
|
185
316
|
// Create a read stream for the log file
|
|
186
317
|
logStream = createReadStream(logFile, {
|
|
187
318
|
encoding: "utf8",
|
|
@@ -236,6 +367,9 @@ const TUIApp = ({
|
|
|
236
367
|
if (logStream) {
|
|
237
368
|
logStream.destroy()
|
|
238
369
|
}
|
|
370
|
+
if (flushTimeout) {
|
|
371
|
+
clearTimeout(flushTimeout)
|
|
372
|
+
}
|
|
239
373
|
unwatchFile(logFile)
|
|
240
374
|
}
|
|
241
375
|
}, [logFile])
|
|
@@ -376,121 +510,9 @@ const TUIApp = ({
|
|
|
376
510
|
{visibleLogs.length === 0 ? (
|
|
377
511
|
<Text dimColor>Waiting for logs...</Text>
|
|
378
512
|
) : (
|
|
379
|
-
visibleLogs.map((log) =>
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
if (parts) {
|
|
384
|
-
let [, timestamp, source, type, message] = parts
|
|
385
|
-
|
|
386
|
-
// Extract HTTP method from SERVER logs as a secondary tag
|
|
387
|
-
if (source === "SERVER" && !type && message) {
|
|
388
|
-
const methodMatch = message.match(/^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s/)
|
|
389
|
-
if (methodMatch) {
|
|
390
|
-
type = methodMatch[1]
|
|
391
|
-
message = message.slice(type.length + 1) // Remove method from message
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// Replace warning emoji in ERROR/WARNING messages for consistent terminal rendering
|
|
396
|
-
if (message && (type === "ERROR" || type === "WARNING")) {
|
|
397
|
-
message = message.replace(/⚠/g, "[!]")
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
// In very compact mode, simplify the output
|
|
401
|
-
if (isVeryCompact) {
|
|
402
|
-
const shortSource = source === "BROWSER" ? "B" : "S"
|
|
403
|
-
const shortType = type ? type.split(".")[0].charAt(0) : ""
|
|
404
|
-
return (
|
|
405
|
-
<Text key={log.id} wrap="truncate-end">
|
|
406
|
-
<Text dimColor>[{shortSource}]</Text>
|
|
407
|
-
{shortType && <Text dimColor>[{shortType}]</Text>}
|
|
408
|
-
<Text> {message}</Text>
|
|
409
|
-
</Text>
|
|
410
|
-
)
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
// Use shared color constants
|
|
414
|
-
const sourceColor = source === "BROWSER" ? LOG_COLORS.BROWSER : LOG_COLORS.SERVER
|
|
415
|
-
const typeColors: Record<string, string> = {
|
|
416
|
-
NETWORK: LOG_COLORS.NETWORK,
|
|
417
|
-
ERROR: LOG_COLORS.ERROR,
|
|
418
|
-
WARNING: LOG_COLORS.WARNING,
|
|
419
|
-
INFO: LOG_COLORS.INFO,
|
|
420
|
-
LOG: LOG_COLORS.LOG,
|
|
421
|
-
DEBUG: LOG_COLORS.DEBUG,
|
|
422
|
-
SCREENSHOT: LOG_COLORS.SCREENSHOT,
|
|
423
|
-
DOM: LOG_COLORS.DOM,
|
|
424
|
-
CDP: LOG_COLORS.CDP,
|
|
425
|
-
CHROME: LOG_COLORS.CHROME,
|
|
426
|
-
CRASH: LOG_COLORS.CRASH,
|
|
427
|
-
REPLAY: LOG_COLORS.REPLAY,
|
|
428
|
-
NAVIGATION: LOG_COLORS.NAVIGATION,
|
|
429
|
-
INTERACTION: LOG_COLORS.INTERACTION,
|
|
430
|
-
GET: LOG_COLORS.SERVER,
|
|
431
|
-
POST: LOG_COLORS.SERVER,
|
|
432
|
-
PUT: LOG_COLORS.SERVER,
|
|
433
|
-
DELETE: LOG_COLORS.SERVER,
|
|
434
|
-
PATCH: LOG_COLORS.SERVER,
|
|
435
|
-
HEAD: LOG_COLORS.SERVER,
|
|
436
|
-
OPTIONS: LOG_COLORS.SERVER
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// In compact mode, skip padding
|
|
440
|
-
if (isCompact) {
|
|
441
|
-
return (
|
|
442
|
-
<Text key={log.id} wrap="truncate-end">
|
|
443
|
-
<Text dimColor>[{timestamp}]</Text>
|
|
444
|
-
<Text> </Text>
|
|
445
|
-
<Text color={sourceColor} bold>
|
|
446
|
-
[{source.charAt(0)}]
|
|
447
|
-
</Text>
|
|
448
|
-
{type && (
|
|
449
|
-
<>
|
|
450
|
-
<Text> </Text>
|
|
451
|
-
<Text color={typeColors[type] || "#A0A0A0"}>[{type}]</Text>
|
|
452
|
-
</>
|
|
453
|
-
)}
|
|
454
|
-
<Text> {message}</Text>
|
|
455
|
-
</Text>
|
|
456
|
-
)
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// Normal mode with minimal padding
|
|
460
|
-
// Single space after source
|
|
461
|
-
const sourceSpacing = ""
|
|
462
|
-
|
|
463
|
-
// Single space after type
|
|
464
|
-
const typeSpacing = ""
|
|
465
|
-
|
|
466
|
-
return (
|
|
467
|
-
<Text key={log.id} wrap="truncate-end">
|
|
468
|
-
<Text dimColor>[{timestamp}]</Text>
|
|
469
|
-
<Text> </Text>
|
|
470
|
-
<Text color={sourceColor} bold>
|
|
471
|
-
[{source}]
|
|
472
|
-
</Text>
|
|
473
|
-
{type ? (
|
|
474
|
-
<>
|
|
475
|
-
<Text>{sourceSpacing} </Text>
|
|
476
|
-
<Text color={typeColors[type] || "#A0A0A0"}>[{type}]</Text>
|
|
477
|
-
<Text>{typeSpacing} </Text>
|
|
478
|
-
</>
|
|
479
|
-
) : (
|
|
480
|
-
<Text> </Text>
|
|
481
|
-
)}
|
|
482
|
-
<Text>{message}</Text>
|
|
483
|
-
</Text>
|
|
484
|
-
)
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// Fallback for unparsed lines
|
|
488
|
-
return (
|
|
489
|
-
<Text key={log.id} wrap="truncate-end">
|
|
490
|
-
{log.content}
|
|
491
|
-
</Text>
|
|
492
|
-
)
|
|
493
|
-
})
|
|
513
|
+
visibleLogs.map((log) => (
|
|
514
|
+
<LogLine key={log.id} log={log} isCompact={isCompact} isVeryCompact={isVeryCompact} />
|
|
515
|
+
))
|
|
494
516
|
)}
|
|
495
517
|
</Box>
|
|
496
518
|
|
|
@@ -524,6 +546,32 @@ export async function runTUI(options: TUIOptions): Promise<{
|
|
|
524
546
|
let statusUpdater: ((status: string | null) => void) | null = null
|
|
525
547
|
let appPortUpdater: ((port: string) => void) | null = null
|
|
526
548
|
|
|
549
|
+
// Wrap stdout.write to add synchronized update escape sequences
|
|
550
|
+
// This tells the terminal to buffer all output until the end marker
|
|
551
|
+
// Supported by iTerm2, Kitty, WezTerm, and other modern terminals
|
|
552
|
+
const originalWrite = process.stdout.write.bind(process.stdout)
|
|
553
|
+
const syncStart = "\x1b[?2026h" // Begin synchronized update (DECSM 2026)
|
|
554
|
+
const syncEnd = "\x1b[?2026l" // End synchronized update (DECRM 2026)
|
|
555
|
+
|
|
556
|
+
process.stdout.write = ((
|
|
557
|
+
chunk: string | Uint8Array,
|
|
558
|
+
encodingOrCb?: BufferEncoding | ((err?: Error | null) => void),
|
|
559
|
+
cb?: (err?: Error | null) => void
|
|
560
|
+
): boolean => {
|
|
561
|
+
if (typeof chunk === "string" && chunk.length > 0) {
|
|
562
|
+
// Wrap output in synchronized update markers to prevent partial renders
|
|
563
|
+
const wrapped = syncStart + chunk + syncEnd
|
|
564
|
+
if (typeof encodingOrCb === "function") {
|
|
565
|
+
return originalWrite(wrapped, encodingOrCb)
|
|
566
|
+
}
|
|
567
|
+
return originalWrite(wrapped, encodingOrCb, cb)
|
|
568
|
+
}
|
|
569
|
+
if (typeof encodingOrCb === "function") {
|
|
570
|
+
return originalWrite(chunk, encodingOrCb)
|
|
571
|
+
}
|
|
572
|
+
return originalWrite(chunk, encodingOrCb, cb)
|
|
573
|
+
}) as typeof process.stdout.write
|
|
574
|
+
|
|
527
575
|
const app = render(
|
|
528
576
|
<TUIApp
|
|
529
577
|
{...options}
|