devlog-tracker 0.34.0 → 1.1.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 +7 -5
- package/README.zh-TW.md +7 -5
- package/codex/hooks/on-interrupt.sh +1 -0
- package/codex/hooks/on-pre-tool.sh +9 -7
- package/codex/hooks/on-session-end.sh +1 -0
- package/codex/hooks/on-session-start.sh +1 -0
- package/codex/hooks/on-stop.sh +1 -0
- package/codex/hooks/on-subagent-start.sh +1 -0
- package/codex/hooks/on-user-prompt-submit.sh +1 -0
- package/codex/hooks/test-adapters.sh +29 -19
- package/commands/clean.md +2 -2
- package/commands/continue.md +1 -1
- package/commands/keep-all.md +4 -4
- package/commands/keep.md +4 -4
- package/commands/migrate.md +2 -2
- package/commands/span.md +4 -4
- package/commands/status.md +1 -1
- package/core/scripts/await-open.sh +4 -4
- package/core/scripts/clean-devlog.sh +11 -5
- package/core/scripts/close-open-round.sh +0 -4
- package/core/scripts/devlog-md.sh +89 -8
- package/core/scripts/devlog-path.sh +128 -10
- package/core/scripts/enforce-devlog.sh +10 -16
- package/core/scripts/keep-all.js +4 -3
- package/core/scripts/keep-all.sh +2 -3
- package/core/scripts/keep-all.test.js +31 -0
- package/core/scripts/keep-move.sh +13 -9
- package/core/scripts/migrate-handoff.sh +2 -2
- package/core/scripts/on-tool-failure.sh +6 -1
- package/core/scripts/pause-devlog.sh +5 -3
- package/core/scripts/round-start.sh +31 -20
- package/core/scripts/segment-watch-set.sh +12 -8
- package/core/scripts/segment-watch.sh +3 -6
- package/core/scripts/session-start-devlog.sh +11 -5
- package/core/scripts/span-close.sh +7 -3
- package/core/scripts/span-open.sh +4 -4
- package/core/scripts/status-devlog.sh +6 -6
- package/core/scripts/tests/test-await-open.sh +9 -0
- package/core/scripts/tests/test-devlog-md.sh +76 -15
- package/core/scripts/tests/test-devlog-path.sh +126 -0
- package/core/scripts/tests/test-multi-platform.sh +286 -0
- package/core/scripts/tests/test-segment-watch-set.sh +10 -0
- package/core/scripts/tests/test-session-start-devlog.sh +15 -0
- package/cursor/hooks/on-pre-tool.sh +1 -0
- package/cursor/hooks/on-session-end.sh +1 -0
- package/cursor/hooks/on-session-start.sh +1 -0
- package/cursor/hooks/on-stop.sh +1 -0
- package/cursor/hooks/on-submit-prompt.sh +1 -0
- package/cursor/hooks/on-tool-failure.sh +1 -0
- package/cursor/hooks/test-adapters.sh +19 -16
- package/package.json +1 -1
- package/skills/devlog-tracker/SKILL.md +23 -18
- package/skills/devlog-tracker/references/contract.md +2 -2
- package/skills/devlog-tracker/references/reply-fold.md +8 -8
- package/skills/devlog-tracker/references/round-segments.md +2 -2
- package/skills/devlog-tracker/references/span-mode.md +10 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
*English | [繁體中文](README.zh-TW.md)*
|
|
4
4
|
|
|
5
|
-
**Version**
|
|
5
|
+
**Version** 1.1.0
|
|
6
6
|
|
|
7
7
|
Maintains a `.devlog/devlog.md` in your project, turning each conversation round's requests, decisions, and outcomes into a permanent record. A conversation disappears the moment you `/clear` or switch sessions; this file fills that gap so work can pause and resume. Nothing is touched until you explicitly run `/devlog-tracker:start` — installing the plugin alone doesn't create or modify any files.
|
|
8
8
|
|
|
@@ -75,9 +75,9 @@ Merges the `hooks` from `codex/hooks.json` into the project's `.codex/hooks.json
|
|
|
75
75
|
|
|
76
76
|
- Interactive mode: Codex warns at startup when hooks need review. Use `/hooks` to inspect and trust them. A later change to hook configuration (e.g. re-running `init` and changing paths or commands) may require another review.
|
|
77
77
|
- Non-interactive `codex exec` (CI, scripts): unapproved hooks are silently skipped. `--dangerously-bypass-hook-trust` lets them run, but that flag skips trust checks for *all* hooks, so it's only appropriate for automation environments where you've already vetted the hook sources yourself.
|
|
78
|
-
- To confirm it's working: after `start`, send a message and check whether `.devlog/.round-current.md` shows this round's User Input skeleton; if not, the hook didn't run.
|
|
78
|
+
- To confirm it's working: after `start`, send a message and check whether `.devlog/.round-current@codex.md` shows this round's User Input skeleton; if not, the hook didn't run.
|
|
79
79
|
|
|
80
|
-
When the silence or workspace guard blocks a tool, Codex can read the current round with a single `cat <project>/.devlog/.round-current.md` command and update it with `apply_patch`. The block message includes the project path.
|
|
80
|
+
When the silence or workspace guard blocks a tool, Codex can read the current round with a single `cat <project>/.devlog/.round-current@codex.md` command and update it with `apply_patch`. The block message includes the project path.
|
|
81
81
|
|
|
82
82
|
Codex's `Interrupt` hook records an interrupted main-thread turn as `INTERRUPTED`. Codex has no `StopFailure` event for other abnormal endings; an open round is recovered on the next prompt or session start, or when `SessionEnd` runs. Codex's `SessionEnd` reason is currently only `other`, and it may run after an idle session rather than immediately when you switch conversations. The `Stop` hook still enforces completion of normal turns. Codex can also start from a subdirectory of an installed project; the hooks find the installation root.
|
|
83
83
|
|
|
@@ -101,6 +101,8 @@ Without `--claude`/`--codex`/`--cursor`, it interactively asks which platform(s)
|
|
|
101
101
|
|
|
102
102
|
Copies `core/scripts/`, `claude/hooks.json`, `codex/hooks/`, `cursor/hooks/`, `skills/`, and `commands/` into the project's `.devlog-tracker/`. Re-running `npx devlog-tracker init` upgrades to the package's current version; `npx devlog-tracker status` checks whether the installed version is behind. `npx devlog-tracker report [--json] [--all-branches]` and `npx devlog-tracker timeline [--all-branches] [--out <path>]` run the same scripts as `/devlog-tracker:report` and `/devlog-tracker:timeline`, using the vendored copy when there is one.
|
|
103
103
|
|
|
104
|
+
Claude Code, Codex, and Cursor can run in the same worktree at the same time. They share one `devlog.md`, but each platform keeps its own open round (`.devlog/.round-current.md` for Claude Code, `.round-current@codex.md`/`.round-current@cursor.md` for the others) and its own Session Handoff; round numbers stay unique across platforms, and Codex/Cursor round headings end with ` · codex`/` · cursor`. `clean`, `keep`, and `keep-all` refuse to run while two or more platforms have a round open. Several windows of the *same* platform in one worktree are not supported — they share one slot. Upgrade every platform's install to the same devlog-tracker version together: an older version on one platform still writes the shared, un-suffixed files and breaks the per-platform split. See [`docs/design/multi-platform-concurrency.md`](docs/design/multi-platform-concurrency.md).
|
|
105
|
+
|
|
104
106
|
`.devlog-tracker/` contains the installed program. `.devlog/` contains your project's tracking data and is created only when you run the start command. Therefore, seeing `.devlog-tracker/` immediately after `npx init` is expected; `init` alone does not start recording.
|
|
105
107
|
|
|
106
108
|
`init` writes this machine's absolute paths into each platform's hooks config and into `.devlog-tracker/env.sh`. If you commit these files to git, each teammate needs to run `npx devlog-tracker init` on their own machine (paths differ per machine); alternatively, add `.devlog-tracker/` and the generated hooks config files to `.gitignore`.
|
|
@@ -214,7 +216,7 @@ See [`docs/design/summary-handoff.md`](docs/design/summary-handoff.md), [`docs/d
|
|
|
214
216
|
|
|
215
217
|
### Upgrading to XML Handoff
|
|
216
218
|
|
|
217
|
-
Rounds written before this change are in the legacy `####`-headed form and are still read fine. Archive, keep and lessons files (`devlog.archive.md`, `devlog.<name>.md`, `devlog.lessons.*.md`) are never rewritten. When the Stop hook blocks on a legacy Handoff in the round it's checking, it tells the agent to run the migrate command (`/devlog-tracker:migrate` on the Claude plugin or `$devlog-migrate` on Codex; underlying script: `migrate-handoff.sh`) itself, then finish the turn again — no action needed from you in the common case. Migrate rewrites `devlog.md`, the branch devlog files,
|
|
219
|
+
Rounds written before this change are in the legacy `####`-headed form and are still read fine. Archive, keep and lessons files (`devlog.archive.md`, `devlog.<name>.md`, `devlog.lessons.*.md`) are never rewritten. When the Stop hook blocks on a legacy Handoff in the round it's checking, it tells the agent to run the migrate command (`/devlog-tracker:migrate` on the Claude plugin or `$devlog-migrate` on Codex; underlying script: `migrate-handoff.sh`) itself, then finish the turn again — no action needed from you in the common case. Migrate rewrites `devlog.md`, the branch devlog files, every platform's open round (`.round-current.md`, `.round-current@codex.md`, `.round-current@cursor.md`) and handoff files (`handoff.md`/`handoff.<branch>.md` and their `@codex`/`@cursor` variants) in place, leaving a `*.pre-migrate` backup next to each file it changes; a round it cannot map exactly is left as-is and listed on a `SKIP` line. If the agent keeps writing the legacy form instead of picking up the fix, update the plugin or rerun `npx devlog-tracker init`, then use the start command for your installation (`/devlog-tracker:start` on the Claude plugin or `$devlog-start` on Codex).
|
|
218
220
|
|
|
219
221
|
## What the hooks do automatically
|
|
220
222
|
|
|
@@ -243,7 +245,7 @@ Non-usage API errors, SessionEnd, and a leftover `.round-open` mark an open Roun
|
|
|
243
245
|
|
|
244
246
|
#### Segment recording
|
|
245
247
|
|
|
246
|
-
Don't hold a long round until the very end — write `### Segment` entries as you go. If `.round-current.md` hasn't been touched for about 10 minutes within the same round, the `PreToolUse` hook blocks the next tool call; Read first, then Edit/StrReplace to append a segment (don't Write over the whole file). The threshold is adjustable with `/devlog-tracker:segment-watch <duration>`. Claude Code subagents/dynamic workflows (`PreToolUse` carrying `agent_id`) don't apply this gate from the parent round. See [`docs/design/segment-watch.md`](docs/design/segment-watch.md).
|
|
248
|
+
Don't hold a long round until the very end — write `### Segment` entries as you go. If the open round file (`.round-current.md`, or `.round-current@codex.md`/`.round-current@cursor.md` on Codex/Cursor) hasn't been touched for about 10 minutes within the same round, the `PreToolUse` hook blocks the next tool call; Read first, then Edit/StrReplace to append a segment (don't Write over the whole file). The threshold is adjustable with `/devlog-tracker:segment-watch <duration>`. Claude Code subagents/dynamic workflows (`PreToolUse` carrying `agent_id`) don't apply this gate from the parent round. See [`docs/design/segment-watch.md`](docs/design/segment-watch.md).
|
|
247
249
|
|
|
248
250
|
#### Checkpoint Mode
|
|
249
251
|
|
package/README.zh-TW.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
*[English](README.md) | 繁體中文*
|
|
4
4
|
|
|
5
|
-
**版本**
|
|
5
|
+
**版本** 1.1.0
|
|
6
6
|
|
|
7
7
|
在專案中維護一份 `.devlog/devlog.md`,把每一輪對話的請求、決策與結果寫成永久紀錄。對話一 `/clear` 或換 session 就沒了;這份檔案取代那個缺口,讓工作可以中斷再接。沒下過 `/devlog-tracker:start` 時,裝著也不會動任何檔案。
|
|
8
8
|
|
|
@@ -75,9 +75,9 @@ npx devlog-tracker init --codex
|
|
|
75
75
|
|
|
76
76
|
- 互動模式:有 hook 待審核時,Codex 啟動時會顯示警告。用 `/hooks` 檢查並信任它們。之後 hook 的設定有變動(例如重跑 `init` 讓路徑或指令改變)也可能要再審核一次。
|
|
77
77
|
- 非互動的 `codex exec`(CI、腳本):未審核的 hook 會被靜默略過。`--dangerously-bypass-hook-trust` 可以讓它們跑起來,但那個旗標會略過所有 hook 的信任檢查,只適合已經自己確認過 hook 來源的自動化環境。
|
|
78
|
-
- 想確認有沒有生效:`start` 之後送一則訊息,看 `.devlog/.round-current.md` 有沒有出現這一輪的 User Input skeleton;沒有就代表 hook 沒被執行。
|
|
78
|
+
- 想確認有沒有生效:`start` 之後送一則訊息,看 `.devlog/.round-current@codex.md` 有沒有出現這一輪的 User Input skeleton;沒有就代表 hook 沒被執行。
|
|
79
79
|
|
|
80
|
-
沉默或工作區檢查擋住工具時,Codex 可用單一 `cat <專案>/.devlog/.round-current.md` 指令讀取當輪,再用 `apply_patch` 修改;封鎖訊息會附上專案路徑。
|
|
80
|
+
沉默或工作區檢查擋住工具時,Codex 可用單一 `cat <專案>/.devlog/.round-current@codex.md` 指令讀取當輪,再用 `apply_patch` 修改;封鎖訊息會附上專案路徑。
|
|
81
81
|
|
|
82
82
|
Codex 的 `Interrupt` hook 會把主執行緒被中斷的輪次標成 `INTERRUPTED`。Codex 沒有處理其他異常結束的 `StopFailure` 事件;未收尾輪次會在下次訊息、下次 session start,或 `SessionEnd` 執行時補記。Codex 的 `SessionEnd` 原因目前只有 `other`,切換對話後也可能等閒置一段時間才觸發。正常輪次仍由 `Stop` hook 強制收尾。從已安裝專案的子目錄啟動 Codex 時,hook 也會找到安裝根目錄。
|
|
83
83
|
|
|
@@ -101,6 +101,8 @@ npx devlog-tracker init
|
|
|
101
101
|
|
|
102
102
|
會把 `core/scripts/`、`claude/hooks.json`、`codex/hooks/`、`cursor/hooks/`、`skills/`、`commands/` 複製進專案的 `.devlog-tracker/`。重新執行 `npx devlog-tracker init` 可以升級到套件目前的版本;`npx devlog-tracker status` 可以查目前裝的版本是否落後。`npx devlog-tracker report [--json] [--all-branches]` 和 `npx devlog-tracker timeline [--all-branches] [--out <路徑>]` 跑的是跟 `/devlog-tracker:report`、`/devlog-tracker:timeline` 同一支腳本,有 vendored 版本就用它。
|
|
103
103
|
|
|
104
|
+
Claude Code、Codex、Cursor 可以在同一個工作樹同時使用。三者共用一份 `devlog.md`,但每個平台各自保有開著的輪次(Claude Code 是 `.devlog/.round-current.md`,其他平台是 `.round-current@codex.md`/`.round-current@cursor.md`)與各自的 Session Handoff;輪次號碼跨平台不重複,Codex/Cursor 的 Round 標題結尾帶 ` · codex`/` · cursor`。有兩個以上平台的輪次開著時,`clean`、`keep`、`keep-all` 會拒絕執行。同一個平台在同一個工作樹開多個視窗不支援——它們共用同一格。各平台的安裝要一起升級到同一個 devlog-tracker 版本:某個平台還停在舊版時,它仍寫共用的無後綴檔案,會破壞各平台分開的狀態。細節見 [`docs/design/multi-platform-concurrency.md`](docs/design/multi-platform-concurrency.md)。
|
|
105
|
+
|
|
104
106
|
`.devlog-tracker/` 放的是安裝進專案的程式;`.devlog/` 放的是這個專案的紀錄資料,執行 start 指令後才會建立。因此 `npx init` 後先看到 `.devlog-tracker/` 是預期行為,單跑 `init` 不會開始記錄。
|
|
105
107
|
|
|
106
108
|
`init` 會把這台機器專屬的絕對路徑寫進各平台的 hooks 設定檔與 `.devlog-tracker/env.sh`。如果你把這些檔案 commit 進 git,每位隊友都要在自己的機器上跑一次 `npx devlog-tracker init`(路徑每台機器不同);或者改成把 `.devlog-tracker/` 與產生出來的 hooks 設定檔加進 `.gitignore`。
|
|
@@ -214,7 +216,7 @@ Stop hook 會做這些事:
|
|
|
214
216
|
|
|
215
217
|
### 升級到 XML Handoff
|
|
216
218
|
|
|
217
|
-
舊輪次是 `####` 小節格式,讀取端照樣相容。archive、keep 與 lessons 檔(`devlog.archive.md`、`devlog.<name>.md`、`devlog.lessons.*.md`)永遠不會被改寫。當 Stop hook 在收尾時擋下舊格式的 Handoff,訊息會叫 agent 自己跑對應的 migrate 指令(Claude plugin 用 `/devlog-tracker:migrate`,Codex 用 `$devlog-migrate`;底層是 `migrate-handoff.sh`)再重新結束這一輪——一般情況不用你動手。migrate 會直接改寫 `devlog.md`、分支 devlog
|
|
219
|
+
舊輪次是 `####` 小節格式,讀取端照樣相容。archive、keep 與 lessons 檔(`devlog.archive.md`、`devlog.<name>.md`、`devlog.lessons.*.md`)永遠不會被改寫。當 Stop hook 在收尾時擋下舊格式的 Handoff,訊息會叫 agent 自己跑對應的 migrate 指令(Claude plugin 用 `/devlog-tracker:migrate`,Codex 用 `$devlog-migrate`;底層是 `migrate-handoff.sh`)再重新結束這一輪——一般情況不用你動手。migrate 會直接改寫 `devlog.md`、分支 devlog 檔、每個平台開著的 Round(`.round-current.md`、`.round-current@codex.md`、`.round-current@cursor.md`)與交接檔(`handoff.md`/`handoff.<branch>.md` 及其 `@codex`/`@cursor` 版本),每個改過的檔旁邊留一份 `*.pre-migrate` 備份;無法精確轉換的輪次保留原樣,列在 `SKIP` 行。如果 agent 一直寫舊格式、沒有照著修,請更新 plugin 或重跑 `npx devlog-tracker init`,再使用對應的 start 指令(Claude plugin 用 `/devlog-tracker:start`,Codex 用 `$devlog-start`)。
|
|
218
220
|
|
|
219
221
|
## Hook 會自動做的事
|
|
220
222
|
|
|
@@ -243,7 +245,7 @@ Stop hook 會做這些事:
|
|
|
243
245
|
|
|
244
246
|
#### 段落記錄
|
|
245
247
|
|
|
246
|
-
長輪不要憋到最後,邊做邊寫 `### 段落`。同一輪連續約 10
|
|
248
|
+
長輪不要憋到最後,邊做邊寫 `### 段落`。同一輪連續約 10 分鐘沒改開著的 round 檔(`.round-current.md`;Codex/Cursor 是 `.round-current@codex.md`/`.round-current@cursor.md`),`PreToolUse` hook 會擋住下一個工具;先 Read 再 Edit/StrReplace 追加一段(不要 Write 覆寫整檔)。門檻可用 `/devlog-tracker:segment-watch <時間長度>` 調整。Claude Code subagent/dynamic workflow(PreToolUse 帶 `agent_id`)不套用父輪這道閥。細節見 [`docs/design/segment-watch.md`](docs/design/segment-watch.md)。
|
|
247
249
|
|
|
248
250
|
#### Checkpoint Mode
|
|
249
251
|
|
|
@@ -9,5 +9,6 @@ PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../core/scripts" 2>/dev/null && pwd)"
|
|
|
9
9
|
INPUT="$(cat 2>/dev/null || true)"
|
|
10
10
|
ROOT="$(printf '%s' "$INPUT" | bash "$SCRIPT_DIR/project-dir.sh")"
|
|
11
11
|
export DEVLOG_PROJECT_DIR="$ROOT"
|
|
12
|
+
export DEVLOG_PLATFORM=codex
|
|
12
13
|
bash "$PLUGIN_SCRIPTS/close-open-round.sh" "Interrupt:cancelled" >/dev/null 2>&1 || true
|
|
13
14
|
exit 0
|
|
@@ -15,10 +15,12 @@ PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../core/scripts" 2>/dev/null && pwd)"
|
|
|
15
15
|
INPUT="$(cat 2>/dev/null || true)"
|
|
16
16
|
ROOT="$(printf '%s' "$INPUT" | bash "$SCRIPT_DIR/project-dir.sh")"
|
|
17
17
|
export DEVLOG_PROJECT_DIR="$ROOT"
|
|
18
|
+
export DEVLOG_PLATFORM=codex
|
|
19
|
+
ROUND_FILE=".devlog/.round-current@codex.md"
|
|
18
20
|
|
|
19
21
|
codex_access_payload() {
|
|
20
|
-
printf '{"tool_name":"%s","tool_input":{"file_path":"
|
|
21
|
-
"$1" "$(json_escape "$(json_str_field "$INPUT" session_id)")" "$(json_escape "$(json_str_field "$INPUT" agent_id)")"
|
|
22
|
+
printf '{"tool_name":"%s","tool_input":{"file_path":"%s"},"session_id":"%s","agent_id":"%s"}' \
|
|
23
|
+
"$1" "$ROUND_FILE" "$(json_escape "$(json_str_field "$INPUT" session_id)")" "$(json_escape "$(json_str_field "$INPUT" agent_id)")"
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
TOOL_NAME="$(json_str_field "$INPUT" tool_name)"
|
|
@@ -35,10 +37,10 @@ fi
|
|
|
35
37
|
if [ "$TOOL_NAME" = Bash ]; then
|
|
36
38
|
CWD="$(json_str_field "$INPUT" cwd)"
|
|
37
39
|
case "$COMMAND" in
|
|
38
|
-
"cat $ROOT
|
|
40
|
+
"cat $ROOT/$ROUND_FILE"|"cat \"$ROOT/$ROUND_FILE\"")
|
|
39
41
|
INPUT="$(codex_access_payload Read)"
|
|
40
42
|
;;
|
|
41
|
-
|
|
43
|
+
"cat $ROUND_FILE"|"cat \"$ROUND_FILE\"")
|
|
42
44
|
[ "$CWD" != "$ROOT" ] || INPUT="$(codex_access_payload Read)"
|
|
43
45
|
;;
|
|
44
46
|
esac
|
|
@@ -51,7 +53,7 @@ if [ "$TOOL_NAME" = apply_patch ]; then
|
|
|
51
53
|
CWD="$(json_str_field "$INPUT" cwd)"
|
|
52
54
|
[ -n "$CWD" ] || CWD="$ROOT"
|
|
53
55
|
PATCH="$COMMAND"
|
|
54
|
-
if printf '%s\n' "$PATCH" | awk -v cwd="$CWD" -v root="$ROOT" '
|
|
56
|
+
if printf '%s\n' "$PATCH" | awk -v cwd="$CWD" -v root="$ROOT" -v round_file="$ROUND_FILE" '
|
|
55
57
|
function normalize(path, count, parts, stack, depth, i, result) {
|
|
56
58
|
if (substr(path, 1, 1) != "/") path = cwd "/" path
|
|
57
59
|
count = split(path, parts, "/")
|
|
@@ -68,7 +70,7 @@ if [ "$TOOL_NAME" = apply_patch ]; then
|
|
|
68
70
|
NR == 1 && $0 != "*** Begin Patch" { bad = 1 }
|
|
69
71
|
/^\*\*\* (Add|Update|Delete) File: / {
|
|
70
72
|
path = $0; sub(/^\*\*\* (Add|Update|Delete) File: /, "", path)
|
|
71
|
-
if ($0 ~ /^\*\*\* Delete File: / || normalize(path) != normalize(root "
|
|
73
|
+
if ($0 ~ /^\*\*\* Delete File: / || normalize(path) != normalize(root "/" round_file)) bad = 1
|
|
72
74
|
files++
|
|
73
75
|
}
|
|
74
76
|
/^\*\*\* Move to: / { bad = 1 }
|
|
@@ -81,7 +83,7 @@ fi
|
|
|
81
83
|
printf '%s' "$INPUT" | bash "$PLUGIN_SCRIPTS/segment-watch.sh"
|
|
82
84
|
RC=$?
|
|
83
85
|
if [ "$RC" -eq 2 ]; then
|
|
84
|
-
printf 'Codex CLI:先用 cat "%s
|
|
86
|
+
printf 'Codex CLI:先用 cat "%s/%s" 讀取,再用 apply_patch 只修改這份檔案;完成後重試原工具。\n' "$ROOT" "$ROUND_FILE" >&2
|
|
85
87
|
exit 2
|
|
86
88
|
fi
|
|
87
89
|
exit 0
|
|
@@ -11,6 +11,7 @@ PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../core/scripts" && pwd)"
|
|
|
11
11
|
INPUT="$(cat 2>/dev/null || true)"
|
|
12
12
|
ROOT="$(printf '%s' "$INPUT" | bash "$SCRIPT_DIR/project-dir.sh")"
|
|
13
13
|
export DEVLOG_PROJECT_DIR="$ROOT"
|
|
14
|
+
export DEVLOG_PLATFORM=codex
|
|
14
15
|
|
|
15
16
|
REASON=""
|
|
16
17
|
if command -v jq >/dev/null 2>&1; then
|
|
@@ -16,6 +16,7 @@ PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../core/scripts" && pwd)"
|
|
|
16
16
|
INPUT="$(cat 2>/dev/null || true)"
|
|
17
17
|
ROOT="$(printf '%s' "$INPUT" | bash "$SCRIPT_DIR/project-dir.sh")"
|
|
18
18
|
export DEVLOG_PROJECT_DIR="$ROOT"
|
|
19
|
+
export DEVLOG_PLATFORM=codex
|
|
19
20
|
|
|
20
21
|
SRC=""
|
|
21
22
|
if command -v jq >/dev/null 2>&1; then
|
package/codex/hooks/on-stop.sh
CHANGED
|
@@ -12,6 +12,7 @@ PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../core/scripts" 2>/dev/null && pwd)"
|
|
|
12
12
|
INPUT="$(cat 2>/dev/null || true)"
|
|
13
13
|
ROOT="$(printf '%s' "$INPUT" | bash "$SCRIPT_DIR/project-dir.sh")"
|
|
14
14
|
export DEVLOG_PROJECT_DIR="$ROOT"
|
|
15
|
+
export DEVLOG_PLATFORM=codex
|
|
15
16
|
printf '%s' "$INPUT" | bash "$PLUGIN_SCRIPTS/enforce-devlog.sh" >/dev/null
|
|
16
17
|
RC=$?
|
|
17
18
|
[ "$RC" -eq 2 ] && exit 2
|
|
@@ -11,5 +11,6 @@ PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../core/scripts" && pwd)"
|
|
|
11
11
|
INPUT="$(cat 2>/dev/null || true)"
|
|
12
12
|
ROOT="$(printf '%s' "$INPUT" | bash "$SCRIPT_DIR/project-dir.sh")"
|
|
13
13
|
export DEVLOG_PROJECT_DIR="$ROOT"
|
|
14
|
+
export DEVLOG_PLATFORM=codex
|
|
14
15
|
printf '%s' "$INPUT" | bash "$PLUGIN_SCRIPTS/round-start.sh"
|
|
15
16
|
exit 0
|
|
@@ -39,14 +39,15 @@ EOF
|
|
|
39
39
|
OUT="$(printf '{"cwd":"%s","source":"startup"}' "$TMP/project" | bash "$SCRIPT_DIR/on-session-start.sh")"
|
|
40
40
|
case "$OUT" in *"Round 1"*) echo "PASS: sessionStart injects context" ;; *) echo "FAIL: sessionStart [$OUT]"; FAIL=1 ;; esac
|
|
41
41
|
|
|
42
|
-
# userPromptSubmit: opens a Round in .round-current.md
|
|
42
|
+
# userPromptSubmit: opens a Round in .round-current@codex.md
|
|
43
43
|
SUBMIT="$TMP/submit"
|
|
44
44
|
mkdir -p "$SUBMIT/.devlog" "$SUBMIT/.devlog-tracker" "$SUBMIT/src"
|
|
45
45
|
touch "$SUBMIT/.devlog/.enabled"
|
|
46
|
+
touch "$SUBMIT/.devlog/.platform-claimed"
|
|
46
47
|
bash "$SCRIPT_DIR/on-user-prompt-submit.sh" <<EOF2 >/dev/null
|
|
47
48
|
{"cwd":"$SUBMIT","prompt":"hello","session_id":"codex-1"}
|
|
48
49
|
EOF2
|
|
49
|
-
if grep -q 'hello' "$SUBMIT/.devlog/.round-current.md" 2>/dev/null; then
|
|
50
|
+
if grep -q 'hello' "$SUBMIT/.devlog/.round-current@codex.md" 2>/dev/null; then
|
|
50
51
|
echo "PASS: userPromptSubmit writes round"
|
|
51
52
|
else
|
|
52
53
|
echo "FAIL: userPromptSubmit round"; FAIL=1
|
|
@@ -55,8 +56,8 @@ fi
|
|
|
55
56
|
# preTool: blocks (exit 2) once the silence window has expired, allows fresh writes
|
|
56
57
|
NOW="$(date +%s)"
|
|
57
58
|
OLD=$((NOW - 1000))
|
|
58
|
-
SUM="$(cksum < "$SUBMIT/.devlog/.round-current.md" | tr -d '\n')"
|
|
59
|
-
printf '{"last_change_epoch": %s, "last_seen_cksum": "%s", "max_silent_seconds": 900, "session_id": "codex-1"}\n' "$OLD" "$SUM" > "$SUBMIT/.devlog/.segment-state"
|
|
59
|
+
SUM="$(cksum < "$SUBMIT/.devlog/.round-current@codex.md" | tr -d '\n')"
|
|
60
|
+
printf '{"last_change_epoch": %s, "last_seen_cksum": "%s", "max_silent_seconds": 900, "session_id": "codex-1"}\n' "$OLD" "$SUM" > "$SUBMIT/.devlog/.segment-state@codex"
|
|
60
61
|
set +e
|
|
61
62
|
ERR="$(printf '{"cwd":"%s","tool_name":"Bash","tool_input":{},"session_id":"codex-1"}' "$SUBMIT" | bash "$SCRIPT_DIR/on-pre-tool.sh" 2>&1 >/dev/null)"
|
|
62
63
|
RC=$?
|
|
@@ -68,20 +69,20 @@ case "$ERR" in
|
|
|
68
69
|
esac
|
|
69
70
|
|
|
70
71
|
set +e
|
|
71
|
-
printf '{"cwd":"%s","tool_name":"Write","tool_input":{"file_path":"%s/.devlog/.round-current.md"},"session_id":"codex-1"}' "$SUBMIT" "$SUBMIT" | bash "$SCRIPT_DIR/on-pre-tool.sh" >/dev/null 2>/dev/null
|
|
72
|
+
printf '{"cwd":"%s","tool_name":"Write","tool_input":{"file_path":"%s/.devlog/.round-current@codex.md"},"session_id":"codex-1"}' "$SUBMIT" "$SUBMIT" | bash "$SCRIPT_DIR/on-pre-tool.sh" >/dev/null 2>/dev/null
|
|
72
73
|
RC=$?
|
|
73
74
|
set -e
|
|
74
75
|
if [ "$RC" -eq 0 ]; then echo "PASS: devlog write allowed (exit 0)"; else echo "FAIL: allowed-tool exit [$RC]"; FAIL=1; fi
|
|
75
76
|
|
|
76
77
|
set +e
|
|
77
|
-
printf '{"cwd":"%s","tool_name":"Bash","tool_input":{"command":"cat %s/.devlog/.round-current.md"},"session_id":"codex-1"}' \
|
|
78
|
+
printf '{"cwd":"%s","tool_name":"Bash","tool_input":{"command":"cat %s/.devlog/.round-current@codex.md"},"session_id":"codex-1"}' \
|
|
78
79
|
"$SUBMIT" "$SUBMIT" | bash "$SCRIPT_DIR/on-pre-tool.sh" >/dev/null 2>/dev/null
|
|
79
80
|
RC=$?
|
|
80
81
|
set -e
|
|
81
82
|
if [ "$RC" -eq 0 ]; then echo "PASS: devlog cat allowed"; else echo "FAIL: devlog cat exit [$RC]"; FAIL=1; fi
|
|
82
83
|
|
|
83
84
|
set +e
|
|
84
|
-
printf '{"cwd":"%s","tool_name":"Bash","tool_input":{"command":"cat %s/.devlog/.round-current.md; echo unsafe"},"session_id":"codex-1"}' \
|
|
85
|
+
printf '{"cwd":"%s","tool_name":"Bash","tool_input":{"command":"cat %s/.devlog/.round-current@codex.md; echo unsafe"},"session_id":"codex-1"}' \
|
|
85
86
|
"$SUBMIT" "$SUBMIT" | bash "$SCRIPT_DIR/on-pre-tool.sh" >/dev/null 2>/dev/null
|
|
86
87
|
RC=$?
|
|
87
88
|
set -e
|
|
@@ -89,7 +90,7 @@ if [ "$RC" -eq 2 ]; then echo "PASS: chained cat blocked"; else echo "FAIL: chai
|
|
|
89
90
|
|
|
90
91
|
# Codex reports file edits as apply_patch with the patch in tool_input.command.
|
|
91
92
|
PATCH='*** Begin Patch
|
|
92
|
-
*** Update File: .devlog/.round-current.md
|
|
93
|
+
*** Update File: .devlog/.round-current@codex.md
|
|
93
94
|
@@
|
|
94
95
|
-before
|
|
95
96
|
+after
|
|
@@ -102,7 +103,7 @@ set -e
|
|
|
102
103
|
if [ "$RC" -eq 0 ]; then echo "PASS: devlog apply_patch allowed"; else echo "FAIL: devlog apply_patch exit [$RC]"; FAIL=1; fi
|
|
103
104
|
|
|
104
105
|
PATCH='*** Begin Patch
|
|
105
|
-
*** Update File: ../.devlog/.round-current.md
|
|
106
|
+
*** Update File: ../.devlog/.round-current@codex.md
|
|
106
107
|
@@
|
|
107
108
|
-before
|
|
108
109
|
+after
|
|
@@ -115,7 +116,7 @@ set -e
|
|
|
115
116
|
if [ "$RC" -eq 0 ]; then echo "PASS: nested cwd devlog apply_patch allowed"; else echo "FAIL: nested cwd apply_patch exit [$RC]"; FAIL=1; fi
|
|
116
117
|
|
|
117
118
|
PATCH='*** Begin Patch
|
|
118
|
-
*** Update File: .devlog/.round-current.md
|
|
119
|
+
*** Update File: .devlog/.round-current@codex.md
|
|
119
120
|
@@
|
|
120
121
|
-before
|
|
121
122
|
+after
|
|
@@ -128,7 +129,7 @@ set -e
|
|
|
128
129
|
if [ "$RC" -eq 2 ]; then echo "PASS: nested cwd unrelated apply_patch blocked"; else echo "FAIL: nested cwd unrelated patch exit [$RC]"; FAIL=1; fi
|
|
129
130
|
|
|
130
131
|
PATCH='*** Begin Patch
|
|
131
|
-
*** Update File: .devlog/.round-current.md
|
|
132
|
+
*** Update File: .devlog/.round-current@codex.md
|
|
132
133
|
@@
|
|
133
134
|
-before
|
|
134
135
|
+after
|
|
@@ -144,9 +145,18 @@ RC=$?
|
|
|
144
145
|
set -e
|
|
145
146
|
if [ "$RC" -eq 2 ]; then echo "PASS: mixed apply_patch blocked"; else echo "FAIL: mixed apply_patch exit [$RC]"; FAIL=1; fi
|
|
146
147
|
|
|
148
|
+
# A patch to Claude's round file is not Codex's own file: still blocked.
|
|
149
|
+
PATCH="$(printf '*** Begin Patch\n*** Update File: .devlog/.round-current.md\n@@\n-a\n+b\n*** End Patch')"
|
|
150
|
+
set +e
|
|
151
|
+
printf '{"cwd":"%s","tool_name":"apply_patch","tool_input":{"command":%s},"session_id":"codex-1"}' \
|
|
152
|
+
"$SUBMIT" "$(node -p 'JSON.stringify(process.argv[1])' "$PATCH")" | bash "$SCRIPT_DIR/on-pre-tool.sh" >/dev/null 2>/dev/null
|
|
153
|
+
RC=$?
|
|
154
|
+
set -e
|
|
155
|
+
if [ "$RC" -eq 2 ]; then echo "PASS: Claude round-file apply_patch blocked"; else echo "FAIL: Claude round-file apply_patch exit [$RC]"; FAIL=1; fi
|
|
156
|
+
|
|
147
157
|
# stop: blocks (exit 2) while the round is unfinished
|
|
148
|
-
printf '{"round": 1, "opened_at": "now"}\n' > "$SUBMIT/.devlog/.round-open"
|
|
149
|
-
cksum < "$SUBMIT/.devlog/.round-current.md" > "$SUBMIT/.devlog/.turn-start"
|
|
158
|
+
printf '{"round": 1, "opened_at": "now"}\n' > "$SUBMIT/.devlog/.round-open@codex"
|
|
159
|
+
cksum < "$SUBMIT/.devlog/.round-current@codex.md" > "$SUBMIT/.devlog/.turn-start@codex"
|
|
150
160
|
set +e
|
|
151
161
|
printf '{"cwd":"%s"}' "$SUBMIT" | bash "$SCRIPT_DIR/on-stop.sh" >/dev/null 2>/dev/null
|
|
152
162
|
RC=$?
|
|
@@ -154,9 +164,9 @@ set -e
|
|
|
154
164
|
if [ "$RC" -eq 2 ]; then echo "PASS: stop blocks unfinished round (exit 2)"; else echo "FAIL: stop exit [$RC]"; FAIL=1; fi
|
|
155
165
|
|
|
156
166
|
# sessionEnd: closes the open round using the documented "reason"
|
|
157
|
-
printf '\n## Round 2 — now\n\n### Status\nIN_PROGRESS\n' > "$SUBMIT/.devlog/.round-current.md"
|
|
158
|
-
printf '{"round": 2, "opened_at": "now"}\n' > "$SUBMIT/.devlog/.round-open"
|
|
159
|
-
cksum < "$SUBMIT/.devlog/.round-current.md" > "$SUBMIT/.devlog/.turn-start"
|
|
167
|
+
printf '\n## Round 2 — now\n\n### Status\nIN_PROGRESS\n' > "$SUBMIT/.devlog/.round-current@codex.md"
|
|
168
|
+
printf '{"round": 2, "opened_at": "now"}\n' > "$SUBMIT/.devlog/.round-open@codex"
|
|
169
|
+
cksum < "$SUBMIT/.devlog/.round-current@codex.md" > "$SUBMIT/.devlog/.turn-start@codex"
|
|
160
170
|
printf '{"cwd":"%s","reason":"other"}' "$SUBMIT" | bash "$SCRIPT_DIR/on-session-end.sh" >/dev/null
|
|
161
171
|
if grep -q 'SessionEnd:other' "$SUBMIT/.devlog/devlog.md" 2>/dev/null; then
|
|
162
172
|
echo "PASS: sessionEnd closes round via reason"
|
|
@@ -165,9 +175,9 @@ else
|
|
|
165
175
|
fi
|
|
166
176
|
|
|
167
177
|
# Interrupt closes the active round immediately, using Codex's event.
|
|
168
|
-
printf '\n## Round 3 — now\n\n### Status\nIN_PROGRESS\n' > "$SUBMIT/.devlog/.round-current.md"
|
|
169
|
-
printf '{"round": 3, "opened_at": "now"}\n' > "$SUBMIT/.devlog/.round-open"
|
|
170
|
-
cksum < "$SUBMIT/.devlog/.round-current.md" > "$SUBMIT/.devlog/.turn-start"
|
|
178
|
+
printf '\n## Round 3 — now\n\n### Status\nIN_PROGRESS\n' > "$SUBMIT/.devlog/.round-current@codex.md"
|
|
179
|
+
printf '{"round": 3, "opened_at": "now"}\n' > "$SUBMIT/.devlog/.round-open@codex"
|
|
180
|
+
cksum < "$SUBMIT/.devlog/.round-current@codex.md" > "$SUBMIT/.devlog/.turn-start@codex"
|
|
171
181
|
printf '{"cwd":"%s","hook_event_name":"Interrupt","turn_id":"turn-3"}' "$SUBMIT" | bash "$SCRIPT_DIR/on-interrupt.sh" >/dev/null
|
|
172
182
|
if grep -q 'Interrupt:cancelled' "$SUBMIT/.devlog/devlog.md" 2>/dev/null; then
|
|
173
183
|
echo "PASS: interrupt closes round"
|
package/commands/clean.md
CHANGED
|
@@ -34,11 +34,11 @@ description: 無條件清空 .devlog/devlog.md(含專案摘要與所有 Round
|
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
36
|
PLUGIN_ROOT="${DEVLOG_TRACKER_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}"
|
|
37
|
-
DEVLOG_PROJECT_DIR="<專案根目錄絕對路徑,不要用 $(pwd) 重新推>" bash "${PLUGIN_ROOT}/core/scripts/clean-devlog.sh" --confirmed
|
|
37
|
+
DEVLOG_PLATFORM="<你所在的平台:claude/codex/cursor>" DEVLOG_PROJECT_DIR="<專案根目錄絕對路徑,不要用 $(pwd) 重新推>" bash "${PLUGIN_ROOT}/core/scripts/clean-devlog.sh" --confirmed
|
|
38
38
|
```
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
`--confirmed` 是必要參數,只有在使用者明確回覆「清空」之後才可以帶這個參數執行;不要在其他情況下跑這支腳本。腳本是唯一的實作來源:有沒有開著的 Round、要重編成 Round 1 還是整份刪除、重置 `.span-open` 與 checkpoint 狀態,都不要自己動手做。exit 1 時原樣顯示 stderr
|
|
41
|
+
`--confirmed` 是必要參數,只有在使用者明確回覆「清空」之後才可以帶這個參數執行;不要在其他情況下跑這支腳本。腳本是唯一的實作來源:有沒有開著的 Round、要重編成 Round 1 還是整份刪除、重置 `.span-open` 與 checkpoint 狀態,都不要自己動手做。exit 1 時原樣顯示 stderr,不要自行重試、不要自己動手改檔案。同一工作樹有兩個以上平台的輪次開著時,腳本會以 `其他平台還有進行中的輪次(…),等它們收尾再執行。若該平台已不再使用,可先 pause 再 start 清掉它的標記。` 拒絕,請使用者等其他平台收尾再跑。
|
|
42
42
|
|
|
43
43
|
## 4. 處理結果並收尾這一輪
|
|
44
44
|
|
package/commands/continue.md
CHANGED
|
@@ -5,7 +5,7 @@ description: 讀取 .devlog/devlog.md,核對最後一輪 Handoff 的工作區
|
|
|
5
5
|
請執行 devlog continue(接續上一題)。這是使用者主動執行 `/devlog-tracker:continue`,或明確說「continue」「接續」「繼續上一題」時才做的事。`/clear` 之後的一般新請求不要先讀檔接舊工作。
|
|
6
6
|
|
|
7
7
|
1. 讀取 `.devlog/devlog.md`。若檔案不存在,告知「目前沒有 devlog 可接續」,不要建立 `.devlog/` 或任何新檔,結束。記下 `.devlog/` 的上層目錄(也就是專案根目錄)的絕對路徑,作為本輪接下來都要用的專案根目錄——後面步驟(尤其是步驟 5.1)一律沿用這個值,不要再用 shell 的 `pwd` 重新推。Bash 工具的工作目錄會在同一段對話裡的呼叫之間持續累積,中途若因為別的原因 `cd` 過,`pwd` 就不再代表這個專案根目錄。
|
|
8
|
-
2.
|
|
8
|
+
2. 若你所在平台的 span 檔存在(Claude Code 是 `.devlog/.span-open`,Codex/Cursor 是 `.devlog/.span-open@codex`/`.devlog/.span-open@cursor`):先告訴使用者有一個還沒關的 span(Round 編號與 `opened_at`,若讀得到),問要繼續這個自動化任務還是先關掉它。沒有明確要關就當成要繼續,不要自己刪 span 檔。
|
|
9
9
|
3. 讀最近的 Round(不夠再往前讀;有 `## Checkpoint` 就一併看最後一個)。不要讀 `devlog.archive.md` 或 `devlog.<name>.md`,除非 Handoff 下一步明確指向它們。
|
|
10
10
|
4. 依**最後一個歷史 Round**(不是這一輪 continue 自己的 skeleton)的 Status 行動。`DONE`:告訴使用者上一題已經結束,等新需求。不要核對、不要自己找下一件工作。
|
|
11
11
|
5. `IN_PROGRESS`、`INTERRUPTED`、`BLOCKED`:先核對,再行動。不要先問「上次做到哪」。不要改歷史 Round。
|
package/commands/keep-all.md
CHANGED
|
@@ -14,7 +14,7 @@ description: 整理所有 devlog:跨主檔、所有分支檔、archive 與既
|
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
PLUGIN_ROOT="${DEVLOG_TRACKER_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}"
|
|
17
|
-
DEVLOG_PROJECT_DIR="<專案根目錄絕對路徑>" bash "${PLUGIN_ROOT}/core/scripts/keep-all.sh" --scan
|
|
17
|
+
DEVLOG_PLATFORM="<你所在的平台:claude/codex/cursor>" DEVLOG_PROJECT_DIR="<專案根目錄絕對路徑>" bash "${PLUGIN_ROOT}/core/scripts/keep-all.sh" --scan
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
- `NO_NODE`:告知 keep-all 需要 Node.js(可改用 `/devlog-tracker:keep` 整理目前分支),結束。
|
|
@@ -76,13 +76,13 @@ DEVLOG_PROJECT_DIR="<專案根目錄絕對路徑>" bash "${PLUGIN_ROOT}/core/scr
|
|
|
76
76
|
然後:
|
|
77
77
|
|
|
78
78
|
```bash
|
|
79
|
-
DEVLOG_PROJECT_DIR="<專案根目錄絕對路徑>" bash "${PLUGIN_ROOT}/core/scripts/keep-all.sh" \
|
|
79
|
+
DEVLOG_PLATFORM="<你所在的平台:claude/codex/cursor>" DEVLOG_PROJECT_DIR="<專案根目錄絕對路徑>" bash "${PLUGIN_ROOT}/core/scripts/keep-all.sh" \
|
|
80
80
|
--apply "<專案根目錄絕對路徑>/.devlog/.keep-all-plan.tsv" --fingerprint <fp> --count <n>
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
`<fp>`/`<n>` 用步驟 1 的值。不要自己搬檔、刪檔或改索引——腳本是唯一的實作:驗證計畫、把所有會動到的檔備份到 `.devlog/.keep-all-backup/<時間戳>/`、組好新檔、改寫來源、刪除被整理掉的 kept 檔、清空的 archive 與搬空的分支檔、重建 `## Kept 索引`(新索引行寫在目前分支的主檔)。搬空的分支檔只在該分支不是 `active` 時才刪;目前主檔與 `devlog.md` 一律不刪。
|
|
84
84
|
|
|
85
|
-
- exit 1:原樣顯示 stderr,不要自行重試或手動補做。驗證錯誤時不會寫任何檔;fingerprint 不符代表掃描後檔案被改過,回到步驟 1
|
|
85
|
+
- exit 1:原樣顯示 stderr,不要自行重試或手動補做。驗證錯誤時不會寫任何檔;fingerprint 不符代表掃描後檔案被改過,回到步驟 1 重新掃描。同一工作樹有兩個以上平台的輪次開著時,腳本會以 `其他平台還有進行中的輪次(…),等它們收尾再執行。若該平台已不再使用,可先 pause 再 start 清掉它的標記。` 拒絕,請使用者等其他平台收尾再跑。
|
|
86
86
|
- 成功後刪除 `.devlog/.keep-all-plan.tsv`。
|
|
87
87
|
|
|
88
88
|
## 5. 選配:摘要
|
|
@@ -93,4 +93,4 @@ DEVLOG_PROJECT_DIR="<專案根目錄絕對路徑>" bash "${PLUGIN_ROOT}/core/scr
|
|
|
93
93
|
|
|
94
94
|
依 stdout 回報:每個 `KEPT=<路徑> ROUNDS=<n>`、每個 `DELETED=<路徑>`、`BACKUP=<目錄>`(出錯時可從這裡還原),以及哪幾段套用了摘要。
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
若你所在平台的 `.round-open` 檔(Claude Code 是 `.devlog/.round-open`,Codex/Cursor 是 `.devlog/.round-open@codex`/`.devlog/.round-open@cursor`)存在:在開著的那一輪補上 `### Summary` / `### Handoff` / `### Status` 再結束(Stop hook 仍會檢查)。
|
package/commands/keep.md
CHANGED
|
@@ -11,7 +11,7 @@ description: 掃描整份 devlog.md,把值得留名的主題段落一次分別
|
|
|
11
11
|
## 1. 讀檔、找出開著的 Round
|
|
12
12
|
|
|
13
13
|
1. 讀取 `.devlog/devlog.md` 全文。若檔案不存在,告知「目前沒有東西可 keep」,不要建立 `.devlog/` 或任何新檔,結束。
|
|
14
|
-
2. 開著的 Round
|
|
14
|
+
2. 開著的 Round:若你所在平台的 `.round-open` 檔(Claude Code 是 `.devlog/.round-open`,Codex/Cursor 是 `.devlog/.round-open@codex`/`.devlog/.round-open@cursor`)存在且有 `"round"` 數字,用那個編號。若它不存在(從未 start 或已 pause),表示沒有開著的 Round,檔案裡所有 `## Round` 都是歷史,不要把最後一個 Round 當成開著的 Round 來排除。
|
|
15
15
|
3. 歷史 Round = 檔案裡除了開著的 Round 以外的所有 `## Round`(判斷 `## ` 標題時,略過圍欄程式碼區塊 ``` 內的行,與 hook 腳本解析方式一致)。若沒有任何歷史 Round,告知「目前沒有東西可 keep」,不要建立新檔,結束。
|
|
16
16
|
|
|
17
17
|
## 2. 切出主題段落,過濾瑣碎段落
|
|
@@ -84,13 +84,13 @@ description: 掃描整份 devlog.md,把值得留名的主題段落一次分別
|
|
|
84
84
|
|
|
85
85
|
```bash
|
|
86
86
|
PLUGIN_ROOT="${DEVLOG_TRACKER_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}"
|
|
87
|
-
DEVLOG_PROJECT_DIR="<專案根目錄絕對路徑,不要用 $(pwd) 重新推>" bash "${PLUGIN_ROOT}/core/scripts/keep-move.sh" \
|
|
87
|
+
DEVLOG_PLATFORM="<你所在的平台:claude/codex/cursor>" DEVLOG_PROJECT_DIR="<專案根目錄絕對路徑,不要用 $(pwd) 重新推>" bash "${PLUGIN_ROOT}/core/scripts/keep-move.sh" \
|
|
88
88
|
--from <from> --to <to> --name "<name>" --desc "<這段在做什麼的一句話>"
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
`<from>`、`<to>`、`<name>` 必須使用該段步驟 4 確認後的值。`<這段在做什麼的一句話>` 用步驟 2.5 記下的那句描述(純文字,不要換行、不要含反引號);腳本會把它原樣接在 `## Kept 索引` 那一行的 `kept_at` 之後。腳本是搬移、Checkpoint 歸屬、full keep 重編與 checkpoint counter reset 的唯一實作來源;它一次只認一段範圍,完全不知道這是批次的一部分,`commands/keep.md` 自己負責依序呼叫。
|
|
92
92
|
|
|
93
|
-
任一段的腳本 exit 1:立刻停止整批,原樣顯示那一段的 stderr
|
|
93
|
+
任一段的腳本 exit 1:立刻停止整批,原樣顯示那一段的 stderr,不要自行重試刪除,也不要手動補做搬移,也不要繼續跑後面還沒處理的段落。已經成功搬走的段落不要回滾。同一工作樹有兩個以上平台的輪次開著時,腳本會以 `其他平台還有進行中的輪次(…),等它們收尾再執行。若該平台已不再使用,可先 pause 再 start 清掉它的標記。` 拒絕,請使用者等其他平台收尾再跑。
|
|
94
94
|
|
|
95
95
|
如果這批段落最終涵蓋了 `devlog.md` 目前剩下的所有歷史 Round(沒有瑣碎段落留下),跑到最後一段(Round 號碼最新的那一段)時,腳本會自動判定為 full keep:專案摘要併入那一檔、開著的 Round 重編號成 1、`.span-open` 刪除、checkpoint counter 歸零。這是預期行為,不用特別處理,也不用另外判斷「這是不是 full keep」。
|
|
96
96
|
|
|
@@ -115,4 +115,4 @@ DEVLOG_PROJECT_DIR="<專案根目錄絕對路徑,不要用 $(pwd) 重新推>"
|
|
|
115
115
|
|
|
116
116
|
依段落回報:每個具名檔路徑、搬走幾輪(哪些編號);再依最後一次成功執行的 `REMAINING` 回報 `devlog.md` 目前剩幾輪(這個數字含還開著的那一輪,不是只算歷史 Round)。若中途因某段腳本失敗而中止,清楚列出哪些段落已經搬走(連檔名)、哪些完全沒嘗試。不要讀寫 `devlog.archive.md`。
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
若你所在平台的 `.round-open` 檔(Claude Code 是 `.round-open`,Codex/Cursor 是 `.round-open@codex`/`.round-open@cursor`)存在:在開著的那一輪補上 `### Summary` / `### Handoff` / `### Status` 再結束(Stop hook 仍會檢查)。若沒有開著的 Round:不要改寫歷史 Round 的收尾。
|
package/commands/migrate.md
CHANGED
|
@@ -13,6 +13,6 @@ description: 把 .devlog 裡舊格式(#### 小節)的 Handoff/Session Hand
|
|
|
13
13
|
- `NO_DEVLOG`:這個專案沒有 `.devlog/`,沒有東西要轉。
|
|
14
14
|
- `LOCKED <pid>`:另一個 session 正在寫 devlog,稍後再跑一次。
|
|
15
15
|
- 否則用 `MIGRATED=` 與 `SKIPPED=` 回報轉了幾輪、跳過幾輪;`BACKUP=` 是轉換前的備份。
|
|
16
|
-
3. 有 `SKIP ... Round <N>: <原因>`
|
|
16
|
+
3. 有 `SKIP ... Round <N>: <原因>` 時:歷史輪次保留原樣即可(讀取端相容舊格式)。只有**這一輪**(你所在平台開著的 round 檔,見 SKILL「檔案位置」)被跳過時,才照 `skills/devlog-tracker/SKILL.md`「每一輪的紀錄格式」的 XML 模板手動改寫這一輪的 Handoff/Session Handoff。
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
只轉每個平台的 round 檔(`.round-current.md`、`.round-current@*.md`)、`devlog.md`、branch 檔(首行是 `<!-- devlog-origin: ... -->`)與 `handoff*.md`(含 `handoff*@*.md`);不轉 `devlog.archive.md`、keep 產生的具名檔、lessons 檔。
|
package/commands/span.md
CHANGED
|
@@ -4,10 +4,10 @@ description: 開啟或關閉 Span Mode,讓自動續接的長任務定期記錄
|
|
|
4
4
|
|
|
5
5
|
先判斷使用者要開啟或關閉:
|
|
6
6
|
|
|
7
|
-
-
|
|
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"`,
|
|
7
|
+
- 使用者明確要求關閉,或你所在平台的 span 檔(Claude Code 是 `.devlog/.span-open`,Codex/Cursor 是 `.devlog/.span-open@codex`/`.devlog/.span-open@cursor`)已存在且沒有明確要求重新開啟:
|
|
8
|
+
先決定 plugin 根目錄(有 `DEVLOG_TRACKER_ROOT` 用它;否則用 `CLAUDE_PLUGIN_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄),設 `PLUGIN_ROOT="${DEVLOG_TRACKER_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}"`,再跑 `DEVLOG_PLATFORM="<你所在的平台:claude/codex/cursor>" 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
|
-
`DEVLOG_PROJECT_DIR="<專案根目錄絕對路徑,不要用 $(pwd) 重新推>" bash "${PLUGIN_ROOT}/core/scripts/span-open.sh"`。
|
|
11
|
+
`DEVLOG_PLATFORM="<你所在的平台:claude/codex/cursor>" DEVLOG_PROJECT_DIR="<專案根目錄絕對路徑,不要用 $(pwd) 重新推>" bash "${PLUGIN_ROOT}/core/scripts/span-open.sh"`。
|
|
12
12
|
|
|
13
|
-
不要手寫
|
|
13
|
+
不要手寫 span 檔的 JSON。腳本 exit 1 時顯示 stderr,停止操作。
|
package/commands/status.md
CHANGED
|
@@ -8,7 +8,7 @@ description: 查看這個專案 devlog 強制記錄是否開著、span / checkpo
|
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
PLUGIN_ROOT="${DEVLOG_TRACKER_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}"
|
|
11
|
-
DEVLOG_PROJECT_DIR="<專案根目錄絕對路徑,不要用 $(pwd) 重新推>" bash "${PLUGIN_ROOT}/core/scripts/status-devlog.sh"
|
|
11
|
+
DEVLOG_PLATFORM="<你所在的平台:claude/codex/cursor>" 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_ADVISORY=<count>/<threshold>`:Lessons Mode 開著時,機制性訊號(工作區漂移不符、或
|
|
@@ -11,13 +11,13 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
11
11
|
|
|
12
12
|
devlog_resolve_paths "${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
13
13
|
[ -f "$DEVLOG_DIR/.enabled" ] || { echo "NOT_ENABLED"; exit 1; }
|
|
14
|
-
[ ! -e "$
|
|
14
|
+
[ ! -e "$AWAITING_FILE" ] || { echo "ALREADY_OPEN"; exit 1; }
|
|
15
15
|
ROUND=""
|
|
16
|
-
[ ! -f "$
|
|
16
|
+
[ ! -f "$ROUND_OPEN" ] || ROUND="$(json_int_get "$ROUND_OPEN" round)"
|
|
17
17
|
if [ -z "$ROUND" ] && [ -f "$DEVLOG_FILE" ]; then
|
|
18
|
-
ROUND="$(
|
|
18
|
+
ROUND="$(devlog_list_round_starts_of "$DEVLOG_FILE" "$DEVLOG_PLATFORM" | awk 'END { print $2 }')"
|
|
19
19
|
fi
|
|
20
20
|
[ -n "$ROUND" ] || { echo "NO_ROUND"; exit 1; }
|
|
21
21
|
OPENED_AT="$(date -Iseconds 2>/dev/null || date '+%Y-%m-%dT%H:%M:%S%z')"
|
|
22
|
-
printf '{"round": %s, "opened_at": "%s"}\n' "$ROUND" "$OPENED_AT" > "$
|
|
22
|
+
printf '{"round": %s, "opened_at": "%s"}\n' "$ROUND" "$OPENED_AT" > "$AWAITING_FILE" || exit 1
|
|
23
23
|
printf 'OPENED=%s\n' "$ROUND"
|
|
@@ -17,8 +17,12 @@ 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"
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
OPEN_ROW="$(devlog_single_open_round)" || exit 1
|
|
21
|
+
if [ -n "$OPEN_ROW" ]; then
|
|
22
|
+
OPEN_PLATFORM="${OPEN_ROW%% *}"
|
|
23
|
+
ROUND_OPEN="$DEVLOG_DIR/$(devlog_platform_file .round-open '' "$OPEN_PLATFORM")"
|
|
24
|
+
ROUND_CURRENT="$DEVLOG_DIR/$(devlog_platform_file .round-current .md "$OPEN_PLATFORM")"
|
|
25
|
+
fi
|
|
22
26
|
# Post-split, devlog.md may legitimately not exist yet (a project's very
|
|
23
27
|
# first round can still be open, with real content sitting only in
|
|
24
28
|
# .round-current.md) — accept either devlog.md existing or .round-current.md
|
|
@@ -55,12 +59,14 @@ if [ "$HAS_OPEN" -eq 1 ]; then
|
|
|
55
59
|
json_int_set "$ROUND_OPEN" round 1
|
|
56
60
|
KEPT_ROUND=1
|
|
57
61
|
else
|
|
58
|
-
rm -f "$MAIN" "$
|
|
62
|
+
rm -f "$MAIN" "$DEVLOG_DIR"/.round-current.md "$DEVLOG_DIR"/.round-current@*.md || exit 1
|
|
59
63
|
KEPT_ROUND=0
|
|
60
64
|
fi
|
|
61
65
|
|
|
62
|
-
rm -f "$DEVLOG_DIR/.span-open
|
|
63
|
-
|
|
66
|
+
rm -f "$DEVLOG_DIR"/.span-open "$DEVLOG_DIR"/.span-open@* \
|
|
67
|
+
"$DEVLOG_DIR"/.interrupted "$DEVLOG_DIR"/.interrupted@* \
|
|
68
|
+
"$DEVLOG_DIR"/.awaiting-reply "$DEVLOG_DIR"/.awaiting-reply@*
|
|
69
|
+
rm -f "$HANDOFF_STEM.md" "$HANDOFF_STEM"@*.md
|
|
64
70
|
if [ -f "$DEVLOG_DIR/.checkpoint-state" ]; then
|
|
65
71
|
json_int_set "$DEVLOG_DIR/.checkpoint-state" rounds_since_checkpoint 0
|
|
66
72
|
json_int_set "$DEVLOG_DIR/.checkpoint-state" checkpoint_marker_count 0
|
|
@@ -35,10 +35,6 @@ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
|
|
|
35
35
|
PROJECT_DIR="${DEVLOG_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
36
36
|
devlog_resolve_paths "$PROJECT_DIR"
|
|
37
37
|
ENABLED_FLAG="$DEVLOG_DIR/.enabled"
|
|
38
|
-
ROUND_OPEN="$DEVLOG_DIR/.round-open"
|
|
39
|
-
INTERRUPTED_FLAG="$DEVLOG_DIR/.interrupted"
|
|
40
|
-
ROUND_CURRENT="$DEVLOG_DIR/.round-current.md"
|
|
41
|
-
TURN_MARKER="$DEVLOG_DIR/.turn-start"
|
|
42
38
|
|
|
43
39
|
drop_markers() {
|
|
44
40
|
rm -f "$ROUND_OPEN" "$INTERRUPTED_FLAG" 2>/dev/null || true
|