feat: add 'read_in' skill and update related documentation

This commit is contained in:
Erik van der Boom 2026-04-07 23:26:25 +02:00
parent b9f4956787
commit ce6b5b3d42
10 changed files with 122 additions and 79 deletions

View file

@ -44,7 +44,7 @@ annotations: { destructiveHint: true } // writes, creates, or modifies files
```
No annotation = mcpb submission rejection. Both annotations on one tool = also wrong.
| Tool behaviour | Annotation |
| Tool behavior | Annotation |
|---|---|
| list, get, read, search, status checks | `readOnlyHint: true` |
| write, append, overwrite, format, commit, create | `destructiveHint: true` |
@ -68,33 +68,7 @@ When adding a tool, touch **all four** of these: missing any breaks one surface.
## MCP tools reference
All tools take a `book` argument (string name from `--book` config). The VS Code surface has no `book` arg — it uses the open workspace root.
| Tool | Annotation | Description |
|---|---|---|
| `list_books` | readOnly | List configured books |
| `identify_book` | readOnly | Match a working directory to a book |
| `health` | readOnly | Server/index/embedding status |
| `init_workspace` | destructive | Create or update .bindery/settings.json + translations.json |
| `index_build` | destructive | Build/rebuild BM25 search index |
| `index_status` | readOnly | Index chunk count and build time |
| `get_text` | readOnly | Read file by relative path, optional line range |
| `get_chapter` | readOnly | Full chapter by number + language |
| `get_overview` | readOnly | Chapter structure (acts, chapters, titles) |
| `get_notes` | readOnly | Notes/ and Details_*.md, filterable |
| `search` | readOnly | BM25 full-text search with ranked snippets |
| `retrieve_context` | readOnly | Semantic passage retrieval |
| `format` | destructive | Apply typography formatting to file/folder |
| `get_review_text` | destructive | Git diff with optional autoStage |
| `git_snapshot` | destructive | Git commit of story/notes/arc changes |
| `get_translation` | readOnly | List glossary entries for a language, or look up a specific term (forgiving) |
| `add_translation` | destructive | Add/update a cross-language glossary entry (agent reference, not auto-applied at export) |
| `get_dialect` | readOnly | List dialect substitution rules, or look up a specific word |
| `add_dialect` | destructive | Add/update a dialect substitution rule (auto-applied at export, e.g. US→UK) |
| `add_language` | destructive | Add language to settings.json and scaffold story folder with stubs |
| `memory_list` | readOnly | List Notes/Memories/ files with line counts |
| `memory_append` | destructive | Append dated session entry to a memory file |
| `memory_compact` | destructive | Overwrite memory file with summary (backs up original) |
see `mcp-ts/src/index.ts` for implementation details and input schemas and `mcpb/readme.md` for user-facing descriptions.
---
@ -137,7 +111,7 @@ All tools take a `book` argument (string name from `--book` config). The VS Code
| `cursor` | `.cursor/rules` |
| `agents` | `AGENTS.md` |
Skills: `review`, `brainstorm`, `memory`, `translate`, `status`, `continuity`, `read_aloud`.
Skills: `review`, `brainstorm`, `memory`, `translate`, `status`, `continuity`, `read_aloud`, `read-in`.
The **memory skill** uses `memory_list``memory_append``memory_compact`. Do not fall back to `get_text` + Edit tool for memory writes.

View file

@ -24,10 +24,11 @@ export type SkillTemplate =
| 'translate'
| 'status'
| 'continuity'
| 'read_aloud';
| 'read_aloud'
| 'read_in';
export const ALL_SKILLS: SkillTemplate[] = [
'review', 'brainstorm', 'memory', 'translate', 'status', 'continuity', 'read_aloud',
'review', 'brainstorm', 'memory', 'translate', 'status', 'continuity', 'read_aloud', 'read_in',
];
export interface AiSetupOptions {
@ -47,7 +48,7 @@ export interface AiSetupResult {
* existing users should regenerate their AI files.
* Must be kept in sync with AI_SETUP_VERSION in vscode-ext/src/ai-setup.ts.
*/
export const AI_SETUP_VERSION = 5;
export const AI_SETUP_VERSION = 6;
// ─── Settings types ───────────────────────────────────────────────────────────

View file

@ -379,7 +379,7 @@ server.registerTool('setup_ai_files', {
inputSchema: {
book: bookSchema,
targets: z.array(z.string()).optional().describe('Which files to generate: claude, copilot, cursor, agents. Default: all.'),
skills: z.array(z.string()).optional().describe('Which Claude skills to generate: review, brainstorm, memory, translate, status, continuity, read_aloud. Default: all.'),
skills: z.array(z.string()).optional().describe('Which Claude skills to generate: review, brainstorm, memory, translate, status, continuity, read_aloud, read_in. Default: all.'),
overwrite: z.boolean().optional().describe('Overwrite existing files? Default false (skip existing).'),
},
annotations: { destructiveHint: true },
@ -418,7 +418,7 @@ server.registerTool('memory_compact', {
description:
'Overwrite a memory file with a compacted version supplied by the model. ' +
'The original is backed up to .bindery/memories/archive/ before overwriting. ' +
'Use this when a memory file has grown too large and needs to be summarised.',
'Use this when a memory file has grown too large and needs to be summarized.',
inputSchema: {
book: bookSchema,
file: z.string().describe('Filename within .bindery/memories/, e.g. global.md'),

View file

@ -47,6 +47,7 @@ export function renderTemplate(name: string, ctx: TemplateContext): string {
case 'status': return skillStatus(ctx);
case 'continuity': return skillContinuity(ctx);
case 'read_aloud': return skillReadAloud(ctx);
case 'read_in': return skillReadIn(ctx);
default: return `Unknown template: ${name}`;
}
}
@ -79,18 +80,17 @@ function claudeMd(ctx: TemplateContext): string {
lines.push(
'## Start of session',
`1. Read COWORK.md (if present) for current focus and context.`,
`2. Read ${memoriesFolder}/global.md for cross-chapter decisions.`,
`3. If working on a specific chapter, read ${memoriesFolder}/chXX.md if it exists.`,
'1. Use /read-in at the start of a session to load context and get your bearings.',
'2. If the skill is not available, read at least COWORK.md (if present) for current focus and context.',
'',
'## Memory system',
'1. When the user ask or otherwise indicates the end of a session: use /memory to save decisions.',
`2. When switching to another chapter read ${memoriesFolder}/chXX.md if it exists. for that chapter`,
'1. When concluding a discussion, or after you give a meaningful (preserve worthy) response: use /memory to store it.',
'2. Also when the user ask or otherwise indicates the end of a session: use /memory to save decisions.',
'',
'## Repo layout',
'```',
`${arcFolder}/ ← story arc files (Overall.md, Act_I_*.md, Act_II_*.md, Act_III_*.md)`,
`${notesFolder}/ ← story bible (characters, world)`,
`${arcFolder}/ ← story arc files`,
`${notesFolder}/ ← story notes (characters, world)`,
`${storyFolder}/`,
...ctx.languages.map(l => ` ${l.folderName}/ ← ${l.code} chapters (one .md per chapter)`),
'```',
@ -116,6 +116,7 @@ function claudeMd(ctx: TemplateContext): string {
'| `/status` | Book progress snapshot |',
'| `/continuity` | Check a chapter for consistency errors |',
'| `/read-aloud` | Test how a passage reads when spoken |',
'| `/read-in` | Load context and get your bearings at the start of a session |',
'',
'## MCP server (bindery-mcp)',
'',
@ -127,6 +128,8 @@ function claudeMd(ctx: TemplateContext): string {
'| `list_books` | List all configured book names |',
'| `identify_book` | Match a working directory to a book name |',
'| `health` | Server status: settings, index, embedding backend |',
'| `init_workspace` | Create or update `.bindery/settings.json` and `translations.json` |',
'| `setup_ai_files` | Generate AI instruction files (CLAUDE.md, copilot-instructions.md, AGENTS.md) and skill templates |',
'| `index_build` | Build or rebuild the full-text search index |',
'| `index_status` | Show index chunk count and build time |',
'| `get_text` | Read any file by relative path, with optional line range |',
@ -146,6 +149,8 @@ function claudeMd(ctx: TemplateContext): string {
'| `memory_list` | List `Notes/Memories/` files with line counts |',
'| `memory_append` | Append a dated session entry to a memory file |',
'| `memory_compact` | Overwrite a memory file with a summary (backs up original) |',
'| `chapter_status_get` | Read the chapter progress tracker — entries grouped by status |',
'| `chapter_status_update` | Upsert chapter progress entries (send only changed chapters) |',
);
return lines.filter(l => l !== '\n').join('\n') + '\n';
}
@ -172,7 +177,7 @@ function copilotMd(ctx: TemplateContext): string {
'',
'## Writing guidelines',
'- HTML comments `<!-- -->` in chapter files are writer notes — treat as context only.',
'- Quotation marks and dashes are managed by the Bindery VS Code extension. Do not normalise them.',
'- Quotation marks and dashes are managed by the Bindery VS Code extension. Do not normalize them.',
'- Check `Notes/Details_Translation_notes.md` before using or translating world-specific terms.',
);
if (ctx.audience) {
@ -199,7 +204,7 @@ function cursorRules(ctx: TemplateContext): string {
'',
'## Rules',
'- HTML comments `<!-- -->` in chapter files are writer notes. Treat as context, not story content.',
'- Do not normalise quotation marks or dashes — these are managed by the Bindery extension.',
'- Do not normalize quotation marks or dashes — these are managed by the Bindery extension.',
'- Do not rewrite prose unless explicitly asked. Suggest edits only.',
];
if (ctx.audience) {
@ -224,9 +229,9 @@ function agentsMd(ctx: TemplateContext): string {
`3. Check \`${notesFolder}/Details_Translation_notes.md\` before using or translating world-specific terms.`,
'',
'## Story files',
`- Chapter files are \`.md\` files in \`${storyFolder}/\`, organised in act subfolders.`,
`- Chapter files are \`.md\` files in \`${storyFolder}/\`, organized in act subfolders.`,
'- HTML comments `<!-- -->` are writer notes — treat as context only, not prose.',
'- Quotation marks and em-dashes are managed by the Bindery extension. Do not normalise them.',
'- Quotation marks and em-dashes are managed by the Bindery extension. Do not normalize them.',
'',
'## Writing guidelines',
'- Do not rewrite paragraphs unless explicitly asked. Suggest edits only.',
@ -396,14 +401,14 @@ Use \`memory_append\` to write to the right file:
Arguments:
- \`file\`: just the filename, e.g. \`global.md\` or \`ch10.md\`
- \`title\`: short topic label, e.g. \`"Daeven introduction — character decisions"\`
- \`title\`: short topic label, e.g. \`"Elder introduction — character decisions"\`
- \`content\`: the decisions to record, one per line
The tool stamps the current date. Do not add a date to the content.
### 4. Compact if needed
If \`memory_list\` shows a file exceeding ~150 lines, offer to compact it:
- Summarise the existing content into a concise replacement
- Summarize the existing content into a concise replacement
- Call \`memory_compact(file, compacted_content)\` — original is backed up automatically
### 5. Snapshot
@ -595,3 +600,58 @@ Brief overall impression (2-3 sentences) after the table.
- Suggestions are gentle ("consider", not "must change")
`;
}
function skillReadIn(ctx: TemplateContext): string {
const { memoriesFolder } = ctx;
return `---
name: Read-in
description: Load project context at the start of a session memory, progress tracker, and chapter notes. Use for /read-in, "get your bearings", "what were we doing", or at the start of any working session.
---
# Skill: /read-in
Load context and get your bearings before starting work.
## Trigger
User says \`/read-in\`, "get your bearings", "what were we working on", or at the start of a session.
## Tools
Use these Bindery MCP tools:
- \`memory_list\` — discover which memory files exist (\`global.md\`, \`chXX.md\` files)
- \`get_text(identifier)\` — read COWORK.md and memory files
- \`chapter_status_get(book)\` — read the structured progress tracker
- \`get_overview(language)\` — list all acts and chapters (only if tracker is empty or sparse)
## Steps
### 1. Check for current focus
Use \`get_text("COWORK.md")\` to read the current focus file (ignore if missing).
### 2. Load global memory
Use \`memory_list\` to discover available memory files, then \`get_text("${memoriesFolder}/global.md")\` to load cross-chapter decisions.
### 3. Read the progress tracker
Use \`chapter_status_get\` to read current chapter progress. If it is empty or has fewer than 3 entries, also call \`get_overview\` for the full chapter listing.
### 4. Determine working chapter
If COWORK.md names a chapter, use that.
Otherwise if the tracker has a single \`in-progress\` chapter, use that.
Otherwise **ask the user**: "Which chapter do you want to work on?"
### 5. Load chapter memory
Once the chapter is known (e.g. chapter 10), check \`memory_list\` output for a matching file (\`ch10.md\`). If it exists, read it with \`get_text("${memoriesFolder}/ch10.md")\`.
### 6. Summarize
Output a short orientation (3-6 lines):
- Which chapter / scene we're in
- Status from the tracker (draft / in-progress / needs-review)
- Key open decisions from global memory relevant to this chapter
- Any chapter-specific notes from the chapter memory file
- End with a phrase like: "Ready — what would you like to work on?"
## Rules
- Do not load *all* chapter memories only the one being worked on
- Keep the summary brief; this is orientation, not a full status report
- Do not suggest work or ask multiple questions one question at most (which chapter?)
`;
}

View file

@ -10,7 +10,9 @@ Works with any Markdown book project structured with the Bindery VS Code extensi
- **Full-text search** — BM25 ranked search across all story and notes files
- **Context retrieval** — "where did X happen" queries with ranked passages
- **Translation management** — list, look up, add, and update translation and dialect substitution rules
- **Session memory** — append, list, and compact persistent session notes in `Notes/Memories/`
- **Session memory** — append, list, and compact persistent cross session notes in `.bindery/Memories/`
- **Workspace setup** — create or update `.bindery/settings.json` and scaffold AI instruction files
- **Chapter status tracking** — record and query per-chapter progress (draft, in-progress, done, needs-review)
- **Typography formatting** — curly quotes, em-dashes, ellipses
- **Version snapshots** — git-based save points after writing sessions
- **Review diffs** — structured git diff of uncommitted changes
@ -29,7 +31,7 @@ To install manually without using published Claude Connectors
| Setting | Required | Description |
|---------|----------|-------------|
| Books | Yes | Semicolon-separated `Name=path` pairs pointing to book projects |
| Ollama URL | No | URL for local Ollama instance (enables semantic reranking) |
| Ollama URL | No | URL for Ollama instance (enables semantic reranking, see [https://docs.ollama.com/quickstart](https://docs.ollama.com/quickstart)) |
**Books** example: `MyBook=C:\Users\Me\MyBook;MyNovel=D:\Writing\MyNovel`
@ -94,7 +96,7 @@ date formatting needed.
> "The global memory file is getting long — please compact it"
Claude reads the current content, summarises it, then calls `memory_compact`
Claude reads the current content, summarizes it, then calls `memory_compact`
with the compacted text. The original is automatically backed up to
`Notes/Memories/archive/global_YYYY-MM-DD.md` before the file is overwritten.
@ -123,6 +125,8 @@ issue type, location, and the reference that contradicts it.
| `list_books` | List all configured book names |
| `identify_book` | Match a working directory to a book name |
| `health` | Server status: settings, index, embedding backend |
| `init_workspace` | Create or update `.bindery/settings.json` and `translations.json` with smart defaults |
| `setup_ai_files` | Generate AI instruction files (CLAUDE.md, copilot-instructions.md, .cursor/rules, AGENTS.md) and Claude skill templates |
| `index_build` | Build or rebuild the full-text search index |
| `index_status` | Show index chunk count and build time |
| `get_text` | Read any file by relative path, with optional line range |
@ -142,6 +146,8 @@ issue type, location, and the reference that contradicts it.
| `memory_list` | List memory files with line counts |
| `memory_append` | Append a dated session entry to a memory file |
| `memory_compact` | Overwrite a memory file with a summary (backs up original) |
| `chapter_status_get` | Read the chapter progress tracker — returns entries grouped by status (done, in-progress, draft, planned, needs-review) |
| `chapter_status_update` | Upsert chapter progress entries — send only changed chapters; unmentioned entries are preserved |
## Privacy Policy

View file

@ -45,4 +45,4 @@ src/
## When suggesting changes
- Prefer editing the smallest surface area possible.
- Check that all command IDs match the `bindery.*` namespace throughout `package.json` AND `extension.ts`.
- Test mentally: does the new behaviour respect the config priority order?
- Test mentally: does the new behavior respect the config priority order?

View file

@ -50,7 +50,7 @@ Supported commands:
- `Bindery: Find Probable US→UK Words`
- `Bindery: Add Substitution Rule`
- `Bindery: Open translations.json`
- `Bindery: Initialise Workspace`
- `Bindery: Initialize Workspace`
- `Bindery: Setup AI Assistant Files`
- `Bindery: Register MCP Server`
@ -138,7 +138,7 @@ Add to `.bindery/settings.json` (or `bindery.languages` in VS Code settings):
## Requirements
- **VS Code** 1.85+
- **Git** (recommended) — needed for version tracking and review features (`get_review_text`, `git_snapshot`). Auto-initialised during workspace setup. [Install](https://git-scm.com)
- **Git** (recommended) — needed for version tracking and review features (`get_review_text`, `git_snapshot`). Auto-initialized during workspace setup. [Install](https://git-scm.com)
- **Pandoc** (needed for DOCX/EPUB/PDF export) — [Install](https://pandoc.org/installing.html)
- **LibreOffice** (needed for PDF export) — used to convert the intermediate DOCX to PDF
- Linux/WSL: `sudo apt install libreoffice`

View file

@ -63,7 +63,7 @@
"bindery.storyFolder": {
"type": "string",
"default": "Story",
"description": "Fallback story folder name if .bindery/settings.json is not present. Run 'Bindery: Initialise Workspace' to create the settings file."
"description": "Fallback story folder name if .bindery/settings.json is not present. Run 'Bindery: Initialize Workspace' to create the settings file."
},
"bindery.mergedOutputDir": {
"type": "string",
@ -121,7 +121,7 @@
"commands": [
{
"command": "bindery.init",
"title": "Initialise Workspace",
"title": "Initialize Workspace",
"category": "Bindery"
},
{
@ -414,7 +414,7 @@
"type": "object",
"properties": {
"targets": { "type": "array", "items": { "type": "string" }, "description": "Files to generate: claude, copilot, cursor, agents. Default: all." },
"skills": { "type": "array", "items": { "type": "string" }, "description": "Claude skills to include: review, brainstorm, memory, translate, status, continuity, read_aloud. Default: all." },
"skills": { "type": "array", "items": { "type": "string" }, "description": "Claude skills to include: review, brainstorm, memory, translate, status, continuity, read_aloud, read_in. Default: all." },
"overwrite": { "type": "boolean", "description": "Overwrite existing files? Default false." }
}
}

View file

@ -47,10 +47,11 @@ export type SkillTemplate =
| 'translate'
| 'status'
| 'continuity'
| 'read_aloud';
| 'read_aloud'
| 'read_in';
export const ALL_SKILLS: SkillTemplate[] = [
'review', 'brainstorm', 'memory', 'translate', 'status', 'continuity', 'read_aloud',
'review', 'brainstorm', 'memory', 'translate', 'status', 'continuity', 'read_aloud', 'read_in',
];
/**
@ -58,7 +59,7 @@ export const ALL_SKILLS: SkillTemplate[] = [
* significantly enough that existing users should regenerate their AI files.
* Written to .bindery/ai-version.json after each successful setupAiFiles() run.
*/
export const AI_SETUP_VERSION = 5;
export const AI_SETUP_VERSION = 6;
// ─── Entry point ──────────────────────────────────────────────────────────────

View file

@ -98,7 +98,7 @@ function getEffectiveConfig(wsSettings: WorkspaceSettings | null): EffectiveConf
/** True if filePath is inside <root>/<storyFolder>/. */
function isInsideStoryFolder(filePath: string, root: string, storyFolder: string): boolean {
// Normalise separators so Windows paths compare correctly
// Normalize separators so Windows paths compare correctly
const norm = (p: string) => p.replace(/\\/g, '/');
const story = norm(path.join(root, storyFolder));
const file = norm(filePath);
@ -231,7 +231,7 @@ async function initWorkspaceCommand() {
if (fs.existsSync(settingsPath)) {
const choice = await vscode.window.showQuickPick(
[
{ label: 'Re-initialise', description: 'Overwrites settings.json (translations.json is kept)', value: true as const },
{ label: 'Re-initialize', description: 'Overwrites settings.json (translations.json is kept)', value: true as const },
{ label: 'Cancel', value: false as const },
],
{ placeHolder: '.bindery/settings.json already exists' }
@ -240,28 +240,28 @@ async function initWorkspaceCommand() {
}
const title = await vscode.window.showInputBox({
title: 'Bindery: Initialise (1/4)',
title: 'Bindery: Initialize (1/4)',
prompt: 'Book title',
placeHolder: 'e.g. The Hollow Road',
});
if (title === undefined) { return; }
const author = await vscode.window.showInputBox({
title: 'Bindery: Initialise (2/4)',
title: 'Bindery: Initialize (2/4)',
prompt: 'Author name',
placeHolder: 'e.g. Jane Smith',
});
if (author === undefined) { return; }
const storyFolder = await vscode.window.showInputBox({
title: 'Bindery: Initialise (3/4)',
title: 'Bindery: Initialize (3/4)',
prompt: 'Story folder name (relative to workspace root)',
value: 'Story',
});
if (!storyFolder) { return; }
const audience = await vscode.window.showInputBox({
title: 'Bindery: Initialise (4/5)',
title: 'Bindery: Initialize (4/5)',
prompt: 'Target audience (used for AI review feedback)',
placeHolder: 'e.g. 12+, adults, 8-10',
});
@ -272,7 +272,7 @@ async function initWorkspaceCommand() {
{ label: 'No', value: false as const },
{ label: 'Yes', value: true as const },
],
{ title: 'Bindery: Initialise (5/5)', placeHolder: 'Auto-apply typography on save (Story folder only)?' }
{ title: 'Bindery: Initialize (5/5)', placeHolder: 'Auto-apply typography on save (Story folder only)?' }
);
if (!formatOption) { return; }
@ -334,7 +334,7 @@ async function initWorkspaceCommand() {
execSync('git add .bindery/ .gitignore', { cwd: root, encoding: 'utf-8', stdio: 'pipe' });
execSync('git commit -m "Bindery: initial setup"', { cwd: root, encoding: 'utf-8', stdio: 'pipe' });
gitNote = ' Git repository initialised.';
gitNote = ' Git repository initialized.';
} catch {
vscode.window.showWarningMessage(
'Git is recommended for version tracking and review features. ' +
@ -347,7 +347,7 @@ async function initWorkspaceCommand() {
? ` Detected: ${detectedLangs.map(l => l.code).join(', ')}.`
: '';
const action = await vscode.window.showInformationMessage(
`Bindery workspace initialised.${langNote}${gitNote}`,
`Bindery workspace initialized.${langNote}${gitNote}`,
'Open settings.json',
'Open translations.json'
);
@ -439,7 +439,7 @@ async function addDialectCommand() {
}
sourceLang ??= getDefaultLanguage(wsSettings);
if (!sourceLang) { vscode.window.showErrorMessage('No language configured. Run Bindery: Initialise Workspace first.'); return; }
if (!sourceLang) { vscode.window.showErrorMessage('No language configured. Run Bindery: Initialize Workspace first.'); return; }
const dialects = getDialectsForLanguage(wsSettings, sourceLang.code);
if (dialects.length === 0) {
@ -515,7 +515,7 @@ async function addTranslationCommand() {
l => !l.isDefault && (l.code !== sourceLang?.code)
);
if (!sourceLang) { vscode.window.showErrorMessage('No default language configured. Run Bindery: Initialise Workspace first.'); return; }
if (!sourceLang) { vscode.window.showErrorMessage('No default language configured. Run Bindery: Initialize Workspace first.'); return; }
if (targetLangs.length === 0) {
vscode.window.showErrorMessage('No target languages configured. Use Bindery: Add Language to add one.');
return;
@ -807,13 +807,14 @@ const AI_TARGET_ITEMS: Array<{ label: string; detail: string; value: AiTarget }>
];
const SKILL_ITEMS: Array<{ label: string; description: string; value: SkillTemplate }> = [
{ label: '/review', description: 'Chapter review — language, arc, age-appropriateness', value: 'review' },
{ label: '/brainstorm', description: 'Generate plot / character / scene ideas', value: 'brainstorm' },
{ label: '/memory', description: 'Update memory files and compact if needed', value: 'memory' },
{ label: '/translate', description: 'Assisted chapter translation', value: 'translate' },
{ label: '/status', description: 'Book progress snapshot', value: 'status' },
{ label: '/continuity', description: 'Cross-check chapter for consistency errors', value: 'continuity' },
{ label: '/read-aloud', description: 'Reading-aloud test for a chapter or passage', value: 'read_aloud' },
{ label: '/review', description: 'Chapter review — language, arc, age-appropriateness', value: 'review' },
{ label: '/brainstorm', description: 'Generate plot / character / scene ideas', value: 'brainstorm' },
{ label: '/memory', description: 'Update memory files and compact if needed', value: 'memory' },
{ label: '/translate', description: 'Assisted chapter translation', value: 'translate' },
{ label: '/status', description: 'Book progress snapshot', value: 'status' },
{ label: '/continuity', description: 'Cross-check chapter for consistency errors', value: 'continuity' },
{ label: '/read-aloud', description: 'Reading-aloud test for a chapter or passage', value: 'read_aloud' },
{ label: '/read-in', description: 'Load context and get your bearings at the start of a session', value: 'read_in' },
];
async function setupAiCommand() {
@ -823,8 +824,8 @@ async function setupAiCommand() {
const wsSettings = readWorkspaceSettings(root);
if (!wsSettings) {
const init = await vscode.window.showWarningMessage(
'No .bindery/settings.json found. Run "Bindery: Initialise Workspace" first.',
'Initialise now'
'No .bindery/settings.json found. Run "Bindery: Initialize Workspace" first.',
'Initialize now'
);
if (init) { await initWorkspaceCommand(); }
return;