devlog-tracker 0.22.0 → 0.23.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # devlog-tracker
2
2
 
3
- **版本** 0.22.0
3
+ **版本** 0.23.0
4
4
 
5
5
  在專案中維護一份 `.devlog/devlog.md`,把每一輪對話的請求、決策與結果寫成永久紀錄。對話一 `/clear` 或換 session 就沒了;這份檔案取代那個缺口,讓工作可以中斷再接。沒下過 `/devlog-tracker:start` 時,裝著也不會動任何檔案。
6
6
 
@@ -46,6 +46,11 @@ npx devlog-tracker init --codex --cursor
46
46
  其他工具已設定的 hook)。重新執行 `npx devlog-tracker init` 可以升級到套件目前的
47
47
  版本;`npx devlog-tracker status` 可以查目前裝的版本是否落後。
48
48
 
49
+ 裝 Codex 時,`init` 還會在專案根目錄的 `AGENTS.md` 加上(或更新)一段以
50
+ `<!-- devlog-tracker:begin/end -->` 包住的說明,告訴 Codex 沒有 slash 指令時該讀
51
+ `.devlog-tracker/commands/*.md`。區塊外的內容不會動,重跑 `init` 只會換掉區塊本身;
52
+ 區塊裡只有相對路徑,可以 commit。
53
+
49
54
  `init` 會把這台機器專屬的絕對路徑寫進 `.codex/hooks.json`、`.cursor/hooks.json` 與
50
55
  `.devlog-tracker/env.sh`。如果你把這些檔案 commit 進 git,每位隊友都要在自己的機器上
51
56
  跑一次 `npx devlog-tracker init`(路徑每台機器不同);或者改成把 `.devlog-tracker/` 與
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ const BEGIN = '<!-- devlog-tracker:begin -->';
6
+ const END = '<!-- devlog-tracker:end -->';
7
+
8
+ const BLOCK = `${BEGIN}
9
+ ## devlog-tracker
10
+
11
+ 這個專案用 devlog-tracker 在 \`.devlog/devlog.md\` 維護逐輪紀錄(Claude Code 與 Codex 共用同一份)。Codex 沒有 \`/devlog-tracker:*\` slash 指令,請照下面對照做:
12
+
13
+ 1. 先 \`source .devlog-tracker/env.sh\`(設定 \`DEVLOG_TRACKER_ROOT\`)。
14
+ 2. 依使用者意圖讀對應的 \`.devlog-tracker/commands/<名稱>.md\`,照裡面的步驟做(腳本在 \`.devlog-tracker/hooks/scripts/\`,執行時 \`CLAUDE_PROJECT_DIR\` 設成專案根目錄)。
15
+
16
+ | 使用者說 | 讀這份 |
17
+ |---|---|
18
+ | 開始追蹤 / start | \`commands/start.md\` |
19
+ | 接續上一題 / continue(換過工具或 \`/clear\` 之後) | \`commands/continue.md\` |
20
+ | 暫停 / pause | \`commands/pause.md\` |
21
+ | 狀態 / status | \`commands/status.md\` |
22
+ | 歸檔 / compact | \`commands/compact.md\` |
23
+ | 保存主題 / keep、接續具名檔 / resume | \`commands/keep.md\`、\`commands/resume.md\` |
24
+
25
+ 寫 devlog 的格式與規則見 \`.devlog-tracker/skills/devlog-tracker/SKILL.md\`。每輪結束前必須把當輪寫進 \`.devlog/\`;已 \`start\` 的專案,Stop hook 會擋沒寫完的輪次。
26
+ ${END}
27
+ `;
28
+
29
+ function upsertAgentsMd(targetDir) {
30
+ const filePath = path.join(targetDir, 'AGENTS.md');
31
+ const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : '';
32
+ const begin = existing.indexOf(BEGIN);
33
+ const end = existing.indexOf(END);
34
+
35
+ let next;
36
+ if (begin !== -1 && end > begin) {
37
+ next = existing.slice(0, begin) + BLOCK + existing.slice(end + END.length).replace(/^\n/, '');
38
+ } else if (existing.trim() === '') {
39
+ next = BLOCK;
40
+ } else {
41
+ next = `${existing.replace(/\n*$/, '\n')}\n${BLOCK}`;
42
+ }
43
+ if (next !== existing) fs.writeFileSync(filePath, next);
44
+ return filePath;
45
+ }
46
+
47
+ module.exports = { upsertAgentsMd, BEGIN, END };
@@ -0,0 +1,52 @@
1
+ 'use strict';
2
+ const test = require('node:test');
3
+ const assert = require('node:assert/strict');
4
+ const fs = require('fs');
5
+ const os = require('os');
6
+ const path = require('path');
7
+ const { upsertAgentsMd, BEGIN, END } = require('./agents-md');
8
+ const { run } = require('./init');
9
+
10
+ function tmp() {
11
+ return fs.mkdtempSync(path.join(os.tmpdir(), 'devlog-tracker-agents-'));
12
+ }
13
+
14
+ test('creates AGENTS.md when missing', () => {
15
+ const dir = tmp();
16
+ const file = upsertAgentsMd(dir);
17
+ const text = fs.readFileSync(file, 'utf8');
18
+ assert.ok(text.startsWith(BEGIN));
19
+ assert.ok(text.includes('.devlog-tracker/commands/'));
20
+ assert.ok(text.trimEnd().endsWith(END));
21
+ });
22
+
23
+ test('appends after existing content without touching it', () => {
24
+ const dir = tmp();
25
+ fs.writeFileSync(path.join(dir, 'AGENTS.md'), '# My rules\n\nBe nice.\n');
26
+ const text = fs.readFileSync(upsertAgentsMd(dir), 'utf8');
27
+ assert.ok(text.startsWith('# My rules\n\nBe nice.\n\n'));
28
+ assert.ok(text.includes(BEGIN));
29
+ });
30
+
31
+ test('is idempotent and replaces the block in place', () => {
32
+ const dir = tmp();
33
+ fs.writeFileSync(path.join(dir, 'AGENTS.md'), `before\n${BEGIN}\nold stale text\n${END}\nafter\n`);
34
+ const once = fs.readFileSync(upsertAgentsMd(dir), 'utf8');
35
+ const twice = fs.readFileSync(upsertAgentsMd(dir), 'utf8');
36
+ assert.equal(once, twice);
37
+ assert.ok(!once.includes('old stale text'));
38
+ assert.ok(once.startsWith('before\n'));
39
+ assert.ok(once.endsWith('after\n'));
40
+ assert.equal(once.split(BEGIN).length, 2);
41
+ });
42
+
43
+ test('init --codex writes AGENTS.md; --cursor alone does not', async () => {
44
+ const repoRoot = path.join(__dirname, '..');
45
+ const withCodex = tmp();
46
+ await run(['--codex'], { repoRoot, targetDir: withCodex, version: '0.0.0' });
47
+ assert.ok(fs.existsSync(path.join(withCodex, 'AGENTS.md')));
48
+
49
+ const cursorOnly = tmp();
50
+ await run(['--cursor'], { repoRoot, targetDir: cursorOnly, version: '0.0.0' });
51
+ assert.ok(!fs.existsSync(path.join(cursorOnly, 'AGENTS.md')));
52
+ });
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
  const path = require('path');
3
3
  const { mergeHooksTemplate } = require('../merge-hooks');
4
+ const { upsertAgentsMd } = require('../agents-md');
4
5
 
5
6
  function install({ repoRoot, targetDir, vendorRoot }) {
6
7
  mergeHooksTemplate({
@@ -8,6 +9,7 @@ function install({ repoRoot, targetDir, vendorRoot }) {
8
9
  targetPath: path.join(targetDir, '.codex', 'hooks.json'),
9
10
  vendorRoot,
10
11
  });
12
+ upsertAgentsMd(targetDir);
11
13
  }
12
14
 
13
15
  module.exports = { install };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devlog-tracker",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "description": "npx installer for the devlog-tracker Claude Code plugin's Cursor and Codex adapters.",
5
5
  "bin": {
6
6
  "devlog-tracker": "bin/devlog-tracker.js"