@web-auto/webauto 0.1.1 → 0.1.3
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/apps/desktop-console/default-settings.json +1 -0
- package/apps/desktop-console/dist/main/index.mjs +1618 -0
- package/apps/desktop-console/{src → dist}/main/preload.mjs +10 -0
- package/apps/desktop-console/dist/renderer/index.js +3063 -0
- package/apps/desktop-console/entry/ui-console.mjs +299 -0
- package/apps/webauto/entry/account.mjs +356 -0
- package/apps/webauto/entry/lib/account-detect.mjs +160 -0
- package/apps/webauto/entry/lib/account-store.mjs +587 -0
- package/apps/webauto/entry/lib/profilepool.mjs +1 -1
- package/apps/webauto/entry/xhs-install.mjs +27 -3
- package/apps/webauto/entry/xhs-status.mjs +152 -0
- package/apps/webauto/entry/xhs-unified.mjs +595 -17
- package/bin/webauto.mjs +263 -15
- package/dist/apps/webauto/server.js +66 -0
- package/dist/modules/camo-backend/src/index.js +575 -0
- package/dist/modules/camo-backend/src/internal/BrowserSession.js +817 -0
- package/dist/modules/camo-backend/src/internal/ElementRegistry.js +61 -0
- package/dist/modules/camo-backend/src/internal/ProfileLock.js +85 -0
- package/dist/modules/camo-backend/src/internal/SessionManager.js +172 -0
- package/dist/modules/camo-backend/src/internal/container-matcher.js +852 -0
- package/dist/modules/camo-backend/src/internal/engine-manager.js +258 -0
- package/dist/modules/camo-backend/src/internal/fingerprint.js +203 -0
- package/dist/modules/camo-backend/src/internal/pageRuntime.js +29 -0
- package/dist/modules/camo-backend/src/internal/runtimeInjector.js +30 -0
- package/dist/modules/camo-backend/src/internal/state-bus.js +46 -0
- package/dist/modules/camo-backend/src/internal/storage-paths.js +36 -0
- package/dist/modules/camo-backend/src/internal/ws-server.js +1202 -0
- package/dist/modules/camo-runtime/src/utils/browser-service.mjs +423 -0
- package/dist/modules/camo-runtime/src/utils/config.mjs +77 -0
- package/dist/modules/container-registry/src/index.js +184 -0
- package/dist/modules/logging/src/index.js +92 -0
- package/dist/modules/operations/src/builtin.js +27 -0
- package/dist/modules/operations/src/container-binding.js +75 -0
- package/dist/modules/operations/src/executor.js +146 -0
- package/dist/modules/operations/src/operations/click.js +167 -0
- package/dist/modules/operations/src/operations/extract.js +204 -0
- package/dist/modules/operations/src/operations/find-child.js +17 -0
- package/dist/modules/operations/src/operations/highlight.js +138 -0
- package/dist/modules/operations/src/operations/key.js +61 -0
- package/dist/modules/operations/src/operations/navigate.js +148 -0
- package/dist/modules/operations/src/operations/scroll.js +126 -0
- package/dist/modules/operations/src/operations/type.js +190 -0
- package/dist/modules/operations/src/queue.js +100 -0
- package/dist/modules/operations/src/registry.js +11 -0
- package/dist/modules/operations/src/system/mouse.js +33 -0
- package/dist/modules/state/src/atomic-json.js +33 -0
- package/dist/modules/workflow/blocks/AnchorVerificationBlock.js +71 -0
- package/dist/modules/workflow/blocks/BehaviorRandomizer.js +26 -0
- package/dist/modules/workflow/blocks/CallWorkflowBlock.js +38 -0
- package/dist/modules/workflow/blocks/CloseDetailBlock.js +209 -0
- package/dist/modules/workflow/blocks/CollectBatch.js +137 -0
- package/dist/modules/workflow/blocks/CollectCommentsBlock.js +415 -0
- package/dist/modules/workflow/blocks/CollectSearchListBlock.js +599 -0
- package/dist/modules/workflow/blocks/CollectWeiboPosts.js +229 -0
- package/dist/modules/workflow/blocks/DetectPageStateBlock.js +259 -0
- package/dist/modules/workflow/blocks/EnsureLoginBlock.js +162 -0
- package/dist/modules/workflow/blocks/EnsureSession.js +426 -0
- package/dist/modules/workflow/blocks/ErrorClassifier.js +164 -0
- package/dist/modules/workflow/blocks/ErrorRecoveryBlock.js +319 -0
- package/dist/modules/workflow/blocks/ExpandCommentsBlock.js +1032 -0
- package/dist/modules/workflow/blocks/ExtractDetailBlock.js +310 -0
- package/dist/modules/workflow/blocks/ExtractPostFields.js +88 -0
- package/dist/modules/workflow/blocks/GenerateSmartReplyBlock.js +68 -0
- package/dist/modules/workflow/blocks/GoToSearchBlock.js +497 -0
- package/dist/modules/workflow/blocks/GracefulFallbackBlock.js +104 -0
- package/dist/modules/workflow/blocks/HighlightBlock.js +66 -0
- package/dist/modules/workflow/blocks/InitAutoScroll.js +65 -0
- package/dist/modules/workflow/blocks/LoadContainerDefinition.js +50 -0
- package/dist/modules/workflow/blocks/LoadContainerIndex.js +43 -0
- package/dist/modules/workflow/blocks/LocateAndGuardBlock.js +176 -0
- package/dist/modules/workflow/blocks/LoginRecoveryBlock.js +242 -0
- package/dist/modules/workflow/blocks/MatchContainers.js +64 -0
- package/dist/modules/workflow/blocks/MonitoringBlock.js +190 -0
- package/dist/modules/workflow/blocks/OpenDetailBlock.js +1240 -0
- package/dist/modules/workflow/blocks/OrganizeXhsNotesBlock.js +117 -0
- package/dist/modules/workflow/blocks/PersistXhsNoteBlock.js +270 -0
- package/dist/modules/workflow/blocks/PickSinglePost.js +69 -0
- package/dist/modules/workflow/blocks/ProgressTracker.js +125 -0
- package/dist/modules/workflow/blocks/RecordFixtureBlock.js +44 -0
- package/dist/modules/workflow/blocks/RenderMarkdown.js +48 -0
- package/dist/modules/workflow/blocks/SaveFile.js +54 -0
- package/dist/modules/workflow/blocks/ScrollNextBatch.js +72 -0
- package/dist/modules/workflow/blocks/SessionHealthBlock.js +73 -0
- package/dist/modules/workflow/blocks/StartBrowserService.js +45 -0
- package/dist/modules/workflow/blocks/ValidateContainerDefinition.js +67 -0
- package/dist/modules/workflow/blocks/ValidateExtract.js +35 -0
- package/dist/modules/workflow/blocks/WaitSearchPermitBlock.js +162 -0
- package/dist/modules/workflow/blocks/WaitStable.js +74 -0
- package/dist/modules/workflow/blocks/WarmupCommentsBlock.js +120 -0
- package/dist/modules/workflow/blocks/WorkflowExecutor.js +156 -0
- package/dist/modules/workflow/blocks/XiaohongshuCollectFromLinksBlock.js +1004 -0
- package/dist/modules/workflow/blocks/XiaohongshuCollectLinksBlock.js +1049 -0
- package/dist/modules/workflow/blocks/XiaohongshuFullCollectBlock.js +782 -0
- package/dist/modules/workflow/blocks/helpers/anchorVerify.js +198 -0
- package/dist/modules/workflow/blocks/helpers/asyncWorkQueue.js +53 -0
- package/dist/modules/workflow/blocks/helpers/commentScroller.js +334 -0
- package/dist/modules/workflow/blocks/helpers/commentSectionLocator.js +126 -0
- package/dist/modules/workflow/blocks/helpers/containerAnchors.js +301 -0
- package/dist/modules/workflow/blocks/helpers/debugArtifacts.js +6 -0
- package/dist/modules/workflow/blocks/helpers/downloadPaths.js +29 -0
- package/dist/modules/workflow/blocks/helpers/expandCommentsController.js +53 -0
- package/dist/modules/workflow/blocks/helpers/expandCommentsExtractor.js +129 -0
- package/dist/modules/workflow/blocks/helpers/macosVisionOcrPlugin.js +116 -0
- package/dist/modules/workflow/blocks/helpers/mergeXhsMarkdown.js +109 -0
- package/dist/modules/workflow/blocks/helpers/openDetailController.js +56 -0
- package/dist/modules/workflow/blocks/helpers/openDetailTypes.js +7 -0
- package/dist/modules/workflow/blocks/helpers/openDetailViewport.js +474 -0
- package/dist/modules/workflow/blocks/helpers/openDetailWaiter.js +104 -0
- package/dist/modules/workflow/blocks/helpers/operationLogger.js +195 -0
- package/dist/modules/workflow/blocks/helpers/persistedNotes.js +107 -0
- package/dist/modules/workflow/blocks/helpers/replyExpander.js +260 -0
- package/dist/modules/workflow/blocks/helpers/scrollIntoView.js +138 -0
- package/dist/modules/workflow/blocks/helpers/searchExecutor.js +328 -0
- package/dist/modules/workflow/blocks/helpers/searchGate.js +46 -0
- package/dist/modules/workflow/blocks/helpers/searchPageState.js +164 -0
- package/dist/modules/workflow/blocks/helpers/searchResultWaiter.js +64 -0
- package/dist/modules/workflow/blocks/helpers/simpleAnchor.js +134 -0
- package/dist/modules/workflow/blocks/helpers/smartReply.js +40 -0
- package/dist/modules/workflow/blocks/helpers/systemInput.js +635 -0
- package/dist/modules/workflow/blocks/helpers/targetCountMode.js +9 -0
- package/dist/modules/workflow/blocks/helpers/xhsCliArgs.js +80 -0
- package/dist/modules/workflow/blocks/helpers/xhsCommentDom.js +805 -0
- package/dist/modules/workflow/blocks/helpers/xhsNoteOrganizer.js +140 -0
- package/dist/modules/workflow/blocks/restore/RestorePhaseBlock.js +204 -0
- package/dist/modules/workflow/config/workflowRegistry.js +32 -0
- package/dist/modules/workflow/definitions/batch-collect-workflow.js +63 -0
- package/dist/modules/workflow/definitions/scroll-extract-workflow.js +74 -0
- package/dist/modules/workflow/definitions/xiaohongshu-collect-workflow-v2.js +81 -0
- package/dist/modules/workflow/definitions/xiaohongshu-collect-workflow.js +57 -0
- package/dist/modules/workflow/definitions/xiaohongshu-full-collect-workflow-v3.js +68 -0
- package/dist/modules/workflow/definitions/xiaohongshu-note-collect.js +49 -0
- package/dist/modules/workflow/definitions/xiaohongshu-phase1-workflow-v3.js +30 -0
- package/dist/modules/workflow/definitions/xiaohongshu-phase2-links-workflow-v3.js +40 -0
- package/dist/modules/workflow/definitions/xiaohongshu-phase3-collect-workflow-v1.js +54 -0
- package/dist/modules/workflow/definitions/xiaohongshu-phase34-from-links-workflow-v3.js +25 -0
- package/dist/modules/workflow/src/WeiboEventDrivenWorkflowRunner.js +308 -0
- package/dist/modules/workflow/src/context.js +70 -0
- package/dist/modules/workflow/src/index.js +5 -0
- package/dist/modules/workflow/src/orchestrator.js +230 -0
- package/dist/modules/workflow/src/runner.js +55 -0
- package/dist/modules/workflow/src/runtime.js +70 -0
- package/dist/modules/workflow/workflows/WeiboFeedExtractionWorkflow.js +359 -0
- package/dist/modules/workflow/workflows/XiaohongshuLoginWorkflow.js +110 -0
- package/dist/modules/xiaohongshu/app/src/blocks/MatchCommentsBlock.js +139 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase1EnsureServicesBlock.js +36 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase1MonitorCookieBlock.js +213 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase1StartProfileBlock.js +121 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase2CollectLinksBlock.js +1249 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase2SearchBlock.js +703 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase34CloseDetailBlock.js +41 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase34CloseTabsBlock.js +44 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase34CollectCommentsBlock.js +150 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase34ExtractDetailBlock.js +117 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase34OpenDetailBlock.js +102 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase34OpenTabsBlock.js +109 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.js +117 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase34ProcessSingleNoteBlock.js +114 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase34ValidateLinksBlock.js +90 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase3InteractBlock.js +1009 -0
- package/dist/modules/xiaohongshu/app/src/blocks/Phase4MultiTabHarvestBlock.js +233 -0
- package/dist/modules/xiaohongshu/app/src/blocks/ReplyInteractBlock.js +291 -0
- package/dist/modules/xiaohongshu/app/src/blocks/XhsDiscoverFallbackBlock.js +240 -0
- package/dist/modules/xiaohongshu/app/src/blocks/helpers/commentMatchDsl.js +126 -0
- package/dist/modules/xiaohongshu/app/src/blocks/helpers/commentMatcher.js +99 -0
- package/dist/modules/xiaohongshu/app/src/blocks/helpers/evidence.js +27 -0
- package/dist/modules/xiaohongshu/app/src/blocks/helpers/sharding.js +42 -0
- package/dist/modules/xiaohongshu/app/src/blocks/helpers/xhsComments.js +270 -0
- package/dist/modules/xiaohongshu/app/src/index.js +9 -0
- package/dist/modules/xiaohongshu/app/src/utils/checkpoints.js +222 -0
- package/dist/modules/xiaohongshu/app/src/utils/controllerAction.js +43 -0
- package/dist/services/controller/src/controller.js +1476 -0
- package/dist/services/controller/src/index.js +2 -0
- package/dist/services/controller/src/payload-normalizer.js +129 -0
- package/dist/services/shared/heartbeat.js +120 -0
- package/dist/services/shared/lib/errorHandler.js +2 -0
- package/dist/services/shared/serviceProcessLogger.js +139 -0
- package/dist/services/unified-api/RemoteBrowserSession.js +176 -0
- package/dist/services/unified-api/RemoteSessionManager.js +148 -0
- package/dist/services/unified-api/container-operations-handler.js +115 -0
- package/dist/services/unified-api/server.js +652 -0
- package/dist/services/unified-api/state-registry.js +274 -0
- package/dist/services/unified-api/task-persistence.js +66 -0
- package/dist/services/unified-api/task-state.js +130 -0
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/search.mjs +12 -5
- package/modules/xiaohongshu/app/pnpm-lock.yaml +24 -0
- package/package.json +38 -10
- package/.beads/README.md +0 -81
- package/.beads/config.yaml +0 -67
- package/.beads/interactions.jsonl +0 -0
- package/.beads/issues.jsonl +0 -180
- package/.beads/metadata.json +0 -4
- package/.claude/settings.local.json +0 -10
- package/.github/workflows/ci.yml +0 -55
- package/AGENTS.md +0 -253
- package/apps/desktop-console/README.md +0 -27
- package/apps/desktop-console/package-lock.json +0 -897
- package/apps/desktop-console/package.json +0 -20
- package/apps/desktop-console/scripts/build-and-install.mjs +0 -19
- package/apps/desktop-console/scripts/build.mjs +0 -45
- package/apps/desktop-console/scripts/test-preload.mjs +0 -13
- package/apps/desktop-console/src/main/config.mts +0 -26
- package/apps/desktop-console/src/main/core-daemon-manager.mts +0 -131
- package/apps/desktop-console/src/main/desktop-settings.mts +0 -267
- package/apps/desktop-console/src/main/heartbeat-watchdog.mts +0 -50
- package/apps/desktop-console/src/main/heartbeat-watchdog.test.mts +0 -68
- package/apps/desktop-console/src/main/index-streaming.test.mts +0 -20
- package/apps/desktop-console/src/main/index.mts +0 -980
- package/apps/desktop-console/src/main/profile-store.mts +0 -239
- package/apps/desktop-console/src/main/profile-store.test.mts +0 -54
- package/apps/desktop-console/src/main/state-bridge.mts +0 -114
- package/apps/desktop-console/src/main/task-state-types.ts +0 -32
- package/apps/desktop-console/src/renderer/hooks/use-task-state.mts +0 -120
- package/apps/desktop-console/src/renderer/index.mts +0 -133
- package/apps/desktop-console/src/renderer/index.test.mts +0 -34
- package/apps/desktop-console/src/renderer/path-helpers.mts +0 -46
- package/apps/desktop-console/src/renderer/path-helpers.test.mts +0 -14
- package/apps/desktop-console/src/renderer/tabs/debug.mts +0 -48
- package/apps/desktop-console/src/renderer/tabs/debug.test.mts +0 -22
- package/apps/desktop-console/src/renderer/tabs/logs.mts +0 -421
- package/apps/desktop-console/src/renderer/tabs/logs.test.mts +0 -27
- package/apps/desktop-console/src/renderer/tabs/preflight.mts +0 -486
- package/apps/desktop-console/src/renderer/tabs/preflight.test.mts +0 -33
- package/apps/desktop-console/src/renderer/tabs/profile-pool.mts +0 -213
- package/apps/desktop-console/src/renderer/tabs/results.mts +0 -171
- package/apps/desktop-console/src/renderer/tabs/run.test.mts +0 -63
- package/apps/desktop-console/src/renderer/tabs/runtime.mts +0 -151
- package/apps/desktop-console/src/renderer/tabs/settings.mts +0 -146
- package/apps/desktop-console/src/renderer/tabs/xiaohongshu/account-flow.mts +0 -486
- package/apps/desktop-console/src/renderer/tabs/xiaohongshu/guide-browser-check.mts +0 -56
- package/apps/desktop-console/src/renderer/tabs/xiaohongshu/helpers.mts +0 -262
- package/apps/desktop-console/src/renderer/tabs/xiaohongshu/layout-block.mts +0 -430
- package/apps/desktop-console/src/renderer/tabs/xiaohongshu/live-stats.mts +0 -847
- package/apps/desktop-console/src/renderer/tabs/xiaohongshu/run-flow.mts +0 -443
- package/apps/desktop-console/src/renderer/tabs/xiaohongshu-state.mts +0 -425
- package/apps/desktop-console/src/renderer/tabs/xiaohongshu.mts +0 -497
- package/apps/desktop-console/src/renderer/tabs/xiaohongshu.test.mts +0 -291
- package/apps/desktop-console/src/renderer/ui-components.mts +0 -31
- package/docs/README_camoufox_chinese.md +0 -141
- package/docs/USAGE_V3.md +0 -163
- package/docs/arch/OCR_MACOS_PLUGIN.md +0 -39
- package/docs/arch/PORTS.md +0 -40
- package/docs/arch/REGRESSION_CHECKLIST.md +0 -121
- package/docs/arch/SEARCH_GATE.md +0 -224
- package/docs/arch/VIEWPORT_SAFETY.md +0 -182
- package/docs/arch/XIAOHONGSHU_OFFLINE_MOCK_DESIGN.md +0 -267
- package/docs/xiaohongshu-container-driven-summary.md +0 -221
- package/docs/xiaohongshu-full-collect-runbook.md +0 -134
- package/docs/xiaohongshu-next-steps.md +0 -228
- package/docs/xiaohongshu-quickstart.md +0 -73
- package/docs/xiaohongshu-workflow-summary.md +0 -227
- package/modules/container-registry/tests/container-registry.test.ts +0 -16
- package/modules/logging/tests/logging.test.ts +0 -38
- package/modules/operations/tests/operations.test.ts +0 -22
- package/modules/operations/tests/viewport-filter.test.ts +0 -161
- package/modules/operations/tests/visible-only.test.ts +0 -250
- package/modules/session-manager/tests/session-manager.test.ts +0 -23
- package/modules/state/src/atomic-json.test.ts +0 -30
- package/modules/state/src/paths.test.ts +0 -59
- package/modules/state/src/xiaohongshu-collect-state.test.ts +0 -259
- package/modules/workflow/blocks/AnchorVerificationBlock.d.ts.map +0 -1
- package/modules/workflow/blocks/AnchorVerificationBlock.js.map +0 -1
- package/modules/workflow/blocks/DetectPageStateBlock.d.ts.map +0 -1
- package/modules/workflow/blocks/DetectPageStateBlock.js.map +0 -1
- package/modules/workflow/blocks/ErrorRecoveryBlock.d.ts.map +0 -1
- package/modules/workflow/blocks/ErrorRecoveryBlock.js.map +0 -1
- package/modules/workflow/blocks/WaitSearchPermitBlock.d.ts.map +0 -1
- package/modules/workflow/blocks/WaitSearchPermitBlock.js.map +0 -1
- package/modules/workflow/blocks/helpers/containerAnchors.d.ts.map +0 -1
- package/modules/workflow/blocks/helpers/containerAnchors.js.map +0 -1
- package/modules/workflow/blocks/helpers/downloadPaths.test.ts +0 -62
- package/modules/workflow/blocks/helpers/mergeXhsMarkdown.test.ts +0 -121
- package/modules/workflow/blocks/helpers/operationLogger.d.ts.map +0 -1
- package/modules/workflow/blocks/helpers/operationLogger.js.map +0 -1
- package/modules/workflow/blocks/helpers/persistedNotes.test.ts +0 -268
- package/modules/workflow/blocks/helpers/searchPageState.d.ts.map +0 -1
- package/modules/workflow/blocks/helpers/searchPageState.js.map +0 -1
- package/modules/workflow/blocks/helpers/targetCountMode.test.ts +0 -29
- package/modules/workflow/blocks/helpers/xhsCliArgs.test.ts +0 -75
- package/modules/workflow/tests/smartReply.test.ts +0 -32
- package/modules/xiaohongshu/app/src/blocks/Phase3Interact.matcher.test.ts +0 -33
- package/modules/xiaohongshu/app/src/utils/__tests__/checkpoints.test.ts +0 -141
- package/modules/xiaohongshu/app/tests/commentMatchDsl.test.ts +0 -50
- package/modules/xiaohongshu/app/tests/commentMatcher.test.ts +0 -46
- package/modules/xiaohongshu/app/tests/sharding.test.ts +0 -31
- package/package-scripts.json +0 -8
- package/runtime/infra/utils/README.md +0 -13
- package/runtime/infra/utils/scripts/README.md +0 -0
- package/runtime/infra/utils/scripts/development/eval-in-session.mjs +0 -40
- package/runtime/infra/utils/scripts/development/highlight-search-containers.mjs +0 -35
- package/runtime/infra/utils/scripts/service/kill-port.mjs +0 -24
- package/runtime/infra/utils/scripts/service/start-api.mjs +0 -39
- package/runtime/infra/utils/scripts/service/start-browser-service.mjs +0 -106
- package/runtime/infra/utils/scripts/service/stop-api.mjs +0 -18
- package/runtime/infra/utils/scripts/service/stop-browser-service.mjs +0 -104
- package/runtime/infra/utils/scripts/test-services.mjs +0 -94
- package/services/shared/heartbeat.test.ts +0 -102
- package/services/unified-api/__tests__/task-state.test.ts +0 -95
- package/sitecustomize.py +0 -19
- package/tests/README.md +0 -194
- package/tests/e2e/workflows/weibo-feed-extraction.test.ts +0 -171
- package/tests/fixtures/data/container-definitions.json +0 -67
- package/tests/fixtures/pages/simple-page.html +0 -69
- package/tests/integration/01-test-container-match.mjs +0 -188
- package/tests/integration/02-test-dom-branch.mjs +0 -161
- package/tests/integration/03-test-container-operation-system.mjs +0 -91
- package/tests/integration/05-test-container-lifecycle-events.mjs +0 -224
- package/tests/integration/05-test-container-lifecycle-with-events.mjs +0 -250
- package/tests/integration/06-test-container-dom-tree-drawing.mjs +0 -256
- package/tests/integration/07-test-weibo-container-lifecycle.mjs +0 -355
- package/tests/integration/08-test-weibo-feed-workflow.test.mjs +0 -164
- package/tests/integration/10-test-visual-analyzer.mjs +0 -312
- package/tests/integration/11-test-visual-loop.mjs +0 -284
- package/tests/integration/12-test-simple-visual-loop.mjs +0 -242
- package/tests/integration/13-test-visual-robust.mjs +0 -185
- package/tests/integration/14-test-visual-highlight-loop.mjs +0 -271
- package/tests/integration/inspect-page.mjs +0 -50
- package/tests/integration/run-all-tests.mjs +0 -95
- package/tests/patch_verification/CODEX_PATCH_TEST.md +0 -103
- package/tests/patch_verification/PHASE2_ANALYSIS.md +0 -179
- package/tests/patch_verification/PHASE2_OPTIMIZATION_REPORT.md +0 -55
- package/tests/patch_verification/PHASE2_TO_PHASE4_SUMMARY.md +0 -126
- package/tests/patch_verification/QUICK_TEST_SEQUENCE.md +0 -262
- package/tests/patch_verification/README.md +0 -143
- package/tests/patch_verification/RUN_TESTS.md +0 -60
- package/tests/patch_verification/TEST_EXECUTION.md +0 -99
- package/tests/patch_verification/TEST_PLAN.md +0 -328
- package/tests/patch_verification/TEST_RESULTS.md +0 -34
- package/tests/patch_verification/TOOL_TEST_PLAN.md +0 -48
- package/tests/patch_verification/run-tool-test.mjs +0 -121
- package/tests/patch_verification/temp_test_files/test01.txt +0 -1
- package/tests/patch_verification/temp_test_files/test02.txt +0 -3
- package/tests/patch_verification/temp_test_files/test02_gnu.txt +0 -3
- package/tests/patch_verification/temp_test_files/test03.txt +0 -1
- package/tests/patch_verification/temp_test_files/test03_multiline.txt +0 -5
- package/tests/patch_verification/temp_test_files/test04_function.ts +0 -5
- package/tests/patch_verification/temp_test_files/test05_import.ts +0 -4
- package/tests/patch_verification/temp_test_files/test06_special_chars.txt +0 -4
- package/tests/patch_verification/temp_test_files/test07_indentation.ts +0 -5
- package/tests/patch_verification/temp_test_files/test08_mismatch.txt +0 -1
- package/tests/patch_verification/temp_test_files/test_add_02.txt +0 -3
- package/tests/patch_verification/temp_test_files/test_simple.txt +0 -1
- package/tests/runner/TestReporter.mjs +0 -57
- package/tests/runner/TestRunner.mjs +0 -244
- package/tests/unit/commands/profile.test.mjs +0 -10
- package/tests/unit/container/change-notifier.test.mjs +0 -181
- package/tests/unit/lifecycle/session-registry.test.mjs +0 -135
- package/tests/unit/operations/registry.test.ts +0 -73
- package/tests/unit/utils/browser-service.test.mjs +0 -153
- package/tests/unit/utils/config.test.mjs +0 -166
- package/tests/unit/utils/fingerprint.test.mjs +0 -166
- package/tsconfig.json +0 -31
- package/tsconfig.services.json +0 -26
- /package/apps/desktop-console/{src → dist}/renderer/index.html +0 -0
- /package/apps/desktop-console/{src/renderer/tabs → dist/renderer}/run.mts +0 -0
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import test from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
|
|
4
|
-
import { matchCommentText } from '../src/blocks/helpers/commentMatcher.js';
|
|
5
|
-
|
|
6
|
-
test('matchCommentText supports any-of (default min=1)', () => {
|
|
7
|
-
const res = matchCommentText('这个评论里有 链接 和别的内容', { any: ['链接', '地址'] });
|
|
8
|
-
assert.equal(res.ok, true);
|
|
9
|
-
assert.deepEqual(res.anyHits, ['链接']);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
test('matchCommentText supports minAnyMatches (any two keywords)', () => {
|
|
13
|
-
const res = matchCommentText('a... c...', { any: ['a', 'b', 'c'], minAnyMatches: 2, caseSensitive: true });
|
|
14
|
-
assert.equal(res.ok, true);
|
|
15
|
-
assert.equal(res.anyCount, 2);
|
|
16
|
-
assert.deepEqual(res.anyHits, ['a', 'c']);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test('matchCommentText supports must + any together', () => {
|
|
20
|
-
const ok = matchCommentText('工作服 这家有链接', { must: ['工作服'], any: ['链接'] });
|
|
21
|
-
assert.equal(ok.ok, true);
|
|
22
|
-
|
|
23
|
-
const badMust = matchCommentText('这家有链接', { must: ['工作服'], any: ['链接'] });
|
|
24
|
-
assert.equal(badMust.ok, false);
|
|
25
|
-
assert.equal(badMust.rejectedBy, 'must');
|
|
26
|
-
|
|
27
|
-
const badAny = matchCommentText('工作服 这家不错', { must: ['工作服'], any: ['链接'] });
|
|
28
|
-
assert.equal(badAny.ok, false);
|
|
29
|
-
assert.equal(badAny.rejectedBy, 'any');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test('matchCommentText supports mustNot exclusion', () => {
|
|
33
|
-
const ok = matchCommentText('可以私信发链接', { any: ['链接'], mustNot: ['淘宝'] });
|
|
34
|
-
assert.equal(ok.ok, true);
|
|
35
|
-
|
|
36
|
-
const bad = matchCommentText('淘宝 链接在这', { any: ['链接'], mustNot: ['淘宝'] });
|
|
37
|
-
assert.equal(bad.ok, false);
|
|
38
|
-
assert.equal(bad.rejectedBy, 'mustNot');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test('matchCommentText defaults to case-insensitive', () => {
|
|
42
|
-
const res = matchCommentText('Hello LINK', { any: ['link'] });
|
|
43
|
-
assert.equal(res.ok, true);
|
|
44
|
-
assert.deepEqual(res.anyHits, ['link']);
|
|
45
|
-
});
|
|
46
|
-
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import test from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
|
|
4
|
-
import { fnv1a32, normalizeShard, shardFilterByNoteIdHash } from '../src/blocks/helpers/sharding.js';
|
|
5
|
-
|
|
6
|
-
test('normalizeShard returns null for invalid specs', () => {
|
|
7
|
-
assert.equal(normalizeShard(null), null);
|
|
8
|
-
assert.equal(normalizeShard({ count: 1, index: 0 }), null);
|
|
9
|
-
assert.equal(normalizeShard({ count: 2, index: 2 }), null);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
test('fnv1a32 is stable', () => {
|
|
13
|
-
assert.equal(fnv1a32('abc'), fnv1a32('abc'));
|
|
14
|
-
assert.notEqual(fnv1a32('abc'), fnv1a32('abcd'));
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test('shardFilterByNoteIdHash partitions without overlap', () => {
|
|
18
|
-
const items = Array.from({ length: 50 }).map((_, i) => ({ noteId: `id_${i}` }));
|
|
19
|
-
const shard0 = shardFilterByNoteIdHash(items, { index: 0, count: 2, by: 'noteId-hash' });
|
|
20
|
-
const shard1 = shardFilterByNoteIdHash(items, { index: 1, count: 2, by: 'noteId-hash' });
|
|
21
|
-
|
|
22
|
-
const set0 = new Set(shard0.map((x) => x.noteId));
|
|
23
|
-
const set1 = new Set(shard1.map((x) => x.noteId));
|
|
24
|
-
let overlap = 0;
|
|
25
|
-
for (const id of set0) {
|
|
26
|
-
if (set1.has(id)) overlap += 1;
|
|
27
|
-
}
|
|
28
|
-
assert.equal(overlap, 0);
|
|
29
|
-
assert.equal(set0.size + set1.size, items.length);
|
|
30
|
-
});
|
|
31
|
-
|
package/package-scripts.json
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"scripts": {
|
|
3
|
-
"test:page-analyzer": "node test-basic.js && node test-discovery-manager.js && node test-hierarchy-builder.js",
|
|
4
|
-
"dev:page-analyzer": "npm run build && npm run test:page-analyzer",
|
|
5
|
-
"clean:page-analyzer": "rm -rf dist/page-analyzer",
|
|
6
|
-
"docs:page-analyzer": "echo 'Documentation generated successfully!'
|
|
7
|
-
}
|
|
8
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# Runtime Utilities
|
|
2
|
-
|
|
3
|
-
运行时工具统一收敛到 `runtime/infra/utils/scripts/`。
|
|
4
|
-
|
|
5
|
-
当前保留目录:
|
|
6
|
-
- `scripts/development/`:开发期调试脚本(会话内执行、高亮等)
|
|
7
|
-
- `scripts/service/`:服务启停与端口清理脚本
|
|
8
|
-
- `scripts/` 根脚本:跨场景工具(例如 `test-services.mjs`)
|
|
9
|
-
|
|
10
|
-
已移除:
|
|
11
|
-
- `local-dev/`
|
|
12
|
-
- `scripts/local-dev/`
|
|
13
|
-
- 其它历史遗留脚本目录
|
|
File without changes
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Post a local JS file (or inline) to Workflow API /browser/eval for the given session
|
|
3
|
-
import { readFileSync, existsSync } from 'node:fs';
|
|
4
|
-
|
|
5
|
-
async function main() {
|
|
6
|
-
const args = process.argv.slice(2);
|
|
7
|
-
if (args.length < 2) {
|
|
8
|
-
console.log('Usage: node scripts/dev/eval-in-session.mjs <sessionId> <file.js|--code="JS..."> [--host=http://127.0.0.1:7701]');
|
|
9
|
-
process.exit(1);
|
|
10
|
-
}
|
|
11
|
-
const sessionId = args[0];
|
|
12
|
-
let codeArg = args[1];
|
|
13
|
-
let host = 'http://127.0.0.1:7701';
|
|
14
|
-
for (const a of args.slice(2)) {
|
|
15
|
-
if (a.startsWith('--host=')) host = a.slice('--host='.length);
|
|
16
|
-
}
|
|
17
|
-
let script = '';
|
|
18
|
-
if (codeArg.startsWith('--code=')) {
|
|
19
|
-
script = codeArg.slice('--code='.length);
|
|
20
|
-
} else {
|
|
21
|
-
if (!existsSync(codeArg)) {
|
|
22
|
-
console.error('File not found:', codeArg);
|
|
23
|
-
process.exit(2);
|
|
24
|
-
}
|
|
25
|
-
script = readFileSync(codeArg, 'utf8');
|
|
26
|
-
}
|
|
27
|
-
const res = await fetch(host + '/browser/eval', {
|
|
28
|
-
method: 'POST',
|
|
29
|
-
headers: { 'Content-Type': 'application/json' },
|
|
30
|
-
body: JSON.stringify({ sessionId, script })
|
|
31
|
-
}).then(r => r.json()).catch(e => ({ success: false, error: String(e) }));
|
|
32
|
-
if (!res || !res.success) {
|
|
33
|
-
console.error('Eval failed:', res?.error || 'unknown');
|
|
34
|
-
process.exit(1);
|
|
35
|
-
}
|
|
36
|
-
console.log('Eval OK:', JSON.stringify(res.value));
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
main().catch(e => { console.error(e); process.exit(1); });
|
|
40
|
-
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Highlight search containers for 3 seconds: root -> listContainer -> first item
|
|
3
|
-
const host = process.env.WORKFLOW_HOST || 'http://127.0.0.1:7701';
|
|
4
|
-
|
|
5
|
-
function arg(k, d){ const a = process.argv.find(x=>x.startsWith(`--${k}=`)); return a ? a.split('=')[1] : d; }
|
|
6
|
-
const sleep = (ms)=>new Promise(r=>setTimeout(r,ms));
|
|
7
|
-
|
|
8
|
-
async function j(u,opt){ const r = await fetch(host+u, { headers:{'Content-Type':'application/json'}, ...(opt||{}) }); return await r.json(); }
|
|
9
|
-
async function lastSession(){ const s = await j('/v1/sessions'); const arr=s.sessions||[]; return arr[arr.length-1]||null; }
|
|
10
|
-
|
|
11
|
-
async function highlight({ sessionId, selector, label }){
|
|
12
|
-
return await j('/v1/containers/highlight', { method:'POST', body: JSON.stringify({ sessionId, containerSelector: selector, label, durationMs: 3000 }) });
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async function validate({ sessionId, selector }){ return await j('/v1/containers/validate', { method:'POST', body: JSON.stringify({ sessionId, containerSelector: selector }) }); }
|
|
16
|
-
|
|
17
|
-
async function main(){
|
|
18
|
-
const sessionId = arg('sessionId', null) || await lastSession();
|
|
19
|
-
if (!sessionId) { console.error('No active session.'); process.exit(1); }
|
|
20
|
-
// container definitions (must match container registry)
|
|
21
|
-
const rootSel = '.search-ui2024, .search-i18nUi, body';
|
|
22
|
-
const listSel = '.space-common-offerlist, .offer-list, #offer-list';
|
|
23
|
-
const itemSel = '.offer-item, .sm-offer, [class*=offer]';
|
|
24
|
-
|
|
25
|
-
const out = { sessionId, checks: [] };
|
|
26
|
-
for (const [label, sel] of [['ROOT', rootSel], ['LIST', listSel], ['ITEM', itemSel]]){
|
|
27
|
-
const v = await validate({ sessionId, selector: sel });
|
|
28
|
-
out.checks.push({ label, selector: sel, found: !!v.found });
|
|
29
|
-
if (v.found) await highlight({ sessionId, selector: sel, label });
|
|
30
|
-
await sleep(400);
|
|
31
|
-
}
|
|
32
|
-
console.log(JSON.stringify({ ok:true, ...out }, null, 2));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
main().catch(e=>{ console.error(e); process.exit(1); });
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// 杀掉占用指定端口的进程(跨平台尽力)
|
|
3
|
-
import { execSync } from 'node:child_process';
|
|
4
|
-
|
|
5
|
-
const port = Number(process.argv[2] || 0);
|
|
6
|
-
if (!port) { console.error('Usage: node runtime/infra/utils/scripts/service/kill-port.mjs <port>'); process.exit(1); }
|
|
7
|
-
|
|
8
|
-
try {
|
|
9
|
-
if (process.platform === 'win32') {
|
|
10
|
-
const out = execSync(`netstat -ano | findstr :${port}`, { encoding: 'utf8' });
|
|
11
|
-
const pids = new Set();
|
|
12
|
-
out.split(/\r?\n/).forEach(line=>{ const m=line.trim().match(/\s(\d+)\s*$/); if (m) pids.add(Number(m[1])); });
|
|
13
|
-
for (const pid of pids) { try { execSync(`taskkill /F /PID ${pid}`); console.log(`killed pid ${pid}`); } catch {} }
|
|
14
|
-
if (pids.size===0) console.log('no process found');
|
|
15
|
-
} else {
|
|
16
|
-
const out = execSync(`lsof -ti :${port}`, { encoding: 'utf8' });
|
|
17
|
-
const pids = out.split(/\s+/).map(s=>Number(s.trim())).filter(Boolean);
|
|
18
|
-
for (const pid of pids) { try { process.kill(pid, 'SIGKILL'); console.log(`killed pid ${pid}`); } catch {} }
|
|
19
|
-
if (pids.length===0) console.log('no process found');
|
|
20
|
-
}
|
|
21
|
-
} catch (e) {
|
|
22
|
-
console.log('nothing to kill or command failed');
|
|
23
|
-
}
|
|
24
|
-
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from 'node:child_process';
|
|
3
|
-
import { writeFileSync } from 'node:fs';
|
|
4
|
-
import { setTimeout as wait } from 'node:timers/promises';
|
|
5
|
-
|
|
6
|
-
const API_PID_FILE = '/tmp/webauto-api.pid';
|
|
7
|
-
|
|
8
|
-
async function health(url='http://127.0.0.1:7701/health'){
|
|
9
|
-
try{
|
|
10
|
-
const res = await fetch(url);
|
|
11
|
-
if (!res.ok) return false;
|
|
12
|
-
const j = await res.json().catch(() => ({}));
|
|
13
|
-
return Boolean(j?.ok ?? true);
|
|
14
|
-
}catch{
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async function main(){
|
|
20
|
-
const { execSync } = await import('node:child_process');
|
|
21
|
-
// build
|
|
22
|
-
execSync('npm run -s build:services', { stdio: 'inherit' });
|
|
23
|
-
// start
|
|
24
|
-
const child = spawn('node', ['dist/apps/webauto/server.js'], {
|
|
25
|
-
detached: true,
|
|
26
|
-
stdio: 'ignore',
|
|
27
|
-
env: {
|
|
28
|
-
...process.env,
|
|
29
|
-
WEBAUTO_RUNTIME_MODE: 'unified',
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
child.unref();
|
|
33
|
-
writeFileSync(API_PID_FILE, String(child.pid));
|
|
34
|
-
// wait for health
|
|
35
|
-
for(let i=0;i<20;i++){ if (await health()) { console.log('API started. PID', child.pid); return; } await wait(500); }
|
|
36
|
-
console.error('API did not become healthy in time'); process.exit(1);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
main().catch(e=>{ console.error(e); process.exit(1); });
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { execSync, spawn } from 'node:child_process';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { setTimeout as wait } from 'node:timers/promises';
|
|
7
|
-
|
|
8
|
-
const RUN_DIR = path.join(os.homedir(), '.webauto', 'run');
|
|
9
|
-
const PID_FILE = path.join(RUN_DIR, 'browser-service.pid');
|
|
10
|
-
const DEFAULT_HOST = process.env.WEBAUTO_BROWSER_HOST || '127.0.0.1';
|
|
11
|
-
const DEFAULT_PORT = Number(process.env.WEBAUTO_BROWSER_PORT || 7704);
|
|
12
|
-
|
|
13
|
-
function isAlive(pid) {
|
|
14
|
-
try {
|
|
15
|
-
process.kill(pid, 0);
|
|
16
|
-
return true;
|
|
17
|
-
} catch {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async function health(host = DEFAULT_HOST, port = DEFAULT_PORT) {
|
|
23
|
-
try {
|
|
24
|
-
const res = await fetch(`http://${host}:${port}/health`);
|
|
25
|
-
if (!res.ok) return false;
|
|
26
|
-
const body = await res.json().catch(() => ({}));
|
|
27
|
-
return Boolean(body?.ok ?? true);
|
|
28
|
-
} catch {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function parseArgs() {
|
|
34
|
-
const args = process.argv.slice(2);
|
|
35
|
-
const hostIdx = args.findIndex((item) => item === '--host');
|
|
36
|
-
const portIdx = args.findIndex((item) => item === '--port');
|
|
37
|
-
const host = hostIdx >= 0 && args[hostIdx + 1] ? String(args[hostIdx + 1]) : DEFAULT_HOST;
|
|
38
|
-
const port = portIdx >= 0 && args[portIdx + 1] ? Number(args[portIdx + 1]) : DEFAULT_PORT;
|
|
39
|
-
return {
|
|
40
|
-
host,
|
|
41
|
-
port: Number.isFinite(port) && port > 0 ? port : DEFAULT_PORT,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function ensureBuild() {
|
|
46
|
-
const distEntry = path.resolve('dist/modules/camo-backend/src/index.js');
|
|
47
|
-
if (fs.existsSync(distEntry)) return distEntry;
|
|
48
|
-
console.log('[browser-service] backend entry missing, running npm run -s build:services');
|
|
49
|
-
execSync('npm run -s build:services', { stdio: 'inherit' });
|
|
50
|
-
if (!fs.existsSync(distEntry)) {
|
|
51
|
-
throw new Error(`backend entry missing after build: ${distEntry}`);
|
|
52
|
-
}
|
|
53
|
-
return distEntry;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async function main() {
|
|
57
|
-
const { host, port } = parseArgs();
|
|
58
|
-
fs.mkdirSync(RUN_DIR, { recursive: true });
|
|
59
|
-
|
|
60
|
-
if (await health(host, port)) {
|
|
61
|
-
console.log(`Browser service already healthy on http://${host}:${port}`);
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (fs.existsSync(PID_FILE)) {
|
|
66
|
-
try {
|
|
67
|
-
const oldPid = Number(fs.readFileSync(PID_FILE, 'utf8'));
|
|
68
|
-
if (oldPid && isAlive(oldPid)) {
|
|
69
|
-
console.log(`Browser service already running (pid=${oldPid}).`);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
} catch {
|
|
73
|
-
// stale pid file will be overwritten
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const entry = ensureBuild();
|
|
78
|
-
const child = spawn(process.execPath, [entry], {
|
|
79
|
-
detached: true,
|
|
80
|
-
stdio: 'ignore',
|
|
81
|
-
env: {
|
|
82
|
-
...process.env,
|
|
83
|
-
BROWSER_SERVICE_HOST: host,
|
|
84
|
-
BROWSER_SERVICE_PORT: String(port),
|
|
85
|
-
WEBAUTO_BROWSER_HOST: host,
|
|
86
|
-
WEBAUTO_BROWSER_PORT: String(port),
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
child.unref();
|
|
90
|
-
fs.writeFileSync(PID_FILE, String(child.pid));
|
|
91
|
-
|
|
92
|
-
for (let i = 0; i < 30; i += 1) {
|
|
93
|
-
if (await health(host, port)) {
|
|
94
|
-
console.log(`Browser service started (pid=${child.pid}) on http://${host}:${port}`);
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
await wait(300);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
throw new Error('browser service did not become healthy in time');
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
main().catch((err) => {
|
|
104
|
-
console.error(`[browser-service] start failed: ${err?.message || String(err)}`);
|
|
105
|
-
process.exit(1);
|
|
106
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { readFileSync, existsSync, unlinkSync } from 'node:fs';
|
|
3
|
-
|
|
4
|
-
function killPid(pid){
|
|
5
|
-
try{ process.kill(pid, 'SIGTERM'); }catch{}
|
|
6
|
-
setTimeout(()=>{ try{ process.kill(pid, 'SIGKILL'); }catch{} }, 1000);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
async function main(){
|
|
10
|
-
const pidFile = '/tmp/webauto-api.pid';
|
|
11
|
-
if (!existsSync(pidFile)) { console.log('No pid file.'); return; }
|
|
12
|
-
const pid = Number(readFileSync(pidFile,'utf8').trim());
|
|
13
|
-
if (pid>0) killPid(pid);
|
|
14
|
-
try{ unlinkSync(pidFile); }catch{}
|
|
15
|
-
console.log('API stopped.');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
main().catch(e=>{ console.error(e); process.exit(1); });
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { execSync } from 'node:child_process';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { setTimeout as wait } from 'node:timers/promises';
|
|
7
|
-
|
|
8
|
-
const RUN_DIR = path.join(os.homedir(), '.webauto', 'run');
|
|
9
|
-
const PID_FILE = path.join(RUN_DIR, 'browser-service.pid');
|
|
10
|
-
const DEFAULT_PORT = Number(process.env.WEBAUTO_BROWSER_PORT || 7704);
|
|
11
|
-
|
|
12
|
-
function isAlive(pid) {
|
|
13
|
-
try {
|
|
14
|
-
process.kill(pid, 0);
|
|
15
|
-
return true;
|
|
16
|
-
} catch {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function killByPort(port) {
|
|
22
|
-
try {
|
|
23
|
-
if (process.platform === 'win32') {
|
|
24
|
-
const out = execSync(`netstat -ano | findstr :${port}`, { encoding: 'utf8' });
|
|
25
|
-
const pids = new Set();
|
|
26
|
-
out.split(/\r?\n/).forEach((line) => {
|
|
27
|
-
const match = line.trim().match(/\s(\d+)\s*$/);
|
|
28
|
-
if (match) pids.add(Number(match[1]));
|
|
29
|
-
});
|
|
30
|
-
for (const pid of pids) {
|
|
31
|
-
try {
|
|
32
|
-
execSync(`taskkill /F /PID ${pid}`, { stdio: 'ignore' });
|
|
33
|
-
} catch {
|
|
34
|
-
// ignore
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return pids.size > 0;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const out = execSync(`lsof -ti :${port} || true`, { encoding: 'utf8' });
|
|
41
|
-
const pids = out.split(/\s+/).map((item) => Number(item.trim())).filter(Boolean);
|
|
42
|
-
for (const pid of pids) {
|
|
43
|
-
try {
|
|
44
|
-
process.kill(pid, 'SIGKILL');
|
|
45
|
-
} catch {
|
|
46
|
-
// ignore
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return pids.length > 0;
|
|
50
|
-
} catch {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async function main() {
|
|
56
|
-
if (!fs.existsSync(PID_FILE)) {
|
|
57
|
-
const killed = killByPort(DEFAULT_PORT);
|
|
58
|
-
console.log(killed ? `Killed processes on :${DEFAULT_PORT}` : 'No PID file found. Service may not be running.');
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const pid = Number(fs.readFileSync(PID_FILE, 'utf8'));
|
|
63
|
-
if (!pid) {
|
|
64
|
-
fs.rmSync(PID_FILE, { force: true });
|
|
65
|
-
killByPort(DEFAULT_PORT);
|
|
66
|
-
console.log('Invalid PID file. Performed port cleanup.');
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (!isAlive(pid)) {
|
|
71
|
-
fs.rmSync(PID_FILE, { force: true });
|
|
72
|
-
killByPort(DEFAULT_PORT);
|
|
73
|
-
console.log(`Process ${pid} is not running. Cleaned stale PID.`);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
process.kill(pid, 'SIGTERM');
|
|
79
|
-
} catch {
|
|
80
|
-
// ignore
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
for (let i = 0; i < 15; i += 1) {
|
|
84
|
-
if (!isAlive(pid)) break;
|
|
85
|
-
await wait(200);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (isAlive(pid)) {
|
|
89
|
-
try {
|
|
90
|
-
process.kill(pid, 'SIGKILL');
|
|
91
|
-
} catch {
|
|
92
|
-
// ignore
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
fs.rmSync(PID_FILE, { force: true });
|
|
97
|
-
killByPort(DEFAULT_PORT);
|
|
98
|
-
console.log(`Browser service stopped (pid=${pid}).`);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
main().catch((err) => {
|
|
102
|
-
console.error(`[browser-service] stop failed: ${err?.message || String(err)}`);
|
|
103
|
-
process.exit(1);
|
|
104
|
-
});
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// 测试脚本:验证服务是否能正常启动
|
|
3
|
-
import { spawn, execSync } from 'node:child_process';
|
|
4
|
-
import { setTimeout as wait } from 'node:timers/promises';
|
|
5
|
-
|
|
6
|
-
function log(msg){ console.log(`[test-services] ${msg}`); }
|
|
7
|
-
|
|
8
|
-
async function testHealth(port, name, timeout = 10000) {
|
|
9
|
-
const startTime = Date.now();
|
|
10
|
-
|
|
11
|
-
while (Date.now() - startTime < timeout) {
|
|
12
|
-
try {
|
|
13
|
-
const response = await fetch(`http://127.0.0.1:${port}/health`);
|
|
14
|
-
if (response.ok) {
|
|
15
|
-
const data = await response.json();
|
|
16
|
-
log(`✅ ${name} (${port}): 健康检查通过 - ${JSON.stringify(data)}`);
|
|
17
|
-
return true;
|
|
18
|
-
}
|
|
19
|
-
} catch (e) {
|
|
20
|
-
// 继续等待
|
|
21
|
-
}
|
|
22
|
-
await wait(500);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
log(`❌ ${name} (${port}): 健康检查失败`);
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function main() {
|
|
30
|
-
log('🧪 测试服务启动...');
|
|
31
|
-
|
|
32
|
-
// 1. 构建服务
|
|
33
|
-
try {
|
|
34
|
-
log('构建服务...');
|
|
35
|
-
execSync('npm run -s build:services', { stdio: 'inherit' });
|
|
36
|
-
log('✅ 构建完成');
|
|
37
|
-
} catch (e) {
|
|
38
|
-
log('❌ 构建失败');
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// 2. 清理端口
|
|
43
|
-
const ports = [7704, 7705, 7706];
|
|
44
|
-
for (const port of ports) {
|
|
45
|
-
try {
|
|
46
|
-
execSync(`lsof -ti :${port} | xargs kill -9 || true`, { stdio: 'ignore' });
|
|
47
|
-
} catch {}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// 3. 测试 Unified API
|
|
51
|
-
log('测试 Unified API...');
|
|
52
|
-
const unifiedProc = spawn('node', ['dist/apps/webauto/server.js'], {
|
|
53
|
-
env: { ...process.env, WEBAUTO_RUNTIME_MODE: 'unified', WEBAUTO_UNIFIED_PORT: '7704' },
|
|
54
|
-
stdio: ['ignore', 'pipe', 'pipe']
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
unifiedProc.stdout.on('data', (data) => {
|
|
58
|
-
log(`[Unified API] ${data.toString().trim()}`);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
unifiedProc.stderr.on('data', (data) => {
|
|
62
|
-
log(`[Unified API ERROR] ${data.toString().trim()}`);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
unifiedProc.on('error', (err) => {
|
|
66
|
-
log(`❌ Unified API 启动错误: ${err.message}`);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
const unifiedOk = await testHealth(7704, 'Unified API', 15000);
|
|
70
|
-
|
|
71
|
-
if (unifiedOk) {
|
|
72
|
-
// 4. 测试基本 API
|
|
73
|
-
try {
|
|
74
|
-
const response = await fetch('http://127.0.0.1:7704/v1/system/state');
|
|
75
|
-
const data = await response.json();
|
|
76
|
-
log(`📋 系统状态: ${JSON.stringify(data)}`);
|
|
77
|
-
} catch (e) {
|
|
78
|
-
log(`❌ 系统状态获取失败: ${e.message}`);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// 5. 清理
|
|
83
|
-
unifiedProc.kill('SIGTERM');
|
|
84
|
-
await wait(1000);
|
|
85
|
-
unifiedProc.kill('SIGKILL');
|
|
86
|
-
|
|
87
|
-
log('🧹 测试完成');
|
|
88
|
-
process.exit(unifiedOk ? 0 : 1);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
main().catch(e => {
|
|
92
|
-
console.error('❌ 测试失败:', e.message);
|
|
93
|
-
process.exit(1);
|
|
94
|
-
});
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { startHeartbeatWriter } from './heartbeat.js';
|
|
7
|
-
|
|
8
|
-
function readHeartbeat(filePath: string) {
|
|
9
|
-
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
10
|
-
return JSON.parse(raw);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
test('heartbeat writer updates status and persists payload', async (t) => {
|
|
14
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'webauto-heartbeat-'));
|
|
15
|
-
const filePath = path.join(root, 'heartbeat.json');
|
|
16
|
-
const previous = {
|
|
17
|
-
file: process.env.WEBAUTO_HEARTBEAT_FILE,
|
|
18
|
-
interval: process.env.WEBAUTO_HEARTBEAT_INTERVAL_MS,
|
|
19
|
-
stale: process.env.WEBAUTO_HEARTBEAT_STALE_MS,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
t.after(() => {
|
|
23
|
-
process.env.WEBAUTO_HEARTBEAT_FILE = previous.file;
|
|
24
|
-
process.env.WEBAUTO_HEARTBEAT_INTERVAL_MS = previous.interval;
|
|
25
|
-
process.env.WEBAUTO_HEARTBEAT_STALE_MS = previous.stale;
|
|
26
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
const writer = startHeartbeatWriter({ filePath, intervalMs: 50, initialStatus: 'idle' });
|
|
30
|
-
const first = readHeartbeat(filePath);
|
|
31
|
-
assert.equal(first.status, 'idle');
|
|
32
|
-
assert.equal(first.pid, process.pid);
|
|
33
|
-
assert.ok(typeof first.ts === 'string');
|
|
34
|
-
|
|
35
|
-
writer.setStatus('running');
|
|
36
|
-
const second = readHeartbeat(filePath);
|
|
37
|
-
assert.equal(second.status, 'running');
|
|
38
|
-
|
|
39
|
-
writer.stop();
|
|
40
|
-
const third = readHeartbeat(filePath);
|
|
41
|
-
assert.equal(third.status, 'stopped');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test('heartbeat watcher exits when stale', async (t) => {
|
|
45
|
-
// NOTE: startHeartbeatWatcher calls process.exit(0) when stale/missing.
|
|
46
|
-
// We temporarily replace process.exit to assert behavior without terminating the test runner.
|
|
47
|
-
const { startHeartbeatWatcher } = await import('./heartbeat.js');
|
|
48
|
-
|
|
49
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'webauto-heartbeat-'));
|
|
50
|
-
const filePath = path.join(root, 'heartbeat.json');
|
|
51
|
-
fs.writeFileSync(filePath, JSON.stringify({ ts: new Date(0).toISOString(), status: 'running' }), 'utf-8');
|
|
52
|
-
|
|
53
|
-
const originalExit = process.exit;
|
|
54
|
-
let exitCode: number | null = null;
|
|
55
|
-
let exitCalled: ((code?: number) => void) | null = null;
|
|
56
|
-
const exitPromise = new Promise<void>((resolve) => {
|
|
57
|
-
exitCalled = (code?: number) => {
|
|
58
|
-
exitCode = typeof code === 'number' ? code : 0;
|
|
59
|
-
resolve();
|
|
60
|
-
};
|
|
61
|
-
});
|
|
62
|
-
process.exit = ((code?: number) => exitCalled?.(code)) as any;
|
|
63
|
-
|
|
64
|
-
t.after(() => {
|
|
65
|
-
process.exit = originalExit;
|
|
66
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
const stop = startHeartbeatWatcher({ serviceName: 'svc', filePath, staleMs: 1, intervalMs: 1 });
|
|
70
|
-
await exitPromise;
|
|
71
|
-
stop();
|
|
72
|
-
assert.equal(exitCode, 0);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test('heartbeat watcher exits when status=stopped', async (t) => {
|
|
76
|
-
const { startHeartbeatWatcher } = await import('./heartbeat.js');
|
|
77
|
-
|
|
78
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'webauto-heartbeat-'));
|
|
79
|
-
const filePath = path.join(root, 'heartbeat.json');
|
|
80
|
-
fs.writeFileSync(filePath, JSON.stringify({ ts: new Date().toISOString(), status: 'stopped' }), 'utf-8');
|
|
81
|
-
|
|
82
|
-
const originalExit = process.exit;
|
|
83
|
-
let exitCode: number | null = null;
|
|
84
|
-
let exitCalled: ((code?: number) => void) | null = null;
|
|
85
|
-
const exitPromise = new Promise<void>((resolve) => {
|
|
86
|
-
exitCalled = (code?: number) => {
|
|
87
|
-
exitCode = typeof code === 'number' ? code : 0;
|
|
88
|
-
resolve();
|
|
89
|
-
};
|
|
90
|
-
});
|
|
91
|
-
process.exit = ((code?: number) => exitCalled?.(code)) as any;
|
|
92
|
-
|
|
93
|
-
t.after(() => {
|
|
94
|
-
process.exit = originalExit;
|
|
95
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
const stop = startHeartbeatWatcher({ serviceName: 'svc', filePath, staleMs: 10_000, intervalMs: 1 });
|
|
99
|
-
await exitPromise;
|
|
100
|
-
stop();
|
|
101
|
-
assert.equal(exitCode, 0);
|
|
102
|
-
});
|