description:Decision-tree questioning until no doubt remains. Checks QUESTION_CONTENTS in the CONTENTS wiki repo and QUESTION_{HASH} in the QUESTION wiki repo first, both keyed by the full 40-character hash-id output, and never re-asks answered questions. Every option states its impact scope; after each answer, save the record back to the wiki. Use whenever a jsc skill needs user input; skip recording when no {owner}/{repo} is known; not for skills whose answer is already on record.
description:Decision-tree questioning until no doubt remains. Checks wiki QUESTION_CONTENTS and QUESTION_{HASH} first and never re-asks answered questions. Every option states its impact scope; after each answer, save the record back to the wiki. Use whenever a jsc skill needs user input; skip recording when no {owner}/{repo} is known; not for skills whose answer is already on record.
---
---
# ask — decision-tree questioning
# ask — decision-tree questioning
@@ -19,9 +19,9 @@ Inside one work session this skill is the only writer of `QUESTION_{HASH}` and `
## Before asking
## Before asking
1. Confirm the repository name `{owner}/{repo}` of the current work. Done when `{owner}/{repo}` is known, or when it is settled that none exists — then skip steps 2 to 4, ask directly, and do NOT record.
1. Confirm the repository name `{owner}/{repo}` of the current work. Done when `{owner}/{repo}` is known, or when it is settled that none exists — then skip steps 2 to 4, ask directly, and do NOT record.
2. Compute `HASH` by running `jsc-gitea/tools/hash-id {owner}/{repo}` (the shared wiki hash rule — see `jsc-meta/references/guidelines.md` for the algorithm). Exit 0: take the printed `HASH` exactly as printed — the full 40-character uppercase hexadecimal SHA-1, never truncated and carrying no `H` prefix. Exit 1 (no SHA-1 helper on this machine): stop the run and report that `sha1sum` or `shasum` must be installed first; never hand-compute the hash and never guess a page name. Any other non-zero exit: stop the same way and report the exit code with the command's stderr. Done when the full 40-character `HASH` is known, or the run stopped with that report.
2. Compute `HASH` by running `jsc-gitea/tools/hash-id {owner}/{repo}` (the shared wiki hash rule — see `jsc-meta/references/guidelines.md` for the algorithm). Exit 0: take the printed 8-character `HASH`. Exit 1 (no SHA-1 helper on this machine): stop the run and report that `sha1sum` or `shasum` must be installed first; never hand-compute the hash and never guess a page name. Any other non-zero exit: stop the same way and report the exit code with the command's stderr. Done when the 8-character `HASH` is known, or the run stopped with that report.
3. Resolve two wiki repos, because the record page and the directory page no longer share one. The content page `QUESTION_{HASH}` uses`wiki-repo QUESTION` (`JSC_WIKI_REPO_QUESTION`→`JSC_WIKI_REPO`), resolved once per session through `jsc-gitea:wiki`; on exit 3 for that type ask the user for that `{owner}/{repo}`, keep the answer in the session and reuse it for every later call — this one answer cannot come from the record, because the wiki location is the question itself, so asking again each call would loop forever — and close the run by advising the user to set `JSC_WIKI_REPO_QUESTION` (or `JSC_WIKI_REPO`) in the environment, which ends the asking permanently. The directory page `QUESTION_CONTENTS` uses `wiki-repo CONTENTS` (`JSC_WIKI_REPO_CONTENTS` → `JSC_WIKI_REPO` → exit 3, and never a fallback to `JSC_WIKI_REPO_QUESTION`); this one is not asked for, because `jsc-gitea/tools/wiki-contents.sh` reads the environment itself and takes no repo argument, so exit 3 there is reported, not answered. Done when the session holds one `{owner}/{repo}` for `QUESTION`, no later call in this session asked for it again, and the `CONTENTS` repo resolved or its exit 3 was reported.
3. Resolve the `QUESTION` wiki repo once per session through `jsc-gitea:wiki`. When that skill reports exit 3 for`wiki-repo QUESTION` (neither `JSC_WIKI_REPO_QUESTION`nor`JSC_WIKI_REPO` is set), ask the user for that `{owner}/{repo}`, then keep the answer in the session and reuse it for every later call — this one answer cannot come from the record, because the wiki location is the question itself, so asking again each call would loop forever. Close the run by advising the user to set `JSC_WIKI_REPO_QUESTION` (or `JSC_WIKI_REPO`) in the environment, which ends the asking permanently. Done when the session holds one `{owner}/{repo}` for `QUESTION` and no later call in this session asked for it again.
4. Load `QUESTION_CONTENTS`(from the `CONTENTS` repo) and `QUESTION_{HASH}` (from the `QUESTION` repo) per "Session cache". A page reported missing (`wiki-get` exit 4) counts as "no record yet": keep going and ask every question of this round. Any other `jsc-gitea:wiki` failure stops the run with a report of the failing page and the underlying exit code; do not ask on a half-read record, because an answer already on file would be asked again. Never re-ask a question already answered in the record; use the recorded answer directly. When reusing an answer, read the section's recorded intent: reuse it when that intent matches the current situation, and ask again when it differs, instead of forcing the old answer. An answer whose intent covers a similar undecided question in this round answers that one too. Done when every question in this round is marked either answered-from-record with the citing section named, or to-be-asked.
4. Load `QUESTION_CONTENTS`and `QUESTION_{HASH}` per "Session cache". A page reported missing (`wiki-get` exit 4) counts as "no record yet": keep going and ask every question of this round. Any other `jsc-gitea:wiki` failure stops the run with a report of the failing page and the underlying exit code; do not ask on a half-read record, because an answer already on file would be asked again. Never re-ask a question already answered in the record; use the recorded answer directly. When reusing an answer, read the section's recorded intent: reuse it when that intent matches the current situation, and ask again when it differs, instead of forcing the old answer. An answer whose intent covers a similar undecided question in this round answers that one too. Done when every question in this round is marked either answered-from-record with the citing section named, or to-be-asked.
## Questioning rules
## Questioning rules
@@ -34,16 +34,5 @@ Inside one work session this skill is the only writer of `QUESTION_{HASH}` and `
## After asking
## After asking
1. Without a repository name, do not record; stop here. Done when the answers are handed back to the calling skill and no wiki page was touched.
1. Without a repository name, do not record; stop here. Done when the answers are handed back to the calling skill and no wiki page was touched.
2. After each Q&A round, hand both wiki writes to one sub agent, content page first and directory page second, so the directory never links a page that failed to write.
2. After each Q&A round, hand both wiki writes to one sub agent. That sub agent MUST write through `jsc-gitea:wiki` — it owns the `JSC_WIKI_REPO_QUESTION` → `JSC_WIKI_REPO` resolution and the tea-token fallback, which a hand-rolled Gitea API call loses. It writes `QUESTION_{HASH}` first, applying `templates/question-record.md`: append this round as a new section, keep every earlier section, and open the section with the user's original intent (why this questioning round happened), which lets a later reader judge why the user chose as they did and whether the answer still applies. It then writes `QUESTION_CONTENTS`, applying `templates/question-contents.md`: read the page back, add the `{owner}/{repo}` row when missing, otherwise set 最後更新 to this run's timestamp, then write the whole page. `QUESTION_CONTENTS` is a directory shared by every repository, so it is never overwritten wholesale and no other repository's row is touched; `QUESTION_{HASH}` belongs to this one repository, which is why appending a section to it is the right shape there. Its read branches by exit code, and only exit 4 creates the directory from the template: exit 0 upserts into the content that came back, while exit 7 (key invalid or no permission) and exit 8 (any other API failure) both mean the old rows are unknown, so the write is abandoned and reported instead — a fresh template over a directory whose rows were never read erases every other repository's row, with no merge and no backup behind it. Content page first, contents page second, so the contents page never links a page that failed to write. Done when the sub agent has reported both writes as succeeded and the main agent has accepted that one report — this single confirmation covers both pages and both templates; do not re-read the pages to prove it.
-`QUESTION_{HASH}` is written through `jsc-gitea:wiki` — it owns the `JSC_WIKI_REPO_QUESTION` → `JSC_WIKI_REPO` resolution and the tea-token fallback, which a hand-rolled Gitea API call loses. Apply `templates/question-record.md`: append this round as a new section, keep every earlier section, and open the section with the user's original intent (why this questioning round happened), which lets a later reader judge why the user chose as they did and whether the answer still applies. `QUESTION_{HASH}` belongs to this one repository, which is why appending a section is the right shape there. Write every link in the section as `[{text}]({url})`, and take each wiki `{url}` from `jsc-gitea/tools/gitea.sh wiki-url` — never assemble a path by hand.
3. On a reported write failure, retry that one page once. Done when the retry succeeded and step 3 of "Session cache" refreshed that page's copy, or — when the retry also failed — the run stops with a report naming the page that stayed unwritten and the exit code behind it, while the answers still go back to the calling skill and the report states plainly that nothing was recorded.
- Verify before writing: hand every link of the new section to `jsc-gitea/tools/link-check.sh` and branch on its exit code. 0: every link answers, so write the section. 1: at least one link is DEAD, so write nothing and report the DEAD lines to the calling skill — a dead link on a record page reads as a real page and nobody finds it again. 2: no URL reached the script, so pass the links again. 3: `GITEA_HOST` is unset, so report that it must be set and run the check again; never write a link that skipped the check. 7: the Gitea key failed, so stop and report the key problem — a failed key makes live pages look dead. A section carrying no link goes straight to the write. Done when the check exited 0 and the section is written, or nothing was written and the report names the failing links or the exit code.
-`QUESTION_CONTENTS` is a list page: one H2 block per repository, the block's fields written one per line as `- {欄位名}:{值}` in the order 存取庫名稱、問詢紀錄、最後更新. It is written by one call to `jsc-gitea/tools/wiki-contents.sh upsert QUESTION 2 QUESTION_{HASH} {block-file} templates/question-contents.md`. `key` is the H2 heading text, which is this repository's record page name `QUESTION_{HASH}` — the script matches the heading text after trimming, so pass it exactly as the block file writes it, with no link, no URL and no affix. The key is the page name and nothing else, because the page name follows from `{owner}/{repo}` alone: renaming the host, pointing `JSC_WIKI_REPO_QUESTION` at another repository, or a change in Gitea's page-name encoding all leave it untouched, so the key still finds the existing block. `key-col` is `2`, and it is not a free choice: it is the 1-based index of the column that held the link to the content page in the legacy markdown table, which for `QUESTION_CONTENTS` is the second column, 問詢紀錄. The script reads it only while converting such a legacy table page, and it takes the H2 heading of each converted block from that column's link. Passing `1` there names the 存取庫名稱 column, whose plain `{owner}/{repo}` text becomes a heading like `## plugins/meta`, which never matches the key `QUESTION_{HASH}`; the existing record is then appended as a new block, the page carries the same repository twice, and the old block can never be updated again. The block file holds this repository's whole H2 block: the `## QUESTION_{HASH}` line, a blank line, then the three field lines. The 存取庫名稱 field keeps the bare `{owner}/{repo}` text, and the 問詢紀錄 field is written as `[QUESTION_{HASH}]({url})`, where `{url}` is the absolute URL printed by `jsc-gitea/tools/gitea.sh wiki-url {question-repo} QUESTION_{HASH}`. Take that URL from the command only; never assemble a path by hand. The two pages sit in different repositories — the directory page in the `CONTENTS` repo, the record page in the `QUESTION` repo — so only an absolute URL crosses from one to the other. Always pass the template argument. The script owns the read-merge-write of that shared directory: it upserts this one block and touches no other repository's block, so do not read the page and rebuild it by hand.
- Branch on `wiki-url`'s exit code before the block is built, because a URL that never arrived leaves that field silently empty and the block still looks written. 0: put the printed URL in the 問詢紀錄 field, verbatim. 4: `QUESTION_{HASH}` is not on the wiki yet, so the record-page write has not landed — write that page again, then ask for the URL once more. 5: the page carries no `html_url`, so report it and never assemble a URL by hand. 7: the key is invalid or has no permission, so stop without retrying. 8: any other API failure, so retry once, then stop. Any other non-zero exit stops the same way. Whenever no URL comes back, write no block at all — an empty or hand-made field is worse than a missing one — stop, report the exit code, and state that this repository's block was not indexed this round.
- Verify before writing: hand that URL, and every other link the block carries, to `jsc-gitea/tools/link-check.sh`, and branch on its exit code. 0: the links answer, so run the upsert. 1: at least one link is DEAD, so write no block and report the DEAD lines; `QUESTION_{HASH}` counts as written and unindexed, and this round's answers still go back to the calling skill. 2: no URL reached the script, so pass the links again. 3: `GITEA_HOST` is unset, so report that it must be set and run the check again; never upsert a block whose link skipped the check. 7: the Gitea key failed, so stop and report the key problem — a failed key makes live pages look dead, and an unchecked block would carry the blame instead. Done when the check exited 0 and the upsert ran, or no block was written and the report names the failing links or the exit code.
- Branch on `wiki-contents.sh`'s exit code, every code its own branch. 0: the block was added or updated, so this round is recorded. 1: the page content could not be built or the write failed, so retry once per step 3 — a page with no block for this repository is not an error, it just means the block is appended. 2: usage error, so stop and report the arguments that were passed — the same call retried fails the same way. A template path that does not exist lands here too, and means the plugin installation is incomplete. 3: no `CONTENTS` repo is configured, so report that `JSC_WIKI_REPO_CONTENTS` (or `JSC_WIKI_REPO`) must be set, note `QUESTION_{HASH}` as written but unindexed, and hand this round's answers back to the calling skill all the same. **Never withhold the answers over this code.**`JSC_WIKI_REPO_CONTENTS` is a `fix=ask` item in `jsc-cli/tools/config-spec.tsv`, so `/jsc-cli:setup` can only learn its value by asking through this skill; an answer dropped here leaves the variable unset, and the unset variable makes the next round drop the answer again. 4: the page does not exist and no template reached the script. The call form above always passes the template as the fifth argument, so this code cannot come out of it — getting it means that argument was dropped, so restore it and run the same call once more. 7: the key is invalid or has no permission, so stop and report without retrying. 8: any other API failure, so retry once per step 3, then stop and report.
- Done when the sub agent has reported both writes as succeeded and the main agent has accepted that one report — this single confirmation covers both pages and both templates; do not re-read the pages to prove it. Exit 2, 3 or 7 from `wiki-contents.sh`, any `wiki-url` failure, and any non-zero `link-check.sh` exit on the directory block, close this step the second way: `QUESTION_{HASH}` counts as written and unindexed, the report names the exit code and the page that stayed unwritten, and this round's answers go back to the calling skill regardless. **The answers of a finished questioning round are never lost because the directory page could not be written.**
3. On a reported write failure, retry that one page once — a `QUESTION_{HASH}` failure, or `wiki-contents.sh` exit 1 or 8. Exit 2, 3 and 7 are not retried, because the same call fails identically until someone fixes the arguments, the environment or the key; they end the recording, not the round. Every one of these paths ends the same way: the answers go back to the calling skill, and the report names the page that stayed unwritten, the exit code behind it, and what was recorded and what was not. Done when the retry succeeded and step 3 of "Session cache" refreshed that page's copy, or — when the retry also failed, or the code was 2, 3 or 7 — the report above has been printed and the answers have been handed back.
4. Record how this run ended. This is the closing step and it runs on every route above, the ones that stopped early included. Run `jsc-hooks/tools/report-status.sh skill-end jsc-ask:ask {status} {exit} "{detail}"`, resolving the script the same sibling-plugin way this skill already resolves `jsc-gitea/tools/hash-id`. The hook that records a skill's start cannot see how it ended — it fires when the skill is loaded, and the work happens in later turns — so a start with no matching end is exactly what an abandoned run looks like, and writing this line is what keeps a finished run from reading as one.
-`{status}` is one of five. `ok`: every question of this round carries an answer, the answers went back to the calling skill, and where `{owner}/{repo}` was known both wiki pages were written. `degraded`: the round finished and part of the recording did not — no `{owner}/{repo}` was known so nothing was recorded at all, or `QUESTION_{HASH}` landed while `QUESTION_CONTENTS` did not (`wiki-contents.sh` exit 2, 3 or 7, any `wiki-url` failure, or a non-zero `link-check.sh` on the directory block). Those stay `degraded` rather than `failed` because the answers still reached the caller, which is this skill's own completion condition. `aborted`: the user stopped the questioning round, so the undecided points were never put to them. `failed`: the run stopped and no answers came back — `hash-id` found no SHA-1 helper, a wiki read failed with anything other than exit 4, or the one retry of a page write failed as well. `blocked` does not arise here, because anything that gates this skill stops it before it ever reaches this step.
-`{exit}` is the exit code of the tool that decided the outcome where one did, and otherwise 0 for `ok` and 1 for every other status. `{detail}` is optional, one line, at most 200 characters: name the page that stayed unwritten, or the tool and the code that stopped the run. Anything longer belongs in the report to the caller, not on this line.
- Reporting never changes the outcome of the round. `report-status.sh` is not on every machine, so a missing file is skipped in silence and nothing else about the run changes; the script swallows its own write failures and always exits 0, so its result is never worth branching on. Done when the call was made, or the script was absent and this step was skipped without a word.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.