Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Normalize line endings: store text as LF and check out as LF on all
# platforms. This prevents Windows CRLF checkouts (core.autocrlf=true) from
# breaking source-scanning tests that match multi-line \n string literals.
* text=auto eol=lf

# Explicit LF for the source and tooling files the tests read.
*.js text eol=lf
*.json text eol=lf
*.md text eol=lf
*.yml text eol=lf
*.svg text eol=lf

# Binary assets must never be normalized.
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.woff binary
*.woff2 binary
*.ttf binary
*.eot binary
11 changes: 6 additions & 5 deletions agent/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@

## Session Summary

- Active focus: Reworked highlight acrylic so the default effect is text-layer glow/underline without background fill, border blocks, or hidden text.
- Verification: `npx qunit test/highlights.tests.js test/schemes.tests.js`, `npm test`, `npm run webpack`, CDP screenshot `/tmp/taskvision-cdp-visual-final-pass2.png`, visual subagent review, and targeted `git diff --check` passed.
- Active focus: Fixed the Windows-only `master` CI failure (`extension applies on-demand stable ID tracking policy`) caused by CRLF checkouts breaking `\n`-based multi-line source-scanning assertions.
- Root cause + fix: no repo `.gitattributes` + `core.autocrlf=true` ⇒ CRLF working tree; added `.gitattributes` (`* text=auto eol=lf`) to force LF checkout everywhere, and a `readSource()` EOL-normalizing helper in `test/extension.tests.js` for robustness against existing CRLF copies. No runtime code changed.
- Verification: isolated worktree off `origin/master` on Windows (CRLF working tree) reproduced the failure, then `node qunit test/extension.tests.js` (15 passing), `npm test` (145 passing), and `npm run webpack` all passed; `git check-attr` confirms `eol=lf`; staged diff is only `.gitattributes` + `test/extension.tests.js`.

## Active Session Task

| Priority | Task | Status | Owner | Due |
| -------- | ------------------------------------- | ------------- | ----- | ---------- |
| P1 | Rework glass highlight transparency model | Completed | AI | 2026-06-04 |
| Priority | Task | Status | Owner | Due |
| -------- | ---------------------------------------- | --------- | ----- | ---------- |
| P1 | Fix Windows CRLF `master` CI test failure | Completed | AI | 2026-07-08 |
1 change: 1 addition & 0 deletions agent/timeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

| 日期时间 | 任务/变更 | 修改文件 | 实现逻辑 | 修改动机 | 结果/备注 |
| ---------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 2026-07-08 14:33 | 修复 Windows CRLF 导致的 master CI 测试失败 | .gitattributes(新增), test/extension.tests.js | 定位 `origin/master` CI 仅 `windows-latest` 失败于 `extension applies on-demand stable ID tracking policy`(`test/extension.tests.js:158`);根因为仓库无 `.gitattributes` 且 Windows `core.autocrlf=true` 使源码以 CRLF 检出,而该断言用 `indexOf` 匹配含 `\n` 的跨行字符串,CRLF 工作树下永不命中(LF 命中、CRLF 未命中已本机复现)。修复:新增仓库根 `.gitattributes`(`* text=auto eol=lf` + `*.js/*.json/*.md/*.yml/*.svg` 显式 LF + 图片/字体 `binary` 保护)根治各平台检出换行;并在 `test/extension.tests.js` 引入 `readSource()`(读后 `replace(/\r\n/g,'\n')`),将 12 处源码扫描断言改为经其读取,使既有 CRLF 工作副本亦健壮。仅动测试与属性文件,未改运行时代码 | `05bb7a7`(glass/alpha 高亮修正,本身无辜)推送触发 master CI,首次在 Windows 上暴露 `9ae1b2b` 引入的既有跨平台测试缺陷;需在不改运行时逻辑前提下修复 CI 并根治此类 EOL 敏感回归 | 已完成;隔离 worktree(基于 `origin/master`)在本机 Windows(CRLF 工作树)先复现 `not ok ... stable ID tracking policy`,应用修复后 `node qunit test/extension.tests.js`(15 passing)、`npm test`(145 passing)、`npm run webpack` 均通过;`git check-attr` 确认 `eol=lf`;`git diff --cached --stat` 仅 `.gitattributes` 与 `test/extension.tests.js` 两文件、无内容 churn |
| 2026-06-16 13:14 | 跨模型 deep-research:调研升级方向并产出 roadmap | agent/reports/taskvision-upgrade-research-2026-06-16.md(仅新增,未改源码) | deep-research 方法论主循环复刻(websearch+gh+codex search 三通道核实竞品与 2026 AI 任务管理趋势),定位差异化空缺=「扫真实代码 TODO+状态机+持久源锚+富上下文+安全 agent surface」完整组合无成熟者;经 mcp__codex__codex 跨模型对抗(REVISE/15 条)reconcile,P0 重构为 LanguageModelTool 或 MCP 双 surface + 只读共享核心 + 安全护栏(P2→P0)+ 类型化窄适配层 | 用户要求「与 codex 一起 deep-research 找网络/GitHub 热门相关项目对项目优化升级」 | 已完成;关键事实三通道核对、核心论断经 codex 对抗降级精确化;codex 反例 CodeGraph 经核实驳回(纯语义图不碰 TODO),ContextCode(13 装机/MCP 与 TODO 树割裂)精确化;未改源码/构建;后续可据 P0 落地 |
| 2026-06-04 14:47 | 深化玻璃高亮透明度模型 | src/highlights.js, src/schemes.js, test/highlights.tests.js, test/schemes.tests.js, README.md, README_zh.md, package.json, agent/tasks.md, agent/timeline.md | 将 8 位 hex 背景从“继承 alpha”改为“颜色提示 + 显式填充控制”;默认 glass scheme 不再生成 `backgroundColor` 或 border,避免背景 decoration 覆盖字形;默认 acrylic 改为文字层轻辉光和下划线,不再使用背景块;显式 `glassOpacity` / `glassBorderOpacity` / `glowOpacity` 仍可打开对应效果;将默认 `glassType` 收敛为 `tag`;把 `null` / `0` opacity 视为未设置,修复 VS Code 未配置 number 返回 0 时把文字变透明的问题;文档说明默认无填充/无边框、文字层 acrylic 和 `tag` / `line` / `whole-line` 的视觉差异 | 用户截图显示高亮仍是彩色长条且短徽标仍遮住标签字形;根因先后定位为默认 fill/border 覆盖、VS Code 默认 number 配置返回 0 导致文字被透明化,以及需要在不使用背景块的前提下恢复 acrylic 质感 | 已完成;验证执行 `npx qunit test/highlights.tests.js test/schemes.tests.js`(30 passing)、`npm test`(145 passing)、`npm run webpack`,均通过;CDP 截图 `/tmp/taskvision-cdp-visual-final-pass2.png` 显示无长彩条/无矩形背景块/文字可读,视觉子 agent 验收通过;`dist/extension.js` 已刷新;目标文件 `git diff --check` 通过 |
| 2026-06-03 19:10 | 纠正 F5 高亮回归根因并恢复 Marketplace 语义 | src/highlights.js, test/highlights.tests.js, agent/tasks.md, agent/timeline.md | 以 Marketplace 2.0.1 正常、F5 当前构建异常为基线重新排查;撤销新增的 legacy `type` 到四通道范围 fallback,恢复 `colorType` / `glowType` / `glassType` / `fontType` 默认语义,避免旧配置 `type: tag` 把文字颜色从 `text` 压成 `tag`、把玻璃背景从 `whole-line` 压成 `tag`;同时修正未配置 ruler opacity 时生成 `rgba(...,NaN)` 的无效颜色 | 用户明确指出 Marketplace 正式版没有高亮显示问题,F5 新版本才异常,需要推翻上一轮错误假设并重新准确定位真实回归 | 已完成;新增 editor-level mock 覆盖 `triggerHighlight()` 到 `setDecorations()` 的可见样式输出,验证文字颜色、text-shadow、玻璃背景、边框和非空 ranges;验证执行 `npx qunit test/highlights.tests.js`(12 passing)、`npm test`(136 passing)、`npm run webpack`、`git diff --check`,均通过;本地 F5 加载的 `dist/extension.js` 已刷新并确认不再包含错误 fallback |
Expand Down
28 changes: 16 additions & 12 deletions test/extension.tests.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
var fs = require('fs');

function readSource(file) {
return fs.readFileSync(file, 'utf8').replace(/\r\n/g, '\n');
}

QUnit.test('extension resolves highlight updates to workspace first', function (assert) {
var source = fs.readFileSync('src/extension.js', 'utf8');
var source = readSource('src/extension.js');

assert.ok(source.indexOf('function resolveConfigTarget()') !== -1);
assert.ok(source.indexOf('vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0') !== -1);
Expand All @@ -10,14 +14,14 @@ QUnit.test('extension resolves highlight updates to workspace first', function (
});

QUnit.test('extension writes customHighlight updates using resolved target', function (assert) {
var source = fs.readFileSync('src/extension.js', 'utf8');
var source = readSource('src/extension.js');

assert.ok(source.indexOf("currentConfig.update('customHighlight', updated, customHighlightTarget);") !== -1);
assert.ok(source.indexOf("cfg.update('customHighlight', updated, customHighlightTarget);") !== -1);
});

QUnit.test('extension exposes independent color/glow/glass/font scope controls', function (assert) {
var source = fs.readFileSync('src/extension.js', 'utf8');
var source = readSource('src/extension.js');

assert.ok(source.indexOf("value: 'scope-color'") !== -1);
assert.ok(source.indexOf("value: 'scope-glow'") !== -1);
Expand All @@ -30,7 +34,7 @@ QUnit.test('extension exposes independent color/glow/glass/font scope controls',
});

QUnit.test('extension refreshes when regex and global opacity settings change', function (assert) {
var source = fs.readFileSync('src/extension.js', 'utf8');
var source = readSource('src/extension.js');

assert.ok(source.indexOf('if (e.affectsConfiguration("taskvision.regex.regex")) {\n return;\n }') === -1);
assert.ok(source.indexOf('e.affectsConfiguration("taskvision.highlights.foregroundOpacity")') !== -1);
Expand All @@ -40,15 +44,15 @@ QUnit.test('extension refreshes when regex and global opacity settings change',
});

QUnit.test('extension updates font appearance in a single customHighlight write', function (assert) {
var source = fs.readFileSync('src/extension.js', 'utf8');
var source = readSource('src/extension.js');

assert.ok(source.indexOf('var updateConfigValues = function (values)') !== -1);
assert.ok(source.indexOf("updateConfig('fontWeight', font.fontWeight);\n updateConfig('fontStyle', font.fontStyle);") === -1);
assert.ok(source.indexOf('updateConfigValues({ fontWeight: font.fontWeight, fontStyle: font.fontStyle });') !== -1);
});

QUnit.test('extension source accepts built-in taskvision icons during validation', function (assert) {
var source = fs.readFileSync('src/icons.js', 'utf8');
var source = readSource('src/icons.js');

assert.ok(source.indexOf("!octicons[icon] && icon !== 'taskvision' && icon !== 'taskvision-filled'") !== -1);
});
Expand Down Expand Up @@ -85,7 +89,7 @@ QUnit.test('package localizes contributed command titles', function (assert) {
});

QUnit.test('buildCodiconNames fails instead of overwriting codicons with a minimal fallback', function (assert) {
var source = fs.readFileSync('buildCodiconNames.js', 'utf8');
var source = readSource('buildCodiconNames.js');

assert.ok(source.indexOf('process.exitCode = 1') !== -1);
assert.ok(source.indexOf('writeMinimalFile') === -1);
Expand Down Expand Up @@ -136,7 +140,7 @@ QUnit.test('package routes tree context menus by task/context/review node types'
});

QUnit.test('tree source differentiates task/context/review labels and context values', function (assert) {
var source = fs.readFileSync('src/tree.js', 'utf8');
var source = readSource('src/tree.js');

assert.ok(source.indexOf('treeItem.contextValue = "task";') !== -1);
assert.ok(source.indexOf('treeItem.contextValue = "context";') !== -1);
Expand All @@ -149,7 +153,7 @@ QUnit.test('tree source differentiates task/context/review labels and context va
});

QUnit.test('extension applies on-demand stable ID tracking policy', function (assert) {
var source = fs.readFileSync('src/extension.js', 'utf8');
var source = readSource('src/extension.js');

assert.ok(source.indexOf('function shouldEnsureStableIdForNode(node, options, referencedStableIds)') !== -1);
assert.ok(source.indexOf('if (ensureOptions.forceStableIds === true)') !== -1);
Expand All @@ -160,7 +164,7 @@ QUnit.test('extension applies on-demand stable ID tracking policy', function (as
});

QUnit.test('extension limits forced stable IDs to the AI export scope', function (assert) {
var source = fs.readFileSync('src/extension.js', 'utf8');
var source = readSource('src/extension.js');

assert.ok(source.indexOf('function getSyncNodesForRoot(rootPath, syncOptions)') !== -1);
assert.ok(source.indexOf('Array.isArray(options.scopeNodes)') !== -1);
Expand All @@ -169,7 +173,7 @@ QUnit.test('extension limits forced stable IDs to the AI export scope', function
});

QUnit.test('extension writes AI status report before updating export baseline', function (assert) {
var source = fs.readFileSync('src/extension.js', 'utf8');
var source = readSource('src/extension.js');
var exportStart = source.indexOf('function exportAiContext(node)');
var markIndex = source.indexOf('taskMetaStore.markTasksExported', exportStart);
var reportIndex = source.indexOf('aiContext.writeStatusReport', exportStart);
Expand All @@ -181,7 +185,7 @@ QUnit.test('extension writes AI status report before updating export baseline',
});

QUnit.test('extension registers commands even when ripgrep is unavailable', function (assert) {
var source = fs.readFileSync('src/extension.js', 'utf8');
var source = readSource('src/extension.js');
var missingRipgrepIndex = source.indexOf("TaskVision: Failed to find vscode-ripgrep");
var firstCommandIndex = source.indexOf("vscode.commands.registerCommand('taskvision.openUrl'");
var missingRipgrepBlock = source.slice(missingRipgrepIndex, firstCommandIndex);
Expand Down
Loading