fix(dashboard): match correction keywords as whole words, add team keywords - #567
Merged
Merged
Conversation
…ywords
`isCorrectionPrompt` used raw substring matching, so the built-in `undo` and
`redo` fired on ordinary Spanish and Portuguese words ("segundo", "mundo",
"redondo"). One false correction scores 20, which is the share-learnings nudge
threshold on its own.
Keywords in a space-separated script now match as whole words (Unicode-aware,
so accented letters count as letters). Keywords containing Han, Hiragana,
Katakana or Hangul keep substring matching.
Teams can add their own words via `sharing.intervention.correctionKeywords` in
teamai.yaml. The prompt_submit hook resolves them and stores a `correction`
flag on the event, because the machine-level events file mixes sessions from
every team. Events without the flag fall back to the built-in list.
For Tencent#564
… word char Cursor runs hooks from ~/.cursor and sends the project in workspace_roots, so resolving the team via autoDetectInit() (process.cwd()) silently dropped the team's correctionKeywords there. Resolve the project from resolveHookCwd(stdin) and fall back to the user-scope config. Underscore joins the word boundary so identifiers such as "test_undo" do not count as `undo`. Drop the regex cache and fold both keyword lists into one `.some`. CHANGELOG separates the whole-word fix from the team-keywords feature and notes the new `correction` event field; both usage guides say the built-in list still covers only zh/en/ja.
jeff-r2026
self-requested a review
September 15, 2026 09:35
hook-dispatch-cli already chdir's to the hook payload's cwd before running handlers, so autoDetectInit() resolves the right project on Cursor too. The explicit detectProjectConfig(resolveHookCwd(stdin)) path added in the previous commit was redundant; drop it and its tests.
9 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
isCorrectionPrompttested every prompt withlower.includes(keyword). The built-inundoandredoare common Spanish and Portuguese word endings, so "dame el segundo fichero" sent within 60 s of a Stop was recorded as a course correction. One correction scoresCONTRIBUTE_CORRECTION_WEIGHT(20), which equalsCONTRIBUTE_SMART_THRESHOLD, so a single false match fired the/teamai-share-learningsnudge and skewed the Human Intervention panel ofteamai dashboard.Two changes:
(?<![\p{L}\p{N}_])…(?![\p{L}\p{N}_])), so "malísimo" does not matchmaland the identifiertest_undodoes not matchundo; JavaScript\bwould have treatedías a boundary.sharing.intervention.correctionKeywordsinteamai.yamlis merged with the built-in list under the same matching rules. Theprompt_submithook resolves the team config and stores acorrection: booleanon the event. This has to happen at capture time:~/.teamai/dashboard/events.jsonlis machine-level and mixes sessions from every team, sorebuildSessionscannot know which team's keywords apply. A side effect is that the full prompt is checked, not only the 200-character summary. Events written before this change carry no flag and fall back to the built-in list overpromptSummary, now with whole-word matching.The built-in list still covers only Chinese, English and Japanese. A correction typed in another language counts once the team adds its words. Interrupts, tool rejections and tool errors are unchanged.
Dashboard, same seeded events, main vs this branch
Type of Change
Test Plan
npx tsc --noEmitpassed.npx vitest runpassed: 226 files, 3154 tests.New unit tests (15):
dashboard-collector.test.tscovers the seven false positives from the issue, whole-word and multi-word English keywords, underscore as a word character, Chinese and Japanese substring matching, team keywords with accented letters, full-prompt checking past the 200-char summary, and the legacy fallback inrebuildSessions.types.test.tscovers the schema andgetInterventionSharing.hook-handlers.test.tscovers passing team keywords toparseHookEvent, the unreadable-config fallback, and that non-prompt hooks do not read team config.npm run buildpassed.Real built CLI, user scope: 72 of 72 checks passed across Claude, Codex, CodeBuddy, OpenCode and
git,gitlab,githubteam configs. Each combination used an isolatedHOMEwith ateamai.yamldeclaringcorrectionKeywords: [rehazlo, "no era eso", mal], dispatchedstopthenprompt-submitthroughteamai hook-dispatch, and read the persisted event:correctionReal built CLI, project scope: 5 of 5 checks passed. A git repo initialised with
teamai init --self --agent cursorunder an isolatedHOME, keywords added to.teamai/teamai.yaml. Hooks dispatched with the process cwd set to~/.cursorand the project passed only throughworkspace_roots(Cursor payload shape) applied the team keywords; a Claude payload withcwdset to the project did too; a prompt from an unrelated cwd did not see the project's keywords.Real
teamai dashboardonmainand on this branch with the same 21 seeded events (table above).git diff --checkpassed.Related Issues
Fixes #564
Notes for Reviewers
teamCorrectionKeywordsresolves the team viaautoDetectInit(), the same pathcontributeHintAlloweduses for the Stop hook.hook-dispatch-clihas alreadychdir'd to the hook payload's cwd by then, so this also works for Cursor, which runs hooks from~/.cursor; the project-scope check above exercises that path.types.ts.teamai.yamlkey in the Human Intervention section and in theteamai.yamlreference.CHANGELOG.mdhas one Bug Fix entry for the whole-word change and one Feature entry for team keywords and the new event field.