devlog-tracker 0.25.0 → 0.27.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 +43 -71
- package/claude/hooks.json +75 -0
- package/cli/agents-md.js +18 -12
- package/cli/agents-md.test.js +37 -9
- package/cli/init.js +6 -4
- package/cli/init.test.js +5 -4
- package/cli/merge-hooks.js +5 -2
- package/cli/merge-hooks.test.js +52 -0
- package/cli/platforms/claude.js +55 -0
- package/cli/platforms/claude.test.js +178 -0
- package/cli/platforms/codex.js +21 -14
- package/cli/skills-from-commands.js +32 -0
- package/cli/skills-from-commands.test.js +51 -0
- package/cli/vendor.js +8 -1
- package/cli/vendor.test.js +24 -5
- package/codex/hooks/on-pre-tool.sh +3 -3
- package/codex/hooks/on-session-end.sh +2 -2
- package/codex/hooks/on-session-start.sh +2 -2
- package/codex/hooks/on-stop.sh +3 -3
- package/codex/hooks/on-user-prompt-submit.sh +2 -2
- package/codex/hooks/test-adapters.sh +2 -2
- package/commands/checkpoint.md +2 -2
- package/commands/clean.md +3 -3
- package/commands/compact.md +3 -3
- package/commands/continue.md +4 -4
- package/commands/keep.md +3 -3
- package/commands/lessons-drift.md +2 -2
- package/commands/lessons-off.md +3 -3
- package/commands/lessons-on.md +3 -3
- package/commands/lessons.md +3 -3
- package/commands/overview.md +3 -3
- package/commands/pause.md +3 -3
- package/commands/resume.md +3 -3
- package/commands/segment-watch.md +3 -3
- package/commands/span.md +2 -2
- package/commands/start.md +3 -3
- package/commands/status.md +3 -3
- package/{hooks → core}/scripts/await-open.sh +1 -1
- package/{hooks → core}/scripts/checkpoint-set.sh +1 -1
- package/{hooks → core}/scripts/clean-devlog.sh +1 -1
- package/{hooks → core}/scripts/close-open-round.sh +1 -1
- package/{hooks → core}/scripts/compact-devlog.sh +1 -1
- package/{hooks → core}/scripts/enforce-devlog.sh +1 -1
- package/{hooks → core}/scripts/keep-move.sh +1 -1
- package/{hooks → core}/scripts/kept-list.sh +1 -1
- package/{hooks → core}/scripts/lessons-append.sh +2 -2
- package/{hooks → core}/scripts/lessons-drift-set.sh +1 -1
- package/{hooks → core}/scripts/lessons-off.sh +1 -1
- package/{hooks → core}/scripts/lessons-on.sh +1 -1
- package/{hooks → core}/scripts/lessons-read.sh +1 -1
- package/{hooks → core}/scripts/on-tool-failure.sh +1 -1
- package/{hooks → core}/scripts/pause-devlog.sh +1 -1
- package/core/scripts/project-dir.sh +19 -0
- package/{hooks → core}/scripts/resume-devlog.sh +1 -1
- package/{hooks → core}/scripts/round-start.sh +1 -1
- package/{hooks → core}/scripts/run-tests.sh +1 -1
- package/{hooks → core}/scripts/segment-watch-set.sh +1 -1
- package/{hooks → core}/scripts/segment-watch.sh +1 -1
- package/{hooks → core}/scripts/session-start-devlog.sh +1 -1
- package/{hooks → core}/scripts/span-close.sh +1 -1
- package/{hooks → core}/scripts/span-open.sh +1 -1
- package/{hooks → core}/scripts/start-devlog.sh +1 -1
- package/{hooks → core}/scripts/status-devlog.sh +1 -1
- package/core/scripts/tests/test-cli-init-e2e.sh +68 -0
- package/core/scripts/tests/test-project-dir.sh +30 -0
- package/{hooks → core}/scripts/tests/test-session-start-devlog.sh +2 -2
- package/{hooks → core}/scripts/workspace-snapshot.sh +2 -2
- package/cursor/hooks/on-pre-tool.sh +2 -2
- package/cursor/hooks/on-session-end.sh +2 -2
- package/cursor/hooks/on-session-start.sh +2 -2
- package/cursor/hooks/on-stop.sh +2 -2
- package/cursor/hooks/on-submit-prompt.sh +2 -2
- package/cursor/hooks/on-tool-failure.sh +2 -2
- package/package.json +4 -3
- package/skills/devlog-tracker/SKILL.md +9 -9
- package/skills/devlog-tracker/references/lessons-mode.md +1 -1
- package/skills/devlog-tracker/references/reply-fold.md +1 -1
- package/hooks/scripts/tests/test-cli-init-e2e.sh +0 -38
- /package/{hooks → core}/scripts/detect-pending-question.sh +0 -0
- /package/{hooks → core}/scripts/devlog-lock.sh +0 -0
- /package/{hooks → core}/scripts/devlog-md.sh +0 -0
- /package/{hooks → core}/scripts/devlog-path.sh +0 -0
- /package/{hooks → core}/scripts/files-snapshot.sh +0 -0
- /package/{hooks → core}/scripts/json-field.sh +0 -0
- /package/{hooks → core}/scripts/on-session-end.sh +0 -0
- /package/{hooks → core}/scripts/on-stop-failure.sh +0 -0
- /package/{hooks → core}/scripts/redact-prompt.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-await-open.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-branch-scoped-integration.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-checkpoint-set.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-clean-devlog.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-close-open-round.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-compact-devlog.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-devlog-lock.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-devlog-md.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-devlog-path.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-enforce-devlog-files.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-enforce-devlog-handoff-order.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-enforce-devlog-workspace.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-enforce-devlog.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-files-snapshot.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-json-field.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-keep-move.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-kept-list.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-lessons-append.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-lessons-drift-set.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-lessons-on-off.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-lessons-read.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-on-interrupt.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-redact-prompt.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-resume-devlog.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-round-start.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-segment-watch-set.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-segment-watch.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-start-pause-devlog.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-status-span.sh +0 -0
- /package/{hooks → core}/scripts/tests/test-workspace-snapshot.sh +0 -0
package/commands/lessons.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
description: 查看 Lessons 索引,或讀某個主題的完整教訓紀錄(純讀取,不核對工作區、不等確認)。
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
取得使用者是否有給 `<topic>`(可能沒有,代表只看索引)。記下你目前已經確認的專案根目錄絕對路徑(後面步驟都要用這個值,不要用 `$(pwd)` 重新推——理由同 `commands/continue.md` 步驟 1)。先決定 plugin 根目錄(有 `
|
|
5
|
+
取得使用者是否有給 `<topic>`(可能沒有,代表只看索引)。記下你目前已經確認的專案根目錄絕對路徑(後面步驟都要用這個值,不要用 `$(pwd)` 重新推——理由同 `commands/continue.md` 步驟 1)。先決定 plugin 根目錄(有 `DEVLOG_TRACKER_ROOT` 用它;否則用 `CLAUDE_PLUGIN_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄),再跑:
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
PLUGIN_ROOT="${
|
|
9
|
-
|
|
8
|
+
PLUGIN_ROOT="${DEVLOG_TRACKER_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}"
|
|
9
|
+
DEVLOG_PROJECT_DIR="<剛才記下的專案根目錄絕對路徑>" bash "${PLUGIN_ROOT}/core/scripts/lessons-read.sh" "<topic,沒有就留空>"
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
沒有 `<topic>`:
|
package/commands/overview.md
CHANGED
|
@@ -8,11 +8,11 @@ description: 把已 keep 的具名檔(devlog.<name>.md)整合成一份跨主
|
|
|
8
8
|
|
|
9
9
|
## 1. 取得已 keep 的檔案清單
|
|
10
10
|
|
|
11
|
-
記下你目前已經確認的專案根目錄絕對路徑(後面步驟都要用這個值,不要用 `$(pwd)` 重新推——理由同 `commands/continue.md` 步驟 1)。先決定 plugin 根目錄(有 `
|
|
11
|
+
記下你目前已經確認的專案根目錄絕對路徑(後面步驟都要用這個值,不要用 `$(pwd)` 重新推——理由同 `commands/continue.md` 步驟 1)。先決定 plugin 根目錄(有 `DEVLOG_TRACKER_ROOT` 用它;否則用 `CLAUDE_PLUGIN_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄),再跑:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
PLUGIN_ROOT="${
|
|
15
|
-
|
|
14
|
+
PLUGIN_ROOT="${DEVLOG_TRACKER_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}"
|
|
15
|
+
DEVLOG_PROJECT_DIR="<剛才記下的專案根目錄絕對路徑>" bash "${PLUGIN_ROOT}/core/scripts/kept-list.sh"
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
- `NO_INDEX`:告知「目前沒有已 keep 的舊檔」,結束。
|
package/commands/pause.md
CHANGED
|
@@ -6,11 +6,11 @@ description: 暫停這個專案的 devlog 強制記錄機制。不會刪除任
|
|
|
6
6
|
|
|
7
7
|
1. 跑:
|
|
8
8
|
```bash
|
|
9
|
-
先決定 plugin 根目錄(有 `
|
|
9
|
+
先決定 plugin 根目錄(有 `DEVLOG_TRACKER_ROOT` 用它;否則用 `CLAUDE_PLUGIN_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄):
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
PLUGIN_ROOT="${
|
|
13
|
-
|
|
12
|
+
PLUGIN_ROOT="${DEVLOG_TRACKER_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}"
|
|
13
|
+
DEVLOG_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/core/scripts/pause-devlog.sh"
|
|
14
14
|
```
|
|
15
15
|
```
|
|
16
16
|
不要自己刪 `.enabled`。
|
package/commands/resume.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
description: 讀取具名保存的 devlog,核對最後一輪 Handoff 工作區後再接續該段工作。
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
取得使用者提供的 `<name>`;沒有名稱時先詢問。記下你目前已經確認的專案根目錄絕對路徑(後面步驟都要用這個值,不要用 `$(pwd)` 重新推——理由同 `commands/continue.md` 步驟 1:Bash 工具的工作目錄會在對話裡持續累積前面呼叫的 `cd`,用當下的 `pwd` 可能已經不是這個專案根目錄)。先決定 plugin 根目錄(有 `
|
|
5
|
+
取得使用者提供的 `<name>`;沒有名稱時先詢問。記下你目前已經確認的專案根目錄絕對路徑(後面步驟都要用這個值,不要用 `$(pwd)` 重新推——理由同 `commands/continue.md` 步驟 1:Bash 工具的工作目錄會在對話裡持續累積前面呼叫的 `cd`,用當下的 `pwd` 可能已經不是這個專案根目錄)。先決定 plugin 根目錄(有 `DEVLOG_TRACKER_ROOT` 用它;否則用 `CLAUDE_PLUGIN_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄),再跑:
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
PLUGIN_ROOT="${
|
|
9
|
-
|
|
8
|
+
PLUGIN_ROOT="${DEVLOG_TRACKER_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}"
|
|
9
|
+
DEVLOG_PROJECT_DIR="<剛才記下的專案根目錄絕對路徑,不要用 $(pwd) 重新推>" bash "${PLUGIN_ROOT}/core/scripts/resume-devlog.sh" --name "<name>"
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
若回傳 `MISSING`,列出 `CANDIDATES` 讓使用者選,不要自動執行工作。
|
|
@@ -6,11 +6,11 @@ description: 調整 Segment Watch 的沉默門檻——同一輪連續多久沒
|
|
|
6
6
|
換算成整數秒數 `<seconds>`,跑:
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
|
-
先決定 plugin 根目錄(有 `
|
|
9
|
+
先決定 plugin 根目錄(有 `DEVLOG_TRACKER_ROOT` 用它;否則用 `CLAUDE_PLUGIN_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄):
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
PLUGIN_ROOT="${
|
|
13
|
-
|
|
12
|
+
PLUGIN_ROOT="${DEVLOG_TRACKER_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}"
|
|
13
|
+
DEVLOG_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/core/scripts/segment-watch-set.sh" <seconds>
|
|
14
14
|
```
|
|
15
15
|
```
|
|
16
16
|
|
package/commands/span.md
CHANGED
|
@@ -5,9 +5,9 @@ description: 開啟或關閉 Span Mode,讓自動續接的長任務定期記錄
|
|
|
5
5
|
先判斷使用者要開啟或關閉:
|
|
6
6
|
|
|
7
7
|
- 使用者明確要求關閉,或 `.devlog/.span-open` 已存在且沒有明確要求重新開啟:
|
|
8
|
-
先決定 plugin 根目錄(有 `
|
|
8
|
+
先決定 plugin 根目錄(有 `DEVLOG_TRACKER_ROOT` 用它;否則用 `CLAUDE_PLUGIN_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄),設 `PLUGIN_ROOT="${DEVLOG_TRACKER_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}"`,再跑 `DEVLOG_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/core/scripts/span-close.sh"`,
|
|
9
9
|
再依 SKILL 的 span 收尾規則寫一個**新的 Round**,總結整段 span。
|
|
10
10
|
- 使用者要求開啟:先把目前 Round 正常寫完,`Status` 設為 `IN_PROGRESS`,再跑
|
|
11
|
-
`
|
|
11
|
+
`DEVLOG_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/core/scripts/span-open.sh"`。
|
|
12
12
|
|
|
13
13
|
不要手寫 `.span-open` JSON。腳本 exit 1 時顯示 stderr,停止操作。
|
package/commands/start.md
CHANGED
|
@@ -4,10 +4,10 @@ description: 啟動這個專案的 devlog 強制記錄機制。之後每一輪
|
|
|
4
4
|
|
|
5
5
|
請執行以下步驟:
|
|
6
6
|
|
|
7
|
-
1. 先決定 plugin 根目錄(有 `
|
|
7
|
+
1. 先決定 plugin 根目錄(有 `DEVLOG_TRACKER_ROOT` 用它;否則用 `CLAUDE_PLUGIN_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄):
|
|
8
8
|
```bash
|
|
9
|
-
PLUGIN_ROOT="${
|
|
10
|
-
|
|
9
|
+
PLUGIN_ROOT="${DEVLOG_TRACKER_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}"
|
|
10
|
+
DEVLOG_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/core/scripts/start-devlog.sh"
|
|
11
11
|
```
|
|
12
12
|
不要自己用手建 `.enabled` / `.checkpoint-state` / `.segment-state`。
|
|
13
13
|
2. 若 stdout 有 `GITIGNORE_DEVLOG=no`:鄭重提醒——`.devlog/` 會寫入使用者原文(遮罩只覆蓋常見 token 前綴,不是通用掃密)。**強烈建議**把 `.devlog/` 加進專案 `.gitignore`。問要不要現在加。只有使用者明確說要,才在 `.gitignore` 末尾追加一行 `.devlog/`(檔案不存在就建立)。不要改其他行。若使用者拒絕,再警告一次「之後若不小心 commit,prompt/殘留密鑰可能進版控」,然後繼續步驟 3。
|
package/commands/status.md
CHANGED
|
@@ -4,11 +4,11 @@ description: 查看這個專案 devlog 強制記錄是否開著、span / checkpo
|
|
|
4
4
|
|
|
5
5
|
跑:
|
|
6
6
|
```bash
|
|
7
|
-
先決定 plugin 根目錄(有 `
|
|
7
|
+
先決定 plugin 根目錄(有 `DEVLOG_TRACKER_ROOT` 用它;否則用 `CLAUDE_PLUGIN_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄):
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
PLUGIN_ROOT="${
|
|
11
|
-
|
|
10
|
+
PLUGIN_ROOT="${DEVLOG_TRACKER_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}"
|
|
11
|
+
DEVLOG_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/core/scripts/status-devlog.sh"
|
|
12
12
|
```
|
|
13
13
|
```
|
|
14
14
|
把 stdout 翻譯成給人看的幾行(含 `LESSONS=yes/no`:Lessons Mode 開關狀態;`LESSONS_DRIFT=<count>/<threshold>`:Lessons Mode 開著時,工作區漂移不符的累積次數/門檻)。不要改任何檔。`NOT_STARTED` 就說還沒 `/devlog-tracker:start`。
|
|
@@ -9,7 +9,7 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
9
9
|
# shellcheck source=devlog-path.sh
|
|
10
10
|
. "$SCRIPT_DIR/devlog-path.sh"
|
|
11
11
|
|
|
12
|
-
devlog_resolve_paths "${CLAUDE_PROJECT_DIR:-.}"
|
|
12
|
+
devlog_resolve_paths "${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
13
13
|
[ -f "$DEVLOG_DIR/.enabled" ] || { echo "NOT_ENABLED"; exit 1; }
|
|
14
14
|
[ ! -e "$DEVLOG_DIR/.awaiting-reply" ] || { echo "ALREADY_OPEN"; exit 1; }
|
|
15
15
|
ROUND=""
|
|
@@ -8,7 +8,7 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
8
8
|
# shellcheck source=json-field.sh
|
|
9
9
|
. "$SCRIPT_DIR/json-field.sh"
|
|
10
10
|
|
|
11
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
11
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
12
12
|
DEVLOG_DIR="$PROJECT_DIR/.devlog"
|
|
13
13
|
|
|
14
14
|
if [ ! -f "$DEVLOG_DIR/.enabled" ]; then
|
|
@@ -13,7 +13,7 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
13
13
|
# replacement for that confirmation.
|
|
14
14
|
[ "${1:-}" = "--confirmed" ] || { echo "需要 --confirmed(使用者尚未確認,不要呼叫這支腳本)" >&2; exit 1; }
|
|
15
15
|
|
|
16
|
-
devlog_resolve_paths "${CLAUDE_PROJECT_DIR:-.}"
|
|
16
|
+
devlog_resolve_paths "${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
17
17
|
devlog_lock_acquire
|
|
18
18
|
trap 'devlog_lock_release' EXIT
|
|
19
19
|
MAIN="$DEVLOG_FILE"
|
|
@@ -32,7 +32,7 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
32
32
|
# shellcheck source=devlog-md.sh
|
|
33
33
|
. "$SCRIPT_DIR/devlog-md.sh"
|
|
34
34
|
|
|
35
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
35
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
36
36
|
devlog_resolve_paths "$PROJECT_DIR"
|
|
37
37
|
ENABLED_FLAG="$DEVLOG_DIR/.enabled"
|
|
38
38
|
ROUND_OPEN="$DEVLOG_DIR/.round-open"
|
|
@@ -7,7 +7,7 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
7
7
|
. "$SCRIPT_DIR/devlog-lock.sh"
|
|
8
8
|
. "$SCRIPT_DIR/devlog-path.sh"
|
|
9
9
|
|
|
10
|
-
devlog_resolve_paths "${CLAUDE_PROJECT_DIR:-.}"
|
|
10
|
+
devlog_resolve_paths "${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
11
11
|
devlog_lock_acquire
|
|
12
12
|
trap 'devlog_lock_release' EXIT
|
|
13
13
|
MAIN="$DEVLOG_FILE"
|
|
@@ -37,7 +37,7 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
37
37
|
# 足以涵蓋 Claude Code 實際送出的 stop_hook_active 欄位形狀),兩種環境都要生效。
|
|
38
38
|
INPUT="$(cat 2>/dev/null || true)"
|
|
39
39
|
|
|
40
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
40
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
41
41
|
# 沒下過 /devlog-tracker:start,代表這個專案沒啟動強制記錄,直接放行。
|
|
42
42
|
# 這是唯一的判斷依據——不猜這輪是否呼叫了某個 skill,也不解析 transcript。
|
|
43
43
|
# 這個 gate 放在路徑解析之前,沒啟用時就不必付 git rev-parse 的成本;
|
|
@@ -33,7 +33,7 @@ NAME="$(slugify "$NAME")"
|
|
|
33
33
|
|| { echo "檔名無效" >&2; exit 1; }
|
|
34
34
|
[ "${#NAME}" -le 64 ] || { echo "檔名超過 64 字元" >&2; exit 1; }
|
|
35
35
|
|
|
36
|
-
devlog_resolve_paths "${CLAUDE_PROJECT_DIR:-.}"
|
|
36
|
+
devlog_resolve_paths "${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
37
37
|
devlog_lock_acquire
|
|
38
38
|
trap 'devlog_lock_release' EXIT
|
|
39
39
|
MAIN="$DEVLOG_FILE"
|
|
@@ -13,7 +13,7 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
13
13
|
# shellcheck source=devlog-path.sh
|
|
14
14
|
. "$SCRIPT_DIR/devlog-path.sh"
|
|
15
15
|
|
|
16
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
16
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
17
17
|
devlog_resolve_paths "$PROJECT_DIR"
|
|
18
18
|
MAIN="$DEVLOG_FILE"
|
|
19
19
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Claude-invoked only (docs/design/lessons-mode.md), never wired into
|
|
3
|
-
#
|
|
3
|
+
# claude/hooks.json — same posture as keep-move.sh. Appends one free-prose
|
|
4
4
|
# entry to .devlog/devlog.lessons.<topic>.md (creating it if new), then
|
|
5
5
|
# rebuilds the trailing "## Lessons 索引" block in devlog.md.
|
|
6
6
|
set -uo pipefail
|
|
@@ -26,7 +26,7 @@ while [ "$#" -gt 0 ]; do
|
|
|
26
26
|
esac
|
|
27
27
|
done
|
|
28
28
|
|
|
29
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
29
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
30
30
|
devlog_resolve_paths "$PROJECT_DIR"
|
|
31
31
|
MAIN="$DEVLOG_FILE"
|
|
32
32
|
|
|
@@ -11,7 +11,7 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
11
11
|
# shellcheck source=json-field.sh
|
|
12
12
|
. "$SCRIPT_DIR/json-field.sh"
|
|
13
13
|
|
|
14
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
14
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
15
15
|
DEVLOG_DIR="$PROJECT_DIR/.devlog"
|
|
16
16
|
|
|
17
17
|
if [ ! -f "$DEVLOG_DIR/.enabled" ]; then
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# or the "## Lessons 索引" block (docs/design/lessons-mode.md), same
|
|
5
5
|
# non-destructive posture as pause-devlog.sh toward devlog.md.
|
|
6
6
|
set -uo pipefail
|
|
7
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
7
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
8
8
|
DEVLOG_DIR="$PROJECT_DIR/.devlog"
|
|
9
9
|
if [ ! -f "$DEVLOG_DIR/.lessons-enabled" ]; then
|
|
10
10
|
echo "NOT_ENABLED"
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# disable」): refuses if .enabled is absent, since there is no Round/Status
|
|
5
5
|
# history to detect a BLOCKED->resolved transition against.
|
|
6
6
|
set -uo pipefail
|
|
7
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
7
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
8
8
|
DEVLOG_DIR="$PROJECT_DIR/.devlog"
|
|
9
9
|
if [ ! -f "$DEVLOG_DIR/.enabled" ]; then
|
|
10
10
|
echo "NOT_ENABLED"
|
|
@@ -14,7 +14,7 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
14
14
|
# shellcheck source=devlog-path.sh
|
|
15
15
|
. "$SCRIPT_DIR/devlog-path.sh"
|
|
16
16
|
|
|
17
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
17
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
18
18
|
devlog_resolve_paths "$PROJECT_DIR"
|
|
19
19
|
MAIN="$DEVLOG_FILE"
|
|
20
20
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# PostToolUseFailure: remember user Esc so Stop can stamp without blocking.
|
|
3
3
|
set -uo pipefail
|
|
4
4
|
|
|
5
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
5
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
6
6
|
DEVLOG_DIR="$PROJECT_DIR/.devlog"
|
|
7
7
|
ENABLED_FLAG="$DEVLOG_DIR/.enabled"
|
|
8
8
|
[ -f "$ENABLED_FLAG" ] || exit 0
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Sourced helper: the single documented definition of "which project
|
|
3
|
+
# directory is a hook/script operating in". Precedence:
|
|
4
|
+
# 1. DEVLOG_PROJECT_DIR — neutral name, harness-agnostic
|
|
5
|
+
# 2. CLAUDE_PROJECT_DIR — Claude Code's own variable, kept as a
|
|
6
|
+
# compatibility fallback so anything that already exports it
|
|
7
|
+
# (Claude Code itself, or an external script) keeps working
|
|
8
|
+
# unmodified
|
|
9
|
+
# 3. "." — current directory, when neither is set
|
|
10
|
+
#
|
|
11
|
+
# Most core/scripts/*.sh scripts inline the equivalent expression
|
|
12
|
+
# (`${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}`) directly rather than
|
|
13
|
+
# sourcing this file, to keep each entry-point script a single self-
|
|
14
|
+
# contained line. This file is the canonical statement of that precedence
|
|
15
|
+
# and is exercised by core/scripts/tests/test-project-dir.sh; source it
|
|
16
|
+
# instead of re-deriving the fallback chain in new code.
|
|
17
|
+
devlog_project_dir() {
|
|
18
|
+
printf '%s\n' "${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
19
|
+
}
|
|
@@ -20,7 +20,7 @@ NAME="$(slugify "$NAME")"
|
|
|
20
20
|
[ -n "$NAME" ] && [ "$NAME" != "archive" ] && [ "${#NAME}" -le 64 ] \
|
|
21
21
|
|| { echo "INVALID_NAME" >&2; exit 1; }
|
|
22
22
|
|
|
23
|
-
DEVLOG_DIR="${CLAUDE_PROJECT_DIR:-.}/.devlog"
|
|
23
|
+
DEVLOG_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}/.devlog"
|
|
24
24
|
FILE="$DEVLOG_DIR/devlog.$NAME.md"
|
|
25
25
|
if [ ! -f "$FILE" ]; then
|
|
26
26
|
candidates=""
|
|
@@ -24,7 +24,7 @@ HOOKS_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
24
24
|
. "$HOOKS_DIR/detect-pending-question.sh"
|
|
25
25
|
# shellcheck source=devlog-path.sh
|
|
26
26
|
. "$HOOKS_DIR/devlog-path.sh"
|
|
27
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
27
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
28
28
|
[ -f "$PROJECT_DIR/.devlog/.enabled" ] || exit 0
|
|
29
29
|
devlog_resolve_paths "$PROJECT_DIR"
|
|
30
30
|
ROUND_CURRENT="$DEVLOG_DIR/.round-current.md"
|
|
@@ -8,7 +8,7 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
8
8
|
# shellcheck source=json-field.sh
|
|
9
9
|
. "$SCRIPT_DIR/json-field.sh"
|
|
10
10
|
|
|
11
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
11
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
12
12
|
DEVLOG_DIR="$PROJECT_DIR/.devlog"
|
|
13
13
|
|
|
14
14
|
if [ ! -f "$DEVLOG_DIR/.enabled" ]; then
|
|
@@ -13,7 +13,7 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
13
13
|
# shellcheck source=devlog-path.sh
|
|
14
14
|
. "$SCRIPT_DIR/devlog-path.sh"
|
|
15
15
|
|
|
16
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
16
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
17
17
|
[ -f "$PROJECT_DIR/.devlog/.enabled" ] || exit 0
|
|
18
18
|
devlog_resolve_paths "$PROJECT_DIR"
|
|
19
19
|
ROUND_CURRENT="$DEVLOG_DIR/.round-current.md"
|
|
@@ -33,7 +33,7 @@ HOOKS_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
33
33
|
# shellcheck source=devlog-path.sh
|
|
34
34
|
. "$HOOKS_DIR/devlog-path.sh"
|
|
35
35
|
|
|
36
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
36
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
37
37
|
devlog_resolve_paths "$PROJECT_DIR"
|
|
38
38
|
ROUND_CURRENT="$DEVLOG_DIR/.round-current.md"
|
|
39
39
|
SPAN_FILE="$DEVLOG_DIR/.span-open"
|
|
@@ -6,7 +6,7 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
6
6
|
. "$SCRIPT_DIR/devlog-md.sh"
|
|
7
7
|
. "$SCRIPT_DIR/devlog-path.sh"
|
|
8
8
|
|
|
9
|
-
devlog_resolve_paths "${CLAUDE_PROJECT_DIR:-.}"
|
|
9
|
+
devlog_resolve_paths "${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
10
10
|
[ -f "$DEVLOG_DIR/.enabled" ] || { echo "NOT_ENABLED" >&2; exit 1; }
|
|
11
11
|
[ ! -e "$DEVLOG_DIR/.span-open" ] || { echo "ALREADY_OPEN" >&2; exit 1; }
|
|
12
12
|
ROUND=""
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# User-invoked: /devlog-tracker:start filesystem side.
|
|
3
3
|
set -uo pipefail
|
|
4
|
-
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
|
|
4
|
+
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
5
5
|
DEVLOG_DIR="$PROJECT_DIR/.devlog"
|
|
6
6
|
mkdir -p "$DEVLOG_DIR" || exit 1
|
|
7
7
|
if [ ! -f "$DEVLOG_DIR/.enabled" ]; then
|
|
@@ -6,7 +6,7 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
6
6
|
. "$SCRIPT_DIR/devlog-md.sh"
|
|
7
7
|
. "$SCRIPT_DIR/devlog-path.sh"
|
|
8
8
|
|
|
9
|
-
devlog_resolve_paths "${CLAUDE_PROJECT_DIR:-.}"
|
|
9
|
+
devlog_resolve_paths "${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
10
10
|
[ -d "$DEVLOG_DIR" ] || { echo "NOT_STARTED"; exit 0; }
|
|
11
11
|
|
|
12
12
|
[ -f "$DEVLOG_DIR/.enabled" ] && echo "ENABLED=yes" || echo "ENABLED=no"
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
4
|
+
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
5
|
+
TMP="$(mktemp -d)"
|
|
6
|
+
trap 'rm -rf "$TMP"' EXIT
|
|
7
|
+
FAIL=0
|
|
8
|
+
|
|
9
|
+
command -v node >/dev/null 2>&1 || { echo "SKIP: node not installed"; exit 0; }
|
|
10
|
+
|
|
11
|
+
PROJECT="$TMP/project"
|
|
12
|
+
mkdir -p "$PROJECT"
|
|
13
|
+
|
|
14
|
+
cd "$PROJECT" || exit 1
|
|
15
|
+
NODE_BIN="$(command -v node)"
|
|
16
|
+
"$NODE_BIN" "$REPO_ROOT/bin/devlog-tracker.js" init --claude --codex --cursor >/dev/null 2>"$TMP/stderr" \
|
|
17
|
+
|| { echo "FAIL: init exited non-zero"; cat "$TMP/stderr"; FAIL=1; }
|
|
18
|
+
|
|
19
|
+
[ -f "$PROJECT/.devlog-tracker/VERSION" ] && echo "PASS: vendored VERSION exists" || { echo "FAIL: no VERSION"; FAIL=1; }
|
|
20
|
+
[ -f "$PROJECT/.devlog-tracker/env.sh" ] && echo "PASS: vendored env.sh exists" || { echo "FAIL: no env.sh"; FAIL=1; }
|
|
21
|
+
[ -f "$PROJECT/.claude/settings.local.json" ] && echo "PASS: .claude/settings.local.json written" || { echo "FAIL: no .claude/settings.local.json"; FAIL=1; }
|
|
22
|
+
[ -f "$PROJECT/.claude/skills/devlog-start/SKILL.md" ] && echo "PASS: Claude start skill written" || { echo "FAIL: no Claude start skill"; FAIL=1; }
|
|
23
|
+
[ -f "$PROJECT/CLAUDE.md" ] && grep -q 'devlog-tracker:begin' "$PROJECT/CLAUDE.md" \
|
|
24
|
+
&& echo "PASS: CLAUDE.md fallback block written" || { echo "FAIL: no devlog-tracker block in CLAUDE.md"; FAIL=1; }
|
|
25
|
+
[ -f "$PROJECT/.codex/hooks.json" ] && echo "PASS: .codex/hooks.json written" || { echo "FAIL: no .codex/hooks.json"; FAIL=1; }
|
|
26
|
+
[ -f "$PROJECT/.agents/skills/devlog-start/SKILL.md" ] && echo "PASS: Codex start skill written" || { echo "FAIL: no Codex start skill"; FAIL=1; }
|
|
27
|
+
[ -f "$PROJECT/.cursor/hooks.json" ] && echo "PASS: .cursor/hooks.json written" || { echo "FAIL: no .cursor/hooks.json"; FAIL=1; }
|
|
28
|
+
|
|
29
|
+
# Controller addition 1a: Check vendored core scripts exist
|
|
30
|
+
[ -f "$PROJECT/.devlog-tracker/core/scripts/enforce-devlog.sh" ] && echo "PASS: vendored core/scripts/enforce-devlog.sh exists" || { echo "FAIL: no core/scripts/enforce-devlog.sh"; FAIL=1; }
|
|
31
|
+
[ -f "$PROJECT/.devlog-tracker/claude/hooks.json" ] && echo "PASS: vendored claude/hooks.json exists" || { echo "FAIL: no claude/hooks.json"; FAIL=1; }
|
|
32
|
+
|
|
33
|
+
# Controller addition 1b: Check merged Claude hook commands are resolved (no placeholders)
|
|
34
|
+
if grep -q '\${CLAUDE_PLUGIN_ROOT\|${DEVLOG_TRACKER_ROOT' "$PROJECT/.claude/settings.local.json"; then
|
|
35
|
+
echo "FAIL: unresolved placeholders in .claude/settings.local.json"; FAIL=1
|
|
36
|
+
else
|
|
37
|
+
echo "PASS: no unresolved placeholders in .claude/settings.local.json"
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Verify that Stop hook command references .devlog-tracker/core/scripts/
|
|
41
|
+
STOP_CMD=$("$NODE_BIN" -e "console.log(JSON.parse(require('fs').readFileSync('$PROJECT/.claude/settings.local.json')).hooks.Stop[0].hooks[0].command)")
|
|
42
|
+
if echo "$STOP_CMD" | grep -q '\.devlog-tracker/core/scripts/enforce-devlog\.sh'; then
|
|
43
|
+
echo "PASS: Claude Stop hook references .devlog-tracker/core/scripts/enforce-devlog.sh"
|
|
44
|
+
else
|
|
45
|
+
echo "FAIL: Claude Stop hook does not reference .devlog-tracker/core/scripts/enforce-devlog.sh"; FAIL=1
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# re-running must not duplicate entries
|
|
49
|
+
COUNT_BEFORE_CODEX=$(node -e "console.log(JSON.parse(require('fs').readFileSync('$PROJECT/.codex/hooks.json')).hooks.Stop.length)")
|
|
50
|
+
COUNT_BEFORE_CLAUDE=$(node -e "console.log(JSON.parse(require('fs').readFileSync('$PROJECT/.claude/settings.local.json')).hooks.Stop.length)")
|
|
51
|
+
"$NODE_BIN" "$REPO_ROOT/bin/devlog-tracker.js" init --claude --codex --cursor >/dev/null 2>"$TMP/stderr" \
|
|
52
|
+
|| { echo "FAIL: second init exited non-zero"; cat "$TMP/stderr"; FAIL=1; }
|
|
53
|
+
COUNT_AFTER_CODEX=$(node -e "console.log(JSON.parse(require('fs').readFileSync('$PROJECT/.codex/hooks.json')).hooks.Stop.length)")
|
|
54
|
+
COUNT_AFTER_CLAUDE=$(node -e "console.log(JSON.parse(require('fs').readFileSync('$PROJECT/.claude/settings.local.json')).hooks.Stop.length)")
|
|
55
|
+
if [ "$COUNT_BEFORE_CODEX" = "$COUNT_AFTER_CODEX" ]; then
|
|
56
|
+
echo "PASS: re-running init does not duplicate Codex hook entries"
|
|
57
|
+
else
|
|
58
|
+
echo "FAIL: Codex hook entries duplicated ($COUNT_BEFORE_CODEX -> $COUNT_AFTER_CODEX)"; FAIL=1
|
|
59
|
+
fi
|
|
60
|
+
if [ "$COUNT_BEFORE_CLAUDE" = "$COUNT_AFTER_CLAUDE" ]; then
|
|
61
|
+
echo "PASS: re-running init does not duplicate Claude hook entries"
|
|
62
|
+
else
|
|
63
|
+
echo "FAIL: Claude hook entries duplicated ($COUNT_BEFORE_CLAUDE -> $COUNT_AFTER_CLAUDE)"; FAIL=1
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
if [ "$FAIL" -eq 0 ]; then echo "All checks passed."; exit 0
|
|
67
|
+
else echo "Some checks FAILED."; exit 1
|
|
68
|
+
fi
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
4
|
+
BASH_BIN="$(command -v bash)"
|
|
5
|
+
FAIL=0
|
|
6
|
+
|
|
7
|
+
run_case() {
|
|
8
|
+
local desc="$1" expected="$2"
|
|
9
|
+
shift 2
|
|
10
|
+
local actual
|
|
11
|
+
actual="$(env -i PATH="$PATH" "$@" "$BASH_BIN" -c '. "'"$DIR"'/project-dir.sh"; devlog_project_dir')"
|
|
12
|
+
if [ "$actual" = "$expected" ]; then
|
|
13
|
+
echo "PASS: $desc"
|
|
14
|
+
else
|
|
15
|
+
echo "FAIL: $desc (expected [$expected], got [$actual])"
|
|
16
|
+
FAIL=1
|
|
17
|
+
fi
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
run_case "neither var set falls back to ." "."
|
|
21
|
+
run_case "CLAUDE_PROJECT_DIR alone is honored" "/legacy" \
|
|
22
|
+
CLAUDE_PROJECT_DIR=/legacy
|
|
23
|
+
run_case "DEVLOG_PROJECT_DIR alone is honored" "/neutral" \
|
|
24
|
+
DEVLOG_PROJECT_DIR=/neutral
|
|
25
|
+
run_case "DEVLOG_PROJECT_DIR wins over CLAUDE_PROJECT_DIR" "/neutral" \
|
|
26
|
+
DEVLOG_PROJECT_DIR=/neutral CLAUDE_PROJECT_DIR=/legacy
|
|
27
|
+
|
|
28
|
+
if [ "$FAIL" -eq 0 ]; then echo "All checks passed."; exit 0
|
|
29
|
+
else echo "Some checks FAILED."; exit 1
|
|
30
|
+
fi
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Self-check for session-start-devlog.sh, including the Span Mode
|
|
3
3
|
# resume-context note. No framework — plain assert-and-exit, matching this
|
|
4
4
|
# repo's existing style. Run directly:
|
|
5
|
-
# bash
|
|
5
|
+
# bash core/scripts/tests/test-session-start-devlog.sh
|
|
6
6
|
set -uo pipefail
|
|
7
7
|
|
|
8
8
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
@@ -181,7 +181,7 @@ echo '{}' | bash "$SCRIPT_DIR/enforce-devlog.sh" >/dev/null 2>&1
|
|
|
181
181
|
assert_exit "after compact skip-heal, Stop still enforces (hash equal) -> exit 2" 2 $?
|
|
182
182
|
|
|
183
183
|
# --- Scenario 7: hooks.json SessionStart matcher includes fork -------------
|
|
184
|
-
HOOKS_JSON="$SCRIPT_DIR
|
|
184
|
+
HOOKS_JSON="$SCRIPT_DIR/../../claude/hooks.json"
|
|
185
185
|
if grep -q '"matcher": "startup|resume|clear|compact|fork"' "$HOOKS_JSON"; then
|
|
186
186
|
echo "PASS: SessionStart matcher includes fork"
|
|
187
187
|
else
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
#
|
|
8
8
|
# Usage (sourced): workspace_snapshot "$PROJECT_DIR"
|
|
9
9
|
# Usage (executed): bash workspace-snapshot.sh [dir]
|
|
10
|
-
# dir defaults to ${CLAUDE_PROJECT_DIR:-.}
|
|
10
|
+
# dir defaults to ${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}
|
|
11
11
|
# Echoes 1 line (clean / non-git / detached-clean / unborn-clean) or 2 lines
|
|
12
12
|
# (dirty / detached-dirty / unborn-dirty). Never fails: any git command error
|
|
13
13
|
# degrades toward "非 git 工作區", matching this hook suite's fail-open design.
|
|
@@ -65,5 +65,5 @@ workspace_snapshot() {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
|
|
68
|
-
workspace_snapshot "${1:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
68
|
+
workspace_snapshot "${1:-${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}}"
|
|
69
69
|
fi
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
set -uo pipefail
|
|
3
3
|
_src="${BASH_SOURCE[0]}"
|
|
4
4
|
SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
5
|
-
PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../
|
|
5
|
+
PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../core/scripts" && pwd)"
|
|
6
6
|
INPUT="$(cat 2>/dev/null || true)"
|
|
7
7
|
ROOT="$(printf '%s' "$INPUT" | bash "$SCRIPT_DIR/project-dir.sh")"
|
|
8
|
-
export
|
|
8
|
+
export DEVLOG_PROJECT_DIR="$ROOT"
|
|
9
9
|
ERR_FILE="$(mktemp "${TMPDIR:-/tmp}/cursor-pre-tool.XXXXXX")" || { echo '{}'; exit 0; }
|
|
10
10
|
printf '%s' "$INPUT" | bash "$PLUGIN_SCRIPTS/segment-watch.sh" >/dev/null 2>"$ERR_FILE"
|
|
11
11
|
RESULT=$?
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
set -uo pipefail
|
|
3
3
|
_src="${BASH_SOURCE[0]}"
|
|
4
4
|
SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
5
|
-
PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../
|
|
5
|
+
PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../core/scripts" && pwd)"
|
|
6
6
|
INPUT="$(cat 2>/dev/null || true)"
|
|
7
7
|
ROOT="$(printf '%s' "$INPUT" | bash "$SCRIPT_DIR/project-dir.sh")"
|
|
8
|
-
export
|
|
8
|
+
export DEVLOG_PROJECT_DIR="$ROOT"
|
|
9
9
|
printf '%s' "$INPUT" | bash "$PLUGIN_SCRIPTS/on-session-end.sh" >/dev/null 2>&1 || true
|
|
10
10
|
echo '{}'
|
|
11
11
|
exit 0
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
set -uo pipefail
|
|
3
3
|
_src="${BASH_SOURCE[0]}"
|
|
4
4
|
SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
5
|
-
PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../
|
|
5
|
+
PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../core/scripts" && pwd)"
|
|
6
6
|
INPUT="$(cat 2>/dev/null || true)"
|
|
7
7
|
ROOT="$(printf '%s' "$INPUT" | bash "$SCRIPT_DIR/project-dir.sh")"
|
|
8
|
-
export
|
|
8
|
+
export DEVLOG_PROJECT_DIR="$ROOT"
|
|
9
9
|
EXCERPT="$(printf '%s' '{"source":"startup"}' | bash "$PLUGIN_SCRIPTS/session-start-devlog.sh" 2>/dev/null || true)"
|
|
10
10
|
if command -v jq >/dev/null 2>&1; then
|
|
11
11
|
jq -n --arg c "$EXCERPT" '{additional_context:$c}'
|
package/cursor/hooks/on-stop.sh
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
set -uo pipefail
|
|
3
3
|
_src="${BASH_SOURCE[0]}"
|
|
4
4
|
SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
5
|
-
PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../
|
|
5
|
+
PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../core/scripts" && pwd)"
|
|
6
6
|
INPUT="$(cat 2>/dev/null || true)"
|
|
7
7
|
ROOT="$(printf '%s' "$INPUT" | bash "$SCRIPT_DIR/project-dir.sh")"
|
|
8
|
-
export
|
|
8
|
+
export DEVLOG_PROJECT_DIR="$ROOT"
|
|
9
9
|
STATUS=""
|
|
10
10
|
LOOP_COUNT=0
|
|
11
11
|
if command -v jq >/dev/null 2>&1; then
|