CLAUDE.md@viber/scripts · git:20261021.24cf1e2 · 2026-10-21 · sha256 e26a2608bdc7788c
CLAUDE.md@viber/scripts git:20261021.24cf1e2B
Immutable. This exact content never changes and is served at /api/v1/blob/e26a2608bdc7788c.
# viber/scripts - the plugin-level bundled scripts This directory holds the scripts more than one viber skill or agent calls: the config parser, the run lifecycle, the switch fragment selector, the skill part printer and the GitHub and browser wrappers. A script of one skill lives under that skill's `scripts/`, the hook scripts under `hooks/scripts/`. ## Terms - Run scripts: the four bash scripts of the run lifecycle, `plan-path.sh`, `plan-index.sh`, `commit-task.sh` and `archive-run.sh`, all `set -euo pipefail`, each refusal a distinct exit code. - GitHub wrappers: the `#!/bin/sh` scripts `issue-facts.sh`, `issue-templates.sh`, `issue-create.sh`, `post-comment.sh`, `pr-facts.sh`, `pr-create.sh`, `pr-threads.sh`, `pr-reply.sh` and `qa-comment.sh`. Each prints its fixed `KEY=value` block only after `gh` succeeded and its output parsed (self-verifying), else one `ERROR <script>: ...` line on stderr; the bash scripts report on stderr as `error: ...`. ## Relationships - Callers: `config.sh` is preloaded by `implementor`, `planner`, `e2e` and run by `skills/extension/scripts/extension.sh` and `hooks/scripts/plan-gate.sh`; `run-clock.sh` by `implementor` alone; `switch-text.sh` by `implementor`, `planner`, `intent`, `fixer`, `triage` and `prototype`; `skill-part.sh` by `implementor` alone (its `close` part); `plan-path.sh` by `planner`, `implementor`, `intent` and `fixer` (`--start`/`--checkout`) and `e2e` (no argument, the latest run); `plan-index.sh` by `planner` (validate), `implementor` (`--split`), `task-reviewer` (`--extra`, through its `scope` line) and `closeout`; `commit-task.sh` by `implementor` (`--drop` included), `e2e` (`--e2e`) and `closeout` (`--outside`); `archive-run.sh` by the `closeout` agent alone; `red-check.sh` by `implementor` alone (`fragments/red-check.true.md`). - GitHub callers: `issue-facts.sh` by `intent`, `fixer`, `triage`, `prototype`; `issue-templates.sh` and `issue-create.sh` by `issue-create`, `intent`, `fixer`; `post-comment.sh` by `intent`, `triage`, `prototype`; `pr-facts.sh` and `pr-create.sh` by `pr-create`; `pr-threads.sh` and `pr-reply.sh` by `pr-feedback`; `qa-comment.sh` by `pr-create` and the `implementor` close (`qa.true.md`); `open-page.sh` by `setup`, `help`, `prototype`; `check-playwright.sh` by `e2e`. - Sibling calls: `plan-path.sh` sources `run-branch.sh`; `run-branch.sh` runs `config.sh --branching` and `sh issue-facts.sh`; `red-check.sh` runs `plan-index.sh` and `config.sh --red-check`. ## Contracts - `run-branch.sh` is a library: sourced by `plan-path.sh`, never invoked, mode 100644 in the index, no `set` line of its own. Its functions return 6 with the reason on stderr and HEAD, index and tree untouched; `plan-path.sh` turns that into its own exit 6 (run branch could not be set). - Exit codes of the run scripts are part of their contract, each documented in the header: `plan-path.sh` 2 argv, 3 no plan, 4 bad `--into` target, 5 copy failed, 6 run branch, 7 unusable `attachments:` map (checked on every `--land` before the branch step); `plan-index.sh` 2 unusable plan or argv (an unknown `--extra` id included), 3 no task blocks, 4 broken task contract; `commit-task.sh` 2 bad arguments (a task commit for a skipped task), 3 no such task, 4 no change (or a bad `--landed`), 5 staging or commit failed with `status.md` restored; `archive-run.sh` 2 argv outside `docs/<runs>/` or with no run key, 3 destination exists, 4 run unfinished, 5 a git step failed. - `archive-run.sh` takes the run directory as `plan-path.sh` printed its `path:` line minus `/plan.md`, and refuses any path outside `docs/<runs>/`, an absolute one outside the repository or one with a `..` segment. An absolute path inside the repository is folded into its relative form by `cwd_relative()`, copied verbatim into `archive-run.sh`, `plan-index.sh` (the plan) and `commit-task.sh` (the plan, a `--from`/`--first-of` file): the run scripts share no library, so a fix to it changes all three. - `commit-task.sh` exports `GIT_LITERAL_PATHSPECS=1`: every path it stages is one exact path, never a pattern (bracketed App Router segments). Every `--with` path and extras line is first folded to its repo-relative form (`named_path()`: a relative path's backslash read as `/`, `./` cut), as is a plan `Files:` entry when claimants are compared, so ownership and the `.temp/` refusal see one spelling; `--defer` calls `cwd_relative()` alone, its path byte for byte; the fix-number and `--repair`/`--chore`/... file lists are not. It refuses any `.temp/` path, and derives the `work/` trail paths it stages from the task id or round, never from the caller. A named path whose staged mode differs from HEAD gets that exec bit on disk before `git add -u` (`sync_tree_modes`), so every form commits an index mode change under either `core.fileMode`. - Extras files: the coder's `<run-dir>/work/<id>-extra.md` and the reviewer's `<id>-extra-review.md`, one path per line (blank lines ignored; a carriage return, surrounding whitespace and a leading `./` stripped; a relative path's backslash read as `/`; an absolute path inside the repository made relative). `plan-index.sh --extra <id>` reads only the coder's, validating the plan as `--split` does, and prints `extra:` (minus a repeat, a `.temp/` path, a path the task's own `Files` lists and one a task not yet done lists) and one `recheck:` per done task owning an extra path; `--split` removes both files of every task not done before printing the index. A plain task commit stages the paths of both files as if on `--with` (same ownership warnings; a path another task's extras file lists is that task's claim, like its `Files:`: refused until it is done), plus the two files and `<id>-options.md`; `--landed` and a fix number ignore them. - `plan-index.sh` read-after (validate only, skipped under `--split` and on a plain call with `status.md` beside the plan, a landed run): exit 4 when a task's `Verification` (the part after ` -> ` included) or `DoD` names, as a whole path token, a file a lower-numbered task lists with no dependency path to it; a file the reader lists itself is skipped. - `commit-task.sh --drop <plan> <path>...` deletes only an untracked, unignored file outside the run directory that no task's `Files` and no extras file lists; any other path is kept with a `warning: kept <path> - <reason>` stderr line and the call goes on, exit 0 (exit 2 with no path or no plan). It commits nothing and leaves the index and `status.md` alone, so a kept path reaches the final summary as `left uncommitted`. - `commit-task.sh --rule <subject> --from <ruling-file>` and `--decide <id> --from <ruling-file>` read the arbiter's ruling file, which must lie under `<run-dir>/work/` with its `RULING:`, `WHY:` and `COST:` lines non-empty (else nothing is recorded and the file stays); `--decide` records `auto: <ruling>`, or with `--first-of <options-file>` the first option of the file's latest `DECIDE:` line. Any form taking a plan stages `work/ruling-*.md` with the register. - `skill-part.sh <skill dir> <part>` prints `<skill dir>/parts/<part>.md`, running only a ```` ```! ```` block whose single body line is the exact `switch-text.sh` call shape (header) and replacing it, fences included, by that call's output; any other block prints as plain text. A fragment's output is appended as `switch-text.sh` printed it, never expanded twice; the placeholders of every other line are expanded here. - `config.sh`'s `--branching` report is read by `run-branch.sh` and `pr-facts.sh` only, its `--red-check` report by `red-check.sh` only; every other reader takes the default block. A report line added or renamed changes those readers. - `red-check.sh "<plan>" "<id>"` prints one `red-check:` line (`FAIL-AS-EXPECTED <log>`, `PASSED-WITHOUT-CHANGE <files>`, `UNRUNNABLE <reason>`) with exit 0, exit 2 on bad arguments or plan. Its worktree lies in the system temp directory. A linked directory (`node_modules`) is a real directory of one link per entry, an `@scope` directory likewise, never one link to the whole; an entry linking into a workspace package of the repository points at the worktree's own copy, so the red run loads HEAD's package code. Each directory holding links is listed in `red-check.owner` before it is made; the trap and the next run's recovery unlink every link entry of a listed directory first, then `git worktree remove --force` and `git worktree prune`, so the forced remove never reaches the main tree through a link. A control-run `<word>: command not found` for a word other than the first is reported as a mangled command. The `verify:`/`recheck:` command of `plan-index.sh` has one pair of wrapping backticks removed. ## Commands - Each script's test is `tests/viber/<basename>.test.ts`, integration tier (CI only). `run-branch.sh` has no file of its own: `tests/viber/plan-path.test.ts` covers it through `--branch`, `--start`, `--checkout` and `--land`. ## Change together - The `Covers:` token grammar (`covnums`) and the `;` cut of a `DoD` line outside backtick spans (`dodcut`) each live in two copies in `plan-index.sh`, validate and split: one edit changes both. ## Traps - `skill-part.sh` is invoked bare by `implementor/SKILL.md`, so its index mode must stay 100755: the portability exec-bit sweep fails on 100644, and `core.fileMode` is false on some machines, so `git update-index --chmod=+x` is the only place the bit holds. - The GitHub wrappers are `#!/bin/sh` and must stay POSIX: CI runs them under every POSIX shell present, and the portability sweep flags bash-only syntax in them. - A failed GitHub call is never retried by its caller: `post-comment.sh` exits 1 when whether the comment landed is unknown, and `pr-create.sh` exits 1 after the push may already have happened (its ERROR line names the pushed branch); `pr-reply.sh` exits 1 when a reply may or may not have landed; the caller reports. - The portability sweep reads the awk block of `pr-threads.sh` as shell: it flags `function NAME` and `((` there, so the block defines no function (a sentinel `T` line closes the last thread) and the `--jq` filter avoids `((`. - `issue-create.sh` never removes a created issue when applying its type or its `--parent` attach fails: the type failure is reported as `TYPE=dropped` (benign: types not enabled, 403, 404) or `TYPE=error`, the attach failure as `PARENT=error` with `PARENT_ERROR=`, always with exit 0. - `plan-index.sh` counts only `AC<n>` tokens of `Covers:`; `#<n>` and a bare `<n>` cover nothing (exit 4). ## Sections - Read `CLAUDE.github.md` before editing `qa-comment.sh`, `pr-threads.sh`, `pr-reply.sh`, `issue-facts.sh` or `post-comment.sh`.