@ngockhoale/ukit 3.4.44 → 3.4.46
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/CHANGELOG.md +18 -0
- package/manifests/documentation.yaml +12 -0
- package/package.json +3 -1
- package/src/core/executionContracts.js +37 -8
- package/src/index/taskRouting.js +22 -4
- package/template_project/.claude/hooks/handoff-model-guard.sh +1 -1
- package/template_project/.claude/hooks/skill-router.sh +62 -15
- package/template_project/.claude/ukit/index/route-resolver.mjs +37 -8
- package/template_project/.claude/ukit/index/route-task.mjs +23 -5
- package/template_project/.claude/ukit/runtime/cron-operation-adapter.mjs +1 -1
- package/template_project/.claude/ukit/runtime/execution-ledger.mjs +122 -3
- package/template_project/.claude/ukit/runtime/handoff-intent.mjs +201 -48
- package/template_project/.omp/hooks/pre/ukit-bridge.js +1 -1
- package/scripts/audit/decision-coverage.mjs +0 -322
- package/scripts/audit/subagent-cost/analyze.mjs +0 -107
- package/scripts/audit/subagent-cost/check-doc.mjs +0 -91
- package/scripts/audit/subagent-cost/duplicates.mjs +0 -195
- package/scripts/audit/subagent-cost/metrics.mjs +0 -193
- package/scripts/audit/subagent-cost/reader.mjs +0 -332
- package/scripts/audit/subagent-cost/render.mjs +0 -34
- package/scripts/audit/subagent-cost/usage-fields.mjs +0 -82
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,24 @@ All notable changes to UKit are documented here.
|
|
|
9
9
|
- New `/ukit:ci-check` command + `ci-check.mjs` helper (core pack): prechecks, fail-closed budget guard, local preflight, at most one dispatch per invocation, write-ahead run-id state, `status` (never dispatches), `--ref`, `--dry-run`, per-OS report. Never pushes, merges or publishes.
|
|
10
10
|
- Default-branch bootstrap stub documented in `docs/design/CI-CROSS-PLATFORM-MATRIX.md` (requires separate approval).
|
|
11
11
|
|
|
12
|
+
## 3.4.46 - 2026-10-18
|
|
13
|
+
|
|
14
|
+
**Completion contract P0: forensic intent, attributable release evidence and conditional NO-GO.**
|
|
15
|
+
- Correct negated/quoted forensic requests and Vietnamese status questions; explicit report artifacts require owned writes and nonempty output. External scratch writes do not count as product changes.
|
|
16
|
+
- Conditional release contracts with a named `release:verify` preflight accept only current-task attributable native failure as terminal `RELEASE_NO_GO`, never publication success. Missing implementation writes still block; passing preflight retains publication obligations. Masked commands and stale receipts remain unproven.
|
|
17
|
+
- Accept standalone `npm view <package> version --prefer-online` evidence without republishing; improve task/obligation diagnostics. OMP artifact checks use the installed project cwd.
|
|
18
|
+
- Exclude only repository coverage/transcript audit scripts from npm; retain runtime and customer assets and the strict artifact budget.
|
|
19
|
+
- Verified locally on macOS/Node 22 with real isolated OMP child-hook chains; no provider calls or GitHub Actions dispatch. Historical release ledger replay remains partial; OMP mid-task freeze remains open. UNIC Decision stays unchanged/off.
|
|
20
|
+
|
|
21
|
+
## 3.4.45 - 2026-10-17
|
|
22
|
+
|
|
23
|
+
**P1 correctness repair: implementation prompts, release identity, large-transcript intent, continuation ownership.**
|
|
24
|
+
- Implementation prompts ("fix/apply ...", Vietnamese "van sua" defer-strip) are no longer misread as READ_ONLY; negation scope is bounded and covered by a classification matrix built from a real prompt fixture.
|
|
25
|
+
- Completion Gate release identity is decided by tag + shipped-file state, not HEAD==tag alone: a docs-only HEAD ahead of the tag passes; uncommitted/untracked shipped files, or a missing tag in a tagging repo, still require `release-publication`.
|
|
26
|
+
- Transcripts above 32 MiB use one shared incremental intent scan (project-local cache under `.ukit/storage/cache/handoff-intent`, never written into `template_project`), wired into the Claude guard, OMP bridge and Stop coordinator. The first inconclusive call is a visible advisory, never a silent allow; append, truncation, rotation and corrupt/forged cache never create false authorization. Bounded-scan limits are unchanged.
|
|
27
|
+
- Continuation phrases ("tiếp tục", "continue", "go on", ...) inherit only the active task instance's contract; completed, blocked, read-only and cross-session tasks do not leak authority or evidence.
|
|
28
|
+
- Known limits: live OMP and Windows/Linux not exercised; verified on macOS/Node 22.
|
|
29
|
+
|
|
12
30
|
## 3.4.44 - 2026-10-14
|
|
13
31
|
|
|
14
32
|
**Completion Gate scope and permission-choice preservation.**
|
|
@@ -955,6 +955,18 @@ entries:
|
|
|
955
955
|
archive_policy: never
|
|
956
956
|
notes: C69 G7 operator doc — timeline render, support bundle contents/exclusions, replay limits
|
|
957
957
|
|
|
958
|
+
- id: docs-completion-decision-assessment
|
|
959
|
+
path: docs/COMPLETION_DECISION_ASSESSMENT.md
|
|
960
|
+
class: canonical
|
|
961
|
+
audience: [maintainer]
|
|
962
|
+
owner: runtime
|
|
963
|
+
source_of_truth: docs/COMPLETION_DECISION_ASSESSMENT.md
|
|
964
|
+
merge_strategy: none
|
|
965
|
+
load_policy: on-demand
|
|
966
|
+
validation: [manual]
|
|
967
|
+
archive_policy: never
|
|
968
|
+
notes: P0 completion contract corrections and offline semantic decision architecture assessment
|
|
969
|
+
|
|
958
970
|
- id: docs-unic-decision-integration-p1-fix
|
|
959
971
|
path: docs/UNIC-DECISION-INTEGRATION-P1-FIX.md
|
|
960
972
|
class: canonical
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ngockhoale/ukit",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.46",
|
|
4
4
|
"description": "Install/update an index-first AI workspace for Claude Code, OpenAI Codex and omp (Oh My Pi).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
"!scripts/audit/c100/implementer-attribution.mjs",
|
|
35
35
|
"!scripts/audit/c100/trees-lifetimes.mjs",
|
|
36
36
|
"!scripts/audit/c100/usage-provenance.mjs",
|
|
37
|
+
"!scripts/audit/decision-coverage.mjs",
|
|
38
|
+
"!scripts/audit/subagent-cost/**",
|
|
37
39
|
"template_project/",
|
|
38
40
|
"template_user/",
|
|
39
41
|
"!template_project/**/.smbdelete*",
|
|
@@ -190,14 +190,43 @@ function nativeOperationGoal(domain, actionable, text) {
|
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
// Task semantics are independent of source execution strategy and observed progress.
|
|
193
|
+
// P1-A (forensic false block): the clause splitter below cuts at commas, so a negation only reached the
|
|
194
|
+
// FIRST item of an enumeration ("Do not implement fixes, modify source code, restart services, ...") and
|
|
195
|
+
// the later items became actionable orders (MIXED + service-runtime). English negators now scope to the
|
|
196
|
+
// sentence end (', and'/', or' continue the list; a bare 'and <verb>' or but/then starts a new clause);
|
|
197
|
+
// Vietnamese negators scope to the sentence end as well. Noun uses of verbs ("write/verification advisory", "each proposed
|
|
198
|
+
// fix", "state change") name things, not orders. Neutralised spans become blanks, never new orders.
|
|
199
|
+
const NON_ORDER_VERBS = 'implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|restart|sua|viet|chinh|them|tao|xoa';
|
|
200
|
+
function neutralizeNonOrders(text) {
|
|
201
|
+
return String(text)
|
|
202
|
+
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|must\\s+not|never|shall\\s+not)\\s+[^.;\\n]*?(?=(?<!,)\\s+(?:and|va)\\s+(?:${NON_ORDER_VERBS})\\b|\\s+(?:but|nhung|then|however)\\b|[.;\\n]|$)`, 'g'), ' ')
|
|
203
|
+
.replace(new RegExp(`\\b(?:khong|chua)\\s+[^.;\\n]*?(?=\\s+(?:nhung|tuy nhien)\\b|[.;\\n]|$)`, 'g'), ' ')
|
|
204
|
+
.replace(/"[^"\n]*\s[^"\n]*"|`[^`\n]*\s[^`\n]*`|\u201c[^\u201d\n]*\u201d/g, ' ')
|
|
205
|
+
.replace(/\b(?:neu\s+(?:phai|can|thieu|khong du|bang chung chua du)|if\s+(?:needed|necessary|required|evidence is insufficient))\b[^.;\n]*/g, ' ')
|
|
206
|
+
.replace(/[^.;\n]*\b(?:nao|gi|sao|the nao|bao nhieu)\b[^.;\n]*\?/g, ' ')
|
|
207
|
+
.replace(/\bchinh\s+xac\b|\b(?:phuong an|cach|de xuat|ban)\s+(?:sua|fix)\b/g, ' ')
|
|
208
|
+
.replace(/\bwrite\s*\/\s*verification\b|\bverification\s*\/\s*write\b|\bwrite\s+(?:or|and)\s+verification\b/g, ' ')
|
|
209
|
+
.replace(/\b(?:state|status)\s+changes?\b/g, ' ')
|
|
210
|
+
.replace(/\b(?:proposed|suggested|recommended|minimal|each|the|an?|any|that|this|no|which|exact|smallest|possible)\s+fix(?:es)?\b/g, ' ');
|
|
211
|
+
}
|
|
212
|
+
|
|
193
213
|
export function classifyTaskSemantics({ promptText = '', targetFile = '' } = {}) {
|
|
194
|
-
|
|
214
|
+
// A named preflight and both explicit branches are required; a failed arbitrary test is not a release policy.
|
|
215
|
+
const releaseText = String(promptText).normalize('NFD').replace(/[̀-ͯ]/g, '').replace(/[đĐ]/g, 'd').toLowerCase();
|
|
216
|
+
const preflight = releaseText.match(/\b(?:yarn\s+release:verify|npm\s+run\s+release:verify)\b/)?.[0];
|
|
217
|
+
const releasePolicy = preflight && /\b(?:if|neu|only when|only if)\b[^\n.;]*(?:pass|go)\b[^\n.;]*(?:release|publish)\b/.test(releaseText)
|
|
218
|
+
&& /\b(?:fail|no-go)\b[^\n.;]*(?:do not publish|don't publish|no publish|khong publish|khong npm publish)\b/.test(releaseText)
|
|
219
|
+
? { kind: 'conditional-release', preflight } : null;
|
|
220
|
+
const text = neutralizeNonOrders(String(promptText).normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[đĐ]/g, 'd').toLowerCase());
|
|
195
221
|
const clauses = text.split(/\s*(?:[;\n,]|\.(?:\s+|$)|\band\b|\bthen\b|\bva\b)\s*/);
|
|
196
222
|
const actionable = clauses.map((clause) => clause.split(/\bwithout\b/)[0]).filter((clause) => !/\b(?:do not|don't|never|khong|dung)\b/.test(clause)
|
|
197
223
|
&& !/^\s*(?:audit|inspect|review|analyze|analyse|explain|read|kiem tra|phan tich)\b/.test(clause));
|
|
198
|
-
const sourceOrder = actionable.some((clause) => /\b(?:implement|fix|refactor|modify|edit|write|update|sua|viet|chinh)\b/.test(clause)
|
|
224
|
+
const sourceOrder = actionable.some((clause) => /\b(?:implement|fix(?:es)?|apply|refactor|modify|edit|write|update|sua|viet|chinh)\b/.test(clause)
|
|
199
225
|
&& /\b(?:source|code|logic|scheduler|implementation|ma nguon)\b|\.[cm]?[jt]sx?\b/.test(clause));
|
|
200
|
-
const codeChangeVerb = actionable.some((clause) => /\b(?:implement|fix|refactor|modify|edit|write|update|sua|viet|chinh)\b/.test(clause));
|
|
226
|
+
const codeChangeVerb = actionable.some((clause) => /\b(?:implement|fix(?:es)?|apply|refactor|modify|edit|write|update|sua|viet|chinh)\b/.test(clause));
|
|
227
|
+
const reportArtifact = String(promptText).match(/(?:^|\s)((?:docs\/|reports\/)[A-Za-z0-9_./-]+\.(?:md|txt))(?=\s|[.,;:]|$)/)?.[1];
|
|
228
|
+
const documentation = !sourceOrder && !/\b(?:implement|fix|refactor|modify|edit|update|sua|chinh)\b/.test(actionable.join(' ')) && reportArtifact && actionable.some((clause) => /\b(?:write|create|save|viet|tao|luu)\b/.test(clause))
|
|
229
|
+
&& /\b(?:report|bao cao|analysis|phan tich|document)\b/.test(text);
|
|
201
230
|
const hasOperationId = /\b[a-f0-9]{8}(?:[a-f0-9-]{0,28})\b/.test(text);
|
|
202
231
|
// A cron/job MENTION is not an operation: with a code-change verb in the request, an
|
|
203
232
|
// operation needs a concrete target id; otherwise it is a coding task about scheduling.
|
|
@@ -222,13 +251,13 @@ export function classifyTaskSemantics({ promptText = '', targetFile = '' } = {})
|
|
|
222
251
|
// lookup verb AND no mutation vocabulary anywhere in the request (fail-closed otherwise).
|
|
223
252
|
const mutationWord = /\b(?:implement|fix|refactor|modify|edit|write|update|add|create|build|make|install|deploy|remove|delete|rename|replace|change|sua|viet|chinh|them|tao|xoa|doi|cai|cap nhat)\b/.test(text);
|
|
224
253
|
const statusReport = !mutationWord && !operation && !config
|
|
225
|
-
&& /\b(?:check|status|report|show|summari[sz]e|result|results|kiem tra|bao cao|trang thai|ket qua)\b/.test(text);
|
|
226
|
-
const readOnly = (/\b(?:audit|inspect|review|analyze|analyse|explain|read|kiem tra|phan tich)\b/.test(text) || statusReport)
|
|
254
|
+
&& /\b(?:check|status|report|show|summari[sz]e|result|results|kiem tra|bao cao|trang thai|ket qua|da len chua)\b/.test(text);
|
|
255
|
+
const readOnly = (/\b(?:audit|inspect|review|analyze|analyse|explain|read|investigate|debug|forensic|root cause|kiem tra|phan tich|dieu tra|doc log|tim hieu)\b/.test(text) || statusReport)
|
|
227
256
|
&& !sourceOrder && !codeChangeVerb && !operation && !config;
|
|
228
257
|
const taskKind = operation ? (sourceOrder || (nativeDomain !== 'scheduled-job' && codeChangeVerb) ? 'MIXED' : 'OPERATIONAL')
|
|
229
|
-
: config ? 'CONFIGURATION' : readOnly ? 'READ_ONLY' : 'CODE_IMPLEMENTATION';
|
|
258
|
+
: config ? 'CONFIGURATION' : documentation ? 'DOCUMENTATION_OUTPUT' : readOnly ? 'READ_ONLY' : 'CODE_IMPLEMENTATION';
|
|
230
259
|
const id = text.match(/\b[a-f0-9]{8}(?:[a-f0-9-]{0,28})\b/)?.[0] || null;
|
|
231
|
-
return { taskKind, ...(taskKind === 'READ_ONLY' && statusReport ? { statusReport: true } : {}), ...(config ? { configurationScope: repository ? 'repository' : 'external' } : {}),
|
|
260
|
+
return { taskKind, ...(releasePolicy ? { releasePolicy } : {}), ...(documentation ? { reportArtifact } : {}), ...(taskKind === 'READ_ONLY' && statusReport ? { statusReport: true } : {}), ...(config ? { configurationScope: repository ? 'repository' : 'external' } : {}),
|
|
232
261
|
...(operation && nativeDomain !== 'scheduled-job' ? { operationGoal: nativeOperationGoal(nativeDomain, actionable, text) } : {}),
|
|
233
262
|
...(operation && nativeDomain === 'scheduled-job' ? { operationGoal: { domain: 'scheduled-job', target: id, desiredState: /\b(?:delete|remove|cancel|xoa|huy|absent|removed|deleted|no longer|khong con)\b/.test(actionable.join(' ')) ? 'absent' : 'present',
|
|
234
263
|
completionSemantics: /\b(?:ensure|dam bao)\b/.test(text) ? 'ensure-state' : 'execute-and-verify' } } : {}) };
|
|
@@ -239,7 +268,7 @@ export function applyTaskSemantics(contract, semantic) {
|
|
|
239
268
|
const operationOnly = semantic.taskKind === 'OPERATIONAL'
|
|
240
269
|
|| (semantic.taskKind === 'CONFIGURATION' && semantic.configurationScope === 'external');
|
|
241
270
|
return { ...(contract || {}), ...semantic,
|
|
242
|
-
completionEvidence: operationOnly ? ['operation-verification']
|
|
271
|
+
completionEvidence: semantic.taskKind === 'DOCUMENTATION_OUTPUT' ? ['report-artifact'] : operationOnly ? ['operation-verification']
|
|
243
272
|
: semantic.taskKind === 'MIXED' ? [...new Set([...evidence, 'write-evidence', 'operation-verification'])]
|
|
244
273
|
: semantic.taskKind === 'READ_ONLY' && semantic.statusReport ? []
|
|
245
274
|
: semantic.taskKind === 'READ_ONLY' ? (evidence.length === 1 && evidence[0] === 'verification-evidence' ? evidence : ['impact-evidence']) : evidence };
|
package/src/index/taskRouting.js
CHANGED
|
@@ -1103,8 +1103,17 @@ function hasAdvisoryOnlyAssertion({ promptText = '', commandText = '' } = {}) {
|
|
|
1103
1103
|
const residue = trimmed
|
|
1104
1104
|
.replace(/"[^"\n]*"|«[^»\n]*»/g, ' ')
|
|
1105
1105
|
// "tạo plan" / "create a plan": the plan is the deliverable, not a mutation order.
|
|
1106
|
-
.replace(/\b(?:tao|lap|create|make|write|draft)\s+(?:cho\s+toi\s+)?(?:a\s+|an\s+|the\s+|1\s+|mot\s+)?(?:plan|ke\s+hoach|phuong\s+an|lo\s+trinh|roadmap)\b/g, ' ')
|
|
1106
|
+
.replace(/\b(?:tao|lap|viet|create|make|write|draft|produce)\s+(?:cho\s+toi\s+)?(?:a\s+|an\s+|the\s+|1\s+|mot\s+)?(?:one\s+)?(?:structured\s+|forensic\s+|short\s+|brief\s+)?(?:plan|ke\s+hoach|phuong\s+an|lo\s+trinh|roadmap|bao\s+cao|report|danh\s+gia|assessment)\b/g, ' ')
|
|
1107
1107
|
.replace(/\bwrite-evidence\b|\bverification-evidence\b|\bimpact-evidence\b|\broot-cause\b/g, ' ')
|
|
1108
|
+
// P1-A (forensic false block): nouns and investigation questions are not orders. 'write/verification
|
|
1109
|
+
// advisory', 'state change', 'each proposed fix' name things; 'whether X may create Y' asks a question to
|
|
1110
|
+
// answer. A negated ENUMERATION with objects ('do not implement fixes, modify source code, ... or create
|
|
1111
|
+
// commits') negates every item to its sentence end; the older verb-only chain broke at 'fixes'.
|
|
1112
|
+
.replace(/\bwrite\s*\/\s*verification\b|\bverification\s*\/\s*write\b|\bwrite\s+(?:or|and)\s+verification\b/g, ' ')
|
|
1113
|
+
.replace(/\b(?:state|status)\s+changes?\b/g, ' ')
|
|
1114
|
+
.replace(/\b(?:proposed|suggested|recommended|minimal|each|the|an?|any|that|this|no|which|exact|smallest|possible)\s+fix(?:es)?\b/g, ' ')
|
|
1115
|
+
.replace(new RegExp(`\\bwhether\\b[^.,;\\n]*?(?=\\s+(?:va|and)\\s+(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\\s+the|cap\\s+nhat|viet|chay|cai|chinh|trien\\s+khai|cau\\s+hinh)(?![A-Za-z0-9_])|[.,;\\n]|$)`, 'g'), ' ')
|
|
1116
|
+
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|must\\s+not|never|not|khong(?:\\s+duoc)?|tuyet\\s+doi\\s+khong)\\s+(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\\s+the|cap\\s+nhat|viet|chay|cai|chinh|trien\\s+khai|cau\\s+hinh)(?![A-Za-z0-9_])(?:[^.,;\\n\u2014]*?(?:\\s*,\\s*(?:(?:or|and|nor|hay|hoac|va)\\s+)?|\\s+(?:or|nor|hay|hoac)\\s+)(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\\s+the|cap\\s+nhat|viet|chay|cai|chinh|trien\\s+khai|cau\\s+hinh|restart|manipulate|resume|push|merge|publish|touch|alter|reset|rollback|revert|commit|kill|release|tag)(?![A-Za-z0-9_]))*[^.,;\\n\u2014]*?(?=\\s+(?:va|and|then|roi|nhung|but)\\s|[.,;\u2014\\n]|\\s*$)`, 'g'), ' ')
|
|
1108
1117
|
.replace(new RegExp(`\\bgiu\\s+nguyen\\b${TAIL}`, 'g'), ' ')
|
|
1109
1118
|
.replace(new RegExp(`\\bmuon\\s+giu\\b${TAIL}`, 'g'), ' ')
|
|
1110
1119
|
.replace(new RegExp(`\\bkhong\\s+(?!chi\\b)${TAIL}`, 'g'), ' ')
|
|
@@ -1125,7 +1134,7 @@ function hasAdvisoryOnlyAssertion({ promptText = '', commandText = '' } = {}) {
|
|
|
1125
1134
|
.replace(new RegExp(`\\b(?:yeu\\s+cau|doi\\s+hoi|ep\\s+phai|bat\\s+buoc|bat\\s+phai)\\b${TAIL}`, 'g'), ' ')
|
|
1126
1135
|
.replace(new RegExp(`\\b(?:demand(?:ed|s)?|require(?:d|s)?|forcing|forced|forcibly|must|has\\s+to|have\\s+to)\\b${TAIL}`, 'g'), ' ')
|
|
1127
1136
|
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|not|never|no)\\s+(?!only\\b)${TAIL}`, 'g'), ' ')
|
|
1128
|
-
.replace(new RegExp(`\\b(?:can|nen|phai|duoc)\\s+(?:duoc\\s+)?(?:sua|cau\\s+hinh|thay\\s+doi|cap\\s+nhat|edit|fix|config)\\b${TAIL}`, 'g'), ' ')
|
|
1137
|
+
.replace(new RegExp(`\\b(?<!\\bvan\\s)(?:can|nen|phai|duoc)\\s+(?:duoc\\s+)?(?:sua|cau\\s+hinh|thay\\s+doi|cap\\s+nhat|edit|fix|config)\\b${TAIL}`, 'g'), ' ')
|
|
1129
1138
|
.replace(/\bco\s+(?:can|nen)\s+sua\b[^.,;\n?]*/g, ' ')
|
|
1130
1139
|
.replace(/(?:^|[.,;\n]\s*)(?:should|shall)\s+(?:i|we|you)\b[^.,;\n?]*/g, ' ')
|
|
1131
1140
|
.replace(/\bchi\s+(?:tu\s+van|hoi|giai\s+thich|xem|la\s+cau\s+hoi|can|la)\b[^.,;\n]*/g, ' ')
|
|
@@ -1216,11 +1225,20 @@ function hasMutationOrder({ promptText = '', commandText = '' } = {}) {
|
|
|
1216
1225
|
const residue = trimmed
|
|
1217
1226
|
.replace(/"[^"\n]*"|«[^»\n]*»/g, ' ')
|
|
1218
1227
|
// "tạo plan" / "create a plan": the plan is the deliverable, not a mutation order.
|
|
1219
|
-
.replace(/\b(?:tao|lap|create|make|write|draft)\s+(?:cho\s+toi\s+)?(?:a\s+|an\s+|the\s+|1\s+|mot\s+)?(?:plan|ke\s+hoach|phuong\s+an|lo\s+trinh|roadmap)\b/g, ' ')
|
|
1228
|
+
.replace(/\b(?:tao|lap|viet|create|make|write|draft|produce)\s+(?:cho\s+toi\s+)?(?:a\s+|an\s+|the\s+|1\s+|mot\s+)?(?:one\s+)?(?:structured\s+|forensic\s+|short\s+|brief\s+)?(?:plan|ke\s+hoach|phuong\s+an|lo\s+trinh|roadmap|bao\s+cao|report|danh\s+gia|assessment)\b/g, ' ')
|
|
1220
1229
|
// Descriptive state, not an order: "đã/vừa [được] + verb" ("hooks vừa được cài đặt") reports
|
|
1221
1230
|
// something already done. Only the verb is stripped, so a later imperative still survives.
|
|
1222
1231
|
.replace(/(?<![a-z0-9_])(?:da|vua)\s+(?:duoc\s+)?(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\s+the|cap\s+nhat|viet|chay|cai|chinh|trien\s+khai|cau\s+hinh)(?![a-z0-9_])/g, ' ')
|
|
1223
1232
|
.replace(/\bwrite-evidence\b|\bverification-evidence\b|\bimpact-evidence\b|\broot-cause\b/g, ' ')
|
|
1233
|
+
// P1-A (forensic false block): nouns and investigation questions are not orders. 'write/verification
|
|
1234
|
+
// advisory', 'state change', 'each proposed fix' name things; 'whether X may create Y' asks a question to
|
|
1235
|
+
// answer. A negated ENUMERATION with objects ('do not implement fixes, modify source code, ... or create
|
|
1236
|
+
// commits') negates every item to its sentence end; the older verb-only chain broke at 'fixes'.
|
|
1237
|
+
.replace(/\bwrite\s*\/\s*verification\b|\bverification\s*\/\s*write\b|\bwrite\s+(?:or|and)\s+verification\b/g, ' ')
|
|
1238
|
+
.replace(/\b(?:state|status)\s+changes?\b/g, ' ')
|
|
1239
|
+
.replace(/\b(?:proposed|suggested|recommended|minimal|each|the|an?|any|that|this|no|which|exact|smallest|possible)\s+fix(?:es)?\b/g, ' ')
|
|
1240
|
+
.replace(new RegExp(`\\bwhether\\b[^.,;\\n]*?(?=\\s+(?:va|and)\\s+(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\\s+the|cap\\s+nhat|viet|chay|cai|chinh|trien\\s+khai|cau\\s+hinh)(?![A-Za-z0-9_])|[.,;\\n]|$)`, 'g'), ' ')
|
|
1241
|
+
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|must\\s+not|never|not|khong(?:\\s+duoc)?|tuyet\\s+doi\\s+khong)\\s+(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\\s+the|cap\\s+nhat|viet|chay|cai|chinh|trien\\s+khai|cau\\s+hinh)(?![A-Za-z0-9_])(?:[^.,;\\n\u2014]*?(?:\\s*,\\s*(?:(?:or|and|nor|hay|hoac|va)\\s+)?|\\s+(?:or|nor|hay|hoac)\\s+)(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\\s+the|cap\\s+nhat|viet|chay|cai|chinh|trien\\s+khai|cau\\s+hinh|restart|manipulate|resume|push|merge|publish|touch|alter|reset|rollback|revert|commit|kill|release|tag)(?![A-Za-z0-9_]))*[^.,;\\n\u2014]*?(?=\\s+(?:va|and|then|roi|nhung|but)\\s|[.,;\u2014\\n]|\\s*$)`, 'g'), ' ')
|
|
1224
1242
|
.replace(new RegExp(`\\bgiu\\s+nguyen\\b${TAIL}`, 'g'), ' ')
|
|
1225
1243
|
.replace(new RegExp(`\\bmuon\\s+giu\\b${TAIL}`, 'g'), ' ')
|
|
1226
1244
|
.replace(new RegExp(`\\bkhong\\s+(?!chi\\b)${TAIL}`, 'g'), ' ')
|
|
@@ -1252,7 +1270,7 @@ function hasMutationOrder({ promptText = '', commandText = '' } = {}) {
|
|
|
1252
1270
|
.replace(new RegExp(`\\b(?:yeu\\s+cau|doi\\s+hoi|ep\\s+phai|bat\\s+buoc|bat\\s+phai)\\b${TAIL}`, 'g'), ' ')
|
|
1253
1271
|
.replace(new RegExp(`\\b(?:demand(?:ed|s)?|require(?:d|s)?|forcing|forced|forcibly|must|has\\s+to|have\\s+to)\\b${TAIL}`, 'g'), ' ')
|
|
1254
1272
|
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|not|never|no)\\s+(?!only\\b)${TAIL}`, 'g'), ' ')
|
|
1255
|
-
.replace(new RegExp(`\\b(?:can|nen|phai|duoc)\\s+(?:duoc\\s+)?(?:sua|cau\\s+hinh|thay\\s+doi|cap\\s+nhat|edit|fix|config)\\b${TAIL}`, 'g'), ' ')
|
|
1273
|
+
.replace(new RegExp(`\\b(?<!\\bvan\\s)(?:can|nen|phai|duoc)\\s+(?:duoc\\s+)?(?:sua|cau\\s+hinh|thay\\s+doi|cap\\s+nhat|edit|fix|config)\\b${TAIL}`, 'g'), ' ')
|
|
1256
1274
|
.replace(/\bco\s+(?:can|nen)\s+sua\b[^.,;\n?]*/g, ' ')
|
|
1257
1275
|
.replace(/(?:^|[.,;\n]\s*)(?:should|shall)\s+(?:i|we|you)\b[^.,;\n?]*/g, ' ')
|
|
1258
1276
|
.replace(/\bchi\s+(?:tu\s+van|hoi|giai\s+thich|xem|la\s+cau\s+hoi|can|la)\b[^.,;\n]*/g, ' ')
|
|
@@ -668,7 +668,7 @@ async function scanTranscript() {
|
|
|
668
668
|
if (readable) {
|
|
669
669
|
try {
|
|
670
670
|
const mod = await import(require('url').pathToFileURL(path.resolve(process.env.HOOK_DIR || '.', '../ukit/runtime/handoff-intent.mjs')).href);
|
|
671
|
-
scan = await (mod.transcriptHandoffIntentInherited || mod.transcriptHandoffIntent)(transcriptPath);
|
|
671
|
+
scan = await (mod.transcriptHandoffIntentInherited || mod.transcriptHandoffIntent)(transcriptPath, { cacheDir: path.join(projectRoot, '.ukit/storage/cache/handoff-intent') });
|
|
672
672
|
} catch {
|
|
673
673
|
scan = { intent: null, known: false };
|
|
674
674
|
}
|
|
@@ -1814,14 +1814,43 @@ function nativeOperationGoal(domain, actionable, text) {
|
|
|
1814
1814
|
}
|
|
1815
1815
|
|
|
1816
1816
|
// Task semantics are independent of source execution strategy and observed progress.
|
|
1817
|
+
// P1-A (forensic false block): the clause splitter below cuts at commas, so a negation only reached the
|
|
1818
|
+
// FIRST item of an enumeration ("Do not implement fixes, modify source code, restart services, ...") and
|
|
1819
|
+
// the later items became actionable orders (MIXED + service-runtime). English negators now scope to the
|
|
1820
|
+
// sentence end (', and'/', or' continue the list; a bare 'and <verb>' or but/then starts a new clause);
|
|
1821
|
+
// Vietnamese negators scope to the sentence end as well. Noun uses of verbs ("write/verification advisory", "each proposed
|
|
1822
|
+
// fix", "state change") name things, not orders. Neutralised spans become blanks, never new orders.
|
|
1823
|
+
const NON_ORDER_VERBS = 'implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|restart|sua|viet|chinh|them|tao|xoa';
|
|
1824
|
+
function neutralizeNonOrders(text) {
|
|
1825
|
+
return String(text)
|
|
1826
|
+
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|must\\s+not|never|shall\\s+not)\\s+[^.;\\n]*?(?=(?<!,)\\s+(?:and|va)\\s+(?:${NON_ORDER_VERBS})\\b|\\s+(?:but|nhung|then|however)\\b|[.;\\n]|$)`, 'g'), ' ')
|
|
1827
|
+
.replace(new RegExp(`\\b(?:khong|chua)\\s+[^.;\\n]*?(?=\\s+(?:nhung|tuy nhien)\\b|[.;\\n]|$)`, 'g'), ' ')
|
|
1828
|
+
.replace(/"[^"\n]*\s[^"\n]*"|`[^`\n]*\s[^`\n]*`|\u201c[^\u201d\n]*\u201d/g, ' ')
|
|
1829
|
+
.replace(/\b(?:neu\s+(?:phai|can|thieu|khong du|bang chung chua du)|if\s+(?:needed|necessary|required|evidence is insufficient))\b[^.;\n]*/g, ' ')
|
|
1830
|
+
.replace(/[^.;\n]*\b(?:nao|gi|sao|the nao|bao nhieu)\b[^.;\n]*\?/g, ' ')
|
|
1831
|
+
.replace(/\bchinh\s+xac\b|\b(?:phuong an|cach|de xuat|ban)\s+(?:sua|fix)\b/g, ' ')
|
|
1832
|
+
.replace(/\bwrite\s*\/\s*verification\b|\bverification\s*\/\s*write\b|\bwrite\s+(?:or|and)\s+verification\b/g, ' ')
|
|
1833
|
+
.replace(/\b(?:state|status)\s+changes?\b/g, ' ')
|
|
1834
|
+
.replace(/\b(?:proposed|suggested|recommended|minimal|each|the|an?|any|that|this|no|which|exact|smallest|possible)\s+fix(?:es)?\b/g, ' ');
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1817
1837
|
function classifyTaskSemantics({ promptText = '', targetFile = '' } = {}) {
|
|
1818
|
-
|
|
1838
|
+
// A named preflight and both explicit branches are required; a failed arbitrary test is not a release policy.
|
|
1839
|
+
const releaseText = String(promptText).normalize('NFD').replace(/[̀-ͯ]/g, '').replace(/[đĐ]/g, 'd').toLowerCase();
|
|
1840
|
+
const preflight = releaseText.match(/\b(?:yarn\s+release:verify|npm\s+run\s+release:verify)\b/)?.[0];
|
|
1841
|
+
const releasePolicy = preflight && /\b(?:if|neu|only when|only if)\b[^\n.;]*(?:pass|go)\b[^\n.;]*(?:release|publish)\b/.test(releaseText)
|
|
1842
|
+
&& /\b(?:fail|no-go)\b[^\n.;]*(?:do not publish|don't publish|no publish|khong publish|khong npm publish)\b/.test(releaseText)
|
|
1843
|
+
? { kind: 'conditional-release', preflight } : null;
|
|
1844
|
+
const text = neutralizeNonOrders(String(promptText).normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[đĐ]/g, 'd').toLowerCase());
|
|
1819
1845
|
const clauses = text.split(/\s*(?:[;\n,]|\.(?:\s+|$)|\band\b|\bthen\b|\bva\b)\s*/);
|
|
1820
1846
|
const actionable = clauses.map((clause) => clause.split(/\bwithout\b/)[0]).filter((clause) => !/\b(?:do not|don't|never|khong|dung)\b/.test(clause)
|
|
1821
1847
|
&& !/^\s*(?:audit|inspect|review|analyze|analyse|explain|read|kiem tra|phan tich)\b/.test(clause));
|
|
1822
|
-
const sourceOrder = actionable.some((clause) => /\b(?:implement|fix|refactor|modify|edit|write|update|sua|viet|chinh)\b/.test(clause)
|
|
1848
|
+
const sourceOrder = actionable.some((clause) => /\b(?:implement|fix(?:es)?|apply|refactor|modify|edit|write|update|sua|viet|chinh)\b/.test(clause)
|
|
1823
1849
|
&& /\b(?:source|code|logic|scheduler|implementation|ma nguon)\b|\.[cm]?[jt]sx?\b/.test(clause));
|
|
1824
|
-
const codeChangeVerb = actionable.some((clause) => /\b(?:implement|fix|refactor|modify|edit|write|update|sua|viet|chinh)\b/.test(clause));
|
|
1850
|
+
const codeChangeVerb = actionable.some((clause) => /\b(?:implement|fix(?:es)?|apply|refactor|modify|edit|write|update|sua|viet|chinh)\b/.test(clause));
|
|
1851
|
+
const reportArtifact = String(promptText).match(/(?:^|\s)((?:docs\/|reports\/)[A-Za-z0-9_./-]+\.(?:md|txt))(?=\s|[.,;:]|$)/)?.[1];
|
|
1852
|
+
const documentation = !sourceOrder && !/\b(?:implement|fix|refactor|modify|edit|update|sua|chinh)\b/.test(actionable.join(' ')) && reportArtifact && actionable.some((clause) => /\b(?:write|create|save|viet|tao|luu)\b/.test(clause))
|
|
1853
|
+
&& /\b(?:report|bao cao|analysis|phan tich|document)\b/.test(text);
|
|
1825
1854
|
const hasOperationId = /\b[a-f0-9]{8}(?:[a-f0-9-]{0,28})\b/.test(text);
|
|
1826
1855
|
// A cron/job MENTION is not an operation: with a code-change verb in the request, an
|
|
1827
1856
|
// operation needs a concrete target id; otherwise it is a coding task about scheduling.
|
|
@@ -1846,13 +1875,13 @@ function classifyTaskSemantics({ promptText = '', targetFile = '' } = {}) {
|
|
|
1846
1875
|
// lookup verb AND no mutation vocabulary anywhere in the request (fail-closed otherwise).
|
|
1847
1876
|
const mutationWord = /\b(?:implement|fix|refactor|modify|edit|write|update|add|create|build|make|install|deploy|remove|delete|rename|replace|change|sua|viet|chinh|them|tao|xoa|doi|cai|cap nhat)\b/.test(text);
|
|
1848
1877
|
const statusReport = !mutationWord && !operation && !config
|
|
1849
|
-
&& /\b(?:check|status|report|show|summari[sz]e|result|results|kiem tra|bao cao|trang thai|ket qua)\b/.test(text);
|
|
1850
|
-
const readOnly = (/\b(?:audit|inspect|review|analyze|analyse|explain|read|kiem tra|phan tich)\b/.test(text) || statusReport)
|
|
1878
|
+
&& /\b(?:check|status|report|show|summari[sz]e|result|results|kiem tra|bao cao|trang thai|ket qua|da len chua)\b/.test(text);
|
|
1879
|
+
const readOnly = (/\b(?:audit|inspect|review|analyze|analyse|explain|read|investigate|debug|forensic|root cause|kiem tra|phan tich|dieu tra|doc log|tim hieu)\b/.test(text) || statusReport)
|
|
1851
1880
|
&& !sourceOrder && !codeChangeVerb && !operation && !config;
|
|
1852
1881
|
const taskKind = operation ? (sourceOrder || (nativeDomain !== 'scheduled-job' && codeChangeVerb) ? 'MIXED' : 'OPERATIONAL')
|
|
1853
|
-
: config ? 'CONFIGURATION' : readOnly ? 'READ_ONLY' : 'CODE_IMPLEMENTATION';
|
|
1882
|
+
: config ? 'CONFIGURATION' : documentation ? 'DOCUMENTATION_OUTPUT' : readOnly ? 'READ_ONLY' : 'CODE_IMPLEMENTATION';
|
|
1854
1883
|
const id = text.match(/\b[a-f0-9]{8}(?:[a-f0-9-]{0,28})\b/)?.[0] || null;
|
|
1855
|
-
return { taskKind, ...(taskKind === 'READ_ONLY' && statusReport ? { statusReport: true } : {}), ...(config ? { configurationScope: repository ? 'repository' : 'external' } : {}),
|
|
1884
|
+
return { taskKind, ...(releasePolicy ? { releasePolicy } : {}), ...(documentation ? { reportArtifact } : {}), ...(taskKind === 'READ_ONLY' && statusReport ? { statusReport: true } : {}), ...(config ? { configurationScope: repository ? 'repository' : 'external' } : {}),
|
|
1856
1885
|
...(operation && nativeDomain !== 'scheduled-job' ? { operationGoal: nativeOperationGoal(nativeDomain, actionable, text) } : {}),
|
|
1857
1886
|
...(operation && nativeDomain === 'scheduled-job' ? { operationGoal: { domain: 'scheduled-job', target: id, desiredState: /\b(?:delete|remove|cancel|xoa|huy|absent|removed|deleted|no longer|khong con)\b/.test(actionable.join(' ')) ? 'absent' : 'present',
|
|
1858
1887
|
completionSemantics: /\b(?:ensure|dam bao)\b/.test(text) ? 'ensure-state' : 'execute-and-verify' } } : {}) };
|
|
@@ -1863,7 +1892,7 @@ function applyTaskSemantics(contract, semantic) {
|
|
|
1863
1892
|
const operationOnly = semantic.taskKind === 'OPERATIONAL'
|
|
1864
1893
|
|| (semantic.taskKind === 'CONFIGURATION' && semantic.configurationScope === 'external');
|
|
1865
1894
|
return { ...(contract || {}), ...semantic,
|
|
1866
|
-
completionEvidence: operationOnly ? ['operation-verification']
|
|
1895
|
+
completionEvidence: semantic.taskKind === 'DOCUMENTATION_OUTPUT' ? ['report-artifact'] : operationOnly ? ['operation-verification']
|
|
1867
1896
|
: semantic.taskKind === 'MIXED' ? [...new Set([...evidence, 'write-evidence', 'operation-verification'])]
|
|
1868
1897
|
: semantic.taskKind === 'READ_ONLY' && semantic.statusReport ? []
|
|
1869
1898
|
: semantic.taskKind === 'READ_ONLY' ? (evidence.length === 1 && evidence[0] === 'verification-evidence' ? evidence : ['impact-evidence']) : evidence };
|
|
@@ -2207,14 +2236,23 @@ function applyTaskSemantics(contract, semantic) {
|
|
|
2207
2236
|
const residue = trimmed
|
|
2208
2237
|
.replace(/"[^"\n]*"|«[^»\n]*»/g, ' ')
|
|
2209
2238
|
// "tạo plan" / "create a plan": the plan is the deliverable, not a mutation order.
|
|
2210
|
-
.replace(/\b(?:tao|lap|create|make|write|draft)\s+(?:cho\s+toi\s+)?(?:a\s+|an\s+|the\s+|1\s+|mot\s+)?(?:plan|ke\s+hoach|phuong\s+an|lo\s+trinh|roadmap)\b/g, ' ')
|
|
2239
|
+
.replace(/\b(?:tao|lap|viet|create|make|write|draft|produce)\s+(?:cho\s+toi\s+)?(?:a\s+|an\s+|the\s+|1\s+|mot\s+)?(?:one\s+)?(?:structured\s+|forensic\s+|short\s+|brief\s+)?(?:plan|ke\s+hoach|phuong\s+an|lo\s+trinh|roadmap|bao\s+cao|report|danh\s+gia|assessment)\b/g, ' ')
|
|
2211
2240
|
.replace(/\bwrite-evidence\b|\bverification-evidence\b|\bimpact-evidence\b|\broot-cause\b/g, ' ')
|
|
2241
|
+
// P1-A (forensic false block): nouns and investigation questions are not orders. 'write/verification
|
|
2242
|
+
// advisory', 'state change', 'each proposed fix' name things; 'whether X may create Y' asks a question to
|
|
2243
|
+
// answer. A negated ENUMERATION with objects ('do not implement fixes, modify source code, ... or create
|
|
2244
|
+
// commits') negates every item to its sentence end; the older verb-only chain broke at 'fixes'.
|
|
2245
|
+
.replace(/\bwrite\s*\/\s*verification\b|\bverification\s*\/\s*write\b|\bwrite\s+(?:or|and)\s+verification\b/g, ' ')
|
|
2246
|
+
.replace(/\b(?:state|status)\s+changes?\b/g, ' ')
|
|
2247
|
+
.replace(/\b(?:proposed|suggested|recommended|minimal|each|the|an?|any|that|this|no|which|exact|smallest|possible)\s+fix(?:es)?\b/g, ' ')
|
|
2248
|
+
.replace(new RegExp(`\\bwhether\\b[^.,;\\n]*?(?=\\s+(?:va|and)\\s+(?:${MUT_VERBS})(?![A-Za-z0-9_])|[.,;\\n]|$)`, 'g'), ' ')
|
|
2249
|
+
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|must\\s+not|never|not|khong(?:\\s+duoc)?|tuyet\\s+doi\\s+khong)\\s+(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\\s+the|cap\\s+nhat|viet|chay|cai|chinh|trien\\s+khai|cau\\s+hinh)(?![A-Za-z0-9_])(?:[^.,;\\n\u2014]*?(?:\\s*,\\s*(?:(?:or|and|nor|hay|hoac|va)\\s+)?|\\s+(?:or|nor|hay|hoac)\\s+)(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\\s+the|cap\\s+nhat|viet|chay|cai|chinh|trien\\s+khai|cau\\s+hinh|restart|manipulate|resume|push|merge|publish|touch|alter|reset|rollback|revert|commit|kill|release|tag)(?![A-Za-z0-9_]))*[^.,;\\n\u2014]*?(?=\\s+(?:va|and|then|roi|nhung|but)\\s|[.,;\u2014\\n]|\\s*$)`, 'g'), ' ')
|
|
2212
2250
|
// A negated LIST ("do not implement, fix, or refactor"; "khong implement, sua, refactor hay chinh") negates every
|
|
2213
2251
|
// verb in the list: the TAIL strip below stops at the first comma, which would leave the later verbs as orders.
|
|
2214
2252
|
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|must\\s+not|never|not|khong(?:\\s+duoc)?|tuyet\\s+doi\\s+khong)\\s+(?:${MUT_VERBS})(?![A-Za-z0-9_])(?:\\s*(?:,|,?\\s+(?:or|and|nor|hay|hoac|va))\\s*(?:(?:${MUT_VERBS})(?![A-Za-z0-9_])|(?:${MUT_VERBS})\\s))*[^.,;\\n\u2014]*?(?=\\s+(?:va|and|then|roi|nhung|but)\\s|[.,;\u2014\\n]|\\s*$)`, 'g'), ' ')
|
|
2215
2253
|
.replace(new RegExp(`\\bgiu\\s+nguyen\\b${TAIL}`, 'g'), ' ')
|
|
2216
2254
|
.replace(new RegExp(`\\bmuon\\s+giu\\b${TAIL}`, 'g'), ' ')
|
|
2217
|
-
.replace(new RegExp(`\\
|
|
2255
|
+
.replace(new RegExp(`\\b(?:khong|chua)\\s+(?!chi\\b)${TAIL}`, 'g'), ' ')
|
|
2218
2256
|
.replace(new RegExp(`\\bdung\\s+${TAIL}`, 'g'), ' ')
|
|
2219
2257
|
// C89-008: a waiting clause narrates what the TURN waits on, not what
|
|
2220
2258
|
// the request orders — verbs inside it ("chờ sửa xong", "waiting for
|
|
@@ -2231,7 +2269,7 @@ function applyTaskSemantics(contract, semantic) {
|
|
|
2231
2269
|
.replace(new RegExp(`\\b(?:de|cho)\\s+${TAIL}`, 'g'), ' ')
|
|
2232
2270
|
.replace(new RegExp(`\\b(?:yeu\\s+cau|doi\\s+hoi|ep\\s+phai|bat\\s+buoc|bat\\s+phai)\\b${TAIL}`, 'g'), ' ')
|
|
2233
2271
|
.replace(new RegExp(`\\b(?:demand(?:ed|s)?|require(?:d|s)?|forcing|forced|forcibly|must|has\\s+to|have\\s+to)\\b${TAIL}`, 'g'), ' ')
|
|
2234
|
-
.replace(new RegExp(`\\b(?:can|nen|phai|duoc)\\s+(?:duoc\\s+)?(?:sua|cau\\s+hinh|thay\\s+doi|cap\\s+nhat|edit|fix|config)\\b${TAIL}`, 'g'), ' ')
|
|
2272
|
+
.replace(new RegExp(`\\b(?<!\\bvan\\s)(?:can|nen|phai|duoc)\\s+(?:duoc\\s+)?(?:sua|cau\\s+hinh|thay\\s+doi|cap\\s+nhat|edit|fix|config)\\b${TAIL}`, 'g'), ' ')
|
|
2235
2273
|
.replace(/\bco\s+(?:can|nen)\s+sua\b[^.,;\n?]*/g, ' ')
|
|
2236
2274
|
.replace(/(?:^|[.,;\n]\s*)(?:should|shall)\s+(?:i|we|you)\b[^.,;\n?]*/g, ' ')
|
|
2237
2275
|
.replace(/\bchi\s+(?:tu\s+van|hoi|giai\s+thich|xem|la\s+cau\s+hoi|can|la)\b[^.,;\n]*/g, ' ')
|
|
@@ -2269,17 +2307,26 @@ function applyTaskSemantics(contract, semantic) {
|
|
|
2269
2307
|
const residue = trimmed
|
|
2270
2308
|
.replace(/"[^"\n]*"|«[^»\n]*»/g, ' ')
|
|
2271
2309
|
// "tạo plan" / "create a plan": the plan is the deliverable, not a mutation order.
|
|
2272
|
-
.replace(/\b(?:tao|lap|create|make|write|draft)\s+(?:cho\s+toi\s+)?(?:a\s+|an\s+|the\s+|1\s+|mot\s+)?(?:plan|ke\s+hoach|phuong\s+an|lo\s+trinh|roadmap)\b/g, ' ')
|
|
2310
|
+
.replace(/\b(?:tao|lap|viet|create|make|write|draft|produce)\s+(?:cho\s+toi\s+)?(?:a\s+|an\s+|the\s+|1\s+|mot\s+)?(?:one\s+)?(?:structured\s+|forensic\s+|short\s+|brief\s+)?(?:plan|ke\s+hoach|phuong\s+an|lo\s+trinh|roadmap|bao\s+cao|report|danh\s+gia|assessment)\b/g, ' ')
|
|
2273
2311
|
// Descriptive state, not an order: "đã/vừa [được] + verb" ("hooks vừa được cài đặt") reports
|
|
2274
2312
|
// something already done. Only the verb is stripped, so a later imperative still survives.
|
|
2275
2313
|
.replace(/(?<![a-z0-9_])(?:da|vua)\s+(?:duoc\s+)?(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\s+the|cap\s+nhat|viet|chay|cai|chinh|trien\s+khai|cau\s+hinh)(?![a-z0-9_])/g, ' ')
|
|
2276
2314
|
.replace(/\bwrite-evidence\b|\bverification-evidence\b|\bimpact-evidence\b|\broot-cause\b/g, ' ')
|
|
2315
|
+
// P1-A (forensic false block): nouns and investigation questions are not orders. 'write/verification
|
|
2316
|
+
// advisory', 'state change', 'each proposed fix' name things; 'whether X may create Y' asks a question to
|
|
2317
|
+
// answer. A negated ENUMERATION with objects ('do not implement fixes, modify source code, ... or create
|
|
2318
|
+
// commits') negates every item to its sentence end; the older verb-only chain broke at 'fixes'.
|
|
2319
|
+
.replace(/\bwrite\s*\/\s*verification\b|\bverification\s*\/\s*write\b|\bwrite\s+(?:or|and)\s+verification\b/g, ' ')
|
|
2320
|
+
.replace(/\b(?:state|status)\s+changes?\b/g, ' ')
|
|
2321
|
+
.replace(/\b(?:proposed|suggested|recommended|minimal|each|the|an?|any|that|this|no|which|exact|smallest|possible)\s+fix(?:es)?\b/g, ' ')
|
|
2322
|
+
.replace(new RegExp(`\\bwhether\\b[^.,;\\n]*?(?=\\s+(?:va|and)\\s+(?:${MUT_VERBS})(?![A-Za-z0-9_])|[.,;\\n]|$)`, 'g'), ' ')
|
|
2323
|
+
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|must\\s+not|never|not|khong(?:\\s+duoc)?|tuyet\\s+doi\\s+khong)\\s+(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\\s+the|cap\\s+nhat|viet|chay|cai|chinh|trien\\s+khai|cau\\s+hinh)(?![A-Za-z0-9_])(?:[^.,;\\n\u2014]*?(?:\\s*,\\s*(?:(?:or|and|nor|hay|hoac|va)\\s+)?|\\s+(?:or|nor|hay|hoac)\\s+)(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\\s+the|cap\\s+nhat|viet|chay|cai|chinh|trien\\s+khai|cau\\s+hinh|restart|manipulate|resume|push|merge|publish|touch|alter|reset|rollback|revert|commit|kill|release|tag)(?![A-Za-z0-9_]))*[^.,;\\n\u2014]*?(?=\\s+(?:va|and|then|roi|nhung|but)\\s|[.,;\u2014\\n]|\\s*$)`, 'g'), ' ')
|
|
2277
2324
|
// A negated LIST ("do not implement, fix, or refactor"; "khong implement, sua, refactor hay chinh") negates every
|
|
2278
2325
|
// verb in the list: the TAIL strip below stops at the first comma, which would leave the later verbs as orders.
|
|
2279
2326
|
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|must\\s+not|never|not|khong(?:\\s+duoc)?|tuyet\\s+doi\\s+khong)\\s+(?:${MUT_VERBS})(?![A-Za-z0-9_])(?:\\s*(?:,|,?\\s+(?:or|and|nor|hay|hoac|va))\\s*(?:(?:${MUT_VERBS})(?![A-Za-z0-9_])|(?:${MUT_VERBS})\\s))*[^.,;\\n\u2014]*?(?=\\s+(?:va|and|then|roi|nhung|but)\\s|[.,;\u2014\\n]|\\s*$)`, 'g'), ' ')
|
|
2280
2327
|
.replace(new RegExp(`\\bgiu\\s+nguyen\\b${TAIL}`, 'g'), ' ')
|
|
2281
2328
|
.replace(new RegExp(`\\bmuon\\s+giu\\b${TAIL}`, 'g'), ' ')
|
|
2282
|
-
.replace(new RegExp(`\\
|
|
2329
|
+
.replace(new RegExp(`\\b(?:khong|chua)\\s+(?!chi\\b)${TAIL}`, 'g'), ' ')
|
|
2283
2330
|
.replace(new RegExp(`\\bdung\\s+${TAIL}`, 'g'), ' ')
|
|
2284
2331
|
// C89-008: a waiting clause narrates what the TURN waits on, not what
|
|
2285
2332
|
// the request orders — verbs inside it belong to the wait.
|
|
@@ -2307,7 +2354,7 @@ function applyTaskSemantics(contract, semantic) {
|
|
|
2307
2354
|
.replace(new RegExp(`\\b(?:de|cho)\\s+${TAIL}`, 'g'), ' ')
|
|
2308
2355
|
.replace(new RegExp(`\\b(?:yeu\\s+cau|doi\\s+hoi|ep\\s+phai|bat\\s+buoc|bat\\s+phai)\\b${TAIL}`, 'g'), ' ')
|
|
2309
2356
|
.replace(new RegExp(`\\b(?:demand(?:ed|s)?|require(?:d|s)?|forcing|forced|forcibly|must|has\\s+to|have\\s+to)\\b${TAIL}`, 'g'), ' ')
|
|
2310
|
-
.replace(new RegExp(`\\b(?:can|nen|phai|duoc)\\s+(?:duoc\\s+)?(?:sua|cau\\s+hinh|thay\\s+doi|cap\\s+nhat|edit|fix|config)\\b${TAIL}`, 'g'), ' ')
|
|
2357
|
+
.replace(new RegExp(`\\b(?<!\\bvan\\s)(?:can|nen|phai|duoc)\\s+(?:duoc\\s+)?(?:sua|cau\\s+hinh|thay\\s+doi|cap\\s+nhat|edit|fix|config)\\b${TAIL}`, 'g'), ' ')
|
|
2311
2358
|
.replace(/\bco\s+(?:can|nen)\s+sua\b[^.,;\n?]*/g, ' ')
|
|
2312
2359
|
.replace(/(?:^|[.,;\n]\s*)(?:should|shall)\s+(?:i|we|you)\b[^.,;\n?]*/g, ' ')
|
|
2313
2360
|
.replace(/\bchi\s+(?:tu\s+van|hoi|giai\s+thich|xem|la\s+cau\s+hoi|can|la)\b[^.,;\n]*/g, ' ')
|
|
@@ -3783,7 +3830,7 @@ function applyTaskSemantics(contract, semantic) {
|
|
|
3783
3830
|
let previous = sessionId
|
|
3784
3831
|
? [storedPrevious, sidecarPrevious].find((state) => String(state?.sessionId || '').trim() === sessionId) || {}
|
|
3785
3832
|
: storedPrevious;
|
|
3786
|
-
const continuationPrompt = /^(?:continue|resume|keep going|proceed|tiep tuc)(?:\s+(?:the
|
|
3833
|
+
const continuationPrompt = /^(?:continue|resume|keep going|go on|proceed|tiep tuc|lam tiep)(?:\s+(?:with\s+)?(?:the\s+|this\s+)?(?:previous\s+|last\s+|current\s+|same\s+)?(?:implementation\s+)?(?:task|work))?(?:\s+(?:thoi|di|đi|nhe|nao|nua|a|ha|please|pls|now|then))*\s*[.!]?$/i.test(
|
|
3787
3834
|
extractPrompt(payload).normalize('NFD').replace(/[̀-ͯ]/g, '').trim());
|
|
3788
3835
|
// Restore a contract parked by an informational turn: only for the SAME session, and only
|
|
3789
3836
|
// on an explicit continuation or a mutating tool event (never a fresh prompt, which routes on its own,
|
|
@@ -1086,14 +1086,43 @@ function nativeOperationGoal(domain, actionable, text) {
|
|
|
1086
1086
|
}
|
|
1087
1087
|
|
|
1088
1088
|
// Task semantics are independent of source execution strategy and observed progress.
|
|
1089
|
+
// P1-A (forensic false block): the clause splitter below cuts at commas, so a negation only reached the
|
|
1090
|
+
// FIRST item of an enumeration ("Do not implement fixes, modify source code, restart services, ...") and
|
|
1091
|
+
// the later items became actionable orders (MIXED + service-runtime). English negators now scope to the
|
|
1092
|
+
// sentence end (', and'/', or' continue the list; a bare 'and <verb>' or but/then starts a new clause);
|
|
1093
|
+
// Vietnamese negators scope to the sentence end as well. Noun uses of verbs ("write/verification advisory", "each proposed
|
|
1094
|
+
// fix", "state change") name things, not orders. Neutralised spans become blanks, never new orders.
|
|
1095
|
+
const NON_ORDER_VERBS = 'implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|restart|sua|viet|chinh|them|tao|xoa';
|
|
1096
|
+
function neutralizeNonOrders(text) {
|
|
1097
|
+
return String(text)
|
|
1098
|
+
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|must\\s+not|never|shall\\s+not)\\s+[^.;\\n]*?(?=(?<!,)\\s+(?:and|va)\\s+(?:${NON_ORDER_VERBS})\\b|\\s+(?:but|nhung|then|however)\\b|[.;\\n]|$)`, 'g'), ' ')
|
|
1099
|
+
.replace(new RegExp(`\\b(?:khong|chua)\\s+[^.;\\n]*?(?=\\s+(?:nhung|tuy nhien)\\b|[.;\\n]|$)`, 'g'), ' ')
|
|
1100
|
+
.replace(/"[^"\n]*\s[^"\n]*"|`[^`\n]*\s[^`\n]*`|\u201c[^\u201d\n]*\u201d/g, ' ')
|
|
1101
|
+
.replace(/\b(?:neu\s+(?:phai|can|thieu|khong du|bang chung chua du)|if\s+(?:needed|necessary|required|evidence is insufficient))\b[^.;\n]*/g, ' ')
|
|
1102
|
+
.replace(/[^.;\n]*\b(?:nao|gi|sao|the nao|bao nhieu)\b[^.;\n]*\?/g, ' ')
|
|
1103
|
+
.replace(/\bchinh\s+xac\b|\b(?:phuong an|cach|de xuat|ban)\s+(?:sua|fix)\b/g, ' ')
|
|
1104
|
+
.replace(/\bwrite\s*\/\s*verification\b|\bverification\s*\/\s*write\b|\bwrite\s+(?:or|and)\s+verification\b/g, ' ')
|
|
1105
|
+
.replace(/\b(?:state|status)\s+changes?\b/g, ' ')
|
|
1106
|
+
.replace(/\b(?:proposed|suggested|recommended|minimal|each|the|an?|any|that|this|no|which|exact|smallest|possible)\s+fix(?:es)?\b/g, ' ');
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1089
1109
|
export function classifyTaskSemantics({ promptText = '', targetFile = '' } = {}) {
|
|
1090
|
-
|
|
1110
|
+
// A named preflight and both explicit branches are required; a failed arbitrary test is not a release policy.
|
|
1111
|
+
const releaseText = String(promptText).normalize('NFD').replace(/[̀-ͯ]/g, '').replace(/[đĐ]/g, 'd').toLowerCase();
|
|
1112
|
+
const preflight = releaseText.match(/\b(?:yarn\s+release:verify|npm\s+run\s+release:verify)\b/)?.[0];
|
|
1113
|
+
const releasePolicy = preflight && /\b(?:if|neu|only when|only if)\b[^\n.;]*(?:pass|go)\b[^\n.;]*(?:release|publish)\b/.test(releaseText)
|
|
1114
|
+
&& /\b(?:fail|no-go)\b[^\n.;]*(?:do not publish|don't publish|no publish|khong publish|khong npm publish)\b/.test(releaseText)
|
|
1115
|
+
? { kind: 'conditional-release', preflight } : null;
|
|
1116
|
+
const text = neutralizeNonOrders(String(promptText).normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[đĐ]/g, 'd').toLowerCase());
|
|
1091
1117
|
const clauses = text.split(/\s*(?:[;\n,]|\.(?:\s+|$)|\band\b|\bthen\b|\bva\b)\s*/);
|
|
1092
1118
|
const actionable = clauses.map((clause) => clause.split(/\bwithout\b/)[0]).filter((clause) => !/\b(?:do not|don't|never|khong|dung)\b/.test(clause)
|
|
1093
1119
|
&& !/^\s*(?:audit|inspect|review|analyze|analyse|explain|read|kiem tra|phan tich)\b/.test(clause));
|
|
1094
|
-
const sourceOrder = actionable.some((clause) => /\b(?:implement|fix|refactor|modify|edit|write|update|sua|viet|chinh)\b/.test(clause)
|
|
1120
|
+
const sourceOrder = actionable.some((clause) => /\b(?:implement|fix(?:es)?|apply|refactor|modify|edit|write|update|sua|viet|chinh)\b/.test(clause)
|
|
1095
1121
|
&& /\b(?:source|code|logic|scheduler|implementation|ma nguon)\b|\.[cm]?[jt]sx?\b/.test(clause));
|
|
1096
|
-
const codeChangeVerb = actionable.some((clause) => /\b(?:implement|fix|refactor|modify|edit|write|update|sua|viet|chinh)\b/.test(clause));
|
|
1122
|
+
const codeChangeVerb = actionable.some((clause) => /\b(?:implement|fix(?:es)?|apply|refactor|modify|edit|write|update|sua|viet|chinh)\b/.test(clause));
|
|
1123
|
+
const reportArtifact = String(promptText).match(/(?:^|\s)((?:docs\/|reports\/)[A-Za-z0-9_./-]+\.(?:md|txt))(?=\s|[.,;:]|$)/)?.[1];
|
|
1124
|
+
const documentation = !sourceOrder && !/\b(?:implement|fix|refactor|modify|edit|update|sua|chinh)\b/.test(actionable.join(' ')) && reportArtifact && actionable.some((clause) => /\b(?:write|create|save|viet|tao|luu)\b/.test(clause))
|
|
1125
|
+
&& /\b(?:report|bao cao|analysis|phan tich|document)\b/.test(text);
|
|
1097
1126
|
const hasOperationId = /\b[a-f0-9]{8}(?:[a-f0-9-]{0,28})\b/.test(text);
|
|
1098
1127
|
// A cron/job MENTION is not an operation: with a code-change verb in the request, an
|
|
1099
1128
|
// operation needs a concrete target id; otherwise it is a coding task about scheduling.
|
|
@@ -1118,13 +1147,13 @@ export function classifyTaskSemantics({ promptText = '', targetFile = '' } = {})
|
|
|
1118
1147
|
// lookup verb AND no mutation vocabulary anywhere in the request (fail-closed otherwise).
|
|
1119
1148
|
const mutationWord = /\b(?:implement|fix|refactor|modify|edit|write|update|add|create|build|make|install|deploy|remove|delete|rename|replace|change|sua|viet|chinh|them|tao|xoa|doi|cai|cap nhat)\b/.test(text);
|
|
1120
1149
|
const statusReport = !mutationWord && !operation && !config
|
|
1121
|
-
&& /\b(?:check|status|report|show|summari[sz]e|result|results|kiem tra|bao cao|trang thai|ket qua)\b/.test(text);
|
|
1122
|
-
const readOnly = (/\b(?:audit|inspect|review|analyze|analyse|explain|read|kiem tra|phan tich)\b/.test(text) || statusReport)
|
|
1150
|
+
&& /\b(?:check|status|report|show|summari[sz]e|result|results|kiem tra|bao cao|trang thai|ket qua|da len chua)\b/.test(text);
|
|
1151
|
+
const readOnly = (/\b(?:audit|inspect|review|analyze|analyse|explain|read|investigate|debug|forensic|root cause|kiem tra|phan tich|dieu tra|doc log|tim hieu)\b/.test(text) || statusReport)
|
|
1123
1152
|
&& !sourceOrder && !codeChangeVerb && !operation && !config;
|
|
1124
1153
|
const taskKind = operation ? (sourceOrder || codeChangeVerb ? 'MIXED' : 'OPERATIONAL')
|
|
1125
|
-
: config ? 'CONFIGURATION' : readOnly ? 'READ_ONLY' : 'CODE_IMPLEMENTATION';
|
|
1154
|
+
: config ? 'CONFIGURATION' : documentation ? 'DOCUMENTATION_OUTPUT' : readOnly ? 'READ_ONLY' : 'CODE_IMPLEMENTATION';
|
|
1126
1155
|
const id = text.match(/\b[a-f0-9]{8}(?:[a-f0-9-]{0,28})\b/)?.[0] || null;
|
|
1127
|
-
return { taskKind, ...(taskKind === 'READ_ONLY' && statusReport ? { statusReport: true } : {}), ...(config ? { configurationScope: repository ? 'repository' : 'external' } : {}),
|
|
1156
|
+
return { taskKind, ...(releasePolicy ? { releasePolicy } : {}), ...(documentation ? { reportArtifact } : {}), ...(taskKind === 'READ_ONLY' && statusReport ? { statusReport: true } : {}), ...(config ? { configurationScope: repository ? 'repository' : 'external' } : {}),
|
|
1128
1157
|
...(operation && nativeDomain !== 'scheduled-job' ? { operationGoal: nativeOperationGoal(nativeDomain, actionable, text) } : {}),
|
|
1129
1158
|
...(operation && nativeDomain === 'scheduled-job' ? { operationGoal: { domain: 'scheduled-job', target: id, desiredState: /\b(?:delete|remove|cancel|xoa|huy|absent|removed|deleted|no longer|khong con)\b/.test(actionable.join(' ')) ? 'absent' : 'present',
|
|
1130
1159
|
completionSemantics: /\b(?:ensure|dam bao)\b/.test(text)
|
|
@@ -1138,7 +1167,7 @@ export function applyTaskSemantics(contract, semantic) {
|
|
|
1138
1167
|
const operationOnly = semantic.taskKind === 'OPERATIONAL'
|
|
1139
1168
|
|| (semantic.taskKind === 'CONFIGURATION' && semantic.configurationScope === 'external');
|
|
1140
1169
|
return { ...(contract || {}), ...semantic,
|
|
1141
|
-
completionEvidence: operationOnly ? ['operation-verification']
|
|
1170
|
+
completionEvidence: semantic.taskKind === 'DOCUMENTATION_OUTPUT' ? ['report-artifact'] : operationOnly ? ['operation-verification']
|
|
1142
1171
|
: semantic.taskKind === 'MIXED' ? [...new Set([...evidence, 'write-evidence', 'operation-verification'])]
|
|
1143
1172
|
: semantic.taskKind === 'READ_ONLY' && semantic.statusReport ? []
|
|
1144
1173
|
: semantic.taskKind === 'READ_ONLY' ? (evidence.length === 1 && evidence[0] === 'verification-evidence' ? evidence : ['impact-evidence']) : evidence };
|
|
@@ -1167,7 +1167,7 @@ async function main() {
|
|
|
1167
1167
|
}
|
|
1168
1168
|
|
|
1169
1169
|
const continuingTask = Boolean(previousState.taskInstanceId && lastPrompt
|
|
1170
|
-
&& /^(?:continue|resume|keep going|proceed|tiep tuc)(?:\s+(?:the
|
|
1170
|
+
&& /^(?:continue|resume|keep going|go on|proceed|tiep tuc|lam tiep)(?:\s+(?:with\s+)?(?:the\s+|this\s+)?(?:previous\s+|last\s+|current\s+|same\s+)?(?:implementation\s+)?(?:task|work))?(?:\s+(?:thoi|di|đi|nhe|nao|nua|a|ha|please|pls|now|then))*\s*[.!]?$/i.test(
|
|
1171
1171
|
promptText.normalize('NFD').replace(/[̀-ͯ]/g, '').trim()));
|
|
1172
1172
|
const taskInstanceId = readFlagValue(args, '--task-instance-id')
|
|
1173
1173
|
|| (((['skill-router', 'skill-router-provisional'].includes(previousState.source)
|
|
@@ -4431,8 +4431,17 @@ function hasAdvisoryOnlyAssertion({ promptText = '', commandText = '' } = {}) {
|
|
|
4431
4431
|
const residue = trimmed
|
|
4432
4432
|
.replace(/"[^"\n]*"|«[^»\n]*»/g, ' ')
|
|
4433
4433
|
// "tạo plan" / "create a plan": the plan is the deliverable, not a mutation order.
|
|
4434
|
-
.replace(/\b(?:tao|lap|create|make|write|draft)\s+(?:cho\s+toi\s+)?(?:a\s+|an\s+|the\s+|1\s+|mot\s+)?(?:plan|ke\s+hoach|phuong\s+an|lo\s+trinh|roadmap)\b/g, ' ')
|
|
4434
|
+
.replace(/\b(?:tao|lap|viet|create|make|write|draft|produce)\s+(?:cho\s+toi\s+)?(?:a\s+|an\s+|the\s+|1\s+|mot\s+)?(?:one\s+)?(?:structured\s+|forensic\s+|short\s+|brief\s+)?(?:plan|ke\s+hoach|phuong\s+an|lo\s+trinh|roadmap|bao\s+cao|report|danh\s+gia|assessment)\b/g, ' ')
|
|
4435
4435
|
.replace(/\bwrite-evidence\b|\bverification-evidence\b|\bimpact-evidence\b|\broot-cause\b/g, ' ')
|
|
4436
|
+
// P1-A (forensic false block): nouns and investigation questions are not orders. 'write/verification
|
|
4437
|
+
// advisory', 'state change', 'each proposed fix' name things; 'whether X may create Y' asks a question to
|
|
4438
|
+
// answer. A negated ENUMERATION with objects ('do not implement fixes, modify source code, ... or create
|
|
4439
|
+
// commits') negates every item to its sentence end; the older verb-only chain broke at 'fixes'.
|
|
4440
|
+
.replace(/\bwrite\s*\/\s*verification\b|\bverification\s*\/\s*write\b|\bwrite\s+(?:or|and)\s+verification\b/g, ' ')
|
|
4441
|
+
.replace(/\b(?:state|status)\s+changes?\b/g, ' ')
|
|
4442
|
+
.replace(/\b(?:proposed|suggested|recommended|minimal|each|the|an?|any|that|this|no|which|exact|smallest|possible)\s+fix(?:es)?\b/g, ' ')
|
|
4443
|
+
.replace(new RegExp(`\\bwhether\\b[^.,;\\n]*?(?=\\s+(?:va|and)\\s+(?:${MUT_VERBS})(?![A-Za-z0-9_])|[.,;\\n]|$)`, 'g'), ' ')
|
|
4444
|
+
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|must\\s+not|never|not|khong(?:\\s+duoc)?|tuyet\\s+doi\\s+khong)\\s+(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\\s+the|cap\\s+nhat|viet|chay|cai|chinh|trien\\s+khai|cau\\s+hinh)(?![A-Za-z0-9_])(?:[^.,;\\n\u2014]*?(?:\\s*,\\s*(?:(?:or|and|nor|hay|hoac|va)\\s+)?|\\s+(?:or|nor|hay|hoac)\\s+)(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\\s+the|cap\\s+nhat|viet|chay|cai|chinh|trien\\s+khai|cau\\s+hinh|restart|manipulate|resume|push|merge|publish|touch|alter|reset|rollback|revert|commit|kill|release|tag)(?![A-Za-z0-9_]))*[^.,;\\n\u2014]*?(?=\\s+(?:va|and|then|roi|nhung|but)\\s|[.,;\u2014\\n]|\\s*$)`, 'g'), ' ')
|
|
4436
4445
|
// A negated LIST ("do not implement, fix, or refactor"; "khong implement, sua, refactor hay chinh") negates every
|
|
4437
4446
|
// verb in the list: the TAIL strip below stops at the first comma, which would leave the later verbs as orders.
|
|
4438
4447
|
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|must\\s+not|never|not|khong(?:\\s+duoc)?|tuyet\\s+doi\\s+khong)\\s+(?:${MUT_VERBS})(?![A-Za-z0-9_])(?:\\s*(?:,|,?\\s+(?:or|and|nor|hay|hoac|va))\\s*(?:(?:${MUT_VERBS})(?![A-Za-z0-9_])|(?:${MUT_VERBS})\\s))*[^.,;\\n\u2014]*?(?=\\s+(?:va|and|then|roi|nhung|but)\\s|[.,;\u2014\\n]|\\s*$)`, 'g'), ' ')
|
|
@@ -4455,7 +4464,7 @@ function hasAdvisoryOnlyAssertion({ promptText = '', commandText = '' } = {}) {
|
|
|
4455
4464
|
.replace(new RegExp(`\\b(?:de|cho)\\s+${TAIL}`, 'g'), ' ')
|
|
4456
4465
|
.replace(new RegExp(`\\b(?:yeu\\s+cau|doi\\s+hoi|ep\\s+phai|bat\\s+buoc|bat\\s+phai)\\b${TAIL}`, 'g'), ' ')
|
|
4457
4466
|
.replace(new RegExp(`\\b(?:demand(?:ed|s)?|require(?:d|s)?|forcing|forced|forcibly|must|has\\s+to|have\\s+to)\\b${TAIL}`, 'g'), ' ')
|
|
4458
|
-
.replace(new RegExp(`\\b(?:can|nen|phai|duoc)\\s+(?:duoc\\s+)?(?:sua|cau\\s+hinh|thay\\s+doi|cap\\s+nhat|edit|fix|config)\\b${TAIL}`, 'g'), ' ')
|
|
4467
|
+
.replace(new RegExp(`\\b(?<!\\bvan\\s)(?:can|nen|phai|duoc)\\s+(?:duoc\\s+)?(?:sua|cau\\s+hinh|thay\\s+doi|cap\\s+nhat|edit|fix|config)\\b${TAIL}`, 'g'), ' ')
|
|
4459
4468
|
.replace(/\bco\s+(?:can|nen)\s+sua\b[^.,;\n?]*/g, ' ')
|
|
4460
4469
|
.replace(/(?:^|[.,;\n]\s*)(?:should|shall)\s+(?:i|we|you)\b[^.,;\n?]*/g, ' ')
|
|
4461
4470
|
.replace(/\bchi\s+(?:tu\s+van|hoi|giai\s+thich|xem|la\s+cau\s+hoi|can|la)\b[^.,;\n]*/g, ' ')
|
|
@@ -4547,11 +4556,20 @@ function hasMutationOrder({ promptText = '', commandText = '' } = {}) {
|
|
|
4547
4556
|
const residue = trimmed
|
|
4548
4557
|
.replace(/"[^"\n]*"|«[^»\n]*»/g, ' ')
|
|
4549
4558
|
// "tạo plan" / "create a plan": the plan is the deliverable, not a mutation order.
|
|
4550
|
-
.replace(/\b(?:tao|lap|create|make|write|draft)\s+(?:cho\s+toi\s+)?(?:a\s+|an\s+|the\s+|1\s+|mot\s+)?(?:plan|ke\s+hoach|phuong\s+an|lo\s+trinh|roadmap)\b/g, ' ')
|
|
4559
|
+
.replace(/\b(?:tao|lap|viet|create|make|write|draft|produce)\s+(?:cho\s+toi\s+)?(?:a\s+|an\s+|the\s+|1\s+|mot\s+)?(?:one\s+)?(?:structured\s+|forensic\s+|short\s+|brief\s+)?(?:plan|ke\s+hoach|phuong\s+an|lo\s+trinh|roadmap|bao\s+cao|report|danh\s+gia|assessment)\b/g, ' ')
|
|
4551
4560
|
// Descriptive state, not an order: "đã/vừa [được] + verb" ("hooks vừa được cài đặt") reports
|
|
4552
4561
|
// something already done. Only the verb is stripped, so a later imperative still survives.
|
|
4553
4562
|
.replace(/(?<![a-z0-9_])(?:da|vua)\s+(?:duoc\s+)?(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\s+the|cap\s+nhat|viet|chay|cai|chinh|trien\s+khai|cau\s+hinh)(?![a-z0-9_])/g, ' ')
|
|
4554
4563
|
.replace(/\bwrite-evidence\b|\bverification-evidence\b|\bimpact-evidence\b|\broot-cause\b/g, ' ')
|
|
4564
|
+
// P1-A (forensic false block): nouns and investigation questions are not orders. 'write/verification
|
|
4565
|
+
// advisory', 'state change', 'each proposed fix' name things; 'whether X may create Y' asks a question to
|
|
4566
|
+
// answer. A negated ENUMERATION with objects ('do not implement fixes, modify source code, ... or create
|
|
4567
|
+
// commits') negates every item to its sentence end; the older verb-only chain broke at 'fixes'.
|
|
4568
|
+
.replace(/\bwrite\s*\/\s*verification\b|\bverification\s*\/\s*write\b|\bwrite\s+(?:or|and)\s+verification\b/g, ' ')
|
|
4569
|
+
.replace(/\b(?:state|status)\s+changes?\b/g, ' ')
|
|
4570
|
+
.replace(/\b(?:proposed|suggested|recommended|minimal|each|the|an?|any|that|this|no|which|exact|smallest|possible)\s+fix(?:es)?\b/g, ' ')
|
|
4571
|
+
.replace(new RegExp(`\\bwhether\\b[^.,;\\n]*?(?=\\s+(?:va|and)\\s+(?:${MUT_VERBS})(?![A-Za-z0-9_])|[.,;\\n]|$)`, 'g'), ' ')
|
|
4572
|
+
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|must\\s+not|never|not|khong(?:\\s+duoc)?|tuyet\\s+doi\\s+khong)\\s+(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\\s+the|cap\\s+nhat|viet|chay|cai|chinh|trien\\s+khai|cau\\s+hinh)(?![A-Za-z0-9_])(?:[^.,;\\n\u2014]*?(?:\\s*,\\s*(?:(?:or|and|nor|hay|hoac|va)\\s+)?|\\s+(?:or|nor|hay|hoac)\\s+)(?:implement|apply|update|modify|add|create|ship|deliver|fix|refactor|remove|delete|rename|change|write|build|make|install|run|deploy|execute|edit|sua|them|tao|xoa|doi|thay\\s+the|cap\\s+nhat|viet|chay|cai|chinh|trien\\s+khai|cau\\s+hinh|restart|manipulate|resume|push|merge|publish|touch|alter|reset|rollback|revert|commit|kill|release|tag)(?![A-Za-z0-9_]))*[^.,;\\n\u2014]*?(?=\\s+(?:va|and|then|roi|nhung|but)\\s|[.,;\u2014\\n]|\\s*$)`, 'g'), ' ')
|
|
4555
4573
|
// A negated LIST ("do not implement, fix, or refactor"; "khong implement, sua, refactor hay chinh") negates every
|
|
4556
4574
|
// verb in the list: the TAIL strip below stops at the first comma, which would leave the later verbs as orders.
|
|
4557
4575
|
.replace(new RegExp(`\\b(?:do\\s+not|don't|dont|must\\s+not|never|not|khong(?:\\s+duoc)?|tuyet\\s+doi\\s+khong)\\s+(?:${MUT_VERBS})(?![A-Za-z0-9_])(?:\\s*(?:,|,?\\s+(?:or|and|nor|hay|hoac|va))\\s*(?:(?:${MUT_VERBS})(?![A-Za-z0-9_])|(?:${MUT_VERBS})\\s))*[^.,;\\n\u2014]*?(?=\\s+(?:va|and|then|roi|nhung|but)\\s|[.,;\u2014\\n]|\\s*$)`, 'g'), ' ')
|
|
@@ -4585,7 +4603,7 @@ function hasMutationOrder({ promptText = '', commandText = '' } = {}) {
|
|
|
4585
4603
|
.replace(new RegExp(`\\b(?:de|cho)\\s+${TAIL}`, 'g'), ' ')
|
|
4586
4604
|
.replace(new RegExp(`\\b(?:yeu\\s+cau|doi\\s+hoi|ep\\s+phai|bat\\s+buoc|bat\\s+phai)\\b${TAIL}`, 'g'), ' ')
|
|
4587
4605
|
.replace(new RegExp(`\\b(?:demand(?:ed|s)?|require(?:d|s)?|forcing|forced|forcibly|must|has\\s+to|have\\s+to)\\b${TAIL}`, 'g'), ' ')
|
|
4588
|
-
.replace(new RegExp(`\\b(?:can|nen|phai|duoc)\\s+(?:duoc\\s+)?(?:sua|cau\\s+hinh|thay\\s+doi|cap\\s+nhat|edit|fix|config)\\b${TAIL}`, 'g'), ' ')
|
|
4606
|
+
.replace(new RegExp(`\\b(?<!\\bvan\\s)(?:can|nen|phai|duoc)\\s+(?:duoc\\s+)?(?:sua|cau\\s+hinh|thay\\s+doi|cap\\s+nhat|edit|fix|config)\\b${TAIL}`, 'g'), ' ')
|
|
4589
4607
|
.replace(/\bco\s+(?:can|nen)\s+sua\b[^.,;\n?]*/g, ' ')
|
|
4590
4608
|
.replace(/(?:^|[.,;\n]\s*)(?:should|shall)\s+(?:i|we|you)\b[^.,;\n?]*/g, ' ')
|
|
4591
4609
|
.replace(/\bchi\s+(?:tu\s+van|hoi|giai\s+thich|xem|la\s+cau\s+hoi|can|la)\b[^.,;\n]*/g, ' ')
|
|
@@ -140,7 +140,7 @@ export function bashOperationReceipt(rawCommand, response, transportSuccess, goa
|
|
|
140
140
|
// the registry actually printed a semver. Agent prose is never evidence; the completion gate compares the
|
|
141
141
|
// recorded version with package.json and live Git state before it treats a release as published.
|
|
142
142
|
const NPM_PUBLISH = /^npm\s+publish(?:\s|$)/;
|
|
143
|
-
const NPM_VIEW = /^npm\s+view\s+(\S+?)(?:@\S+)?\s+version(?:\s+2>&1)?\s*$/;
|
|
143
|
+
const NPM_VIEW = /^npm\s+view\s+(\S+?)(?:@\S+)?\s+version(?:\s+--prefer-online)?(?:\s+2>&1)?\s*$/;
|
|
144
144
|
const SEMVER_LINE = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
145
145
|
export function releaseReceipt(rawCommand, response, transportSuccess) {
|
|
146
146
|
if (typeof rawCommand !== 'string') return null;
|