maka-agent 0.2.0-dev.24.20260907 → 0.2.0-dev.26.20260909
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/README.md +38 -19
- package/README.zh-CN.md +34 -19
- package/dist/mcp-capability-provider.js +4 -1
- package/dist/pi-transcript-tools.js +6 -0
- package/dist/pi-tui-layout.js +56 -10
- package/dist/pi-tui-mcp-status.js +2 -2
- package/dist/pi-tui-pickers.js +121 -30
- package/dist/pi-tui-runner.js +156 -42
- package/dist/pi-tui-todo.js +221 -0
- package/dist/pi-tui-transcript-viewer.js +134 -7
- package/dist/runtime-host-cli-context.js +70 -13
- package/dist/runtime-host-handoff-surface.js +51 -26
- package/dist/runtime-host-local-handoff.js +11 -1
- package/dist/runtime-host-service-manager.js +0 -3
- package/dist/runtime-host-session-channel.js +13 -0
- package/dist/runtime-host-session-driver.js +42 -1
- package/dist/tui-autocomplete-layout.js +3 -1
- package/dist/tui-copy-catalog.js +85 -6
- package/dist/tui-editor-render.js +36 -0
- package/dist/tui-mcp-control.js +41 -6
- package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
- package/node_modules/@maka/core/dist/agent-run.js +1 -0
- package/node_modules/@maka/core/dist/attachments.js +3 -0
- package/node_modules/@maka/core/dist/canonical-json.js +27 -0
- package/node_modules/@maka/core/dist/capabilities.js +35 -0
- package/node_modules/@maka/core/dist/computer-use.js +0 -1
- package/node_modules/@maka/core/dist/display-redaction.js +18 -0
- package/node_modules/@maka/core/dist/llm-connections.js +13 -0
- package/node_modules/@maka/core/dist/model-call-attempt.js +2 -0
- package/node_modules/@maka/core/dist/model-metadata.js +4 -0
- package/node_modules/@maka/core/dist/redaction.js +35 -0
- package/node_modules/@maka/core/dist/run-composition.js +77 -2
- package/node_modules/@maka/core/dist/runtime-event.js +3 -0
- package/node_modules/@maka/core/dist/session.js +57 -6
- package/node_modules/@maka/core/dist/slash-command-catalog.js +1 -0
- package/node_modules/@maka/core/dist/tool-result-record-schema.js +2 -1
- package/node_modules/@maka/core/dist/workhub-action-result.js +68 -0
- package/node_modules/@maka/core/package.json +3 -3
- package/node_modules/@maka/eval/dist/experiment-directory.js +4 -13
- package/node_modules/@maka/eval/dist/toolchain-verification.js +1 -1
- package/node_modules/@maka/mcp/dist/form-elicitation.js +213 -0
- package/node_modules/@maka/mcp/dist/index.js +337 -71
- package/node_modules/@maka/runtime/dist/agent-run-inspect.js +0 -13
- package/node_modules/@maka/runtime/dist/agent-run.js +90 -2
- package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +16 -8
- package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +57 -50
- package/node_modules/@maka/runtime/dist/archive-read-tool.js +2 -2
- package/node_modules/@maka/runtime/dist/context-budget-helpers.js +0 -16
- package/node_modules/@maka/runtime/dist/conversation-copy.js +153 -11
- package/node_modules/@maka/runtime/dist/github-copilot-oauth-enrollment.js +3 -3
- package/node_modules/@maka/runtime/dist/goal-continuation.js +5 -1
- package/node_modules/@maka/runtime/dist/ledger-tool-result-archive-reader.js +69 -1
- package/node_modules/@maka/runtime/dist/mcp-tools.js +7 -2
- package/node_modules/@maka/runtime/dist/model-fetcher.js +42 -2
- package/node_modules/@maka/runtime/dist/model-history.js +0 -112
- package/node_modules/@maka/runtime/dist/plugin-runtime.js +20 -10
- package/node_modules/@maka/runtime/dist/plugin-tool-service.js +205 -0
- package/node_modules/@maka/runtime/dist/provider-request-telemetry.js +8 -1
- package/node_modules/@maka/runtime/dist/request-shape.js +23 -0
- package/node_modules/@maka/runtime/dist/runtime-event-backfill.js +1 -1
- package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +24 -1
- package/node_modules/@maka/runtime/dist/runtime-kernel.js +127 -13
- package/node_modules/@maka/runtime/dist/session-manager.js +20 -36
- package/node_modules/@maka/runtime/dist/stream-graph-coordinator.js +21 -0
- package/node_modules/@maka/runtime/dist/stream-graph-supervisor-tools.js +0 -5
- package/node_modules/@maka/runtime/dist/test-connection.js +0 -1
- package/node_modules/@maka/runtime/dist/tool-activation-identity.js +41 -0
- package/node_modules/@maka/runtime/dist/tool-availability.js +11 -1
- package/node_modules/@maka/runtime/dist/tool-result-archive-resource.js +63 -1
- package/node_modules/@maka/runtime/dist/tool-result-archive-transition.js +42 -12
- package/node_modules/@maka/runtime/dist/tool-result-archive.js +27 -4
- package/node_modules/@maka/runtime/package.json +1 -0
- package/node_modules/@maka/runtime-host/dist/client/connection.js +30 -5
- package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +52 -13
- package/node_modules/@maka/runtime-host/dist/client/host-handoff.js +2 -0
- package/node_modules/@maka/runtime-host/dist/client/host-retirement.js +4 -2
- package/node_modules/@maka/runtime-host/dist/client/peer-client.js +18 -1
- package/node_modules/@maka/runtime-host/dist/client/session-subscription.js +19 -0
- package/node_modules/@maka/runtime-host/dist/control/endpoint.js +1 -3
- package/node_modules/@maka/runtime-host/dist/node-error.js +22 -0
- package/node_modules/@maka/runtime-host/dist/operator/managed-deployment.js +1 -3
- package/node_modules/@maka/runtime-host/dist/peer-mesh/limits.js +0 -1
- package/node_modules/@maka/runtime-host/dist/peer-mesh/model.js +1 -1
- package/node_modules/@maka/runtime-host/dist/peer-reachability/publisher.js +1 -3
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +9 -1
- package/node_modules/@maka/runtime-host/dist/protocol/operations.js +3 -2
- package/node_modules/@maka/runtime-host/dist/protocol/plan.js +1 -0
- package/node_modules/@maka/runtime-host/dist/protocol/plugin-platform.js +27 -5
- package/node_modules/@maka/runtime-host/dist/protocol/project-catalog.js +2 -2
- package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +1 -0
- package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +86 -157
- package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +4 -0
- package/node_modules/@maka/runtime-host/dist/server/agent-graph-coordinator.js +0 -3
- package/node_modules/@maka/runtime-host/dist/server/canonical-session-projection.js +2 -1
- package/node_modules/@maka/runtime-host/dist/server/connection-session.js +28 -8
- package/node_modules/@maka/runtime-host/dist/server/daily-review-coordinator.js +112 -56
- package/node_modules/@maka/runtime-host/dist/server/execution-artifacts.js +32 -32
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +85 -25
- package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +42 -14
- package/node_modules/@maka/runtime-host/dist/server/failure-diagnostic.js +24 -0
- package/node_modules/@maka/runtime-host/dist/server/goal-coordinator.js +7 -3
- package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +3 -3
- package/node_modules/@maka/runtime-host/dist/server/host-session-availability.js +5 -2
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +3 -2
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-tool-profile.js +34 -4
- package/node_modules/@maka/runtime-host/dist/server/interactive-run-composer.js +51 -23
- package/node_modules/@maka/runtime-host/dist/server/operation-dispatcher.js +2 -7
- package/node_modules/@maka/runtime-host/dist/server/plugin-platform-coordinator.js +6 -0
- package/node_modules/@maka/runtime-host/dist/server/plugin-platform.js +6 -0
- package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +110 -14
- package/node_modules/@maka/runtime-host/dist/server/runtime-resource-coordinator.js +11 -8
- package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +31 -21
- package/node_modules/@maka/runtime-host/dist/server/serial-outbound-writer.js +1 -1
- package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +20 -8
- package/node_modules/@maka/runtime-host/dist/server/session-retirement-coordinator.js +5 -2
- package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +4 -0
- package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +15 -104
- package/node_modules/@maka/runtime-host/dist/server/shared-session-transcript.js +3 -0
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +59 -82
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +132 -139
- package/node_modules/@maka/runtime-host/dist/server/workhub-message-attachments.js +46 -0
- package/node_modules/@maka/storage/dist/agent-run-store.js +14 -1
- package/node_modules/@maka/storage/dist/artifact-store.js +40 -3
- package/node_modules/@maka/storage/dist/atomic-file-write.js +74 -0
- package/node_modules/@maka/storage/dist/claude-code-session-adapter.js +0 -1
- package/node_modules/@maka/storage/dist/codex-session-adapter.js +284 -196
- package/node_modules/@maka/storage/dist/credential-store.js +12 -63
- package/node_modules/@maka/storage/dist/execution-stores.js +4 -1
- package/node_modules/@maka/storage/dist/git-exec.js +61 -0
- package/node_modules/@maka/storage/dist/git-worktree-child-executor.js +8 -35
- package/node_modules/@maka/storage/dist/goal-authority.js +2 -2
- package/node_modules/@maka/storage/dist/interaction-store.js +2 -2
- package/node_modules/@maka/storage/dist/mcp-config-store.js +10 -25
- package/node_modules/@maka/storage/dist/project-catalog.js +2 -23
- package/node_modules/@maka/storage/dist/runtime-event-invariants.js +2 -2
- package/node_modules/@maka/storage/dist/runtime-policy/connection-catalog-document.js +8 -3
- package/node_modules/@maka/storage/dist/scheduled-task-store.js +249 -283
- package/node_modules/@maka/storage/dist/session-bundle-manifest.js +5 -17
- package/node_modules/@maka/storage/dist/session-bundle-policy.js +2 -1
- package/node_modules/@maka/storage/dist/session-copy-cleanup.js +2 -1
- package/node_modules/@maka/storage/dist/session-store.js +14 -2
- package/node_modules/@maka/storage/dist/settings-store.js +8 -4
- package/node_modules/@maka/storage/dist/sqlite-artifact-metadata.js +11 -0
- package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +1 -2
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-schema.js +12 -1
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +67 -3
- package/node_modules/@maka/storage/dist/stable-storage.js +14 -1
- package/node_modules/@maka/storage/dist/storage-id.js +28 -0
- package/node_modules/@maka/storage/dist/tool-result-archive-evidence.js +31 -4
- package/node_modules/@maka/storage/dist/workspace-identity.js +2 -15
- package/node_modules/@maka/storage/dist/workspace-version-authority-internal.js +1 -8
- package/package.json +1 -1
- package/node_modules/@maka/core/dist/workhub-creation-intent.js +0 -990
- package/node_modules/@maka/core/dist/workhub-session-resolver.js +0 -50
|
@@ -1,990 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
-
* or more contributor license agreements. See the NOTICE file
|
|
4
|
-
* distributed with this work for additional information
|
|
5
|
-
* regarding copyright ownership. The ASF licenses this file
|
|
6
|
-
* to you under the Apache License, Version 2.0 (the
|
|
7
|
-
* "License"); you may not use this file except in compliance
|
|
8
|
-
* with the License. You may obtain a copy of the License at
|
|
9
|
-
*
|
|
10
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
-
*
|
|
12
|
-
* Unless required by applicable law or agreed to in writing,
|
|
13
|
-
* software distributed under the License is distributed on an
|
|
14
|
-
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
15
|
-
* KIND, either express or implied. See the License for the
|
|
16
|
-
* specific language governing permissions and limitations
|
|
17
|
-
* under the License.
|
|
18
|
-
*/
|
|
19
|
-
const EXPLICIT_CREATION = /(?:创建|新建|新开|开一个)(?:一个)?(?:全新的?|新的?)?(?:普通)?\s*(?:Session|会话|工作|任务)|\b(?:creat(?:e|ing)|start(?:ing)?|open(?:ing)?)\s+(?:a\s+)?(?:brand[- ]new|new)\s+(?:session|work|task)\b/iu;
|
|
20
|
-
const NEGATOR = /(?:(?:不是|并非)(?:要|想|让你|叫你|请你|说要|打算|准备)|没(?:有)?(?:要|想|让你|叫你|请你|说要|打算|准备)|未(?:打算|准备|想|要)|不希望(?:你)?|不要|别|无需|不用|不需要|先不|暂不|禁止|请勿|切勿|不可|不能|不准|不想|不打算|无意|莫|勿)|\b(?:under\s+no\s+circumstances|do\s+not|don't|never|without|must\s+not|should\s+not|cannot|can't|may\s+not|will\s+not|won't|would\s+not|wouldn't|no\s+need\s+to|refrain\s+from|refuse\s+to|decline\s+to|avoid|not(?!\s+only\b))\b/iu;
|
|
21
|
-
const ANAPHORIC_CANCELLATION = /(?:不要|别|无需|不用|不需要|先不|暂不|请勿|切勿|不可|不能|不准)(?:再)?(?:这样|这么|照此)(?:做|操作|执行)?|(?:算了|取消)(?:吧|这个|这项操作)?|\b(?:(?:do\s+not|don't|never|must\s+not|should\s+not|cannot|can't)\s+(?:do\s+)?(?:that|it)|(?:cancel|scratch)\s+(?:that|it)|never\s+mind)\b/iu;
|
|
22
|
-
const BARE_TRAILING_CANCELLATION = /(^|\r\n|[\r\n,.!?;,。!?;—–-]|\b(?:but|and(?:\s+then)?)\b|不过|但是|但|然后|随后)([^\S\r\n]*)((?:还是)?(?:别|不要)了|(?:actually\s*,?\s*)?(?:do\s+not|don't))\s*[.!?。!?]?\s*$/iu;
|
|
23
|
-
const ABBREVIATION_BEFORE_BOUNDARY = /(?:\b[a-z0-9]\.[a-z0-9]|\b(?:etc|vs|mr|mrs|dr))\.\s*,?$/iu;
|
|
24
|
-
const MULTILINE_LITERAL_INTRODUCER = /[::]\s*$/u;
|
|
25
|
-
const EXACT_LITERAL_HEADER = /^(?:(?:this|the|these|following|list)\s+)?(?:token|tokens|value|values|label|labels|literal|literals|input|inputs|code|example|examples|case|cases|item|items|text|string|strings)$|^(?:此|这个|这些|以下)?(?:文案|值|文本|字符串|输入|代码|示例|字面量|令牌)$/iu;
|
|
26
|
-
const ACTION_INTRODUCER_PREFIX = /^(?:please|(?:can|could|would)\s+you|请|帮我|请帮我|麻烦(?:你)?)?$/iu;
|
|
27
|
-
const STRUCTURED_LITERAL_LINE = /^\s*(?:(?:[-*+]|\d+[.)])\s*)?(?:(?:do\s+not|don't)|(?:还是)?(?:别|不要)了)\s*[.!?。!?]?\s*$/iu;
|
|
28
|
-
const PRIOR_STRUCTURED_LITERAL_ITEM = /^(?:\t| {4}|\s*(?:[-*+]|\d+[.)])\s+\S)/u;
|
|
29
|
-
const EXECUTION_ACTION = /(?:修复|修改|更新|实现|创建|新增|删除|移除|处理|完成|运行|测试|提交|推送|检查|诊断|复现|优化|补充|整理)|\b(?:fix|modify|implement|update|create|add|remove|delete|handle|finish|run|test|commit|push|check|optimize|try|reproduce|diagnose|work)\b/iu;
|
|
30
|
-
const CREATION_ACTION = /(?:创建|新建|新开|开一个)|\b(?:create|start|open)\b/iu;
|
|
31
|
-
const ANAPHORIC_OBJECT = /^\s*(?:(?:it|one|that|this)\b|(?:它|这个|这项工作|这项任务))/iu;
|
|
32
|
-
const DELIBERATIVE_REQUEST = /^\s*(?:(?:(?:我们|我)\s*)?(?:是否|要不要|该不该|应不应该|能不能|可不可以|为什么|如何|怎么|想知道(?:是否|为什么|如何|怎么)|应该(?:如何|怎么))|(?:should|whether|why|how|(?:can|could|would)\s+(?:we|i)|what\s+(?:is|are|was|were|should|would|could|do|does|did|can))\b|(?:i|we)\s+(?:(?:want|would\s+like)\s+to\s+(?:know|understand)|wonder)\s+(?:whether|why|how)\b|(?:(?:(?:can|could|would)\s+you\s+)?(?:(?:please|kindly)\s+)?(?:explain|discuss|consider|tell\s+me|help\s+me\s+understand)\s+(?:whether|why|how|when|if|in\s+which\s+cases?)\b)|(?:(?:请|帮我|请帮我|麻烦(?:你)?)\s*)?(?:解释|讨论|考虑|告诉我|帮我理解).{0,18}(?:是否|为什么|如何|怎么|何时|什么时候|在什么情况))/iu;
|
|
33
|
-
const ADVISORY_SPEECH_ACT = /^\s*(?:(?:can|could|would)\s+you(?:\s+(?:please|kindly))?|please|kindly)?\s*(?:recommend|suggest|advise|explain|discuss|consider|tell\s+me|help\s+me\s+understand|show\s+me|teach\s+me|walk\s+me\s+through)\b|^\s*(?:(?:请|帮我|请帮我|麻烦(?:你)?)\s*)?(?:建议|解释|讨论|考虑|告诉我|帮我理解|教我|讲讲)/iu;
|
|
34
|
-
const COORDINATED_DIRECT_ACTION_PREFIX = /(?:(?:[,.;]\s*)(?:(?:and|but)\s*)?|(?:and\s+then|then)\s*|(?:[,。;]\s*)(?:(?:并且|并|但|不过)\s*)?|然后\s*)$/iu;
|
|
35
|
-
const ADVISORY_MATRIX_ACTION_BOUNDARY = /(?:,\s*(?:and|but|then)|[.;]\s*(?:(?:and|but|then)\s*)?|,\s*(?:然后|并且|并|但|不过)|[。;]\s*(?:(?:然后|并且|并|但|不过)\s*)?)\s*$/iu;
|
|
36
|
-
const BARE_COORDINATED_ACTION_PREFIX = /(?:\band\s*|并且\s*|并\s*)$/iu;
|
|
37
|
-
const ADVISORY_COMPLEMENT_NOUN = /\b(?:ways?|methods?|techniques?|approaches?|circumstances?|cases?|steps?|options?|strategies?|solutions?|patterns?|process(?:es)?|procedures?|frameworks?|workflows?|proposals?|tools?)\b|(?:方法|方式|技巧|方案|步骤|流程|框架|工作流|提案|工具|选项|策略|模式|情形|情况)/iu;
|
|
38
|
-
const ADVISORY_COMPLEMENT_RELATIVE = /\b(?:to|that|which|where)\b[^,.;!?]{0,80}\band\s*$/iu;
|
|
39
|
-
const TRAILING_QUESTION = /[??]\s*$/u;
|
|
40
|
-
const DELIBERATIVE_LEAD_MARKER = /\b(?:how|why|whether|when)\b|\bin\s+which\s+cases?\b|\bif\s+(?:(?:i|we|you|they|it)\s+(?:should|could|would|can|need|must|ought)\b|it\s+is\s+necessary\b)|\b(?:what|which)\s+(?:steps?|approach|method|way|cases?)\b|\b(?:show|teach)\s+me\b|\bwalk\s+me\s+through\b|(?:想知道|想了解|是否|应否|要不要|该不该|应不应该|能不能|可不可以|为什么|如何|怎么|何时|什么时候|在什么情况|教我|讲讲)/iu;
|
|
41
|
-
const DIRECT_EXECUTION_PREFIX = /^\s*(?:(?:(?:if|when)\b[^,\r\n]{1,80}?(?:,\s*|\bthen\s+|\s+(?=(?:can|could|would)\s+you\b))|如果[^,\r\n]{1,48}?(?:,\s*|然后\s*|\s+(?=请|帮我|请帮我|麻烦))))?(?:(?:can|could|would)\s+you(?:\s+(?:please|kindly))?|(?:i\s+(?:want|need|would\s+like)|we\s+need)\s+(?:you\s+)?to|let['’]s|let\s+us|please|kindly|请|帮我|请帮我|麻烦(?:你)?|我想(?:让你)?|我要(?:让你)?|我们需要(?:你)?)?\s*$/iu;
|
|
42
|
-
const CONDITIONAL_EXECUTION_PREFIX = /^\s*(?:(?:if|when)\b[^??\r\n]{1,80}|如果[^??\r\n]{1,48})\s*$/iu;
|
|
43
|
-
const ELLIPTICAL_CONDITIONAL_PREFIX = /^\s*(?:if|when)\s+(?:needed|required|necessary|possible|safe|appropriate|convenient|ready|available|feasible|desired|applicable|practical|advisable|permitted|complete|urgent|sensible)\s*$/iu;
|
|
44
|
-
const DELIBERATIVE_CONDITIONAL_PREFIX = /^(?:(?:if|when)\s+(?:(?:the\s+)?[\p{L}][\p{L}'’-]*|[^,,??]{1,64}\b(?:should|could|would|can|need|must|ought|will|may|might|do|does|did|is|are|was|were|has|have|had))|如果(?:(?:我|我们|你|你们|他们|她们|它们)|[^,,??]{1,32}(?:能|会|将|要|可以|应该)))\s*$|\bif\s+(?:i|we|you|they|it)\s+(?:should|could|would|can|need|must|ought)\b|\bwhen\s+(?:should|could|would|can|may|might|must|ought|will|do|does|did|is|are|was|were)\b|\bif\b[^,,??]{0,64}\b(?:think|believe|suppose|wonder|feel|guess|asked?|wanted?|preferred?)\b|\bif\b[^,,??]{0,64}\bplan\s+(?:is|was|were|would\s+be)\s+to\b|\b(?:if|when)\b[^,,]{0,64}\b(?:whether|how|why|unsure|uncertain|unclear|appropriate|advisable|wise|good\s+idea|makes?\s+sense|in\s+doubt|ask)\b|如果[^,,]{0,32}(?:是否|应否|应不应该|该不该|要不要|什么时候|不确定|不清楚|疑问|适合|合适|可行|明智|合理|(?:我|我们)?(?:让|叫|要求)你)/iu;
|
|
45
|
-
const POST_ACTION_DELIBERATIVE = /\b(?:or|but|however|actually|instead)\b[^??\r\n]{0,80}\b(?:should|could|would|maybe|perhaps|not\s+sure|changed?\s+(?:my|our)\s+mind|take\s+(?:it|that)\s+back)\b|(?:^|[.;!?])\s*(?:(?:on\s+second\s+thought)\s*,?\s*)?(?:(?:maybe|perhaps)\b|(?:(?:do\s+you\s+(?:think|agree)|(?:is|are|was|were|do|does|did|can|could|should|would)\s+(?:i|we|it|that|this)|(?:are|were)\s+(?:you|they)\s+sure)\b|(?:i|we)(?:\s+(?:am|are)|['’](?:m|re))?\s+not\s+sure))|(?:还是|或者|但是|但|不过|其实|不然|[。;!?])[^??\r\n]{0,48}(?:应该|要不要|是否|也许|可能|不确定|改主意|等等|先等|搁置|明智|合适|合理|可行|可以吗|好吗|妥当)|(?:合适|合理|可行|明智|妥当|可以吗|好吗)\s*吗???\s*$/iu;
|
|
46
|
-
const POST_ACTION_QUESTION_ALTERNATIVE = /\bor\b|还是|或者/iu;
|
|
47
|
-
const POST_ACTION_QUESTION_CLAUSE_LEAD = /^(?:what|how|why|whether|when|who|where)\b|^(?:would|could|should|can|do|does|did|is|are|was|were|will|may|might|must)\s+(?:i|we|you|they|it|that|this|the)\b|^(?:什么|如何|为什么|是否|何时|什么时候|谁|哪里|哪种|可以|应该|要不要|是不是)/iu;
|
|
48
|
-
const POST_ACTION_EMBEDDED_QUESTION = /\b(?:what|how|why|whether|when|who|where)\s+(?:would|could|should|will|can|do|does|did|is|are)\b|\b(?:would|could|should|can|will|may|might|must)\s+(?:that|this|it|the)\b|(?:会怎样|会如何|怎么办|是否合适|是否可行)/iu;
|
|
49
|
-
const POST_ACTION_UNCERTAINTY_TAG = /^(?:maybe|perhaps|okay|ok|right|agreed|not\s+sure|any\s+(?:concerns?|objections?)|sound\s+good)\b|^(?:可以吗|好吗|行吗|对吗|没问题吧|有问题吗|有疑问吗)/iu;
|
|
50
|
-
const UNQUOTED_LITERAL_QUESTION_TARGET = /\b(?:to|as|say(?:ing)?|answer(?:ing)?(?:\s+the\s+question)?)\s+(?:what|how|why|when|where|who)\b/iu;
|
|
51
|
-
const POSITIVE_CONTRAST = /而是|\b(?:but|instead)\b/iu;
|
|
52
|
-
const HARD_CLAUSE_BOUNDARY = /[.!?;。!?;]/u;
|
|
53
|
-
const SOFT_CLAUSE_BOUNDARY = /[,,]/u;
|
|
54
|
-
const ACTION_TARGET_SCAFFOLDING = /^(?:(?:\s+\b(?:and|then|also|please|kindly|really|actually|absolutely|just|simply|can|could|would|you)\b)|(?:并且|并|且|然后|随后|请|麻烦|你|真的|确实|务必|千万))+\s*$/iu;
|
|
55
|
-
const CORRECTION_CUE = /^\s*(?:(?:不是|不要再继续)\s*(?:这个|那个|当前这个|刚才那个)(?:工作|任务|Session|会话)?|(?:这个|那个|当前这个|刚才那个)(?:工作|任务|Session|会话)?\s*(?:不对|搞错了|弄错了)|(?:不对|错了|搞错了|弄错了)|(?:no|nope)\b(?=\s*[,.;:!?—–-])|not\s+(?:this|that|the\s+current)(?:\s+(?:one|session|work|task))?|wrong\s+(?:one|session|work|task))/iu;
|
|
56
|
-
const CORRECTION_RETARGET_ACTION = /(?:应该(?:是|用|改成|改为|切到|转到)|而是|改成|改为|换成|换到|切到|转到|用)|\b(?:use|switch(?:\s+(?:it|this|that))?\s+to|change(?:\s+(?:it|this|that))?\s+to|move(?:\s+(?:it|this|that))?\s+to|send(?:\s+(?:it|this|that))?\s+to)\b/iu;
|
|
57
|
-
const CORRECTION_CLAUSE_BOUNDARY = /[\r\n,.;!?,。;!?—–]/u;
|
|
58
|
-
const CORRECTION_TRAILING_WITHDRAWAL = /(?:(?:\b(?:but|however|actually|and(?:\s+then)?)\b|[,.;!?—–])[^\r\n]{0,80}\b(?:(?:do\s+not|don't)\s+(?:(?:want|intend|plan)\s+to\s+)?(?:move|switch|change|send|use|do)|never(?:\s+(?:move|switch|change|send|use|do|again|mind))?|no\s+longer\s+(?:move|switch|change|send|use|do))\b|(?:但|不过|其实|然后|随后|[,。;!?])[^\r\n]{0,48}(?:不想|不要|别|不再|不用)[^\r\n]{0,12}(?:转|换|切|用|做|了))/iu;
|
|
59
|
-
const TERMINAL_WITHDRAWAL_CLAUSE = /(?:^|[\r\n,.;!?—–-]|\b(?:and|then|but|or|however|actually|instead)\b)\s*(?:abort|cancel|stop|halt|cease|quit|pause|terminate|withdraw|revoke|abandon|retract|forget)(?:\s+(?:(?:it|this|that|my|our|your|the)(?:\s+(?:operation|work|request|job|task|session|creation|change|action))?|everything|all|(?:the\s+)?new\s+session))?(?:\s+(?:immediately|now|here|for\s+now))?[.!?]?\s*$|(?:^|[\r\n,.;!?—–-]|\b(?:and|then|but|or|however|actually|instead)\b)\s*(?:(?:on\s+second\s+thought)\s*,?\s*)?(?:(?:maybe|perhaps)\s+)?(?:(?:(?:should|could|would)\s+(?:we|i)|(?:we|i)\s+(?:should|could|would))\s+)?(?:wait|hold\s+off|leave\s+(?:it|this|that)(?:\s+(?:here|alone|for\s+now))?|keep\s+(?:it|this|that)\s+here|scratch\s+(?:it|this|that)|stand\s+down|back\s+out|call\s+it\s+off|do\s+nothing|take\s+(?:it|that)\s+back)[.!?]?\s*$|(?:^|[\r\n,.;!?—–-]|\b(?:and|then|but|or|however|actually|instead)\b)\s*(?:(?:on\s+second\s+thought)\s*,?\s*)?(?:(?:i|we)(?:\s+(?:have|had))?\s+changed?\s+(?:my|our)\s+mind|(?:i|we)(?:\s+(?:am|are)|['’](?:m|re))?\s+not\s+sure|(?:i\s+)?take\s+(?:it|that)\s+back)[.!?]?\s*$/iu;
|
|
60
|
-
// Extends the compact terminal-state grammar above with polite speech acts,
|
|
61
|
-
// qualified objects, and unambiguous command synonyms.
|
|
62
|
-
const TERMINAL_QUALIFIED_WITHDRAWAL_COMMAND = /(?:^|[\r\n,.;!?,。!?;—–-]|\b(?:and|then|but|or|however|actually|instead)\b|然后|随后|但是|但|不过|其实|还是|或者)\s*(?:(?:(?:please|kindly|let['’]s|let\s+us|(?:can|could|would)\s+you|(?:i|we)\s+(?:(?:would\s+)?prefer|want|need|would\s+like)\s+to)\s+)(?:abort|cancel|stop|halt|cease|quit|pause|terminate|withdraw|revoke|abandon|retract|forget|rescind|drop|scrap|undo|discontinue|ditch|discard)(?:\s+(?:(?:it|this|that)(?:\s+(?:operation|work|request|job|task|session|creation|change|action))?|(?:(?:my|our|your|the)\s+)?(?:(?:current|pending|active|existing|new)\s+)?(?:operation|work|request|job|task|session|creation|change|action)|everything|all))?|(?:abort|cancel|stop|halt|cease|quit|pause|terminate|withdraw|revoke|abandon|retract|forget)\s+(?:(?:my|our|your|the)\s+)?(?:current|pending|active|existing)\s+(?:operation|work|request|job|task|session|creation|change|action)|(?:rescind|drop|scrap|undo|discontinue|ditch|discard)(?:\s+(?:(?:it|this|that)(?:\s+(?:operation|work|request|job|task|session|creation|change|action))?|(?:(?:my|our|your|the)\s+)?(?:(?:current|pending|active|existing|new)\s+)?(?:operation|work|request|job|task|session|creation|change|action)|everything|all))?)(?:\s+(?:immediately|now|here|for\s+now))?[.!?]?\s*$/iu;
|
|
63
|
-
const TERMINAL_NEGATED_CONTINUATION = /(?:^|[\r\n,.;!?,。!?;::—–-]|\b(?:and|then|but|or|however|actually|instead)\b|然后|随后|但是|但|不过|其实|还是|或者)\s*(?:please\s+)?(?:(?:(?:i|we)\s+)?(?:do\s+not|don't|never)\s+(?:(?:wish|want|prefer|intend|plan)\s+to\s+)?(?:proceed|continue|go\s+ahead)(?:\s+(?:with\s+)?(?:(?:it|this|that)|(?:(?:my|our|your|the)\s+)?(?:current\s+)?(?:operation|work|request|job|task|session|creation|change|action)))?|never\s+mind)[.!?]?\s*$/iu;
|
|
64
|
-
const TERMINAL_CHINESE_WITHDRAWAL = /(?:^|[\r\n,。;!?—–-]|然后|随后|但是|但|不过|其实|还是|或者)\s*(?:(?:不要|别|不想|不再|不用)(?:再)?(?:继续|执行|推进|转|换|切|用|做)|(?:作罢|取消|停止|停下|中止|终止|放弃|暂停|算了|撤回)(?:吧|它|这个|这项(?:操作|工作|请求)|全部|现在|执行|创建(?:新(?:的)?(?:会话|工作|任务))?)?|(?:(?:也许|可能)?(?:还是)?(?:应该|可以)?\s*)?(?:等等|先等|搁置|推迟|我(?:改主意了?|不确定|再想想))|当我没说|维持原样|保持原样|还是算了)[。!?]?\s*$/iu;
|
|
65
|
-
const CREATION_REQUEST_PREFIX = /^(?:(?:please|kindly|(?:can|could|would)\s+you|i\s+(?:want|need|would\s+like)\s+to|we\s+need\s+to|let['’]s)|(?:请|帮我|请帮我|麻烦(?:你)?|我想|我要|我们需要))?\s*$/iu;
|
|
66
|
-
const NAMED_CREATION_TITLE_INTRODUCER = /\b(?:new|brand[- ]new)\s+(?:session|work|task)[\s,,::-]+(?:(?:called|named|titled)|with\s+(?:the\s+)?title)\s+|(?:新的?|全新的?)?\s*(?:Session|会话|工作|任务)[\s,,::-]*(?:叫做?|名叫|名为|命名为|标题为|名称为|名字为)\s*/iu;
|
|
67
|
-
const LEADING_CORRECTION_SEPARATOR = /^[\s,.;:!?,。;:!?—–-]+/u;
|
|
68
|
-
const DIRECT_STOP_REQUEST = /^\s*(?:(?:please|kindly)\s+)?(?:stop|cancel|terminate|halt)\s+(?:(?:the|this)\s+)?(?:(?:session|work|task|job)\s+)?(.+?)\s*[.!。!]?\s*$/iu;
|
|
69
|
-
// `停掉` and `停下` are the spoken forms of `停止`, as ordinary as the written
|
|
70
|
-
// one. Without them `停掉支付任务` was not a stop at all, so the words were
|
|
71
|
-
// delivered to Payments as new work — the opposite of what was asked. English
|
|
72
|
-
// covers its own colloquial range with stop/cancel/terminate/halt; this is the
|
|
73
|
-
// same range, not a wider claim. `关掉` stays out: it reads as "switch off",
|
|
74
|
-
// which is usually work to do inside a Session, and English admits no
|
|
75
|
-
// equivalent either.
|
|
76
|
-
const DIRECT_CHINESE_STOP_REQUEST = /^\s*(?:(?:请|请帮我|帮我|麻烦你?)\s*)?(?:停止|停掉|停下|取消|终止|中止)\s*(?:(?:这个|该)?(?:会话|工作|任务)\s*)?(.+?)\s*[。!]?\s*$/iu;
|
|
77
|
-
const DIRECT_RESUME_REQUEST = /^\s*(?:(?:please|kindly)\s+)?resume\s+(?:(?:the|this)\s+)?(?:(?:session|work|task|job)\s+)?(.+?)\s*[.!。!]?\s*$/iu;
|
|
78
|
-
const DIRECT_CHINESE_RESUME_REQUEST = /^\s*(?:(?:请|请帮我|帮我|麻烦你?)\s*)?(?:恢复|恢復|接着跑|接著跑)\s*(?:(?:这个|该)?(?:会话|工作|任务)\s*)?(.+?)\s*[。!]?\s*$/iu;
|
|
79
|
-
const UNSAFE_NAMED_ACTION_TARGET = /^(?:it|this|that|one|everything|all|current|session|work|task|job|(?:this|that|current)\s+(?:session|work|task|job)|它|这个|那个|全部|当前|会话|工作|任务|(?:这个|那个|当前)(?:会话|工作|任务))$/iu;
|
|
80
|
-
/**
|
|
81
|
-
* Whether trusted user text affirmatively asks WorkHub to create a new Session.
|
|
82
|
-
*
|
|
83
|
-
* Routing is advisory, so both renderer policy and the Runtime Action Gate use
|
|
84
|
-
* this conservative predicate. Weak punctuation never separates a negator from
|
|
85
|
-
* its creation verb; only an explicit contrast can introduce a later positive
|
|
86
|
-
* creation clause.
|
|
87
|
-
*/
|
|
88
|
-
function isExplicitWorkHubCreationRequest(value) {
|
|
89
|
-
const normalized = value.replace(/[’‘]/gu, "'");
|
|
90
|
-
const creations = allMatches(normalized, EXPLICIT_CREATION);
|
|
91
|
-
if (creations.length === 0 ||
|
|
92
|
-
isDeliberative(normalized) ||
|
|
93
|
-
hasUnquotedTerminalWithdrawal(normalized) ||
|
|
94
|
-
hasUnsafeUnquotedNamedCreationTail(normalized) ||
|
|
95
|
-
!creations.some((creation) => hasAffirmativeCreationGrammar(normalized, creation))) {
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
|
-
return !hasNegatedWorkHubCreationRequest(normalized);
|
|
99
|
-
}
|
|
100
|
-
/** The explicit title when an affirmative creation request names its new Session. */
|
|
101
|
-
function affirmativeWorkHubNamedCreationTitle(value) {
|
|
102
|
-
if (!isExplicitWorkHubCreationRequest(value))
|
|
103
|
-
return undefined;
|
|
104
|
-
const normalized = value.replace(/[’‘]/gu, "'");
|
|
105
|
-
const lastIntroducer = affirmativeNamedCreationIntroducer(normalized);
|
|
106
|
-
if (lastIntroducer?.index === undefined)
|
|
107
|
-
return undefined;
|
|
108
|
-
return parseNamedCreationTitle(normalized.slice(lastIntroducer.index + lastIntroducer[0].length));
|
|
109
|
-
}
|
|
110
|
-
/** Whether the request contains syntax that explicitly names its new Session. */
|
|
111
|
-
function hasWorkHubNamedCreationClause(value) {
|
|
112
|
-
return NAMED_CREATION_TITLE_INTRODUCER.test(value.replace(/[’‘]/gu, "'"));
|
|
113
|
-
}
|
|
114
|
-
function affirmativeNamedCreationIntroducer(value) {
|
|
115
|
-
const affirmativeCreation = allMatches(value, EXPLICIT_CREATION)
|
|
116
|
-
.filter((creation) => creation.index !== undefined &&
|
|
117
|
-
hasAffirmativeCreationGrammar(value, creation) &&
|
|
118
|
-
!isMatchNegated(value, creation))
|
|
119
|
-
.at(-1);
|
|
120
|
-
if (affirmativeCreation?.index === undefined)
|
|
121
|
-
return undefined;
|
|
122
|
-
const creationStart = affirmativeCreation.index;
|
|
123
|
-
const creationEnd = creationStart + affirmativeCreation[0].length;
|
|
124
|
-
return allMatches(value, NAMED_CREATION_TITLE_INTRODUCER).find((introducer) => introducer.index !== undefined &&
|
|
125
|
-
introducer.index >= creationStart &&
|
|
126
|
-
introducer.index < creationEnd);
|
|
127
|
-
}
|
|
128
|
-
function hasAffirmativeCreationGrammar(value, creation) {
|
|
129
|
-
if (creation.index === undefined)
|
|
130
|
-
return false;
|
|
131
|
-
const correctionCue = CORRECTION_CUE.exec(value);
|
|
132
|
-
if (correctionCue?.index !== undefined) {
|
|
133
|
-
const correctionClause = value
|
|
134
|
-
.slice(correctionCue.index + correctionCue[0].length)
|
|
135
|
-
.replace(LEADING_CORRECTION_SEPARATOR, '');
|
|
136
|
-
if (isDeliberative(correctionClause))
|
|
137
|
-
return false;
|
|
138
|
-
const prefix = afterLastDecisionReset(value.slice(0, creation.index))
|
|
139
|
-
.replace(CORRECTION_CUE, '')
|
|
140
|
-
.replace(LEADING_CORRECTION_SEPARATOR, '')
|
|
141
|
-
.trim();
|
|
142
|
-
return CREATION_REQUEST_PREFIX.test(prefix);
|
|
143
|
-
}
|
|
144
|
-
return CREATION_REQUEST_PREFIX.test(afterLastDecisionReset(value.slice(0, creation.index)).trim());
|
|
145
|
-
}
|
|
146
|
-
/** Whether trusted user text negates creation rather than authorizing it. */
|
|
147
|
-
function hasNegatedWorkHubCreationRequest(value) {
|
|
148
|
-
const normalized = value.replace(/[’‘]/gu, "'");
|
|
149
|
-
const lastCreation = lastMatch(normalized, EXPLICIT_CREATION);
|
|
150
|
-
const trailing = lastCreation?.index === undefined
|
|
151
|
-
? ''
|
|
152
|
-
: normalized.slice(lastCreation.index + lastCreation[0].length);
|
|
153
|
-
if (lastCreation?.index !== undefined &&
|
|
154
|
-
(ANAPHORIC_CANCELLATION.test(trailing) ||
|
|
155
|
-
hasBareTrailingCancellation(normalized) ||
|
|
156
|
-
hasNegatedAnaphoricCreation(normalized, lastCreation))) {
|
|
157
|
-
return true;
|
|
158
|
-
}
|
|
159
|
-
let lastDecision;
|
|
160
|
-
for (const segment of normalized.split(POSITIVE_CONTRAST)) {
|
|
161
|
-
const creation = lastMatch(segment, EXPLICIT_CREATION);
|
|
162
|
-
if (!creation || creation.index === undefined)
|
|
163
|
-
continue;
|
|
164
|
-
lastDecision = NEGATOR.test(segment.slice(0, creation.index));
|
|
165
|
-
}
|
|
166
|
-
return lastDecision ?? false;
|
|
167
|
-
}
|
|
168
|
-
/** Whether already-normalized, literal-masked text is an executable instruction. */
|
|
169
|
-
/**
|
|
170
|
-
* `naming` is resolved from the unmasked text by the caller. A quoted title is
|
|
171
|
-
* a literal span, so the mask blanks it, and re-deriving the title from masked
|
|
172
|
-
* text would read every quoted name as an unusable one — the reason
|
|
173
|
-
* `Create a new Session called "Payments"` was refused while the same sentence
|
|
174
|
-
* without quotes was admitted. The mask still decides everything else here: it
|
|
175
|
-
* exists so quoted words cannot be read as commands, and that is unchanged.
|
|
176
|
-
*/
|
|
177
|
-
function isImperativeWorkHubNewTopicRequest(normalized, naming) {
|
|
178
|
-
const actions = allMatches(normalized, EXECUTION_ACTION);
|
|
179
|
-
if (isDeliberative(normalized) || hasUnquotedTerminalWithdrawal(normalized)) {
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
if (naming.kind === 'unusable') {
|
|
183
|
-
return false;
|
|
184
|
-
}
|
|
185
|
-
const explicitCreation = isExplicitWorkHubCreationRequest(normalized);
|
|
186
|
-
if (EXPLICIT_CREATION.test(normalized) &&
|
|
187
|
-
!isExplicitWorkHubCreationRequest(normalized) &&
|
|
188
|
-
actions.length > 0 &&
|
|
189
|
-
actions.every((action) => CREATION_ACTION.test(action[0]))) {
|
|
190
|
-
return false;
|
|
191
|
-
}
|
|
192
|
-
if (hasNegatedWorkHubCreationRequest(normalized)) {
|
|
193
|
-
const lastCreation = lastMatch(normalized, EXPLICIT_CREATION);
|
|
194
|
-
if (!lastCreation || lastCreation.index === undefined)
|
|
195
|
-
return false;
|
|
196
|
-
if (isMatchNegated(normalized, lastCreation))
|
|
197
|
-
return false;
|
|
198
|
-
const trailing = normalized.slice(lastCreation.index + lastCreation[0].length);
|
|
199
|
-
return [...executionActionDecisions(trailing).values()].some(Boolean);
|
|
200
|
-
}
|
|
201
|
-
return ((explicitCreation || hasAffirmativeExecutableGrammar(normalized, actions)) &&
|
|
202
|
-
[...executionActionDecisions(normalized).values()].some(Boolean));
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Read trusted user text once at the WorkHub intent boundary.
|
|
206
|
-
*
|
|
207
|
-
* Heuristics may demote toward doing nothing; they must never promote an
|
|
208
|
-
* advisory or malformed phrase into authority to create work.
|
|
209
|
-
*/
|
|
210
|
-
export function readWorkHubRequestIntent(value) {
|
|
211
|
-
const literalMask = maskLiteralSpans(value);
|
|
212
|
-
const source = value.replace(/[’‘]/gu, "'");
|
|
213
|
-
const masked = literalMask.value.replace(/[’‘]/gu, "'");
|
|
214
|
-
const explicit = isExplicitWorkHubCreationRequest(masked);
|
|
215
|
-
const hasNamingClause = hasWorkHubNamedCreationClause(source);
|
|
216
|
-
const namedTitle = explicit ? affirmativeWorkHubNamedCreationTitle(source) : undefined;
|
|
217
|
-
const naming = !hasNamingClause
|
|
218
|
-
? { kind: 'none' }
|
|
219
|
-
: namedTitle
|
|
220
|
-
? { kind: 'named', title: namedTitle }
|
|
221
|
-
: { kind: 'unusable' };
|
|
222
|
-
const correctionCue = hasWorkHubCorrectionCue(source);
|
|
223
|
-
const existingTarget = affirmativeWorkHubExistingCorrectionTarget(source);
|
|
224
|
-
const stop = directWorkHubNamedAction(source, literalMask.malformed, [
|
|
225
|
-
DIRECT_STOP_REQUEST,
|
|
226
|
-
DIRECT_CHINESE_STOP_REQUEST,
|
|
227
|
-
]);
|
|
228
|
-
const resume = directWorkHubNamedAction(source, literalMask.malformed, [
|
|
229
|
-
DIRECT_RESUME_REQUEST,
|
|
230
|
-
DIRECT_CHINESE_RESUME_REQUEST,
|
|
231
|
-
]);
|
|
232
|
-
const actions = allMatches(masked, EXECUTION_ACTION);
|
|
233
|
-
const execution = literalMask.malformed || naming.kind === 'unusable' || hasDominatingDeliberation(masked)
|
|
234
|
-
? 'non_executable'
|
|
235
|
-
: hasAmbiguousAdvisoryCommand(masked, actions)
|
|
236
|
-
? 'ambiguous'
|
|
237
|
-
: isImperativeWorkHubNewTopicRequest(masked, naming)
|
|
238
|
-
? 'imperative'
|
|
239
|
-
: 'non_executable';
|
|
240
|
-
return {
|
|
241
|
-
execution,
|
|
242
|
-
creation: { explicit, naming },
|
|
243
|
-
correction: {
|
|
244
|
-
cue: correctionCue,
|
|
245
|
-
...(existingTarget ? { existingTarget } : {}),
|
|
246
|
-
},
|
|
247
|
-
stop: {
|
|
248
|
-
cue: stop.cue,
|
|
249
|
-
imperative: Boolean(stop.target),
|
|
250
|
-
...(stop.target ? { target: stop.target } : {}),
|
|
251
|
-
},
|
|
252
|
-
resume: {
|
|
253
|
-
cue: resume.cue,
|
|
254
|
-
imperative: Boolean(resume.target),
|
|
255
|
-
...(resume.target ? { target: resume.target } : {}),
|
|
256
|
-
},
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
/** Whether a parsed correction names exactly this Session. */
|
|
260
|
-
export function workHubCorrectionTargetsSession(intent, sessionName) {
|
|
261
|
-
return Boolean(intent.correction.existingTarget &&
|
|
262
|
-
correctionTargetMatchesSession(intent.correction.existingTarget, sessionName));
|
|
263
|
-
}
|
|
264
|
-
/** Whether parsed trusted text authorizes the title proposed for new work. */
|
|
265
|
-
export function workHubCreationAuthorizesTitle(intent, title) {
|
|
266
|
-
if (intent.execution !== 'imperative')
|
|
267
|
-
return false;
|
|
268
|
-
if (intent.creation.naming.kind === 'unusable')
|
|
269
|
-
return false;
|
|
270
|
-
if (intent.creation.naming.kind === 'none')
|
|
271
|
-
return true;
|
|
272
|
-
return (normalizeCorrectionIdentity(intent.creation.naming.title) === normalizeCorrectionIdentity(title));
|
|
273
|
-
}
|
|
274
|
-
/** Whether trusted user text affirmatively redirects an existing WorkHub delegation. */
|
|
275
|
-
function isAffirmativeWorkHubExistingTargetCorrectionRequest(value, expectedTargetName) {
|
|
276
|
-
const target = affirmativeWorkHubExistingCorrectionTarget(value);
|
|
277
|
-
return Boolean(target && (!expectedTargetName || correctionTargetMatchesSession(target, expectedTargetName)));
|
|
278
|
-
}
|
|
279
|
-
/** The bounded target phrase from an affirmative existing-Session correction. */
|
|
280
|
-
function affirmativeWorkHubExistingCorrectionTarget(value) {
|
|
281
|
-
const normalized = value.replace(/[’‘]/gu, "'");
|
|
282
|
-
if (!hasWorkHubCorrectionCue(normalized) || isDeliberative(normalized))
|
|
283
|
-
return undefined;
|
|
284
|
-
const actions = allMatches(normalized, CORRECTION_RETARGET_ACTION);
|
|
285
|
-
let lastDecision = false;
|
|
286
|
-
let lastAction;
|
|
287
|
-
let lastTarget = '';
|
|
288
|
-
for (const action of actions) {
|
|
289
|
-
if (action.index === undefined)
|
|
290
|
-
continue;
|
|
291
|
-
const prefix = normalized.slice(0, action.index);
|
|
292
|
-
const clausePrefix = prefix.slice(lastBoundaryEnd(prefix, CORRECTION_CLAUSE_BOUNDARY));
|
|
293
|
-
const target = normalized.slice(action.index + action[0].length).trim();
|
|
294
|
-
if (!target)
|
|
295
|
-
continue;
|
|
296
|
-
lastDecision = !NEGATOR.test(clausePrefix);
|
|
297
|
-
lastAction = action;
|
|
298
|
-
lastTarget = target;
|
|
299
|
-
}
|
|
300
|
-
if (!lastDecision || lastAction?.index === undefined)
|
|
301
|
-
return undefined;
|
|
302
|
-
const trailing = normalized.slice(lastAction.index + lastAction[0].length);
|
|
303
|
-
if (ANAPHORIC_CANCELLATION.test(trailing) ||
|
|
304
|
-
CORRECTION_TRAILING_WITHDRAWAL.test(trailing) ||
|
|
305
|
-
hasBareTrailingCancellation(normalized)) {
|
|
306
|
-
return undefined;
|
|
307
|
-
}
|
|
308
|
-
return lastTarget;
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* The one rule for reading a Session name out of a trusted reference.
|
|
312
|
-
*
|
|
313
|
-
* It is deliberately action-agnostic: it reports where the name matched and
|
|
314
|
-
* what text was left over, and says nothing about whether that leftover is
|
|
315
|
-
* acceptable. Each action's policy owns that question, because the answer
|
|
316
|
-
* genuinely differs — a stop reference may carry only punctuation after the
|
|
317
|
-
* name, while a correction may carry a further instruction.
|
|
318
|
-
*/
|
|
319
|
-
export function matchWorkHubSessionName(reference, sessionName) {
|
|
320
|
-
const normalizedTarget = normalizeCorrectionIdentity(reference);
|
|
321
|
-
const normalizedName = normalizeCorrectionIdentity(sessionName);
|
|
322
|
-
if (!normalizedName)
|
|
323
|
-
return { kind: 'none' };
|
|
324
|
-
const quotedNames = [
|
|
325
|
-
`"${normalizedName}"`,
|
|
326
|
-
`“${normalizedName}”`,
|
|
327
|
-
`'${normalizedName}'`,
|
|
328
|
-
`‘${normalizedName}’`,
|
|
329
|
-
];
|
|
330
|
-
const matchedName = [normalizedName, ...quotedNames]
|
|
331
|
-
.sort((left, right) => right.length - left.length)
|
|
332
|
-
.find((candidate) => normalizedTarget.startsWith(candidate) &&
|
|
333
|
-
!/[\p{L}\p{N}]/u.test(normalizedTarget[candidate.length] ?? ''));
|
|
334
|
-
if (!matchedName) {
|
|
335
|
-
// A name whose own trailing punctuation the reference dropped still names
|
|
336
|
-
// it, but nothing may follow: there is no boundary left to trust.
|
|
337
|
-
return /[.!。!]$/u.test(normalizedName) &&
|
|
338
|
-
normalizedTarget === normalizedName.replace(/[.!。!]+$/u, '').trim()
|
|
339
|
-
? { kind: 'elided_name_punctuation' }
|
|
340
|
-
: { kind: 'none' };
|
|
341
|
-
}
|
|
342
|
-
if (matchedName === normalizedName && hasUnsafeUnquotedHardClauseBoundary(sessionName)) {
|
|
343
|
-
return { kind: 'none' };
|
|
344
|
-
}
|
|
345
|
-
return { kind: 'named', remainder: normalizedTarget.slice(matchedName.length).trim() };
|
|
346
|
-
}
|
|
347
|
-
/** Whether a direct stop/resume reference names exactly this Session. */
|
|
348
|
-
export function workHubNamedDelegationActionTargetsSession(action, sessionName) {
|
|
349
|
-
if (!action.imperative || !action.target)
|
|
350
|
-
return false;
|
|
351
|
-
const match = matchWorkHubSessionName(action.target, sessionName);
|
|
352
|
-
return (match.kind === 'elided_name_punctuation' ||
|
|
353
|
-
(match.kind === 'named' && /^[.!?。!?]*$/u.test(match.remainder)));
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* The correction policy's tail rule. A correction may name its target and then
|
|
357
|
-
* say what to do with it, but a withdrawal anywhere in the reference retracts
|
|
358
|
-
* the whole thing.
|
|
359
|
-
*
|
|
360
|
-
* It takes a match rather than a Session name so that a caller which already
|
|
361
|
-
* resolved candidates through the shared Session Resolver applies exactly this
|
|
362
|
-
* rule to exactly that recall, instead of matching names a second time.
|
|
363
|
-
*/
|
|
364
|
-
export function workHubCorrectionAdmitsReference(reference, match) {
|
|
365
|
-
if (match.kind !== 'named' || hasUnquotedTerminalWithdrawal(reference))
|
|
366
|
-
return false;
|
|
367
|
-
const { remainder } = match;
|
|
368
|
-
if (!remainder || /^(?:instead\s*)?[.!?。!?]?$/iu.test(remainder))
|
|
369
|
-
return true;
|
|
370
|
-
const supplemental = remainder.match(/^[,;,;]\s*(.+)$/u)?.[1]?.trim();
|
|
371
|
-
const supplementalBody = supplemental?.replace(/[.!?。!?]+\s*$/u, '').trim();
|
|
372
|
-
return Boolean(supplementalBody &&
|
|
373
|
-
!/[\r\n,.!?;,。!?;—–]|\b(?:and|then|but|however|actually)\b|(?:然后|随后|但|不过|其实)/iu.test(supplementalBody) &&
|
|
374
|
-
readWorkHubRequestIntent(supplementalBody).execution === 'imperative');
|
|
375
|
-
}
|
|
376
|
-
function correctionTargetMatchesSession(target, sessionName) {
|
|
377
|
-
return workHubCorrectionAdmitsReference(target, matchWorkHubSessionName(target, sessionName));
|
|
378
|
-
}
|
|
379
|
-
function directWorkHubNamedAction(value, malformedLiteral, patterns) {
|
|
380
|
-
if (malformedLiteral || /[??]\s*$/u.test(value))
|
|
381
|
-
return { cue: false };
|
|
382
|
-
const match = patterns[0].exec(value) ?? patterns[1].exec(value);
|
|
383
|
-
const rawTarget = match?.[1]?.trim();
|
|
384
|
-
if (!rawTarget)
|
|
385
|
-
return { cue: Boolean(match) };
|
|
386
|
-
const target = stripMatchingActionQuotes(rawTarget.replace(/[.!。!]+\s*$/u, '').trim());
|
|
387
|
-
return !target || UNSAFE_NAMED_ACTION_TARGET.test(target) ? { cue: true } : { cue: true, target };
|
|
388
|
-
}
|
|
389
|
-
function stripMatchingActionQuotes(value) {
|
|
390
|
-
const pairs = new Map([
|
|
391
|
-
['"', '"'],
|
|
392
|
-
["'", "'"],
|
|
393
|
-
['“', '”'],
|
|
394
|
-
['‘', '’'],
|
|
395
|
-
]);
|
|
396
|
-
const closer = pairs.get(value[0] ?? '');
|
|
397
|
-
return closer && value.endsWith(closer) ? value.slice(1, -1).trim() : value;
|
|
398
|
-
}
|
|
399
|
-
function normalizeCorrectionIdentity(value) {
|
|
400
|
-
return value.normalize('NFKC').toLocaleLowerCase().replace(/\s+/gu, ' ').trim();
|
|
401
|
-
}
|
|
402
|
-
function hasUnquotedTerminalWithdrawal(value) {
|
|
403
|
-
const masked = maskLiteralSpans(value).value;
|
|
404
|
-
const withdrawal = TERMINAL_WITHDRAWAL_CLAUSE.exec(masked) ??
|
|
405
|
-
TERMINAL_QUALIFIED_WITHDRAWAL_COMMAND.exec(masked) ??
|
|
406
|
-
TERMINAL_NEGATED_CONTINUATION.exec(masked) ??
|
|
407
|
-
TERMINAL_CHINESE_WITHDRAWAL.exec(masked);
|
|
408
|
-
return withdrawal?.index !== undefined;
|
|
409
|
-
}
|
|
410
|
-
function hasUnsafeUnquotedNamedCreationTail(value) {
|
|
411
|
-
const introducer = affirmativeNamedCreationIntroducer(value);
|
|
412
|
-
if (introducer?.index === undefined)
|
|
413
|
-
return false;
|
|
414
|
-
const trailing = value.slice(introducer.index + introducer[0].length).trim();
|
|
415
|
-
if (!trailing || new Set(['"', "'", '“', '‘']).has(trailing[0] ?? ''))
|
|
416
|
-
return false;
|
|
417
|
-
const boundary = unquotedCreationTitleBoundary(trailing);
|
|
418
|
-
if (boundary >= trailing.length)
|
|
419
|
-
return false;
|
|
420
|
-
const separator = trailing[boundary] ?? '';
|
|
421
|
-
const suffix = trailing.slice(boundary + 1).trim();
|
|
422
|
-
if (!suffix)
|
|
423
|
-
return false;
|
|
424
|
-
const actionableSuffix = stripExecutionScaffolding(suffix);
|
|
425
|
-
if (isDeliberative(actionableSuffix) || hasUnquotedTerminalWithdrawal(actionableSuffix)) {
|
|
426
|
-
return true;
|
|
427
|
-
}
|
|
428
|
-
if (/[.!?;。!?;]/u.test(separator)) {
|
|
429
|
-
return !isScaffoldedDirectExecutableClause(actionableSuffix);
|
|
430
|
-
}
|
|
431
|
-
return !/^(?:(?:and|then|but)\b|然后|随后|但是|但|只)/iu.test(suffix);
|
|
432
|
-
}
|
|
433
|
-
function isDirectExecutableClause(value) {
|
|
434
|
-
const action = EXECUTION_ACTION.exec(value);
|
|
435
|
-
if (action?.index === undefined || !isDirectExecutionPrefix(value.slice(0, action.index))) {
|
|
436
|
-
return false;
|
|
437
|
-
}
|
|
438
|
-
return [...executionActionDecisions(value).values()].some(Boolean);
|
|
439
|
-
}
|
|
440
|
-
function isScaffoldedDirectExecutableClause(value) {
|
|
441
|
-
return isDirectExecutableClause(stripExecutionScaffolding(value));
|
|
442
|
-
}
|
|
443
|
-
function stripExecutionScaffolding(value) {
|
|
444
|
-
let current = value.trim();
|
|
445
|
-
while (current) {
|
|
446
|
-
const next = current
|
|
447
|
-
.replace(/^(?:(?:and\s+then|then|next|first|also|now|finally|afterwards?|thereafter|subsequently|eventually|immediately|urgently|promptly|directly|and|but)\b[\s,]*|(?:please|kindly|proceed\s+to|go\s+ahead\s+(?:and|to)|continue\s+to|at\s+that\s+point)\b[\s,]*|(?:然后|随后|接着|接下来|下一步|最后|并且|并|但是|但)[\s,,]*)/iu, '')
|
|
448
|
-
.trimStart();
|
|
449
|
-
if (next === current)
|
|
450
|
-
break;
|
|
451
|
-
current = next;
|
|
452
|
-
}
|
|
453
|
-
return current;
|
|
454
|
-
}
|
|
455
|
-
function parseNamedCreationTitle(value) {
|
|
456
|
-
const trailing = value.trim();
|
|
457
|
-
const quotePair = new Map([
|
|
458
|
-
['"', '"'],
|
|
459
|
-
["'", "'"],
|
|
460
|
-
['“', '”'],
|
|
461
|
-
['‘', '’'],
|
|
462
|
-
]).get(trailing[0] ?? '');
|
|
463
|
-
if (quotePair) {
|
|
464
|
-
const closing = trailing.indexOf(quotePair, 1);
|
|
465
|
-
return closing > 1 ? trailing.slice(1, closing).trim() || undefined : undefined;
|
|
466
|
-
}
|
|
467
|
-
const boundary = unquotedCreationTitleBoundary(trailing);
|
|
468
|
-
return (trailing
|
|
469
|
-
.slice(0, boundary)
|
|
470
|
-
.trim()
|
|
471
|
-
.replace(/[.!?。!?]+\s*$/u, '')
|
|
472
|
-
.replace(/\s+instead\s*$/iu, '')
|
|
473
|
-
.trim() || undefined);
|
|
474
|
-
}
|
|
475
|
-
function unquotedCreationTitleBoundary(value) {
|
|
476
|
-
let boundary = /[\r\n,!?;,。!?;—–]/u.exec(value)?.index ?? value.length;
|
|
477
|
-
for (let index = value.indexOf('.'); index >= 0 && index < boundary; index = value.indexOf('.', index + 1)) {
|
|
478
|
-
const prefix = value.slice(0, index);
|
|
479
|
-
const after = value.slice(index + 1);
|
|
480
|
-
if (isTitleAbbreviation(prefix, after))
|
|
481
|
-
continue;
|
|
482
|
-
if (!after || /^\s/u.test(after) || /^\p{Lu}/u.test(after))
|
|
483
|
-
boundary = index;
|
|
484
|
-
}
|
|
485
|
-
return boundary;
|
|
486
|
-
}
|
|
487
|
-
function hasUnsafeUnquotedHardClauseBoundary(value) {
|
|
488
|
-
const trimmed = value.trim();
|
|
489
|
-
const hardBoundary = /[!?;。!?;]/u.exec(trimmed);
|
|
490
|
-
if (hardBoundary?.index !== undefined && trimmed.slice(hardBoundary.index + 1).trim())
|
|
491
|
-
return true;
|
|
492
|
-
for (let index = trimmed.indexOf('.'); index >= 0; index = trimmed.indexOf('.', index + 1)) {
|
|
493
|
-
const after = trimmed.slice(index + 1);
|
|
494
|
-
if (!after.trim() || isTitleAbbreviation(trimmed.slice(0, index), after))
|
|
495
|
-
continue;
|
|
496
|
-
if (/^\s|^\p{Lu}/u.test(after))
|
|
497
|
-
return true;
|
|
498
|
-
}
|
|
499
|
-
return false;
|
|
500
|
-
}
|
|
501
|
-
function isTitleAbbreviation(prefix, after) {
|
|
502
|
-
const token = prefix.match(/[A-Za-z.]+$/u)?.[0] ?? '';
|
|
503
|
-
if (isScaffoldedDirectExecutableClause(after.trimStart()))
|
|
504
|
-
return false;
|
|
505
|
-
if (/\d$/u.test(prefix) && /^\d/u.test(after))
|
|
506
|
-
return true;
|
|
507
|
-
if (/^[A-Z]$/u.test(token) && /^[A-Z]\./u.test(after))
|
|
508
|
-
return true;
|
|
509
|
-
if (/^[A-Z][a-z]{0,2}$/u.test(token) && /^[A-Z]\./u.test(after))
|
|
510
|
-
return true;
|
|
511
|
-
if (/^(?:[A-Za-z]\.)+[A-Za-z]$/u.test(token))
|
|
512
|
-
return true;
|
|
513
|
-
if (/^[A-Z][a-z]{0,2}(?:\.[A-Z])+$/u.test(token))
|
|
514
|
-
return true;
|
|
515
|
-
return /^(?:mr|mrs|ms|dr|prof|sr|jr|st|vs|etc|inc|no|ltd|co|corp)$/iu.test(token);
|
|
516
|
-
}
|
|
517
|
-
/** Whether trusted user text affirmatively corrects to an existing or new target. */
|
|
518
|
-
function isAffirmativeWorkHubCorrectionRequest(value) {
|
|
519
|
-
const normalized = value.replace(/[’‘]/gu, "'");
|
|
520
|
-
if (!hasWorkHubCorrectionCue(normalized))
|
|
521
|
-
return false;
|
|
522
|
-
const affirmativeCreation = isExplicitWorkHubCreationRequest(normalized) &&
|
|
523
|
-
(!hasWorkHubNamedCreationClause(normalized) ||
|
|
524
|
-
Boolean(affirmativeWorkHubNamedCreationTitle(normalized)));
|
|
525
|
-
return affirmativeCreation || isAffirmativeWorkHubExistingTargetCorrectionRequest(normalized);
|
|
526
|
-
}
|
|
527
|
-
/** Whether trusted user text contains an explicit WorkHub route-correction cue. */
|
|
528
|
-
function hasWorkHubCorrectionCue(value) {
|
|
529
|
-
return CORRECTION_CUE.test(value.replace(/[’‘]/gu, "'"));
|
|
530
|
-
}
|
|
531
|
-
function hasAffirmativeExecutableGrammar(value, actions) {
|
|
532
|
-
const decisions = executionActionDecisions(value);
|
|
533
|
-
return (hasLaterCoordinatedDirectExecutableAction(value, actions, decisions) ||
|
|
534
|
-
actions.some((action, index) => {
|
|
535
|
-
if (action.index === undefined || decisions.get(String(index)) !== true)
|
|
536
|
-
return false;
|
|
537
|
-
const clausePrefix = afterLastDecisionReset(value.slice(0, action.index));
|
|
538
|
-
const directPrefix = clausePrefix
|
|
539
|
-
.replace(CORRECTION_CUE, '')
|
|
540
|
-
.replace(LEADING_CORRECTION_SEPARATOR, '');
|
|
541
|
-
return (isDirectExecutionPrefix(directPrefix) ||
|
|
542
|
-
(ADVISORY_SPEECH_ACT.test(value) && hasCoordinatedDirectAction(clausePrefix)) ||
|
|
543
|
-
hasImperativeCoordinatedLead(directPrefix, value.slice(action.index + action[0].length)));
|
|
544
|
-
}));
|
|
545
|
-
}
|
|
546
|
-
function hasLaterCoordinatedDirectExecutableAction(value, actions, decisions = executionActionDecisions(value)) {
|
|
547
|
-
return actions.slice(1).some((action, offset) => {
|
|
548
|
-
if (action.index === undefined || decisions.get(String(offset + 1)) !== true)
|
|
549
|
-
return false;
|
|
550
|
-
const previous = actions[offset];
|
|
551
|
-
if (previous?.index === undefined)
|
|
552
|
-
return false;
|
|
553
|
-
const between = value.slice(previous.index + previous[0].length, action.index);
|
|
554
|
-
return COORDINATED_DIRECT_ACTION_PREFIX.test(between);
|
|
555
|
-
});
|
|
556
|
-
}
|
|
557
|
-
function hasDominatingDeliberation(value) {
|
|
558
|
-
if (hasUnquotedTerminalWithdrawal(value))
|
|
559
|
-
return true;
|
|
560
|
-
const firstAction = EXECUTION_ACTION.exec(value);
|
|
561
|
-
if (firstAction?.index === undefined)
|
|
562
|
-
return false;
|
|
563
|
-
const actionTail = value.slice(firstAction.index + firstAction[0].length);
|
|
564
|
-
return POST_ACTION_DELIBERATIVE.test(actionTail) || hasPostActionDeliberativeQuestion(actionTail);
|
|
565
|
-
}
|
|
566
|
-
/**
|
|
567
|
-
* Advisory `how to` complements have an attachment ambiguity at a later
|
|
568
|
-
* coordinator. This check can only demote to clarification; it never grants
|
|
569
|
-
* execution authority.
|
|
570
|
-
*/
|
|
571
|
-
function hasAmbiguousAdvisoryCommand(value, actions) {
|
|
572
|
-
if (!ADVISORY_SPEECH_ACT.test(value) || actions.length < 2)
|
|
573
|
-
return false;
|
|
574
|
-
const complementAction = actions[0];
|
|
575
|
-
if (complementAction?.index === undefined)
|
|
576
|
-
return false;
|
|
577
|
-
const complementPrefix = value.slice(0, complementAction.index);
|
|
578
|
-
if (!/(?:\bhow\s+to\s*|(?:如何|怎么)\s*)$/iu.test(complementPrefix))
|
|
579
|
-
return false;
|
|
580
|
-
const decisions = executionActionDecisions(value);
|
|
581
|
-
let sawBareComma = false;
|
|
582
|
-
for (let index = 1; index < actions.length; index += 1) {
|
|
583
|
-
const previous = actions[index - 1];
|
|
584
|
-
const directAction = actions[index];
|
|
585
|
-
if (previous?.index === undefined || directAction?.index === undefined)
|
|
586
|
-
continue;
|
|
587
|
-
if (decisions.get(String(index)) !== true)
|
|
588
|
-
continue;
|
|
589
|
-
const between = value.slice(previous.index + previous[0].length, directAction.index);
|
|
590
|
-
const boundary = ADVISORY_MATRIX_ACTION_BOUNDARY.exec(between);
|
|
591
|
-
if (!boundary) {
|
|
592
|
-
sawBareComma ||= /[,,]/u.test(between);
|
|
593
|
-
continue;
|
|
594
|
-
}
|
|
595
|
-
const hardBoundary = /[.;。;]/u.test(boundary[0]);
|
|
596
|
-
const priorBareComma = sawBareComma || /[,,]/u.test(between.slice(0, boundary.index));
|
|
597
|
-
if (priorBareComma && !hardBoundary) {
|
|
598
|
-
sawBareComma = true;
|
|
599
|
-
continue;
|
|
600
|
-
}
|
|
601
|
-
const directTail = value.slice(directAction.index + directAction[0].length);
|
|
602
|
-
if (isLikelyDeclarativeActionTail(directTail))
|
|
603
|
-
continue;
|
|
604
|
-
return true;
|
|
605
|
-
}
|
|
606
|
-
return false;
|
|
607
|
-
}
|
|
608
|
-
function hasImperativeCoordinatedLead(value, actionTail) {
|
|
609
|
-
const normalized = value.trim();
|
|
610
|
-
if (!isBoundedPreparatoryActionTail(actionTail))
|
|
611
|
-
return false;
|
|
612
|
-
return /^(?:(?:(?:please|kindly|first|next)\s+)|(?:先|接下来)\s*)*(?:(?:investigate|analy[sz]e|debug|review|inspect|audit|research|triage|assess|examine)(?:\s+[^,.;!?,。;!?]{0,80})?(?:(?:,\s*)?(?:and\s+then|then|and))|(?:调查|分析|排查|审查|评估|研究)(?:[^,.;!?,。;!?]{0,48})?(?:(?:,\s*)?(?:并且|并|然后)))\s*$/iu.test(normalized);
|
|
613
|
-
}
|
|
614
|
-
function isLikelyDeclarativeActionTail(value) {
|
|
615
|
-
const unquoted = maskLiteralSpans(value).value;
|
|
616
|
-
const words = unquoted
|
|
617
|
-
.replace(/[.!?。!?]+\s*$/u, '')
|
|
618
|
-
.trim()
|
|
619
|
-
.split(/\s+/u)
|
|
620
|
-
.filter(Boolean);
|
|
621
|
-
if (/(?:仍然|都很|都已|很重要|附上|可用)/u.test(unquoted) ||
|
|
622
|
-
(/(?:已经|正在)/u.test(unquoted) && !/^\s*(?:已经|正在).{1,24}的/u.test(unquoted))) {
|
|
623
|
-
return true;
|
|
624
|
-
}
|
|
625
|
-
if (words.length < 2)
|
|
626
|
-
return false;
|
|
627
|
-
const startsWithDeterminer = /^(?:the|a|an|both|this|that|these|those|my|our|your)\b/iu.test(words[0] ?? '');
|
|
628
|
-
if (words
|
|
629
|
-
.slice(1)
|
|
630
|
-
.some((word) => /^(?:is|are|was|were|has|have|will|would|can|could|should|must|remain|remains|seem|seems|look|looks)$/iu.test(word))) {
|
|
631
|
-
return true;
|
|
632
|
-
}
|
|
633
|
-
return (/^(?:matter|matters|changed|changes|improved|improves|increased|increases|failed|fails|succeeded|succeeds|exists|exist)$/iu.test(words.at(-1) ?? '') ||
|
|
634
|
-
(!startsWithDeterminer && words.slice(1).some((word) => /ed$/iu.test(word))));
|
|
635
|
-
}
|
|
636
|
-
function isBoundedPreparatoryActionTail(value) {
|
|
637
|
-
const normalized = value
|
|
638
|
-
.trim()
|
|
639
|
-
.replace(/[.!?。!?]+\s*$/u, '')
|
|
640
|
-
.trim();
|
|
641
|
-
if (!normalized)
|
|
642
|
-
return false;
|
|
643
|
-
if (/^[\p{Script=Han}][\p{Script=Han}\p{L}\p{N}_-]{0,48}$/u.test(normalized)) {
|
|
644
|
-
return !isLikelyDeclarativeActionTail(normalized);
|
|
645
|
-
}
|
|
646
|
-
if (isLikelyDeclarativeActionTail(normalized))
|
|
647
|
-
return false;
|
|
648
|
-
return /^(?:(?:the|a|an|both|this|that|these|those|my|our|your)\s+)?[\p{L}\p{N}_.:/-]+(?:\s+[\p{L}\p{N}_.:/-]+){0,5}(?:\s+(?:for|in|on|with|without|before|after|under)\s+[\p{L}\p{N}_.:/-]+(?:\s+[\p{L}\p{N}_.:/-]+){0,3})?$/iu.test(normalized);
|
|
649
|
-
}
|
|
650
|
-
function maskLiteralSpans(value) {
|
|
651
|
-
const scope = buildLiteralScope(value);
|
|
652
|
-
return {
|
|
653
|
-
value: value
|
|
654
|
-
.split('')
|
|
655
|
-
.map((character, index) => (scope.contains(index) ? ' ' : character))
|
|
656
|
-
.join(''),
|
|
657
|
-
malformed: scope.malformed,
|
|
658
|
-
};
|
|
659
|
-
}
|
|
660
|
-
function buildLiteralScope(value) {
|
|
661
|
-
const covered = new Uint8Array(value.length);
|
|
662
|
-
const bracketClosers = new Map([
|
|
663
|
-
['(', ')'],
|
|
664
|
-
['(', ')'],
|
|
665
|
-
['[', ']'],
|
|
666
|
-
['【', '】'],
|
|
667
|
-
]);
|
|
668
|
-
const quoteClosers = new Map([
|
|
669
|
-
['"', '"'],
|
|
670
|
-
['“', '”'],
|
|
671
|
-
['‘', '’'],
|
|
672
|
-
['`', '`'],
|
|
673
|
-
]);
|
|
674
|
-
const bracketClosingCharacters = new Set(bracketClosers.values());
|
|
675
|
-
const brackets = [];
|
|
676
|
-
let quote;
|
|
677
|
-
let malformed = false;
|
|
678
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
679
|
-
const character = value[index] ?? '';
|
|
680
|
-
if (quote) {
|
|
681
|
-
covered[index] = 1;
|
|
682
|
-
if (character === quote)
|
|
683
|
-
quote = undefined;
|
|
684
|
-
continue;
|
|
685
|
-
}
|
|
686
|
-
if (brackets.length > 0) {
|
|
687
|
-
covered[index] = 1;
|
|
688
|
-
const nested = bracketClosers.get(character);
|
|
689
|
-
if (nested)
|
|
690
|
-
brackets.push(nested);
|
|
691
|
-
else if (character === brackets.at(-1))
|
|
692
|
-
brackets.pop();
|
|
693
|
-
else if (bracketClosingCharacters.has(character))
|
|
694
|
-
malformed = true;
|
|
695
|
-
continue;
|
|
696
|
-
}
|
|
697
|
-
const quoteCloser = quoteClosers.get(character);
|
|
698
|
-
if (quoteCloser) {
|
|
699
|
-
covered[index] = 1;
|
|
700
|
-
quote = quoteCloser;
|
|
701
|
-
continue;
|
|
702
|
-
}
|
|
703
|
-
const bracketCloser = bracketClosers.get(character);
|
|
704
|
-
if (bracketCloser) {
|
|
705
|
-
covered[index] = 1;
|
|
706
|
-
brackets.push(bracketCloser);
|
|
707
|
-
continue;
|
|
708
|
-
}
|
|
709
|
-
if (bracketClosingCharacters.has(character) || character === '”') {
|
|
710
|
-
malformed = true;
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
malformed ||= Boolean(quote || brackets.length > 0);
|
|
714
|
-
return {
|
|
715
|
-
contains: (index) => covered[index] === 1,
|
|
716
|
-
malformed,
|
|
717
|
-
};
|
|
718
|
-
}
|
|
719
|
-
function isDeliberative(value) {
|
|
720
|
-
const firstAction = EXECUTION_ACTION.exec(value);
|
|
721
|
-
const actionPrefix = firstAction?.index === undefined ? '' : value.slice(0, firstAction.index);
|
|
722
|
-
const directActionPrefix = actionPrefix
|
|
723
|
-
.replace(CORRECTION_CUE, '')
|
|
724
|
-
.replace(LEADING_CORRECTION_SEPARATOR, '');
|
|
725
|
-
const actionTail = firstAction?.index === undefined ? '' : value.slice(firstAction.index + firstAction[0].length);
|
|
726
|
-
const hasDeliberativeLead = firstAction?.index !== undefined &&
|
|
727
|
-
firstAction.index > 0 &&
|
|
728
|
-
!isDirectExecutionPrefix(directActionPrefix) &&
|
|
729
|
-
!hasCoordinatedDirectAction(actionPrefix) &&
|
|
730
|
-
(DELIBERATIVE_LEAD_MARKER.test(actionPrefix) ||
|
|
731
|
-
ADVISORY_COMPLEMENT_NOUN.test(actionPrefix) ||
|
|
732
|
-
(/(?:告诉我|给我)/u.test(actionPrefix) &&
|
|
733
|
-
/(?:的?(?:步骤|方法|方式)|怎么做)/u.test(actionTail)));
|
|
734
|
-
const hasAdvisoryComplement = firstAction?.index !== undefined &&
|
|
735
|
-
ADVISORY_COMPLEMENT_NOUN.test(actionPrefix) &&
|
|
736
|
-
ADVISORY_COMPLEMENT_RELATIVE.test(actionPrefix);
|
|
737
|
-
return (DELIBERATIVE_REQUEST.test(value) ||
|
|
738
|
-
hasAdvisoryComplement ||
|
|
739
|
-
(ADVISORY_SPEECH_ACT.test(value) && !hasCoordinatedDirectAction(actionPrefix)) ||
|
|
740
|
-
hasDeliberativeLead ||
|
|
741
|
-
(firstAction?.index !== undefined && POST_ACTION_DELIBERATIVE.test(actionTail)) ||
|
|
742
|
-
(firstAction?.index !== undefined && hasPostActionDeliberativeQuestion(actionTail)) ||
|
|
743
|
-
(TRAILING_QUESTION.test(value) &&
|
|
744
|
-
(firstAction?.index === undefined ||
|
|
745
|
-
!isDirectExecutionPrefix(directActionPrefix) ||
|
|
746
|
-
POST_ACTION_QUESTION_ALTERNATIVE.test(actionTail))));
|
|
747
|
-
}
|
|
748
|
-
function hasCoordinatedDirectAction(value) {
|
|
749
|
-
if (COORDINATED_DIRECT_ACTION_PREFIX.test(value))
|
|
750
|
-
return true;
|
|
751
|
-
return BARE_COORDINATED_ACTION_PREFIX.test(value);
|
|
752
|
-
}
|
|
753
|
-
function hasPostActionDeliberativeQuestion(value) {
|
|
754
|
-
if (!TRAILING_QUESTION.test(value))
|
|
755
|
-
return false;
|
|
756
|
-
if (POST_ACTION_EMBEDDED_QUESTION.test(value) && !UNQUOTED_LITERAL_QUESTION_TARGET.test(value)) {
|
|
757
|
-
return true;
|
|
758
|
-
}
|
|
759
|
-
const body = value.replace(/[??]\s*$/u, '');
|
|
760
|
-
const boundary = allMatches(body, /[,.!?;:—–,。!?;:]/u).at(-1);
|
|
761
|
-
if (boundary?.index === undefined)
|
|
762
|
-
return false;
|
|
763
|
-
const question = body.slice(boundary.index + boundary[0].length).trim();
|
|
764
|
-
const requiresQuestionLead = /[,,]/u.test(boundary[0]);
|
|
765
|
-
return Boolean(question &&
|
|
766
|
-
(!requiresQuestionLead ||
|
|
767
|
-
POST_ACTION_QUESTION_CLAUSE_LEAD.test(question) ||
|
|
768
|
-
POST_ACTION_UNCERTAINTY_TAG.test(question)) &&
|
|
769
|
-
!isScaffoldedDirectExecutableClause(question));
|
|
770
|
-
}
|
|
771
|
-
function isDirectExecutionPrefix(value) {
|
|
772
|
-
return (ELLIPTICAL_CONDITIONAL_PREFIX.test(value) ||
|
|
773
|
-
DIRECT_EXECUTION_PREFIX.test(value) ||
|
|
774
|
-
(CONDITIONAL_EXECUTION_PREFIX.test(value) && !DELIBERATIVE_CONDITIONAL_PREFIX.test(value)));
|
|
775
|
-
}
|
|
776
|
-
function lastMatch(value, pattern) {
|
|
777
|
-
const matches = allMatches(value, pattern);
|
|
778
|
-
return matches.at(-1);
|
|
779
|
-
}
|
|
780
|
-
function allMatches(value, pattern) {
|
|
781
|
-
return [...value.matchAll(new RegExp(pattern.source, `${pattern.flags}g`))];
|
|
782
|
-
}
|
|
783
|
-
function lastBoundaryEnd(value, pattern) {
|
|
784
|
-
return allMatches(value, pattern).reduce((latest, match) => match.index === undefined ? latest : Math.max(latest, match.index + match[0].length), 0);
|
|
785
|
-
}
|
|
786
|
-
function executionActionDecisions(value) {
|
|
787
|
-
const decisions = new Map();
|
|
788
|
-
const actions = allMatches(value, EXECUTION_ACTION);
|
|
789
|
-
const priorActions = [];
|
|
790
|
-
let previous;
|
|
791
|
-
let previousDecision;
|
|
792
|
-
for (const [index, action] of actions.entries()) {
|
|
793
|
-
if (action.index === undefined)
|
|
794
|
-
continue;
|
|
795
|
-
const previousEnd = previous?.index === undefined ? 0 : previous.index + previous[0].length;
|
|
796
|
-
const prefix = value.slice(previousEnd, action.index);
|
|
797
|
-
if (ANAPHORIC_CANCELLATION.test(prefix)) {
|
|
798
|
-
withdrawAll(decisions);
|
|
799
|
-
previousDecision = false;
|
|
800
|
-
}
|
|
801
|
-
const reset = hasDecisionReset(prefix);
|
|
802
|
-
const decision = NEGATOR.test(afterLastDecisionReset(prefix))
|
|
803
|
-
? false
|
|
804
|
-
: previousDecision === false && !reset
|
|
805
|
-
? false
|
|
806
|
-
: true;
|
|
807
|
-
const id = String(index);
|
|
808
|
-
const key = action[0].toLocaleLowerCase();
|
|
809
|
-
const target = actionObject(value, action, actions[index + 1]);
|
|
810
|
-
if (decision === false) {
|
|
811
|
-
if (hasAnaphoricObjectAfter(value, action, actions[index + 1])) {
|
|
812
|
-
withdrawAll(decisions);
|
|
813
|
-
}
|
|
814
|
-
else if (target) {
|
|
815
|
-
for (const prior of priorActions) {
|
|
816
|
-
if (prior.key === key && sameActionTarget(prior.target, target)) {
|
|
817
|
-
decisions.set(prior.id, false);
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
decisions.set(id, decision);
|
|
823
|
-
priorActions.push({ id, key, target });
|
|
824
|
-
previous = action;
|
|
825
|
-
previousDecision = decision;
|
|
826
|
-
}
|
|
827
|
-
if (previous?.index !== undefined) {
|
|
828
|
-
const trailing = value.slice(previous.index + previous[0].length);
|
|
829
|
-
if (ANAPHORIC_CANCELLATION.test(trailing) || hasBareTrailingCancellation(value)) {
|
|
830
|
-
withdrawAll(decisions);
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
return decisions;
|
|
834
|
-
}
|
|
835
|
-
function hasBareTrailingCancellation(value) {
|
|
836
|
-
const match = BARE_TRAILING_CANCELLATION.exec(value);
|
|
837
|
-
if (!match || match.index === undefined)
|
|
838
|
-
return false;
|
|
839
|
-
const boundary = match[1] ?? '';
|
|
840
|
-
const horizontalWhitespace = match[2] ?? '';
|
|
841
|
-
const prefix = value.slice(0, match.index);
|
|
842
|
-
if (isMultilineLiteral(prefix, boundary, horizontalWhitespace))
|
|
843
|
-
return false;
|
|
844
|
-
const prefixWithBoundary = prefix + boundary;
|
|
845
|
-
if (!ABBREVIATION_BEFORE_BOUNDARY.test(prefixWithBoundary))
|
|
846
|
-
return true;
|
|
847
|
-
return boundary === '.' && /^[A-Z]/u.test(match[3] ?? '');
|
|
848
|
-
}
|
|
849
|
-
function isMultilineLiteral(prefix, boundary, horizontalWhitespace) {
|
|
850
|
-
const currentLine = prefix.slice(Math.max(prefix.lastIndexOf('\n'), prefix.lastIndexOf('\r')) + 1);
|
|
851
|
-
if (/[\r\n]/u.test(boundary) && /[\r\n]$/u.test(prefix))
|
|
852
|
-
return false;
|
|
853
|
-
const lines = prefix.split(/\r\n|[\r\n]/u);
|
|
854
|
-
if (!/[\r\n]/u.test(boundary) && !lines.at(-1))
|
|
855
|
-
lines.pop();
|
|
856
|
-
if (boundary === '-' && !/\s$/u.test(prefix))
|
|
857
|
-
return true;
|
|
858
|
-
const structuralLiteral = (boundary === '-' && !currentLine.trim()) ||
|
|
859
|
-
(boundary === '.' && /^\s*\d+$/u.test(currentLine)) ||
|
|
860
|
-
(/[\r\n]/u.test(boundary) &&
|
|
861
|
-
(/\t/u.test(horizontalWhitespace) || horizontalWhitespace.length >= 4));
|
|
862
|
-
if (structuralLiteral) {
|
|
863
|
-
if (boundary === '.' && lines.at(-1)?.trim() === currentLine.trim())
|
|
864
|
-
lines.pop();
|
|
865
|
-
return hasValidatedStructuralLiteralContext(lines);
|
|
866
|
-
}
|
|
867
|
-
if (!/[\r\n]/u.test(boundary))
|
|
868
|
-
return false;
|
|
869
|
-
return hasValidatedColonLiteralContext(lines);
|
|
870
|
-
}
|
|
871
|
-
function hasValidatedStructuralLiteralContext(lines) {
|
|
872
|
-
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
873
|
-
const rawLine = lines[index] ?? '';
|
|
874
|
-
if (!rawLine.trim())
|
|
875
|
-
return false;
|
|
876
|
-
if (PRIOR_STRUCTURED_LITERAL_ITEM.test(rawLine))
|
|
877
|
-
continue;
|
|
878
|
-
const line = normalizeMarkdownLine(rawLine);
|
|
879
|
-
if (!line)
|
|
880
|
-
return false;
|
|
881
|
-
if (STRUCTURED_LITERAL_LINE.test(line))
|
|
882
|
-
continue;
|
|
883
|
-
if (MULTILINE_LITERAL_INTRODUCER.test(line))
|
|
884
|
-
return isExecutableLiteralIntroducer(line);
|
|
885
|
-
return isExecutableLiteralContext(line);
|
|
886
|
-
}
|
|
887
|
-
return false;
|
|
888
|
-
}
|
|
889
|
-
function hasValidatedColonLiteralContext(lines) {
|
|
890
|
-
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
891
|
-
const line = normalizeMarkdownLine(lines[index] ?? '');
|
|
892
|
-
if (!line)
|
|
893
|
-
return false;
|
|
894
|
-
if (MULTILINE_LITERAL_INTRODUCER.test(line))
|
|
895
|
-
return isExecutableLiteralIntroducer(line);
|
|
896
|
-
}
|
|
897
|
-
return false;
|
|
898
|
-
}
|
|
899
|
-
function normalizeMarkdownLine(line) {
|
|
900
|
-
return line
|
|
901
|
-
.trim()
|
|
902
|
-
.replace(/^#{1,6}\s+/u, '')
|
|
903
|
-
.replace(/^(\*{1,3}|_{1,3})(.*)\1$/u, '$2')
|
|
904
|
-
.trim();
|
|
905
|
-
}
|
|
906
|
-
function isExecutableLiteralIntroducer(line) {
|
|
907
|
-
const content = line.replace(MULTILINE_LITERAL_INTRODUCER, '').trim();
|
|
908
|
-
return isExecutableLiteralContext(content);
|
|
909
|
-
}
|
|
910
|
-
function isExecutableLiteralContext(content) {
|
|
911
|
-
const action = EXECUTION_ACTION.exec(content);
|
|
912
|
-
const actionPrefix = action?.index === undefined ? '' : content.slice(0, action.index).trim();
|
|
913
|
-
const target = action?.index === undefined ? '' : content.slice(action.index + action[0].length).trim();
|
|
914
|
-
if (ACTION_INTRODUCER_PREFIX.test(actionPrefix) && target && !/^(?:to|为)$/iu.test(target)) {
|
|
915
|
-
return true;
|
|
916
|
-
}
|
|
917
|
-
return EXACT_LITERAL_HEADER.test(content);
|
|
918
|
-
}
|
|
919
|
-
function hasNegatedAnaphoricCreation(value, explicitCreation) {
|
|
920
|
-
if (explicitCreation.index === undefined)
|
|
921
|
-
return false;
|
|
922
|
-
const offset = explicitCreation.index + explicitCreation[0].length;
|
|
923
|
-
const trailing = value.slice(offset);
|
|
924
|
-
let previousEnd = 0;
|
|
925
|
-
for (const action of allMatches(trailing, CREATION_ACTION)) {
|
|
926
|
-
if (action.index === undefined)
|
|
927
|
-
continue;
|
|
928
|
-
const prefix = trailing.slice(previousEnd, action.index);
|
|
929
|
-
const after = trailing.slice(action.index + action[0].length);
|
|
930
|
-
if (NEGATOR.test(prefix) && ANAPHORIC_OBJECT.test(after))
|
|
931
|
-
return true;
|
|
932
|
-
previousEnd = action.index + action[0].length;
|
|
933
|
-
}
|
|
934
|
-
return false;
|
|
935
|
-
}
|
|
936
|
-
function hasAnaphoricObjectAfter(value, action, next) {
|
|
937
|
-
if (action.index === undefined)
|
|
938
|
-
return false;
|
|
939
|
-
const end = next?.index ?? value.length;
|
|
940
|
-
return ANAPHORIC_OBJECT.test(value.slice(action.index + action[0].length, end));
|
|
941
|
-
}
|
|
942
|
-
function actionObject(value, action, next) {
|
|
943
|
-
if (action.index === undefined)
|
|
944
|
-
return '';
|
|
945
|
-
const end = next?.index ?? value.length;
|
|
946
|
-
const trailing = value.slice(action.index + action[0].length, end);
|
|
947
|
-
const cutters = [
|
|
948
|
-
...allMatches(trailing, HARD_CLAUSE_BOUNDARY),
|
|
949
|
-
...allMatches(trailing, SOFT_CLAUSE_BOUNDARY),
|
|
950
|
-
...allMatches(trailing, POSITIVE_CONTRAST),
|
|
951
|
-
...allMatches(trailing, NEGATOR),
|
|
952
|
-
];
|
|
953
|
-
const cut = cutters.reduce((earliest, match) => (match.index === undefined ? earliest : Math.min(earliest, match.index)), trailing.length);
|
|
954
|
-
return trailing
|
|
955
|
-
.slice(0, cut)
|
|
956
|
-
.trim()
|
|
957
|
-
.replace(/^(?:a|an|the)\s+/iu, '')
|
|
958
|
-
.replace(/(?:(?:\s+\b(?:and|then|also|please|kindly)\b)|(?:并且|并|且|然后|随后|请|麻烦))+\s*$/iu, '')
|
|
959
|
-
.toLocaleLowerCase();
|
|
960
|
-
}
|
|
961
|
-
function isMatchNegated(value, match) {
|
|
962
|
-
if (match.index === undefined)
|
|
963
|
-
return false;
|
|
964
|
-
return NEGATOR.test(afterLastDecisionReset(value.slice(0, match.index)));
|
|
965
|
-
}
|
|
966
|
-
function sameActionTarget(left, right) {
|
|
967
|
-
if (!left || !right)
|
|
968
|
-
return false;
|
|
969
|
-
if (left === right)
|
|
970
|
-
return true;
|
|
971
|
-
if (!left.startsWith(right))
|
|
972
|
-
return false;
|
|
973
|
-
const remainder = left.slice(right.length);
|
|
974
|
-
return ACTION_TARGET_SCAFFOLDING.test(remainder);
|
|
975
|
-
}
|
|
976
|
-
function withdrawAll(decisions) {
|
|
977
|
-
for (const key of decisions.keys())
|
|
978
|
-
decisions.set(key, false);
|
|
979
|
-
}
|
|
980
|
-
function hasDecisionReset(value) {
|
|
981
|
-
return HARD_CLAUSE_BOUNDARY.test(value) || POSITIVE_CONTRAST.test(value);
|
|
982
|
-
}
|
|
983
|
-
function afterLastDecisionReset(value) {
|
|
984
|
-
const resets = [
|
|
985
|
-
...allMatches(value, HARD_CLAUSE_BOUNDARY),
|
|
986
|
-
...allMatches(value, POSITIVE_CONTRAST),
|
|
987
|
-
];
|
|
988
|
-
const lastReset = resets.reduce((latest, match) => match.index === undefined ? latest : Math.max(latest, match.index + match[0].length), 0);
|
|
989
|
-
return value.slice(lastReset);
|
|
990
|
-
}
|