evdboom_Bindery/vscode-ext/package.json
2026-04-16 23:46:35 +02:00

1035 lines
32 KiB
JSON

{
"name": "bindery",
"displayName": "Bindery",
"description": "Markdown book authoring tools: typography formatting (curly quotes, em-dashes, ellipses), multi-language chapter export (DOCX, EPUB, PDF), and dialect conversion.",
"version": "0.0.0",
"publisher": "option-a",
"repository": {
"type": "git",
"url": "https://github.com/evdboom/bindery"
},
"engines": {
"vscode": "^1.116.0"
},
"categories": [
"Formatters",
"Other"
],
"keywords": [
"markdown",
"book",
"writing",
"author",
"typography",
"epub",
"docx",
"merge",
"export",
"dialect"
],
"activationEvents": [
"onStartupFinished",
"onLanguage:markdown"
],
"main": "./out/extension.js",
"icon": "icon.png",
"contributes": {
"configuration": {
"title": "Bindery",
"properties": {
"bindery.pandocPath": {
"type": "string",
"default": "pandoc",
"description": "Path to the pandoc executable. Machine-specific — set in user settings, not workspace settings. Install from https://pandoc.org"
},
"bindery.libreOfficePath": {
"type": "string",
"default": "libreoffice",
"description": "Path to the LibreOffice executable for PDF export. Machine-specific — set in user settings. On Windows use the full path to soffice.exe, e.g. C:\\Program Files\\LibreOffice\\program\\soffice.exe"
},
"bindery.generalSubstitutions": {
"type": "array",
"default": [],
"description": "Dialect substitution rules applied across all projects (e.g. US→UK spelling). Applied after the built-in rules but before project-specific rules in .bindery/translations.json. Store in user settings so they follow you to every workspace.",
"items": {
"type": "object",
"required": [
"from",
"to"
],
"properties": {
"from": {
"type": "string",
"description": "Source word (e.g. US English)"
},
"to": {
"type": "string",
"description": "Target word (e.g. UK English)"
}
}
}
},
"bindery.storyFolder": {
"type": "string",
"default": "Story",
"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",
"default": "Merged",
"description": "Fallback output directory for merged files (relative to workspace root). Prefer .bindery/settings.json."
},
"bindery.mergeFilePrefix": {
"type": "string",
"default": "Book",
"description": "Fallback prefix for merged output filenames, e.g. 'Book' → Book_EN_Merged.md. Prefer .bindery/settings.json."
},
"bindery.author": {
"type": "string",
"default": "",
"description": "Fallback author name for EPUB/DOCX metadata. Prefer .bindery/settings.json."
},
"bindery.bookTitle": {
"type": "string",
"default": "",
"description": "Fallback book title for EPUB/DOCX metadata. Prefer .bindery/settings.json, which also supports per-language titles."
},
"bindery.formatOnSave": {
"type": "boolean",
"default": false,
"description": "Fallback: auto-apply typography formatting when saving markdown files inside the story folder. Prefer .bindery/settings.json."
},
"bindery.languages": {
"type": "array",
"default": [
{
"code": "EN",
"folderName": "EN",
"chapterWord": "Chapter",
"actPrefix": "Act",
"prologueLabel": "Prologue",
"epilogueLabel": "Epilogue"
}
],
"description": "Fallback language configurations for merge/export. Prefer .bindery/settings.json.",
"items": {
"type": "object",
"required": [
"code",
"folderName",
"chapterWord",
"actPrefix",
"prologueLabel",
"epilogueLabel"
],
"properties": {
"code": {
"type": "string"
},
"folderName": {
"type": "string"
},
"chapterWord": {
"type": "string"
},
"actPrefix": {
"type": "string"
},
"prologueLabel": {
"type": "string"
},
"epilogueLabel": {
"type": "string"
}
}
}
}
}
},
"commands": [
{
"command": "bindery.init",
"title": "Initialize Workspace",
"category": "Bindery"
},
{
"command": "bindery.setupAI",
"title": "Setup AI Assistant Files",
"category": "Bindery"
},
{
"command": "bindery.formatDocument",
"title": "Format Typography",
"category": "Bindery"
},
{
"command": "bindery.formatFolder",
"title": "Format All Markdown in Folder",
"category": "Bindery"
},
{
"command": "bindery.mergeMarkdown",
"title": "Merge Chapters → Markdown",
"category": "Bindery"
},
{
"command": "bindery.mergeDocx",
"title": "Merge Chapters → DOCX",
"category": "Bindery"
},
{
"command": "bindery.mergeEpub",
"title": "Merge Chapters → EPUB",
"category": "Bindery"
},
{
"command": "bindery.mergePdf",
"title": "Merge Chapters → PDF",
"category": "Bindery"
},
{
"command": "bindery.mergeAll",
"title": "Merge Chapters → All Formats",
"category": "Bindery"
},
{
"command": "bindery.findProbableUsToUkWords",
"title": "Find Probable US→UK Words",
"category": "Bindery"
},
{
"command": "bindery.addDialect",
"title": "Add Dialect Rule",
"category": "Bindery"
},
{
"command": "bindery.addTranslation",
"title": "Add Translation (Glossary)",
"category": "Bindery"
},
{
"command": "bindery.addLanguage",
"title": "Add Language",
"category": "Bindery"
},
{
"command": "bindery.addUkReplacement",
"title": "Add Dialect Rule (UK alias)",
"category": "Bindery"
},
{
"command": "bindery.openTranslations",
"title": "Open translations.json",
"category": "Bindery"
},
{
"command": "bindery.registerMcp",
"title": "Register MCP Server",
"category": "Bindery"
}
],
"languageModelTools": [
{
"name": "bindery_health",
"tags": [
"bindery"
],
"displayName": "Bindery: Health",
"toolReferenceName": "binderyHealth",
"canBeReferencedInPrompt": true,
"modelDescription": "Check Bindery workspace status: settings, index, embedding backend.",
"inputSchema": {
"type": "object",
"properties": {}
}
},
{
"name": "bindery_index_build",
"tags": [
"bindery"
],
"displayName": "Bindery: Build Index",
"toolReferenceName": "binderyIndexBuild",
"canBeReferencedInPrompt": true,
"modelDescription": "Build or rebuild the lexical search index and, when enabled, the semantic embedding index for the book workspace.",
"inputSchema": {
"type": "object",
"properties": {}
}
},
{
"name": "bindery_index_status",
"tags": [
"bindery"
],
"displayName": "Bindery: Index Status",
"toolReferenceName": "binderyIndexStatus",
"canBeReferencedInPrompt": true,
"modelDescription": "Show lexical and semantic index metadata, including stale-status hints.",
"inputSchema": {
"type": "object",
"properties": {}
}
},
{
"name": "bindery_get_text",
"tags": [
"bindery"
],
"displayName": "Bindery: Get Text",
"toolReferenceName": "binderyGetText",
"canBeReferencedInPrompt": true,
"modelDescription": "Read a source file by relative path, optionally restricted to a line range.",
"inputSchema": {
"type": "object",
"properties": {
"identifier": {
"type": "string",
"description": "Relative path from workspace root"
},
"startLine": {
"type": "number"
},
"endLine": {
"type": "number"
}
},
"required": [
"identifier"
]
}
},
{
"name": "bindery_get_chapter",
"tags": [
"bindery"
],
"displayName": "Bindery: Get Chapter",
"toolReferenceName": "binderyGetChapter",
"canBeReferencedInPrompt": true,
"modelDescription": "Fetch the full content of a chapter by number and language code (e.g. EN or NL).",
"inputSchema": {
"type": "object",
"properties": {
"chapterNumber": {
"type": "number"
},
"language": {
"type": "string"
}
},
"required": [
"chapterNumber",
"language"
]
}
},
{
"name": "bindery_get_book_until",
"tags": [
"bindery"
],
"displayName": "Bindery: Get Book Until",
"toolReferenceName": "binderyGetBookUntil",
"canBeReferencedInPrompt": true,
"modelDescription": "Fetch chapters from a start chapter through a target chapter (inclusive), concatenated in reading order.",
"inputSchema": {
"type": "object",
"properties": {
"chapterNumber": {
"type": "number",
"description": "Final chapter number (inclusive, 1-based)"
},
"language": {
"type": "string",
"description": "Language code, e.g. EN or NL"
},
"startChapter": {
"type": "number",
"description": "Starting chapter number (default 1)"
}
},
"required": [
"chapterNumber",
"language"
]
}
},
{
"name": "bindery_get_overview",
"tags": [
"bindery"
],
"displayName": "Bindery: Get Overview",
"toolReferenceName": "binderyGetOverview",
"canBeReferencedInPrompt": true,
"modelDescription": "List the chapter structure (acts, chapters, titles) for one or all languages.",
"inputSchema": {
"type": "object",
"properties": {
"language": {
"type": "string",
"description": "Language code or ALL"
},
"act": {
"type": "number",
"description": "Act number 1, 2 or 3"
}
}
}
},
{
"name": "bindery_get_notes",
"tags": [
"bindery"
],
"displayName": "Bindery: Get Notes",
"toolReferenceName": "binderyGetNotes",
"canBeReferencedInPrompt": true,
"modelDescription": "Read from Notes/, optionally filtered by category or character name.",
"inputSchema": {
"type": "object",
"properties": {
"category": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
},
{
"name": "bindery_search",
"tags": [
"bindery"
],
"displayName": "Bindery: Search",
"toolReferenceName": "binderySearch",
"canBeReferencedInPrompt": true,
"modelDescription": "Search in lexical, semantic-rerank, or full-semantic mode. Semantic modes fall back to lexical results with warnings if prerequisites are unavailable.",
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string"
},
"language": {
"type": "string"
},
"maxResults": {
"type": "number"
},
"mode": {
"type": "string",
"enum": [
"lexical",
"semantic_rerank",
"full_semantic"
]
}
},
"required": [
"query"
]
}
},
{
"name": "bindery_format",
"tags": [
"bindery"
],
"displayName": "Bindery: Format",
"toolReferenceName": "binderyFormat",
"canBeReferencedInPrompt": true,
"modelDescription": "Apply typography formatting (curly quotes, em-dashes, ellipses) to a file or folder.",
"inputSchema": {
"type": "object",
"properties": {
"filePath": {
"type": "string"
},
"dryRun": {
"type": "boolean"
},
"noRecurse": {
"type": "boolean"
}
}
}
},
{
"name": "bindery_get_review_text",
"tags": [
"bindery"
],
"displayName": "Bindery: Review Text",
"toolReferenceName": "binderyGetReviewText",
"canBeReferencedInPrompt": true,
"modelDescription": "Structured git diff of uncommitted changes with context lines. Filter by language (EN, NL, ALL). Set autoStage to true to stage reviewed files so the next call only shows new changes.",
"inputSchema": {
"type": "object",
"properties": {
"language": {
"type": "string",
"description": "Language filter: EN, NL, or ALL (default ALL)"
},
"contextLines": {
"type": "number",
"description": "Context lines around each change (default 3)"
},
"autoStage": {
"type": "boolean",
"description": "Stage reviewed files after producing diff (default false)"
}
}
}
},
{
"name": "bindery_git_snapshot",
"tags": [
"bindery"
],
"displayName": "Bindery: Git Snapshot",
"toolReferenceName": "binderyGitSnapshot",
"canBeReferencedInPrompt": true,
"modelDescription": "Save a snapshot (git commit) of all changes in story, notes, and arc folders. Use after writing sessions or successful reviews.",
"inputSchema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "Snapshot message (default: timestamp)"
}
}
}
},
{
"name": "bindery_add_translation",
"tags": [
"bindery"
],
"displayName": "Bindery: Add Translation",
"toolReferenceName": "binderyAddTranslation",
"canBeReferencedInPrompt": true,
"modelDescription": "Add or update a substitution rule in .bindery/translations.json. Used for dialect conversion (e.g. US→UK spelling).",
"inputSchema": {
"type": "object",
"properties": {
"langKey": {
"type": "string",
"description": "Language key in translations.json, e.g. 'en-gb' or 'nl'"
},
"from": {
"type": "string",
"description": "Source word or phrase"
},
"to": {
"type": "string",
"description": "Target word or phrase"
}
},
"required": [
"langKey",
"from",
"to"
]
}
},
{
"name": "bindery_get_translation",
"tags": [
"bindery"
],
"displayName": "Bindery: Get Translation",
"toolReferenceName": "binderyGetTranslation",
"canBeReferencedInPrompt": true,
"modelDescription": "Look up translation/substitution rules in .bindery/translations.json. Without a word, lists all rules for the language. With a word, does a forgiving case-insensitive lookup including plural and inflected forms.",
"inputSchema": {
"type": "object",
"properties": {
"language": {
"type": "string",
"description": "Language key, label, or code (e.g. 'nl', 'en-gb', 'British English')"
},
"word": {
"type": "string",
"description": "Word or term to look up (omit to list all rules for the language)"
}
},
"required": [
"language"
]
}
},
{
"name": "bindery_setup_ai_files",
"tags": [
"bindery"
],
"displayName": "Bindery: Setup AI Files",
"toolReferenceName": "binderySetupAiFiles",
"canBeReferencedInPrompt": true,
"modelDescription": "Generate AI assistant instruction files (CLAUDE.md, copilot-instructions.md, .cursor/rules, AGENTS.md) and Claude skill templates from .bindery/settings.json. Run init_workspace first. Skips existing files unless overwrite is true.",
"inputSchema": {
"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, read-in, proof-read. Default: all."
},
"overwrite": {
"type": "boolean",
"description": "Overwrite existing files? Default false."
}
}
}
},
{
"name": "bindery_settings_update",
"tags": [
"bindery"
],
"displayName": "Bindery: Settings Update",
"toolReferenceName": "binderySettingsUpdate",
"canBeReferencedInPrompt": true,
"modelDescription": "Merge a partial patch into .bindery/settings.json without replacing unrelated keys.",
"inputSchema": {
"type": "object",
"properties": {
"patch": {
"type": "object",
"description": "Partial settings object to deep-merge into .bindery/settings.json"
}
},
"required": [
"patch"
]
}
},
{
"name": "bindery_init_workspace",
"tags": [
"bindery"
],
"displayName": "Bindery: Init Workspace",
"toolReferenceName": "binderyInitWorkspace",
"canBeReferencedInPrompt": true,
"modelDescription": "Create or update .bindery/settings.json and translations.json. All arguments optional — smart defaults used for any omitted values. Detects language folders automatically. Safe to run on an existing workspace.",
"inputSchema": {
"type": "object",
"properties": {
"bookTitle": {
"type": "string",
"description": "Book title (defaults to folder name)"
},
"author": {
"type": "string"
},
"storyFolder": {
"type": "string",
"description": "Story folder name relative to root (default: Story)"
},
"genre": {
"type": "string"
},
"description": {
"type": "string",
"description": "One-line description for AI instruction files"
},
"targetAudience": {
"type": "string",
"description": "Target audience, e.g. 12+ or adults"
}
}
}
},
{
"name": "bindery_add_dialect",
"tags": [
"bindery"
],
"displayName": "Bindery: Add Dialect Rule",
"toolReferenceName": "binderyAddDialect",
"canBeReferencedInPrompt": true,
"modelDescription": "Add or update a dialect substitution rule in .bindery/translations.json (e.g. EN→en-gb spelling). Source is auto-detected from the active file's language folder.",
"inputSchema": {
"type": "object",
"properties": {
"dialectCode": {
"type": "string",
"description": "Dialect key in translations.json, e.g. 'en-gb'"
},
"from": {
"type": "string",
"description": "Source word (e.g. 'airplane')"
},
"to": {
"type": "string",
"description": "Dialect form (e.g. 'aeroplane')"
}
},
"required": [
"dialectCode",
"from",
"to"
]
}
},
{
"name": "bindery_get_dialect",
"tags": [
"bindery"
],
"displayName": "Bindery: Get Dialect Rules",
"toolReferenceName": "binderyGetDialect",
"canBeReferencedInPrompt": true,
"modelDescription": "List or look up dialect substitution rules from .bindery/translations.json. Without a word, lists all rules for the dialect. With a word, does a forgiving case-insensitive lookup including inflected forms.",
"inputSchema": {
"type": "object",
"properties": {
"dialectCode": {
"type": "string",
"description": "Dialect key, e.g. 'en-gb'"
},
"word": {
"type": "string",
"description": "Word to look up (optional)"
}
},
"required": [
"dialectCode"
]
}
},
{
"name": "bindery_add_language",
"tags": [
"bindery"
],
"displayName": "Bindery: Add Language",
"toolReferenceName": "binderyAddLanguage",
"canBeReferencedInPrompt": true,
"modelDescription": "Add a new main language to settings.json and create its folder structure under Story/ with stub .md files mirroring the default language. Use for manually translated editions (e.g. French, Spanish).",
"inputSchema": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "Language code (e.g. FR, DE, NL)"
},
"folderName": {
"type": "string",
"description": "Folder name under Story/ (default: same as code)"
},
"chapterWord": {
"type": "string",
"description": "Word for 'Chapter' in target language"
},
"actPrefix": {
"type": "string",
"description": "Word for 'Act' in target language"
},
"prologueLabel": {
"type": "string",
"description": "Word for 'Prologue'"
},
"epilogueLabel": {
"type": "string",
"description": "Word for 'Epilogue'"
},
"createStubs": {
"type": "boolean",
"description": "Create stub .md files mirroring source (default true)"
}
},
"required": [
"code"
]
}
},
{
"name": "bindery_memory_list",
"tags": [
"bindery"
],
"displayName": "Bindery: Memory List",
"toolReferenceName": "binderyMemoryList",
"canBeReferencedInPrompt": true,
"modelDescription": "List all session memory files in .bindery/memories/ with their line counts.",
"inputSchema": {
"type": "object",
"properties": {}
}
},
{
"name": "bindery_memory_append",
"tags": [
"bindery"
],
"displayName": "Bindery: Memory Append",
"toolReferenceName": "binderyMemoryAppend",
"canBeReferencedInPrompt": true,
"modelDescription": "Append a dated session entry to a memory file in .bindery/memories/. The tool stamps the date; supply a short title and content.",
"inputSchema": {
"type": "object",
"properties": {
"file": {
"type": "string",
"description": "Filename within .bindery/memories/, e.g. global.md or ch10.md"
},
"title": {
"type": "string",
"description": "Short session title describing the topic"
},
"content": {
"type": "string",
"description": "Text to record under this session entry"
}
},
"required": [
"file",
"title",
"content"
]
}
},
{
"name": "bindery_memory_compact",
"tags": [
"bindery"
],
"displayName": "Bindery: Memory Compact",
"toolReferenceName": "binderyMemoryCompact",
"canBeReferencedInPrompt": true,
"modelDescription": "Overwrite a memory file with a compacted summary. The original is backed up to .bindery/memories/archive/ first.",
"inputSchema": {
"type": "object",
"properties": {
"file": {
"type": "string",
"description": "Filename within .bindery/memories/, e.g. global.md"
},
"compacted_content": {
"type": "string",
"description": "Full replacement content (model-supplied summary)"
}
},
"required": [
"file",
"compacted_content"
]
}
},
{
"name": "bindery_chapter_status_get",
"tags": [
"bindery"
],
"displayName": "Bindery: Chapter Status",
"toolReferenceName": "binderyChapterStatusGet",
"canBeReferencedInPrompt": true,
"modelDescription": "Read the current chapter progress tracker from .bindery/chapter-status.json. Returns a grouped summary (done, in-progress, draft, planned, needs-review). Returns a clear empty-state message if no status has been recorded yet.",
"inputSchema": {
"type": "object",
"properties": {}
}
},
{
"name": "bindery_chapter_status_update",
"tags": [
"bindery"
],
"displayName": "Bindery: Chapter Status Update",
"toolReferenceName": "binderyChapterStatusUpdate",
"canBeReferencedInPrompt": true,
"modelDescription": "Upsert chapter progress entries in .bindery/chapter-status.json. Send only the chapters that changed — existing entries are preserved. status must be one of: done, in-progress, draft, planned, needs-review.",
"inputSchema": {
"type": "object",
"properties": {
"chapters": {
"type": "array",
"items": {
"type": "object",
"properties": {
"number": {
"type": "number",
"description": "Chapter number"
},
"title": {
"type": "string",
"description": "Chapter title"
},
"language": {
"type": "string",
"description": "Language code, e.g. EN or NL"
},
"status": {
"type": "string",
"enum": [
"done",
"in-progress",
"draft",
"planned",
"needs-review"
]
},
"wordCount": {
"type": "number",
"description": "Approximate word count"
},
"notes": {
"type": "string",
"description": "Short agent note about this chapter"
}
},
"required": [
"number",
"title",
"language",
"status"
]
}
}
},
"required": [
"chapters"
]
}
}
],
"menus": {
"editor/context": [
{
"submenu": "bindery.contextMenu",
"when": "resourceLangId == markdown",
"group": "1_modification@10"
}
],
"explorer/context": [
{
"submenu": "bindery.contextMenu",
"when": "resourceLangId == markdown || explorerResourceIsFolder",
"group": "7_modification@10"
}
],
"editor/title": [
{
"submenu": "bindery.exportMenu",
"when": "resourceLangId == markdown",
"group": "navigation@100"
}
],
"bindery.contextMenu": [
{
"command": "bindery.formatDocument",
"when": "resourceLangId == markdown",
"group": "1_format@1"
},
{
"command": "bindery.formatFolder",
"when": "explorerResourceIsFolder",
"group": "1_format@2"
},
{
"command": "bindery.findProbableUsToUkWords",
"when": "resourceLangId == markdown",
"group": "2_dialect@1"
},
{
"command": "bindery.addDialect",
"when": "resourceLangId == markdown",
"group": "2_dialect@2"
},
{
"command": "bindery.addTranslation",
"when": "resourceLangId == markdown",
"group": "2_dialect@3"
},
{
"command": "bindery.mergeMarkdown",
"group": "3_export@1"
},
{
"command": "bindery.mergeDocx",
"group": "3_export@2"
},
{
"command": "bindery.mergeEpub",
"group": "3_export@3"
},
{
"command": "bindery.mergePdf",
"group": "3_export@4"
},
{
"command": "bindery.mergeAll",
"group": "3_export@5"
}
],
"bindery.exportMenu": [
{
"command": "bindery.mergeMarkdown",
"group": "1_merge@1"
},
{
"command": "bindery.mergeDocx",
"group": "1_merge@2"
},
{
"command": "bindery.mergeEpub",
"group": "1_merge@3"
},
{
"command": "bindery.mergePdf",
"group": "1_merge@4"
},
{
"command": "bindery.mergeAll",
"group": "2_all@1"
}
]
},
"submenus": [
{
"id": "bindery.contextMenu",
"label": "Bindery",
"icon": "$(book)"
},
{
"id": "bindery.exportMenu",
"label": "Bindery Export",
"icon": "$(book)"
}
]
},
"scripts": {
"vscode:prepublish": "npm run build:mcp && npm run typecheck && npm run bundle",
"compile": "tsc -p ./",
"typecheck": "tsc --noEmit -p ./",
"bundle": "node ./esbuild.mjs",
"watch": "tsc -watch -p ./",
"lint": "eslint src --ext ts",
"build:mcp": "cd ../mcp-ts && npm ci && npm run compile",
"test": "vitest run",
"test:watch": "vitest",
"test:ci": "vitest run --reporter=verbose --reporter=json --outputFile=test-results.json"
},
"devDependencies": {
"esbuild": "^0.28.0",
"@types/node": "^25.6.0",
"@types/vscode": "1.116.0",
"typescript": "6.0.2",
"vitest": "^4.1.4"
}
}