Repo State - xsyetopz/claudetto GitHub Wiki
This page describes the repostate slice of the core plugin claudetto.
It is for a user who wants to know why Claude asks before an edit of CHANGELOG.md or before a package install, and for a contributor who edits the slice.
Three failures repeat in long sessions:
- Claude states the version, the branch, or the release state from memory, and the state is wrong.
- Claude adds a line to
[Unreleased]for a version that has no tag yet, so the line goes to the wrong release. - Claude installs a package with a name that it made up, and the registry has no such package.
The slice reads the facts and asks before the risky call. It makes no model call.
A classic.SessionStart hook gives Claude one context text.
The text holds the output of git describe --tags --always, the branch, the version in the manifests, and whether the tag of that version exists.
The manifests are package.json and .claude-plugin/plugin.json.
The tag names that the check tries are 1.2.3, v1.2.3, and <name>--v1.2.3.
A folder with no git gives no text.
A project with no manifest gives the git state and says that the manifests give no version.
The text is a fact that the hook read, never a fact from memory (D56 in Engine Facts).
A tool.check hook asks before an Edit, a MultiEdit, or a Write of CHANGELOG.md that changes the [Unreleased] section, when the version in the manifest has no tag.
The hook parses the Markdown structure.
A heading in a code block is no heading, and the section ends at the next heading of level 1 or 2.
The hook applies the edit to the text of the file and compares the section before and after.
So an edit of another section gets no ask.
The reason names the version and the manifest that holds it.
When the version has a tag, the release is out, and the hook asks nothing.
A tool.check hook asks before a bun, npm, pnpm, or yarn command that adds a package.
The add words are add and a for bun, install, i, and add for npm, add, install, and i for pnpm, and add for yarn.
src/kernel/shell.ts parses the command, so a chain, a wrapper, and a quoted text are right.
A spec that is a path, a URL, or a user/repo form is no registry name and gets no check.
The hook checks each name in this order:
- The lockfile or
package.jsonholds the name as a whole name. Then the package is known, and the hook makes no request. - The registry page of the name answers with
404or410. Then the hook asks, and the reason names the missing package.
The request has a timeout of REGISTRY_TIMEOUT_MS (4 seconds).
When the registry cannot be reached, answers late, or answers with a status that says nothing, the hook does not ask.
It writes a notice for the user with $.ui.log, and the model does not read the notice.
A turn.complete hook compares the model of the response (usage.model) with the model that the session requested ($.session.model()).
When both are Claude ids that name different models, the hook sets the text of $.ui.status to a mark that names both models.
A date suffix in an id is no difference.
When a later response comes from the requested model, the hook clears the mark.
A turn of a subagent has its own model, so it sets no mark.
The status-line command of Claude Code gets no served model in its input, so the mark goes through $.ui.status.
The bounds are in slices/repostate/limits.ts: the timeout of git, the timeout of the registry, the registry URL, the largest file, the lockfiles, and the largest count of packages for one command.
No hook makes a model call.
The session start runs up to four git commands.
A package that no lockfile holds costs one request to the registry.
- Guards: the hooks that ask or deny before a call.
- Read Gates: the gates for a rejected call and a second read.
- Status Line: the status line of the plugin.
- Engine Facts: D56.
- Session Facts: D62.
- Architecture: the slices of the core plugin.