Commit Graph
11 Commits
Author SHA1 Message Date
jiantw83andClaude Opus 5 03ce382220 refactor(issue-body): 工作包的歸屬判準收成一個函式
wp-extract 與 wp-list 都在問「這顆工作包掛在哪顆需求底下」。規則寫兩份,
某天只會有一邊被改到,而分岔的樣子是「清單裡看得到、抽取卻說不是」。
順手把測試裡兩種取段落的寫法統一,並刪掉沒有人傳過的參數。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 18:19:33 +08:00
jiantw83andClaude Opus 5 c1ab712afd feat(議題解析): 換掉一個段落的內容,標題與其餘段落一字不動
整併留言裡的決策時用它。不整份重寫的理由跟 upsertLineInSection 一樣,只是代價更大:
重寫會把別人在其他段落的編輯一起蓋掉,而議題的編輯紀錄沒有人會去比對。

三件事照著同檔既有的規矩做:圍欄裡的假標題不算段落;同名標題出現不只一次時交回 ambiguous
而不賭第一個(蓋掉的是一整段,猜錯的代價比 tickLine 更高);換行沿用 body 原本的那一種,
CRLF 的 body 裡混進 LF 會讓抽取契約交出的 raw 對不上原文,之後就勾不動那幾行。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 09:19:08 +00:00
jiantw83andClaude Opus 5 9582553c41 feat(議題解析): 勾選 checkbox 的精確替換,並統一清單項的文法
tickLine 把指定那一行的方框換成已勾,其餘一字不動。四件事決定它會不會靜靜改壞議題:

- **跳過圍欄。** 這是 issue-body.js 全檔的前提,而勾選是本檔唯一會寫回議題的路徑。
  工作包模板的架構圖就是一塊 fenced mermaid,裡面出現減號開頭的行是常態,
  把它當成待辦勾下去,改壞的是一張圖。
- **限定段落。** 待辦與整體驗收常有一模一樣的一句話,不限定就會回報「分不出來」,
  而使用者其實講得很清楚。理由與 upsertLineInSection 相同:弄錯的代價是靜靜改壞內容。
- **整行比對,認不出就交回 ambiguous。** 巢狀待辦底下常有一樣的驗收,賭第一個會讓
  進度條指著錯的那一項,而沒有人會去比對編輯紀錄。
- **[ ]、[x]、[X] 指的是同一行。** [X] 是合法的 GFM,Gitea 也渲染成已勾;只認小寫的話,
  中斷後重跑會硬失敗,錯誤訊息還會誣指「議題被改過」。

清單項的文法收斂成一份 LIST_ITEM,parseChecklistItem 與 tickLine 共用。先前兩端各寫一份,
鬆緊不一致:`- [ ]甲` 抽得出來卻勾不動,正本那句「一律用 wp-extract 給的 raw」就成了
做不到的指示。沒有方框的項目交回 no-checkbox,不再謊報「已經勾過」。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 07:39:43 +00:00
jiantw83andClaude Opus 5 fc30df15f2 feat(工時報表): 以 report.js 產出週/月/年工時報表
期間固定以週五當錨點:一週為週一至週日,跨月那一週依該週週五所屬月份歸屬,
一筆工時因此只會落在一個月裡,不會被前後兩個月各算一次。

工時取自 /user/times——它永遠只回傳自己的工時,不必有 issue manager 權限,
repo 的篩選因此在本地做。估算讀的是議題「關聯」段落裡的那一行,不是 Gitea 的
time_estimate 欄位:該欄位的 API 寫不進去,議題上唯一可信的估算就是那一行;
內嵌的議題沒帶 body 時補查一次議題,否則估算會整欄靜靜變成 null。

總計的落差只拿有估算的議題的實際去比。拿全部實際去比只有部分議題的估算,
會讓沒估算的工時全部變成「超出估算」,落差就永遠是灌水的正數。

labelledNumber 放進 issue-body:body 的解析正本在那裡,格式改一次不該動兩個模組。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 06:50:34 +00:00
jiantw83andClaude Opus 5 98861cecbd feat(議題解析): 解析巢狀待辦、多欄表格與關聯裡的議題編號
工作包議題比需求議題多三種結構,抽取契約(#9)要靠它們:

- checklistInSection 收 body 而不收切好的段落。它要交出的 `raw` 是下游勾選 checkbox
  時做精確字串替換的依據,那一行必須逐字等於 body 裡的原樣,連縮排與行尾的 \r 都不能
  動;段落切分會修掉前後空白,給不出這種保證。兩種畸形寫法都不丟內容:巢狀超過一層攤
  進所在待辦的驗收,還沒有上層待辦就先出現的縮排項目升格成待辦。
- tableRows 保留全部欄位,tableSection 改寫成它的兩欄版。介面契約是四欄,先前那一支
  只留兩欄。短的資料列補空字串——正本明講「不產出對外介面就寫一列『無』」,那一列不該
  與「沒有這一段」混為一談。
- referencedIndex 從關聯段落讀出 `需求議題:#N`。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 06:30:23 +00:00
jiantw83andClaude Opus 5 3977523eb3 fix(議題解析): CRLF 的 body 不再讓清單靜靜變成空的
瀏覽器送出 textarea 一律用 CRLF,議題只要在 Gitea 網頁上被編輯過,body 逐行切開後
每一行行尾就掛著 \r。JS 的 . 不吃 \r,`(.*)$` 因此整行比不中——listSection 會把
目標、非目標、驗收標準這些段落一律回成空陣列,而且不報錯,下游拿到的是「這一段沒寫」
而不是「解析失敗」。

改用 [\s\S] 比對行尾,text 本來就有 trim 會把 \r 修掉。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 06:30:21 +00:00
jiantw83andClaude Opus 5 e494bd534e fix(議題解析): upsertLineInSection 限定在目標段落內
三個實際重現過的污染情境:

- 圍欄裡的 `## 關聯` 被當成真標題,估算插進圍欄後面。本檔的共同前提是「圍欄裡的
  東西不是內容」,這支卻自己用 indexOf 找標題,繞過了那個判斷。
- `## 關聯度說明` 被 indexOf 當成 `## 關聯` 命中,改到別人的段落。
- 「這一行是否已存在」用整份 body 比對,於是別的段落剛好有 `估算人天:` 時被改掉,
  真正的關聯段落反而一直拿不到值。

改成沿用同檔的 eachLine 走行、標題要完全相同、既有那一行只在段落範圍內找。
弄錯的代價是靜靜改壞別人的內容,所以三道判斷都收緊。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 06:06:09 +00:00
jiantw83andClaude Opus 5 45bfd99d80 feat(issue-update): 掛 Milestone、寫截止日、記人天估算
三件事經同一個 PATCH 送出,因為排時程時它們幾乎總是一起改,分開發等於多兩次往返。

Milestone 只認既有的:指到不存在的就中止並列出可選項目,本工具不建立 Milestone。

人天估算只寫進 body 的人類可讀一行。Gitea 1.27 的 API 沒有任何請求定義接受
time_estimate——它只出現在 Issue 的回應裡——所以議題的估算欄位無法由 API 寫入。
新增的 upsertLineInSection 負責就地更新那一行:重跑改估算不會累積成兩行,值沒變
就不把 body 塞進 PATCH,免得在議題上留下一筆沒有內容的編輯紀錄。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 06:06:05 +00:00
jiantw83andClaude Opus 5 7b54d566e2 docs(議題解析): 標明 tableSection 只處理兩欄
工作包的介面契約是四欄(介面/產出者/消費者/形狀),直接沿用這一支會無聲
丟掉第三、四欄。把限制寫在函式註解上,讓接手 wp-extract 的人一眼看到,而不是
自己踩一次才發現。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 05:43:25 +00:00
jiantw83andClaude Opus 5 a5f28ec2c8 fix(議題解析): 圍欄與表格的邊界,五個會污染下游的解析缺陷
code review 逐項驗出來的,全部可重現:

- `~~~` 圍欄完全沒被認出來,裡面的井字號會被當成段落標題。
- 段落內的圍欄不影響清單解析,於是程式碼範例裡的減號變成假的驗收標準。
  這是最嚴重的一個——輸出多出一條沒有人寫過的標準。
- 表格欄位裡逸脫的直線 `\|` 會把欄位切斷,內容整段消失。
- 同一段落裡若出現第二條分隔列,它會變成一筆 {term:'---'} 的假名詞。
- 圍欄開了沒關時,其後內容的歸屬沒有明確定義。

改法是把「圍欄裡的東西不是內容」這件事收斂到 eachLine 處理一次,段落切分、
清單、表格三者都靠它,而不是各自寫一份半套的判斷。圍欄需同種標記才算關閉;
沒關就到結尾時,其後內容一律算在圍欄內,這與 markdown 的實際渲染一致。

巢狀清單改為明確攤平並寫進註解:需求議題的模板沒有巢狀,真的出現時寧可多帶
一項,也不要無聲吃掉內容。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 05:00:28 +00:00
jiantw83andClaude Opus 5 0bac5ee186 feat(議題解析): 把議題 body 的 markdown 解析抽成純函式
段落切分、列表、兩欄表格三種解析,需求議題與工作包議題共用同一套,
所以獨立成一支不碰網路也不碰檔案系統的模組,而不是塞進 lib。

段落切分會追蹤圍欄狀態:mermaid 或程式碼區塊裡的井字號不得被當成標題,
否則流程圖一畫,後面的段落就全被切碎。

缺段落回傳空值而非報錯——缺段落是模板的正常變體,不是解析失敗。
名詞表以分隔列為界,之後才是資料列,避免把表頭當成一筆名詞。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 05:00:26 +00:00