@tea-agent/loop-agent 0.39.0-next.9 → 0.39.1
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/AGENTS.md +4 -1
- package/CHANGELOG.md +269 -69
- package/README.md +11 -5
- package/bin/loop-agent.js +7 -3
- package/dist/application/dag/generate-task-dag.js +9 -0
- package/dist/application/task-lifecycle/advance.js +16 -0
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +16 -5
- package/dist/cli/program.js +16 -2
- package/dist/cli/update/notifier.js +2 -2
- package/dist/cli/update/runtime-activity.js +1 -29
- package/dist/cli.js +2 -1
- package/dist/commands/dag-rerun.js +55 -1
- package/dist/commands/init-model-catalog.js +464 -0
- package/dist/commands/init-upgrade.js +265 -97
- package/dist/commands/init.js +428 -27
- package/dist/commands/inspect-next.js +8 -0
- package/dist/commands/task-advance.js +31 -0
- package/dist/executors/dag-pi-executor.js +124 -18
- package/dist/executors/pi-event-serializer.js +42 -1
- package/dist/executors/pi-executor.js +51 -0
- package/dist/executors/pi-extension-resolver.js +233 -0
- package/dist/executors/pi-playwright-cli-tool.js +74 -28
- package/dist/executors/pi-sdk-executor.js +187 -59
- package/dist/executors/shell-executor.js +555 -34
- package/dist/executors/shell-write-guard.js +7 -0
- package/dist/shared/dag-failure-category.js +138 -0
- package/dist/shared/dag-prompt-override.js +27 -0
- package/dist/shared/operator/capabilities.js +181 -27
- package/dist/shared/playwright-cli-command-policy.js +15 -0
- package/dist/shared/update/console-notifier.js +100 -0
- package/dist/{cli → shared}/update/npm-client.js +70 -15
- package/dist/{cli → shared}/update/state.js +41 -13
- package/dist/task/config-types.js +28 -0
- package/dist/task/contract/apply.js +11 -1
- package/dist/task/contract/constants.js +3 -0
- package/dist/task/contract/diff.js +26 -0
- package/dist/task/contract/hash.js +3 -0
- package/dist/task/contract/observe.js +25 -4
- package/dist/task/contract/paths.js +2 -1
- package/dist/task/contract/project.js +20 -1
- package/dist/task/contract/schema.js +8 -1
- package/dist/task/contract/transaction.js +12 -0
- package/dist/task/source-prepare/build-draft.js +15 -0
- package/dist/task/source-prepare/completeness.js +188 -0
- package/dist/task/source-prepare/fragment-inventory.js +474 -0
- package/dist/task/source-prepare/index.js +3 -0
- package/dist/task/source-prepare/ledger-reconciliation.js +127 -0
- package/dist/task/source-prepare/ledger-review.js +214 -0
- package/dist/task/source-prepare/ledger.js +545 -0
- package/dist/task/source-prepare/parse-intent.js +24 -4
- package/dist/task/source-prepare/prepare.js +262 -1
- package/dist/task/source-prepare/semantic-intake.js +19 -3
- package/dist/task/source-prepare/source-fidelity-pi.js +384 -0
- package/dist/task/source-prepare/types.js +22 -0
- package/dist/worker/cli.js +18 -2
- package/dist/worker/console/chat/deferred-turn.js +91 -0
- package/dist/worker/console/chat/mcp-inventory.js +221 -0
- package/dist/worker/console/chat/operation-card.js +8 -1
- package/dist/worker/console/chat/pi-console-config.js +81 -10
- package/dist/worker/console/chat/pi-runtime.js +165 -83
- package/dist/worker/console/chat/repo-walk.js +10 -1
- package/dist/worker/console/chat/routes.js +480 -55
- package/dist/worker/console/chat/semantic-activity.js +20 -8
- package/dist/worker/console/chat/session-store.js +146 -2
- package/dist/worker/console/chat/turn-process.js +10 -10
- package/dist/worker/console/console-handoff.js +82 -0
- package/dist/worker/console/console-update-and-init.js +115 -0
- package/dist/worker/console/console-update-runtime.js +84 -0
- package/dist/worker/console/dag-execution-receipt.js +33 -0
- package/dist/worker/console/draft-store.js +49 -0
- package/dist/worker/console/inspect-split.js +18 -0
- package/dist/worker/console/operation-run-facts.js +19 -3
- package/dist/worker/console/operation-store.js +1 -1
- package/dist/worker/console/operator-actions.js +320 -4
- package/dist/worker/console/operator-surface-health.js +1 -0
- package/dist/worker/console/operator-user-error.js +2 -2
- package/dist/worker/console/pi-readiness.js +5 -4
- package/dist/worker/console/prd-intake-bridge.js +13 -0
- package/dist/worker/console/recovery-cta.js +4 -4
- package/dist/worker/console/recovery-error-copy.js +4 -4
- package/dist/worker/console/routes.js +46 -2
- package/dist/worker/console/security.js +63 -9
- package/dist/worker/console/server.js +111 -7
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-BLXFe4qI.js → abnfDiagram-N423BO3Z-CTx1TrNa.js} +1 -1
- package/dist/worker/console/static/assets/{arc-7iOJeqho.js → arc-B4i9cVxX.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CYoyj5K7.js → architectureDiagram-T3A2C74G-BAXE8_Rl.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-fK01JNlR.js → blockDiagram-VBNYF7ZC-C5Xh59at.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-bzbw5D_Z.js → c4Diagram-5PPSVZJV-B_asOzAu.js} +1 -1
- package/dist/worker/console/static/assets/channel-Dj_4Moei.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-Cf6hJFFG.js → chunk-2GRJ4B5K-wRO_iRNc.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DSFXR-et.js → chunk-2Q5K7J3B-ByOaSh_G.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BagJechl.js → chunk-5RXB4S5H-DjLzudan.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-E7QNMFaW.js → chunk-5VM5RSS4-JCNGkXYT.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BG_eOBrC.js → chunk-6Q2QTUOP-BhrPXXMZ.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-Bo42dqol.js → chunk-GF5L2VYU-TJ5JuEBT.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-dibM-87v.js → chunk-JWPE2WC7-VVthn_mD.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-Bytrp3Oe.js → chunk-KBJHAD2P-D60-Mny4.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DBABILrr.js → chunk-RYQCIY6F-zXv7aVye.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-DCUk5Pf9.js → chunk-XXDRQBXY-By9VQoi1.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C0YYAyCa.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C0YYAyCa.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BlGE9v6E.js → cose-bilkent-JH36ORCC-C4zQLe-M.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-DGl5ewph.js → cynefin-VYW2F7L2-wh5N2ReN.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-DsJ_SVH_.js → cynefinDiagram-MW4NZA55-Dlu5wIqs.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BIhjFdzv.js → dagre-VZM6K2ZE-CrDgthc6.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-Dmy1ctTb.js → diagram-7IWD3JNH-zN1clg27.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-DYCtWUF3.js → diagram-B4RE2ZJO-BN-o7J7-.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-BMZFHVd2.js → diagram-LBJQPF4R-C8SuPt0d.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-b_U8gfaO.js → diagram-Q27KOJAE-BoizuHbZ.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-Dzy_bn-I.js → diagram-UB23O5K3-BzUzXixG.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DJCiMNEI.js → ebnfDiagram-BXEA7PRR-Ev3lA4Cf.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-28lD016B.js → erDiagram-JOGREHBK-GALUzRbs.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-DGyHJmIw.js → flowDiagram-UKHOOZJN-CZJN65Sb.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-CzdwUjrO.js → ganttDiagram-PKOTCBZU-JLB9OESl.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-D9bGwuo8.js → gitGraphDiagram-DS77QQ5N-CcvCr4GD.js} +1 -1
- package/dist/worker/console/static/assets/index-CW88Fjbw.js +406 -0
- package/dist/worker/console/static/assets/index-DP0ZJl39.css +1 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-LJgJUQFC.js → infoDiagram-6WML65LV-HG5z7aVg.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-98LaB8zb.js → ishikawaDiagram-WSZJBQD7-BHEu9chR.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-D-ISzwlQ.js → journeyDiagram-NVQOT4AX-Cp_Up8-a.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-gfYOI-EL.js → kanban-definition-27J2QSJJ-DvVeY-em.js} +1 -1
- package/dist/worker/console/static/assets/{linear-CyntZgKV.js → linear-aGmcjgTn.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-BBOR7dg0.js → mermaid.core-Biyo-tqA.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-CQAgwPMk.js → mindmap-definition-FAOFIHXS-DyxY2pIb.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-DkMiZFuV.js → pegDiagram-VL7TDLO6-CkdGuc50.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-DLNXa_0J.js → pieDiagram-7S7Q4E2Y-NNQI9xVR.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-Dc7bdzjm.js → quadrantDiagram-CIZ2JOQS-PAJkuz_G.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BxMB0QqW.js → railroadDiagram-AXF67PYL-ZwrQod0O.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-FjumoKn4.js → requirementDiagram-LRYGKXZP-D3ZfrzM2.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-CkhKc_E3.js → sankeyDiagram-W5VNT64P-DDGFmWk5.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DoBWqTTH.js → sequenceDiagram-SI44F4Z6-DO6mmXTA.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-CQeh_YeE.js → sizeCapture-X5ZJPWSS-DMbCQiJt.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-LuHmFW-I.js → stateDiagram-OKZ733FA-Di_YUEfC.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DrdDvela.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-CHwbDctY.js → swimlanes-SLNWSIFB-Bn2PphNJ.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DPkEAULl.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CoMngk0X.js → timeline-definition-Z64GVDOM-DPh8pRsp.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-CURYbtbO.js → vennDiagram-T6HMQDX7-GMfl26pW.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-BdqSECjU.js → wardleyDiagram-T6FBY63Y-DTlmVrmF.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-DbMUYuAg.js → xychartDiagram-ELKLHX3M-YGBjKAS5.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/app/console-types.js +40 -1
- package/dist/worker/console/static-src/app/useOperatorActions.js +6 -1
- package/dist/worker/console/static-src/app/useRecoveryActions.js +2 -2
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +38 -2
- package/dist/worker/console/static-src/app/useRunProgress.js +46 -0
- package/dist/worker/console/static-src/app/useTaskWizard.js +73 -1
- package/dist/worker/console/static-src/operator-chat/cards/failure-category-advice.js +25 -0
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +74 -26
- package/dist/worker/console/static-src/operator-chat/input-history.js +76 -0
- package/dist/worker/console/static-src/operator-chat/mutation-gate.js +1 -1
- package/dist/worker/console/static-src/operator-chat/open-preview-in-browser.js +328 -0
- package/dist/worker/console/static-src/operator-chat/resource-diagnostics.js +204 -0
- package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +8 -1
- package/dist/worker/console/static-src/operator-chat/turn-submission.js +54 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +3 -0
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +237 -11
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +50 -22
- package/dist/worker/console/static-src/operator-chat/useComposer.js +32 -0
- package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +26 -1
- package/dist/worker/console/static-src/pages/tasks/run-id-resolution.js +79 -0
- package/dist/worker/console/static-src/pages/tasks/run-ownership-verify.js +23 -0
- package/dist/worker/console/static-src/pages/tasks/run-panel-progress.js +110 -0
- package/dist/worker/loop-agent/loop-agent-client.js +7 -3
- package/dist/worker/materialize/harness-task-lineage.js +5 -2
- package/dist/worker/observability/init-runtime-activity.js +26 -0
- package/dist/worker/observability/read-model.js +22 -0
- package/dist/worker/observe/node-input.js +160 -3
- package/dist/worker/observe/node-process.js +377 -0
- package/dist/worker/observe/routes.js +224 -3
- package/dist/worker/observe/shell-handler-keys.js +34 -0
- package/dist/worker/observe/static/api.js +67 -1
- package/dist/worker/observe/static/constants.js +8 -1
- package/dist/worker/observe/static/dag-history-labels.js +4 -0
- package/dist/worker/observe/static/format.js +60 -0
- package/dist/worker/observe/static/index.html +5 -0
- package/dist/worker/observe/static/markdown-render.js +20 -1
- package/dist/worker/observe/static/operator-chrome.js +4 -0
- package/dist/worker/observe/static/prompt-restart-candidates.d.ts +18 -0
- package/dist/worker/observe/static/prompt-restart-candidates.js +36 -0
- package/dist/worker/observe/static/state.js +13 -2
- package/dist/worker/observe/static/styles.css +85 -0
- package/dist/worker/observe/static/views/dag-inspector.js +912 -8
- package/dist/worker/observe/static/views/dag.js +8 -1
- package/dist/worker/observe/static/views/failures.js +5 -2
- package/dist/worker/observe/static/views/session-timeline.js +78 -9
- package/dist/worker/observe/static/views/task.js +55 -0
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +856 -54
- package/dist/workflows/dag/backend-test-case-manifest.js +4 -0
- package/dist/workflows/dag/backend-test-execution-contract.js +18 -9
- package/dist/workflows/dag/backend-test-gap-fill.js +205 -0
- package/dist/workflows/dag/backend-test-intake-context.js +32 -0
- package/dist/workflows/dag/backend-test-layout.js +133 -0
- package/dist/workflows/dag/backend-test-markdown-workflow.js +343 -33
- package/dist/workflows/dag/backend-test-module-stem.js +5 -0
- package/dist/workflows/dag/backend-test-pytest-collection.js +454 -36
- package/dist/workflows/dag/backend-test-result-contract.js +1 -1
- package/dist/workflows/dag/backend-test-scenario-param.js +884 -140
- package/dist/workflows/dag/backend-test-scenario-partitions.js +321 -0
- package/dist/workflows/dag/backend-test-writer-completeness.js +110 -61
- package/dist/workflows/dag/contract-output-registry.js +15 -0
- package/dist/workflows/dag/contract-validator-registrations.js +3 -1
- package/dist/workflows/dag/convergence/controller.js +141 -0
- package/dist/workflows/dag/dynamic-runtime/loop-until.js +1 -1
- package/dist/workflows/dag/dynamic-runtime/map.js +25 -9
- package/dist/workflows/dag/dynamic-runtime/shared.js +1 -1
- package/dist/workflows/dag/failure-category.js +7 -116
- package/dist/workflows/dag/frontend-implementation-contract.js +465 -6
- package/dist/workflows/dag/frontend-plan-render.js +24 -0
- package/dist/workflows/dag/frontend-prewrite-gate.js +293 -84
- package/dist/workflows/dag/frontend-repair.js +14 -0
- package/dist/workflows/dag/frontend-review-context.js +92 -10
- package/dist/workflows/dag/frontend-risk.js +15 -2
- package/dist/workflows/dag/frontend-test-case-checklist.js +30 -4
- package/dist/workflows/dag/frontend-test-case-manifest.js +11 -4
- package/dist/workflows/dag/frontend-test-case-quality.js +11 -16
- package/dist/workflows/dag/frontend-test-environment-probe.js +230 -0
- package/dist/workflows/dag/frontend-test-html-report.js +3 -1
- package/dist/workflows/dag/frontend-test-l5-report.js +3 -1
- package/dist/workflows/dag/frontend-test-layout.js +159 -0
- package/dist/workflows/dag/frontend-test-markdown.js +61 -0
- package/dist/workflows/dag/frontend-test-result-contract.js +188 -42
- package/dist/workflows/dag/frontend-test-standard-scenarios.js +70 -0
- package/dist/workflows/dag/frontend-verification-trace.js +29 -4
- package/dist/workflows/dag/init-hybrid.js +1019 -209
- package/dist/workflows/dag/node-execution.js +228 -15
- package/dist/workflows/dag/prompt.js +60 -1
- package/dist/workflows/dag/rerun-feedback.js +212 -0
- package/dist/workflows/dag/rerun-plan.js +224 -27
- package/dist/workflows/dag/rerun-run.js +61 -6
- package/dist/workflows/dag/rerun-task.js +61 -2
- package/dist/workflows/dag/retry-policy.js +109 -0
- package/dist/workflows/dag/structured-output-repair.js +712 -0
- package/dist/workflows/dag/types.js +185 -12
- package/dist/workflows/dag/validate.js +64 -20
- package/docs/README.md +1 -0
- package/docs/architecture/evolution.md +45 -0
- package/docs/init-surface.manifest.json +6 -0
- package/docs/operations/README.md +1 -1
- package/docs/operations/local-development-environment.md +1 -5
- package/docs/skills/vetted-skill-registry.md +14 -0
- package/docs/templates/README.md +2 -2
- package/docs/templates/agent-dag.schema.json +44 -0
- package/docs/templates/backend-test-dag.json +60 -35
- package/docs/templates/frontend-implementation-contract.schema.json +681 -24
- package/docs/templates/frontend-test-case-checklist.md +2 -2
- package/docs/templates/frontend-test-dag.json +8 -10
- package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +1 -1
- package/docs/templates/init-managed-agents.md +13 -3
- package/harness.json +6 -4
- package/package.json +12 -4
- package/scripts/next-info.mjs +356 -0
- package/scripts/next-publish-gate.mjs +238 -0
- package/scripts/release-source-binding.mjs +251 -0
- package/skills/analyze-product-requirements/SKILL.md +8 -5
- package/skills/analyze-product-requirements/references/acceptance-criteria.md +1 -1
- package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +10 -6
- package/skills/analyze-product-requirements/references/example.md +50 -0
- package/skills/analyze-product-requirements/references/forward-test-cases.md +11 -7
- package/skills/analyze-product-requirements/references/kb-integration.md +5 -5
- package/skills/analyze-product-requirements/references/product-analysis-schema.md +8 -4
- package/skills/analyze-product-requirements/references/product-requirement-schema.md +2 -2
- package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +1 -1
- package/skills/analyze-product-requirements/scripts/test-validators.mjs +11 -1
- package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +20 -1
- package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +9 -0
- package/skills/codebase-scout/SKILL.md +1 -1
- package/skills/fe-test-ui-scout/SKILL.md +65 -0
- package/skills/fe-test-ui-scout/references/ledger-schema.md +62 -0
- package/skills/fe-test-ui-scout/references/recon-protocol.md +54 -0
- package/skills/frontend-implementation/references/node-contracts.md +2 -2
- package/skills/improve-codebase-architecture/SKILL.md +81 -0
- package/skills/improve-codebase-architecture/deepening.md +37 -0
- package/skills/improve-codebase-architecture/html-report.md +123 -0
- package/skills/improve-codebase-architecture/interface-design.md +44 -0
- package/skills/improve-codebase-architecture/language.md +53 -0
- package/skills/loop-agent/references/command-reference.md +11 -4
- package/skills/loop-agent/references/hybrid-dag.md +7 -0
- package/skills/playwright-cli/SKILL.md +23 -1
- package/skills/playwright-cli-case-generator/SKILL.md +29 -8
- package/dist/worker/console/static/assets/channel-BBOTJHvD.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-Cm8Yf8tD.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-Cm8Yf8tD.js +0 -1
- package/dist/worker/console/static/assets/index-B-qWGThd.js +0 -325
- package/dist/worker/console/static/assets/index-C-xRgY_0.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DZihfdKc.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CKnXCjHX.js +0 -8
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
2
|
import { ensureUniqueDocumentNames, operatorRequestFits, operatorRequestTooLargeMessage, } from "../prd-file-import.js";
|
|
3
3
|
import { requestId, WORKFLOW_OPTIONS, } from "./console-types.js";
|
|
4
|
+
export async function fetchLedgerSummary(taskId, fetchImpl) {
|
|
5
|
+
const impl = fetchImpl ?? fetch;
|
|
6
|
+
const response = await impl(`/api/tasks/${encodeURIComponent(taskId)}/ledger`, { credentials: "same-origin" });
|
|
7
|
+
if (!response.ok)
|
|
8
|
+
return { ok: false };
|
|
9
|
+
const summary = (await response.json());
|
|
10
|
+
return { ok: true, summary };
|
|
11
|
+
}
|
|
4
12
|
/** Happy Path task wizard: import-prd → interview → contract → dag-confirm →
|
|
5
13
|
* run. Owns task identity, interview projection and contract preflight/apply. */
|
|
6
14
|
export function useTaskWizard(params) {
|
|
@@ -24,16 +32,27 @@ export function useTaskWizard(params) {
|
|
|
24
32
|
const [contractDiffSummary, setContractDiffSummary] = useState(null);
|
|
25
33
|
const [contractApplied, setContractApplied] = useState(false);
|
|
26
34
|
const [spineOk, setSpineOk] = useState(null);
|
|
35
|
+
const [ledgerLoading, setLedgerLoading] = useState(false);
|
|
36
|
+
const [ledgerError, setLedgerError] = useState(null);
|
|
37
|
+
const [ledgerSummary, setLedgerSummary] = useState(null);
|
|
27
38
|
const [contractPreflightKey, setContractPreflightKey] = useState(null);
|
|
28
39
|
const contractPreflightRunning = useRef(false);
|
|
40
|
+
/** Epoch guard for ledger fetches: only the newest request may write wizard
|
|
41
|
+
* state, so a concurrent in-flight preflight response can never overwrite
|
|
42
|
+
* a fresh post-apply result (AC-001). */
|
|
43
|
+
const ledgerFetchEpoch = useRef(0);
|
|
29
44
|
const resetContractLanding = useCallback(() => {
|
|
30
45
|
setContractValidateOk(null);
|
|
31
46
|
setContractValidateSummary(null);
|
|
32
47
|
setContractDiffSummary(null);
|
|
33
48
|
setContractApplied(false);
|
|
34
49
|
setSpineOk(null);
|
|
50
|
+
setLedgerLoading(false);
|
|
51
|
+
setLedgerError(null);
|
|
52
|
+
setLedgerSummary(null);
|
|
35
53
|
setContractPreflightKey(null);
|
|
36
54
|
contractPreflightRunning.current = false;
|
|
55
|
+
ledgerFetchEpoch.current = 0;
|
|
37
56
|
}, []);
|
|
38
57
|
const enterContractStep = useCallback(() => {
|
|
39
58
|
resetContractLanding();
|
|
@@ -56,6 +75,39 @@ export function useTaskWizard(params) {
|
|
|
56
75
|
: "访谈已完成:草稿已绑定完整评估结果");
|
|
57
76
|
}
|
|
58
77
|
}, [enterContractStep, setOpMessage]);
|
|
78
|
+
/** Epoch-guarded shared ledger refresh used by both the contract-step
|
|
79
|
+
* preflight and the post-apply re-GET. `failureSemantics` keeps the
|
|
80
|
+
* preflight five-state behavior (non-ok → empty state, no error) while the
|
|
81
|
+
* post-apply refresh treats a non-ok/network failure as a safe-degrade
|
|
82
|
+
* error per AC-001. */
|
|
83
|
+
const refreshLedgerState = useCallback(async (id, failureSemantics) => {
|
|
84
|
+
const epoch = ++ledgerFetchEpoch.current;
|
|
85
|
+
setLedgerLoading(true);
|
|
86
|
+
setLedgerError(null);
|
|
87
|
+
try {
|
|
88
|
+
const outcome = await fetchLedgerSummary(id);
|
|
89
|
+
if (ledgerFetchEpoch.current !== epoch)
|
|
90
|
+
return;
|
|
91
|
+
if (!outcome.ok) {
|
|
92
|
+
setLedgerSummary(null);
|
|
93
|
+
if (failureSemantics) {
|
|
94
|
+
setLedgerError("ledger 接口不可达(安全降级)");
|
|
95
|
+
}
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
setLedgerSummary(outcome.summary);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
if (ledgerFetchEpoch.current !== epoch)
|
|
102
|
+
return;
|
|
103
|
+
setLedgerError("ledger 接口不可达(安全降级)");
|
|
104
|
+
setLedgerSummary(null);
|
|
105
|
+
}
|
|
106
|
+
finally {
|
|
107
|
+
if (ledgerFetchEpoch.current === epoch)
|
|
108
|
+
setLedgerLoading(false);
|
|
109
|
+
}
|
|
110
|
+
}, []);
|
|
59
111
|
const runContractPreflight = useCallback(async (force = false) => {
|
|
60
112
|
const id = taskId.trim();
|
|
61
113
|
if (!id)
|
|
@@ -74,6 +126,9 @@ export function useTaskWizard(params) {
|
|
|
74
126
|
setContractDiffSummary(null);
|
|
75
127
|
setSpineOk(null);
|
|
76
128
|
setContractApplied(false);
|
|
129
|
+
// Shared epoch-guarded refresh preserves the five-state semantics:
|
|
130
|
+
// non-ok → empty state, network failure → safe-degrade error.
|
|
131
|
+
await refreshLedgerState(id, false);
|
|
77
132
|
try {
|
|
78
133
|
const validateBody = await runAction("contractValidate", {
|
|
79
134
|
taskId: id,
|
|
@@ -101,6 +156,7 @@ export function useTaskWizard(params) {
|
|
|
101
156
|
contractPreflightKey,
|
|
102
157
|
contractValidateOk,
|
|
103
158
|
isActionSuccess,
|
|
159
|
+
refreshLedgerState,
|
|
104
160
|
runAction,
|
|
105
161
|
setOpMessage,
|
|
106
162
|
summarizeEnvelope,
|
|
@@ -116,6 +172,11 @@ export function useTaskWizard(params) {
|
|
|
116
172
|
return;
|
|
117
173
|
}
|
|
118
174
|
setContractApplied(true);
|
|
175
|
+
// AC-001: re-GET the read-only ledger right after apply succeeds and
|
|
176
|
+
// write the latest summary BEFORE spineCheck/setStep, so the first
|
|
177
|
+
// dag-confirm frame shows post-apply statistics (never a loading/empty
|
|
178
|
+
// flash); refresh failure safe-degrades via ledgerError.
|
|
179
|
+
await refreshLedgerState(id, true);
|
|
119
180
|
const spineBody = await runAction("spineCheck", { taskId: id });
|
|
120
181
|
if (isActionSuccess(spineBody)) {
|
|
121
182
|
setSpineOk(true);
|
|
@@ -125,7 +186,15 @@ export function useTaskWizard(params) {
|
|
|
125
186
|
}
|
|
126
187
|
setSpineOk(false);
|
|
127
188
|
setOpMessage("契约已应用,但 Spine 审计未通过:可重试 Spine");
|
|
128
|
-
}, [
|
|
189
|
+
}, [
|
|
190
|
+
assessmentId,
|
|
191
|
+
isActionSuccess,
|
|
192
|
+
refreshLedgerState,
|
|
193
|
+
runAction,
|
|
194
|
+
setOpMessage,
|
|
195
|
+
setStep,
|
|
196
|
+
taskId,
|
|
197
|
+
]);
|
|
129
198
|
const retrySpineOnly = useCallback(async () => {
|
|
130
199
|
const id = taskId.trim();
|
|
131
200
|
if (!id)
|
|
@@ -282,6 +351,9 @@ export function useTaskWizard(params) {
|
|
|
282
351
|
contractValidateOk,
|
|
283
352
|
contractValidateSummary,
|
|
284
353
|
contractDiffSummary,
|
|
354
|
+
ledgerLoading,
|
|
355
|
+
ledgerError,
|
|
356
|
+
ledgerSummary,
|
|
285
357
|
contractApplied,
|
|
286
358
|
spineOk,
|
|
287
359
|
applyInterviewPayload,
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Operator-facing recovery advice per normalized DAG failure category
|
|
3
|
+
* (mirrors DAG_NORMALIZED_FAILURE_CATEGORIES). The task journey card used to
|
|
4
|
+
* stop at "原因分类为 X" without telling the operator what to do next; this
|
|
5
|
+
* maps each class to the concrete next move, aligned with the Recovery
|
|
6
|
+
* workspace CTAs (node rerun / reconcile / models page).
|
|
7
|
+
*/
|
|
8
|
+
const FAILURE_CATEGORY_ADVICE = {
|
|
9
|
+
validation: "节点输出未通过契约或门禁校验。可在恢复页从失败节点重跑;若错误指向任务契约(如验证命令、Mock 策略),先修正任务配置并重新生成 DAG。",
|
|
10
|
+
executor: "执行器或模型提供方调用失败(网络、配额或运行时错误)。稍后可在恢复页从失败节点重跑;反复出现请到「模型与认证」页检查配置与凭据。",
|
|
11
|
+
"write-guard": "写入越过了授权边界(writeSet / allowedPaths)。检查计划中的写入路径是否越界,修正后从失败节点重跑。",
|
|
12
|
+
timeout: "节点执行超时。可在恢复页从失败节点重跑;反复超时建议缩小任务范围或排查卡住的命令。",
|
|
13
|
+
auth: "模型或服务认证失败。请先到「模型与认证」页检查 API Key 与模型配置,再从失败节点重跑。",
|
|
14
|
+
"human-required": "节点正在等待人工审批。完成审批后该节点可继续执行;也可在恢复页查看对账状态。",
|
|
15
|
+
"human-rejected": "人工审批被拒绝。请调整任务描述或契约后重新发起任务。",
|
|
16
|
+
"shell-command": "验证/构建命令以非零退出。进入 DAG 查看命令输出定位具体失败,修复后从失败节点重跑。",
|
|
17
|
+
"static-error": "静态检查(typecheck / lint 等)失败。修复对应代码错误后从失败节点重跑。",
|
|
18
|
+
"decision-envelope": "决策与证据不匹配(决策包络校验失败)。进入 DAG 查看节点决策依据,修正后重跑。",
|
|
19
|
+
unknown: "失败原因未归类。进入 DAG 查看节点详情,或在恢复页使用对账 / 诊断入口。",
|
|
20
|
+
};
|
|
21
|
+
export function failureCategoryAdvice(category) {
|
|
22
|
+
if (!category)
|
|
23
|
+
return undefined;
|
|
24
|
+
return FAILURE_CATEGORY_ADVICE[category];
|
|
25
|
+
}
|
|
@@ -10,7 +10,7 @@ import { parseAssistantContent } from "../../chat/assistant-content.js";
|
|
|
10
10
|
* original request would have. `assistantId` is the in-flight assistant
|
|
11
11
|
* message id to patch for streaming text; reconnect creates one if none. */
|
|
12
12
|
export function createChatSseEventApplier(deps) {
|
|
13
|
-
const { refs, onReconcile, setError, setInterview, setHumanGateCards, setArtifactCards, setStreaming, setStreamingAssistantId, setUnread, setOperationCards, setUsage, setMessages, setToolCalls, } = deps;
|
|
13
|
+
const { refs, onReconcile, setError, setInterview, setHumanGateCards, setArtifactCards, setStreaming, setTurnPhase = () => undefined, setDeferredTurn = () => undefined, setStreamingAssistantId, setUnread, setOperationCards, setUsage, setMessages, setToolCalls, } = deps;
|
|
14
14
|
return (eventName, data, assistantId, options) => {
|
|
15
15
|
if (options?.generation !== undefined &&
|
|
16
16
|
refs.sessionGenerationRef.current !== options.generation)
|
|
@@ -49,6 +49,41 @@ export function createChatSseEventApplier(deps) {
|
|
|
49
49
|
const eventAt = typeof data.at === "string" && Number.isFinite(Date.parse(data.at))
|
|
50
50
|
? Date.parse(data.at)
|
|
51
51
|
: Date.now();
|
|
52
|
+
if (eventName === "queue_update") {
|
|
53
|
+
const revision = typeof payload.revision === "number" ? payload.revision : -1;
|
|
54
|
+
setDeferredTurn((current) => {
|
|
55
|
+
if (current && revision < current.revision)
|
|
56
|
+
return current;
|
|
57
|
+
return payload.deferredTurn && typeof payload.deferredTurn === "object"
|
|
58
|
+
? payload.deferredTurn
|
|
59
|
+
: null;
|
|
60
|
+
});
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (eventName === "user_message") {
|
|
64
|
+
const message = payload.message && typeof payload.message === "object"
|
|
65
|
+
? payload.message
|
|
66
|
+
: null;
|
|
67
|
+
if (message &&
|
|
68
|
+
typeof message.id === "string" &&
|
|
69
|
+
typeof message.text === "string") {
|
|
70
|
+
const createdAt = typeof message.at === "string" && Number.isFinite(Date.parse(message.at))
|
|
71
|
+
? Date.parse(message.at)
|
|
72
|
+
: Date.now();
|
|
73
|
+
setMessages((messages) => messages.some((item) => item.id === message.id)
|
|
74
|
+
? messages
|
|
75
|
+
: [
|
|
76
|
+
...messages,
|
|
77
|
+
{
|
|
78
|
+
id: message.id,
|
|
79
|
+
role: "user",
|
|
80
|
+
text: message.text,
|
|
81
|
+
createdAt,
|
|
82
|
+
},
|
|
83
|
+
]);
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
52
87
|
if (turnId &&
|
|
53
88
|
(eventName === "agent_start" || eventName === "message_update") &&
|
|
54
89
|
refs.settledTurnIdsRef.current.has(turnId)) {
|
|
@@ -153,6 +188,7 @@ export function createChatSseEventApplier(deps) {
|
|
|
153
188
|
}
|
|
154
189
|
refs.streamingRef.current = true;
|
|
155
190
|
setStreaming(true);
|
|
191
|
+
setTurnPhase("running");
|
|
156
192
|
setStreamingAssistantId(resolvedAssistantId);
|
|
157
193
|
return;
|
|
158
194
|
}
|
|
@@ -168,6 +204,7 @@ export function createChatSseEventApplier(deps) {
|
|
|
168
204
|
refs.activeTurnIdRef.current = null;
|
|
169
205
|
refs.streamingRef.current = false;
|
|
170
206
|
setStreaming(false);
|
|
207
|
+
setTurnPhase("idle");
|
|
171
208
|
setStreamingAssistantId(null);
|
|
172
209
|
if (eventName === "agent_settled" &&
|
|
173
210
|
!replay &&
|
|
@@ -175,19 +212,30 @@ export function createChatSseEventApplier(deps) {
|
|
|
175
212
|
document.hidden) {
|
|
176
213
|
setUnread((current) => current + 1);
|
|
177
214
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
215
|
+
// Close dangling running tools first so the empty-bubble decision can
|
|
216
|
+
// see whether this assistant still owns any cards.
|
|
217
|
+
let assistantOwnsTools = false;
|
|
218
|
+
setToolCalls((prev) => {
|
|
219
|
+
assistantOwnsTools = prev.some((t) => t.assistantMessageId === resolvedAssistantId);
|
|
220
|
+
return prev.map((t) => t.status === "running" &&
|
|
221
|
+
((turnId !== undefined && t.turnId === turnId) ||
|
|
222
|
+
t.assistantMessageId === resolvedAssistantId)
|
|
223
|
+
? { ...t, status: "error", finishedAt: Date.now() }
|
|
224
|
+
: t);
|
|
225
|
+
});
|
|
226
|
+
// Drop only a true placeholder. An empty bubble that still owns tools
|
|
227
|
+
// (or has content blocks) is the grouping anchor; deleting it orphans
|
|
228
|
+
// the previous turn's bash cards onto the next prompt.
|
|
229
|
+
setMessages((m) => m.filter((msg) => {
|
|
230
|
+
if (msg.id !== resolvedAssistantId || msg.role !== "assistant") {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
if (msg.text.trim())
|
|
234
|
+
return true;
|
|
235
|
+
if (msg.content && msg.content.length > 0)
|
|
236
|
+
return true;
|
|
237
|
+
return assistantOwnsTools;
|
|
238
|
+
}));
|
|
191
239
|
return;
|
|
192
240
|
}
|
|
193
241
|
if (eventName === "operation-ref" || eventName === "operation-status") {
|
|
@@ -227,6 +275,15 @@ export function createChatSseEventApplier(deps) {
|
|
|
227
275
|
const cacheWrite = sample.cacheWriteTokens ?? 0;
|
|
228
276
|
const total = sample.totalTokens ?? input + output + cacheRead + cacheWrite;
|
|
229
277
|
const cu = sample.contextUsage;
|
|
278
|
+
const nextContext = cu && typeof cu === "object"
|
|
279
|
+
? {
|
|
280
|
+
tokens: typeof cu.tokens === "number" ? cu.tokens : null,
|
|
281
|
+
contextWindow: typeof cu.contextWindow === "number"
|
|
282
|
+
? cu.contextWindow
|
|
283
|
+
: 0,
|
|
284
|
+
percent: typeof cu.percent === "number" ? cu.percent : null,
|
|
285
|
+
}
|
|
286
|
+
: current.contextUsage;
|
|
230
287
|
return {
|
|
231
288
|
inputTokens: current.inputTokens + input,
|
|
232
289
|
outputTokens: current.outputTokens + output,
|
|
@@ -236,18 +293,9 @@ export function createChatSseEventApplier(deps) {
|
|
|
236
293
|
cost: sample.cost === undefined
|
|
237
294
|
? current.cost
|
|
238
295
|
: (current.cost ?? 0) + sample.cost,
|
|
239
|
-
// Context
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
contextUsage: {
|
|
243
|
-
tokens: typeof cu.tokens === "number" ? cu.tokens : null,
|
|
244
|
-
contextWindow: typeof cu.contextWindow === "number"
|
|
245
|
-
? cu.contextWindow
|
|
246
|
-
: 0,
|
|
247
|
-
percent: typeof cu.percent === "number" ? cu.percent : null,
|
|
248
|
-
},
|
|
249
|
-
}
|
|
250
|
-
: {}),
|
|
296
|
+
// Context fill is independent of per-message token deltas. Keep the
|
|
297
|
+
// last known snapshot unless this event carries a fresh one.
|
|
298
|
+
...(nextContext ? { contextUsage: nextContext } : {}),
|
|
251
299
|
};
|
|
252
300
|
});
|
|
253
301
|
return;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure composer input-history state machine for Operator Chat.
|
|
3
|
+
*
|
|
4
|
+
* Extracted so ArrowUp/ArrowUp recall, unsent-draft retention and history
|
|
5
|
+
* recording can be unit-tested without mounting the React composer.
|
|
6
|
+
*/
|
|
7
|
+
export const INPUT_HISTORY_LIMIT = 100;
|
|
8
|
+
export function createInputHistoryState() {
|
|
9
|
+
return { entries: [], index: -1, draft: "" };
|
|
10
|
+
}
|
|
11
|
+
/** Record one sent text and reset browsing back to the present draft. */
|
|
12
|
+
export function recordInputHistoryEntry(state, text) {
|
|
13
|
+
if (!text.trim())
|
|
14
|
+
return state;
|
|
15
|
+
if (state.entries[state.entries.length - 1] === text) {
|
|
16
|
+
return state.index === -1 ? state : { ...state, index: -1, draft: "" };
|
|
17
|
+
}
|
|
18
|
+
const entries = [...state.entries, text].slice(-INPUT_HISTORY_LIMIT);
|
|
19
|
+
return { entries, index: -1, draft: "" };
|
|
20
|
+
}
|
|
21
|
+
/** Leave browse mode (manual typing edits the recalled text in place). */
|
|
22
|
+
export function resetInputHistoryBrowsing(state) {
|
|
23
|
+
return state.index === -1 ? state : { ...state, index: -1 };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Recall an earlier input with the arrow keys (terminal-style).
|
|
27
|
+
*
|
|
28
|
+
* Up only engages while the caret sits on the first line and Down while it
|
|
29
|
+
* sits on the last line, so plain caret movement inside multi-line drafts is
|
|
30
|
+
* never swallowed. The unsent draft is stashed when browsing leaves the
|
|
31
|
+
* present position and restored when Down walks past the newest entry.
|
|
32
|
+
*/
|
|
33
|
+
export function navigateInputHistory(state, direction, context) {
|
|
34
|
+
const { text, caretStart, caretEnd } = context;
|
|
35
|
+
if (state.entries.length === 0)
|
|
36
|
+
return { handled: false };
|
|
37
|
+
if (direction === "up") {
|
|
38
|
+
if (text.slice(0, caretStart).includes("\n"))
|
|
39
|
+
return { handled: false };
|
|
40
|
+
if (state.index === -1) {
|
|
41
|
+
const index = state.entries.length - 1;
|
|
42
|
+
return {
|
|
43
|
+
handled: true,
|
|
44
|
+
state: { ...state, index, draft: text },
|
|
45
|
+
text: state.entries[index],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (state.index === 0) {
|
|
49
|
+
// Already at the oldest entry: stay there (terminal behaviour).
|
|
50
|
+
return { handled: true, state, text: state.entries[0] };
|
|
51
|
+
}
|
|
52
|
+
const index = state.index - 1;
|
|
53
|
+
return {
|
|
54
|
+
handled: true,
|
|
55
|
+
state: { ...state, index },
|
|
56
|
+
text: state.entries[index],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (state.index === -1)
|
|
60
|
+
return { handled: false };
|
|
61
|
+
if (text.slice(caretEnd).includes("\n"))
|
|
62
|
+
return { handled: false };
|
|
63
|
+
if (state.index >= state.entries.length - 1) {
|
|
64
|
+
return {
|
|
65
|
+
handled: true,
|
|
66
|
+
state: { ...state, index: -1 },
|
|
67
|
+
text: state.draft,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const index = state.index + 1;
|
|
71
|
+
return {
|
|
72
|
+
handled: true,
|
|
73
|
+
state: { ...state, index },
|
|
74
|
+
text: state.entries[index],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -30,7 +30,7 @@ export function isStaleTokenFailure(code) {
|
|
|
30
30
|
/** Chinese, actionable copy for mutation-gate rejections. */
|
|
31
31
|
export function describeMutationGateFailure(code) {
|
|
32
32
|
if (isStaleTokenFailure(code)) {
|
|
33
|
-
return "
|
|
33
|
+
return "页面凭证已失效(控制台可能已重启),请刷新页面(F5)后重试。";
|
|
34
34
|
}
|
|
35
35
|
if (code === "host-not-loopback") {
|
|
36
36
|
return "请求主机校验失败:非回环绑定时要求 Host 头,请刷新页面或检查访问地址。";
|