diff --git a/skills/learn/SKILL.md b/skills/learn/SKILL.md index d7d4afb..00d426c 100644 --- a/skills/learn/SKILL.md +++ b/skills/learn/SKILL.md @@ -1,6 +1,6 @@ --- name: learn -description: Record a lesson learned after a skill run to wiki LEARN_{HASH} plus LEARN_CONTENTS, or consult past lessons before a skill run. Each entry is one table row with date, skill, CLI, situation, lesson, and next-time approach. HASH is the full 40-character uppercase SHA-1 of {owner}/{repo}; LEARN_{HASH} sits in the LEARN wiki repo while LEARN_CONTENTS sits in the separate CONTENTS repo, so the directory row goes through jsc-gitea/tools/wiki-contents.sh upsert and links the lesson page by its absolute wiki-url. Use when a skill run produced a reusable lesson, or before running a skill to consult past lessons; not for work-time logs (see worklog). +description: Record a lesson learned after a skill run to wiki LEARN_{HASH} plus LEARN_CONTENTS, or consult past lessons before a skill run. Each entry is one table row with date, skill, CLI, situation, lesson, and next-time approach. HASH is the full 40-character uppercase SHA-1 of {owner}/{repo}; LEARN_{HASH} sits in the LEARN wiki repo while LEARN_CONTENTS sits in the separate CONTENTS repo, so the directory entry goes through jsc-gitea/tools/wiki-contents.sh upsert as one H2 block keyed by the page name LEARN_{HASH}, with a bullet per field and the lesson page linked by its absolute wiki-url. Use when a skill run produced a reusable lesson, or before running a skill to consult past lessons; not for work-time logs (see worklog). --- # learn — lessons learned @@ -11,10 +11,11 @@ Close the loop on skill runs: record what a run taught you, consult it before th - Directory page: `LEARN_CONTENTS`. Content page: `LEARN_{HASH}`, one page per repository. - The two pages live in different wikis. `LEARN_{HASH}` goes to `jsc-gitea/tools/gitea.sh wiki-repo LEARN`; `LEARN_CONTENTS` goes to `gitea.sh wiki-repo CONTENTS` (`JSC_WIKI_REPO_CONTENTS`, then `JSC_WIKI_REPO`, then exit 3), which never falls back to the LEARN repo. Exit 3 on either hands the question to `jsc-gitea:wiki`, which owns the resolution order and the wording; exit 2 means the type argument was misspelled, so fix it and rerun. -- Every link this skill writes takes the shape `[{text}]({absolute URL})`. The directory row links the lesson page as `[LEARN_{HASH}]()`, with `` from `gitea.sh wiki-url LEARN_{HASH}` — never assembled by hand, and never the same-wiki `[[...]]` form, which resolves inside one wiki only and dead-links from the directory without reporting an error. `wiki-url` exit 4 means the lesson page is not written yet, so write it first; exit 5 means the page carries no `html_url`, so stop and report it and never assemble the URL by hand; exit 7 or 8 means the token or the API failed, so stop and report that status. +- Every link this skill writes takes the shape `[{text}]({absolute URL})`. The directory block's 教訓紀錄 bullet links the lesson page as `[LEARN_{HASH}]()`, with `` from `gitea.sh wiki-url LEARN_{HASH}` — never assembled by hand, and never the same-wiki `[[...]]` form, which resolves inside one wiki only and dead-links from the directory without reporting an error. `wiki-url` exit 4 means the lesson page is not written yet, so write it first; exit 5 means the page carries no `html_url`, so stop and report it and never assemble the URL by hand; exit 7 or 8 means the token or the API failed, so stop and report that status. - Check every link before it reaches a page: `jsc-gitea/tools/link-check.sh {url}...`. Only exit 0 permits the write. - Compute `{HASH}` from `{owner}/{repo}` with `jsc-gitea/tools/hash-id`. It prints the full 40-character uppercase SHA-1 — no truncation and no prefix rewrite, so never shorten it. Exit 1 means no SHA-1 helper on this machine: stop and report that `sha1sum` or `shasum` has to be installed, and never hand-compute the hash. Exit 2 means the input was empty, so fix the `{owner}/{repo}` parse and rerun. -- All wiki reads and writes go through `jsc-gitea:wiki`, except the `LEARN_CONTENTS` row, which goes through `jsc-gitea/tools/wiki-contents.sh`. +- All wiki reads and writes go through `jsc-gitea:wiki`, except the `LEARN_CONTENTS` block, which goes through `jsc-gitea/tools/wiki-contents.sh`. +- The two pages carry different shapes. `LEARN_{HASH}` stays a markdown table, one row per lesson. `LEARN_CONTENTS` is a list page: `# 教訓目錄`, a `>` preamble, then one H2 block per repository whose heading is that repository's lesson page name. ## Mode: record @@ -46,37 +47,37 @@ Run after a skill run that produced a reusable lesson. | Exit | Do | | --- | --- | - | 0 | Every link answered. Write the row | + | 0 | Every link answered. Write the row and the directory block | | 1 | At least one link is DEAD. Write nothing and report the DEAD lines to the caller | | 2 | No URL reached the script. Pass the URLs and rerun | | 3 | The list holds a Gitea URL but `GITEA_HOST` is unset. Set it and rerun; never skip the check | | 7 | The Gitea token was rejected (HTTP 401/403). Stop and report the token problem. A rejected token makes live pages look missing, and one batch judged on that answer wipes out links that still work | - - Update `LEARN_CONTENTS` in the same pass, and let `jsc-gitea/tools/wiki-contents.sh` do the row work — never hand-edit the directory page. Build one file holding the single row from `templates/learn-contents.md` (the repository name, the absolute link from `gitea.sh wiki-url LEARN_{HASH}`, and the update time), then run: + - Update `LEARN_CONTENTS` in the same pass, and let `jsc-gitea/tools/wiki-contents.sh` do the block work — never hand-edit the directory page. Build one file holding the single H2 block from `templates/learn-contents.md` — the `## LEARN_{HASH}` heading, a blank line, then one `- {欄位名}:{值}` bullet per field in the template's order: the repository name, the absolute link from `gitea.sh wiki-url LEARN_{HASH}`, and the update time. Then run: - `jsc-gitea/tools/wiki-contents.sh upsert LEARN 1 "{owner}/{repo}" {row file} templates/learn-contents.md` + `jsc-gitea/tools/wiki-contents.sh upsert LEARN 2 "LEARN_{HASH}" {block file} templates/learn-contents.md` - Column 1 is the repository name, so the key stays the same string across every run and one repository keeps exactly one row. The script reads the whole page, replaces the matching row and appends when none matches, so every row that belongs to another repository stays as it was. + The key is the H2 heading itself, the content page name `LEARN_{HASH}`, so it stays the same string across every run and one repository keeps exactly one block. The 教訓紀錄 bullet carries that same page as a link, and that link is what must not be the key: it embeds the host and the encoded page name, so one change of `GITEA_HOST`, one move of `JSC_WIKI_REPO_LEARN`, or one difference in how Gitea encodes the page name makes the match fail and appends a second block for the same repository. The page name depends only on `{owner}/{repo}`. The `2` is ``, which the script uses only while the directory page is still an old markdown table — it names the column whose cell text (the link text alone) becomes the H2 heading, and a page already in list shape ignores it. The script reads the whole page, replaces the matching block and appends when none matches, so every block that belongs to another repository stays as it was. | Exit | Do | | --- | --- | - | 0 | The row is in place. It prints `updated` or `added` plus the page it wrote | - | 1 | The write failed, or the directory page holds no markdown table. Report `LEARN_CONTENTS` as not written, together with the row content | + | 0 | The block is in place. It prints `updated` or `added` plus the page it wrote | + | 1 | The page content could not be assembled, or the write failed. Report `LEARN_CONTENTS` as not written, together with the block content. A page with no matching block is not this code: the block is appended instead | | 2 | An argument was rejected. Fix the argument and rerun this bullet; nothing was written | | 3 | No CONTENTS wiki repo is configured. Report `JSC_WIKI_REPO_CONTENTS` and `JSC_WIKI_REPO` as the two variables to set. The lesson itself is on `LEARN_{HASH}` and stays there | | 4 | The directory page is absent and the script received no template. The call above always passes one, so this code means `templates/learn-contents.md` is not at that path — a partial plugin install, not a missing argument. Stop and report the path; rerunning the same command changes nothing. Reinstall the plugin, confirm the file is there, then rerun. A mistyped template path exits 2, not 4 | - | 7 | The token is invalid or lacks permission, so the other repositories' rows are unknown. Stop and report the token problem; the script wrote nothing, which is what keeps those rows alive | + | 7 | The token is invalid or lacks permission, so the other repositories' blocks are unknown. Stop and report the token problem; the script wrote nothing, which is what keeps those blocks alive | | 8 | Some other API failure. Stop and report that status and retry only after the API is back | - - A failed write on either page: retry once. Still failing, stop and report which page was not written (`LEARN_{HASH}` or `LEARN_CONTENTS`) together with the row content that was meant to go in, so the lesson is not lost. Never report a page as written when it was not. - - Done when the sub agent reports both pages written, the main agent has confirmed the row exists on `LEARN_{HASH}`, and the rows that were there before are still there. + - A failed write on either page: retry once. Still failing, stop and report which page was not written (`LEARN_{HASH}` or `LEARN_CONTENTS`) together with the row or block content that was meant to go in, so the lesson is not lost. Never report a page as written when it was not. + - Done when the sub agent reports both pages written, the main agent has confirmed the row exists on `LEARN_{HASH}` and the block on `LEARN_CONTENTS`, and every row and block that was there before is still there. ## Mode: consult Run before a skill run, to apply past lessons. 1. Resolve `{owner}/{repo}` and compute `{HASH}` as in record mode. Done when `LEARN_{HASH}` is known. -2. Read `LEARN_CONTENTS` from the CONTENTS repo and the repo's `LEARN_{HASH}` from the LEARN repo via `jsc-gitea:wiki` — two `wiki-repo` calls, two different wikis — and branch on the exit code `jsc-gitea/tools/gitea.sh` returned. Only 4 means the page is absent; every other failure code means the read never happened, so an empty page must never be inferred from it. The rows on `LEARN_CONTENTS` point at lesson pages by absolute URL, and rows for other repositories point outside the LEARN repo resolved here, so follow each link as given rather than treating the page name as local. +2. Read `LEARN_CONTENTS` from the CONTENTS repo and the repo's `LEARN_{HASH}` from the LEARN repo via `jsc-gitea:wiki` — two `wiki-repo` calls, two different wikis — and branch on the exit code `jsc-gitea/tools/gitea.sh` returned. Only 4 means the page is absent; every other failure code means the read never happened, so an empty page must never be inferred from it. The blocks on `LEARN_CONTENTS` point at lesson pages by absolute URL, and blocks for other repositories point outside the LEARN repo resolved here, so follow each link as given rather than treating the H2 heading as a page in this wiki. | Exit | Do | | --- | --- | @@ -98,9 +99,9 @@ Resolve that path the way this file already resolves `jsc-gitea/tools/hash-id` a | status | This skill's case | | --- | --- | -| `ok` | record — both pages carry the new row and every row that was there before is still there. consult — both pages were read, or a page was reported absent under exit 4, and the matched 下次做法 lines reached the caller | +| `ok` | record — `LEARN_{HASH}` carries the new row and `LEARN_CONTENTS` this repository's block, and everything that was there before is still there. consult — both pages were read, or a page was reported absent under exit 4, and the matched 下次做法 lines reached the caller | | `blocked` | The run never reached a page: `hash-id` exit 1 (no SHA-1 helper), `wiki-repo LEARN` or `wiki-repo CONTENTS` exit 3 (no wiki repo configured for that page type), or `link-check.sh` exit 3 (`GITEA_HOST` unset) | -| `degraded` | record — the lesson row is on `LEARN_{HASH}` but `wiki-contents.sh upsert` did not land the directory row (exit 1, 3, 7 or 8), so the lesson is on the wiki and nothing points at it. consult — one of the two pages was read and the other stopped the run, so the caller got part of the lesson set and knows it | +| `degraded` | record — the lesson row is on `LEARN_{HASH}` but `wiki-contents.sh upsert` did not land the directory block (exit 1, 3, 7 or 8), so the lesson is on the wiki and nothing points at it. consult — one of the two pages was read and the other stopped the run, so the caller got part of the lesson set and knows it | | `failed` | An API call answered with something unexpected after the work started: `link-check.sh` exit 1 on a DEAD link, a `wiki-get` that came back 7 or 8, or a page write that failed its retry as well. Nothing reached `LEARN_{HASH}` | | `aborted` | The user stopped the run, or record mode was called with nothing reusable to record, so the six facts never formed an entry and no write was attempted | diff --git a/templates/learn-contents.md b/templates/learn-contents.md index cfc5026..1848df5 100644 --- a/templates/learn-contents.md +++ b/templates/learn-contents.md @@ -1,13 +1,16 @@ # 教訓目錄 -> 由 `jsc-log:learn` 維護。這是教訓目錄頁 `LEARN_CONTENTS`。每個存取庫一列;`LEARN_{HASH}` 的 `{HASH}` 依共用 wiki hash 規則產生:取 `{owner}/{repo}` 的完整 SHA-1 四十碼,a-f 轉大寫,不截短、不加前綴。 +> 由 `jsc-log:learn` 維護。這是教訓目錄頁 `LEARN_CONTENTS`。每個存取庫一個區塊;`LEARN_{HASH}` 的 `{HASH}` 依共用 wiki hash 規則產生:取 `{owner}/{repo}` 的完整 SHA-1 四十碼,a-f 轉大寫,不截短、不加前綴。 > 本頁落在 `JSC_WIKI_REPO_CONTENTS` 解出的專用存取庫,教訓頁 `LEARN_{HASH}` 落在 `JSC_WIKI_REPO_LEARN` 的存取庫,兩者分屬不同 wiki。 -> 連結寫法:教訓紀錄那一欄寫成 `[{頁名}]({絕對網址})`,網址取自 `jsc-gitea/tools/gitea.sh wiki-url`,不用 `[[...]]`。兩頁分屬不同存取庫,`[[...]]` 連不過去,畫面上還看不出壞掉。 +> 連結寫法:教訓紀錄那一條寫成 `[{頁名}]({絕對網址})`,網址取自 `jsc-gitea/tools/gitea.sh wiki-url`,不用 `[[...]]`。兩頁分屬不同存取庫,`[[...]]` 連不過去,畫面上還看不出壞掉。 > 連結驗證:每個要寫進本頁的連結先交給 `jsc-gitea/tools/link-check.sh`,退出碼 0 才寫入。出現 DEAD 就不寫,把連不到的那幾筆回報給呼叫端。 -> 寫入語意:一列代表一個存取庫。一律用 `jsc-gitea/tools/wiki-contents.sh upsert LEARN 1 {owner}/{repo} {列檔} {本範本}` 單列整頁寫回——它讀整頁、找得到該存取庫既有的那一列就換掉那一列,找不到才附加。 -> 鍵取第 1 欄的存取庫名稱,不取第 2 欄的連結。存取庫名稱每一輪都一樣,連結會隨主機名與頁名編碼變動。 -> 禁止整頁覆蓋,也不得改動別人的列。 +> 寫入語意:一個區塊代表一個存取庫。一律用 `jsc-gitea/tools/wiki-contents.sh upsert LEARN 2 LEARN_{HASH} {區塊檔} {本範本}` 單一區塊整頁寫回——它讀整頁、找得到該存取庫既有的那個區塊就換掉,找不到才附加到頁尾。 +> 參數語意:`` 的 `2` 只在舊頁還是表格時用得到,代表轉檔時取第 2 欄格子的文字當 H2 標題,格子是 `[文字](網址)` 就只取文字;頁面已經是條列格式就完全忽略它。`` 是 H2 標題文字,也就是內容頁頁名 `LEARN_{HASH}`。第四個參數是區塊檔,內容是 `## {key}` 那一行加空行加各條欄位,不是一列表格。 +> 鍵是 H2 標題的頁名,不是連結。頁名只由 `{owner}/{repo}` 決定,換主機名、改存取庫、頁名編碼有差都動不到它;連結帶著主機名與存取庫名,一變就比不到鍵,同一個存取庫會多出第二個區塊。 +> 禁止整頁覆蓋,也不得改動別人的區塊。 -| 存取庫名稱 | 教訓紀錄 | 最後更新時間 | -| --- | --- | --- | -| {owner}/{repo} | [LEARN_{HASH}]({教訓頁絕對網址}) | {yyyy-MM-dd HH:mm} | +## LEARN_{HASH} + +- 存取庫名稱:{owner}/{repo} +- 教訓紀錄:[LEARN_{HASH}]({教訓頁絕對網址}) +- 最後更新時間:{yyyy-MM-dd HH:mm}