diff --git a/.claude/commands/density-check.md b/.claude/commands/density-check.md new file mode 100644 index 0000000..72d03fa --- /dev/null +++ b/.claude/commands/density-check.md @@ -0,0 +1,26 @@ +description: Audit a document for low-information, fillable sentences. +--- + +Audit the document at $ARGUMENTS for information density. Identify every sentence or paragraph that does not deliver new, actionable information to the reader. + +## What counts as low-density content + +* Restatements: sentences that repeat what a heading, previous sentence, or adjacent paragraph already says +* Throat-clearing: opening sentences that announce what is coming instead of delivering it. "This section describes how to..." "In this guide, you will learn..." +* Transition filler: sentences whose only purpose is connecting two paragraphs. If removing the sentence does not break the reader's understanding, it is filler. +* Redundant qualifiers: "very important", "absolutely necessary", "completely optional". The qualifier adds no information the noun does not already carry. +* UI narration: describing what the reader can already see on screen. "The Save button saves your changes." +* Defensive hedging: "It should be noted that...", "Keep in mind that...", "Please be aware that...". Strip the hedge and keep the content. + +## Output format + +For each finding, report on its own line: +Line [N]: [quoted sentence or phrase] +Problem: [which low-density pattern it matches] +Action: [delete / merge with adjacent sentence / replace with: "..."] + +End with a summary: +* Total sentences in document +* Sentences flagged as low-density +* Percentage that could be cut or compressed +* Estimated word count reduction \ No newline at end of file diff --git a/.claude/commands/review-doc.md b/.claude/commands/review-doc.md new file mode 100644 index 0000000..90d5e35 --- /dev/null +++ b/.claude/commands/review-doc.md @@ -0,0 +1,53 @@ +description: Structured editorial review against the style guide, findings only. +--- + +Review the technical document at $ARGUMENTS against our style guide. Do not rewrite or modify the source text. Provide findings only. Do not invent product behavior. + +## Review dimensions + +Evaluate each dimension independently. Only flag genuine problems. + +### Concision +Flag sentences using more words than necessary. Setup phrases, hedging language, and redundant qualifiers are the common culprits. Test: can the sentence be shortened without losing meaning? + +### Information density +Flag sentences or paragraphs delivering little or no new information: restatements of what a heading already says, throat-clearing introductions, transition sentences describing what the next paragraph will say. + +### Scanability +Flag: +* Paragraphs longer than 5 sentences that could be lists +* Sections with no visual break between dense prose blocks +* Missing or weak lead sentences that do not orient the reader + +### Progressive disclosure +Flag when information appears before the reader needs it. Background and context follow actionable content, not precede it. + +### Action clarity +For procedural sections, flag instructions that are ambiguous, incomplete, or missing an explicit outcome. + +### AI-sounding phrasing +Flag: "delve into", "it's worth noting", "comprehensive", "robust", "leverage", "seamlessly", "empower", "streamline", "unlock", "harness", "moreover", "furthermore", "take advantage of", "this allows you to", "this enables you to." + +### Style guide compliance +* No em dashes +* No semicolons +* No bare demonstrative pronouns +* Sentence case for all headings +* Consistent list marker style + +## Output format + +### Summary +One paragraph: what the doc covers, whether it meets its goals. + +### Findings table + +| Severity | Location | Issue | Rule violated | Fix | +|---|---|---|---|---| +| Critical/Major/Minor | heading or phrase | description | style rule | one-line fix | + +### Top 3 changes for biggest impact +Format: Outcome → Action. + +### Open questions +Clarifying questions about gaps or ambiguous content. \ No newline at end of file diff --git a/.claude/commands/revise-doc.md b/.claude/commands/revise-doc.md new file mode 100644 index 0000000..6c36f48 --- /dev/null +++ b/.claude/commands/revise-doc.md @@ -0,0 +1,19 @@ +description: Rewrite a passage or file to publication-ready style, in place. +--- + +Rewrite the following text to publication-ready technical documentation standard. If $ARGUMENTS is a file path, read that file's content as the text to edit; otherwise treat $ARGUMENTS as the text itself. + +Rules: +* Active voice. Subject performs the action. +* Sentence case for headings. +* No em dashes, semicolons, or smart quotes. +* No bare demonstrative pronouns. Follow "This/These/That/Those" with a noun. +* No filler: remove "it's worth noting", "please note", "keep in mind", "in order to", "due to the fact that". +* No AI-sounding language: remove "leverage", "utilize", "streamline", "comprehensive", "robust", "seamlessly". +* Lead each sentence with its information, not a preamble announcing the information. +* One idea per sentence. Split compounds. +* Conditions before instructions: "To X, do Y." + +Preserve technical accuracy. Do not invent behavior, parameters, or UI labels not present in the original text. + +Text to edit: $ARGUMENTS \ No newline at end of file diff --git a/.claude/commands/terminology-audit.md b/.claude/commands/terminology-audit.md new file mode 100644 index 0000000..9feeb89 --- /dev/null +++ b/.claude/commands/terminology-audit.md @@ -0,0 +1,30 @@ +description: Audit a document for inconsistent naming of the same concept. +--- + +Audit the document at $ARGUMENTS for terminology consistency. Identify every instance where the same concept, feature, component, or action is referred to by different names. + +## What to check + +* Feature names: Is the same feature called different things in different sections? +* UI element names: Are buttons, fields, pages, and tabs named consistently? +* Actions: Is the same user action described with different verbs? "Configure" vs "set up" vs "enable" +* Technical terms: Are API objects, parameters, and values referred to the same way throughout? "API key" vs "api_key" vs "access token" +* Roles and actors: "User" vs "admin" vs "account owner" vs "you". Is the audience addressed consistently? + +## Output format + +### Terminology map + +For each concept with inconsistent naming: + +| Concept | Terms used | Locations | Recommended term | +|---|---|---|---| +| [concept] | [all variants found] | [sections/lines] | [one term to standardize on] | + +### Undefined terms +List any technical terms, acronyms, or jargon used without definition on first occurrence. + +### Recommendations +* Which term to standardize on for each inconsistency +* Whether any terms need a glossary entry +* Whether any inconsistencies reflect actual product inconsistencies that need to be escalated \ No newline at end of file diff --git a/.claude/skills/branch/SKILL.md b/.claude/skills/branch/SKILL.md new file mode 100644 index 0000000..2a52bbb --- /dev/null +++ b/.claude/skills/branch/SKILL.md @@ -0,0 +1,66 @@ +--- +name: branch +description: Create a correctly named git branch from a ticket ID before starting any documentation work. +--- + +# branch + +Create a correctly named git branch from a ticket before starting any documentation work. + +## When to use this skill + +Run this as the first step when starting work on any ticket. It ensures branch names are consistent, traceable to the ticket, and do not require the writer to manually construct the slug. + +## Inputs + +* Ticket ID: the full ticket identifier, for example `DOC-1234` or `ISSUE-567` + +## Steps + +### Step 1: Check the current branch + +Run `git branch --show-current`. + +If the current branch is not the main branch, stop and tell the writer: + +> Cannot create branch: you are currently on `[branch-name]`, not `main`. Switch to `main` first. + +Do not proceed until the writer is on the main branch. + +### Step 2: Fetch the ticket title + +Use your issue tracker integration to fetch the ticket and read its title or summary field. The field name varies by tool: `summary` in Jira, `title` in GitHub Issues and Linear. + +### Step 3: Derive the branch name slug + +Transform the ticket title into a URL-safe slug: + +* Replace spaces with hyphens +* Remove parentheses, commas, and periods +* Replace any remaining special characters (except letters, digits, and hyphens) with hyphens +* Collapse consecutive hyphens into one +* Preserve original casing + +Examples: + +| Ticket | Title | Branch name | +|---|---|---| +| DOC-1234 | Release notes (June 3, 2024) | `DOC-1234-Release-notes-June-3-2024` | +| DOC-1189 | Add rate limiting to API reference | `DOC-1189-Add-rate-limiting-to-API-reference` | + +### Step 4: Create the branch + +```bash +git checkout -b [TICKET-ID]-[TITLE-SLUG] +``` + +Confirm the branch was created and report the full branch name to the writer. + +## Output + +A new local git branch named `[TICKET-ID]-[TITLE-SLUG]`. + +## Rules + +* Never create a branch from anything other than the main branch. +* Never modify the ticket title when deriving the slug. Only apply the transformations in Step 3. diff --git a/.claude/skills/copyedit-reference/SKILL.md b/.claude/skills/copyedit-reference/SKILL.md new file mode 100644 index 0000000..e629744 --- /dev/null +++ b/.claude/skills/copyedit-reference/SKILL.md @@ -0,0 +1,108 @@ +--- +name: copyedit-reference +description: Grammar, style, and consistency copyedit for reference documentation, parameter tables, and API reference material. +--- + +# copyedit-reference + +Grammar, style, and consistency copyedit for reference documentation: parameter tables, field descriptions, configuration options, and API reference material. + +## When to use this skill + +Use this on reference docs that describe parameters, fields, configuration options, or API inputs and outputs. It applies a focused set of rules specific to the challenges of reference material: inconsistent formatting, missing required/optional labels, unclear descriptions, and raw URLs. + +## Inputs + +* File path of the reference document to review + +## Steps + +### Step 1: Grammar and spelling check + +Check for basic grammar errors, spelling mistakes, and punctuation inconsistencies. Flag each issue with its location. + +### Step 2: Code formatting + +* Variable names, parameter names, and values that appear inline use code formatting (backticks). +* Uppercase words (like UUID, ID) do not use backticks unless they are specifically a parameter name in this document. +* Example values are always code-formatted. + +### Step 3: Links + +* Every raw URL gets descriptive link text. +* Link text is the destination page title or a clear description. Do not use "click here," "here," or the raw URL. +* Internal links use relative paths, not absolute URLs. + +### Step 4: Sentences and punctuation + +* Every sentence ends with a period, including sentences that end with a link. +* If a sentence ends with a link, the period comes after the closing link markup. +* Capitalize the first word after a colon when it introduces a complete sentence. + +### Step 5: Word choice + +* Write out abbreviations: "for example" not "e.g.," "such as" not "i.e.," "and so on" not "etc." +* Use "ID" not "id" or "Id." + +### Step 6: Capitalization + +* Use sentence case for parameter titles, field labels, and action titles. +* Do not capitalize common nouns unless a vendor requires it (for example, a brand name). +* Product and feature names follow the project's terminology guide. + +### Step 7: Required/optional labels + +* Label each parameter as **(Required)**, **(Optional)**, or **(Recommended)**. +* Labels appear in parentheses at the beginning of the description. +* Do not use all caps (REQUIRED) or other formatting variations. + +### Step 8: Parameter description structure + +Where possible, descriptions follow this order: + +1. What the parameter does +1. Format, accepted values, and example inputs +1. Additional behavior notes or conditions +1. Link to supporting documentation (if applicable) + +### Step 9: Report findings and produce revision + +List each issue found with: +* Location (field name, section, or line number) +* Problem description +* Recommended fix + +Then provide the full revised text. + +## Output + +Findings list followed by the complete revised document. + +## Example: before and after + +**Before:** +``` +API Key (REQUIRED): The API Key for your account e.g. abc123. You can find this +in Settings > API Keys. Utilize this to authenticate requests. +``` + +**After:** +``` +`api_key` (Required): Your account API key, used to authenticate requests. +Format: alphanumeric string. Example: `abc123`. +To find your key, go to **Settings > API Keys**. +``` + +What changed: +* `api_key` is code-formatted because it is a parameter name +* "(REQUIRED)" → "(Required)": sentence case, not all caps +* "e.g." → inline example with code formatting +* "Utilize" → removed. Description rewritten as direct action. +* Description follows the structure: what it does → format → where to find it + +## Rules + +* Preserve technical accuracy while simplifying wording. +* Do not rewrite descriptions that are technically correct. Only fix language and formatting issues. +* Do not invent accepted values, defaults, or behaviors. +* If a description is unclear about what a parameter does, mark it as a gap rather than guessing. diff --git a/.claude/skills/discover-feature/SKILL.md b/.claude/skills/discover-feature/SKILL.md new file mode 100644 index 0000000..eadfb51 --- /dev/null +++ b/.claude/skills/discover-feature/SKILL.md @@ -0,0 +1,105 @@ +--- +name: discover-feature +description: Research a ticket and produce a structured research brief before any writing begins. +--- + +# discover-feature + +Research a ticket and produce a structured research brief before any writing begins. + +## When to use this skill + +Run this before planning or drafting any documentation. It is the foundation everything else builds on. The research brief produced here becomes the input to `plan-doc` and `draft-doc`. + +Use it any time you need to document a feature or change that you did not build yourself and are not yet fully familiar with. + +## Inputs + +* Ticket ID: the full ticket identifier + +## Steps + +### Step 1: Parse the ticket ID + +Extract the ticket ID from whatever the writer provided: a URL, a plain ID, or a mention. Use the full ID as-is. + +### Step 2: Create the workspace directory + +Create a workspace directory for this ticket (for example, `.claude/workspace/[TICKET-ID]/` or your tool's equivalent). This directory holds all working files for this ticket and is scoped to the feature branch. It never merges to main. + +### Step 3: Fetch the ticket + +Use your issue tracker integration to fetch the ticket. This could be a Jira MCP, the GitHub Issues API, a Linear integration, or any tool that gives the agent access to your tickets. Collect: + +* Title and description +* Acceptance criteria +* Any linked tickets +* Any linked documentation pages (fetch each one) +* Any file attachments: read text-based files directly and note binary files you cannot read + +For each attachment you cannot read, note the filename and type in the brief under "Unread attachments." + +### Step 4: Search the knowledge base + +Search your internal knowledge base for context related to this feature. Use the ticket title and key terms as your search query. This could be Confluence, Notion, a search tool like Glean, or any internal wiki your team uses. Look for: + +* Engineering documentation or design specs +* Product specs +* Related feature context that fills gaps in the ticket + +### Step 5: Find related existing documentation + +Search the content directory for existing documentation related to this feature. Note the file paths of any docs that may need to be updated or cross-linked. + +### Step 6: Write the research brief + +Write `[workspace]/[TICKET-ID]/discover-feature.md` using this structure: + +```markdown +# [TICKET-ID]: [Ticket title] + +## What this feature does +Plain-language explanation. What it is, what problem it solves, what a user +can do with it that they could not do before. + +## What's changing +Specifically what is new, changed, or removed. Be concrete. +* New: [what was added] +* Changed: [what was modified and how it differs from before] +* Removed: [what no longer exists] + +## Target audience +Who uses this feature. Their technical level, role, and goal. + +## Existing docs +List of related files with paths. Note whether each needs to be updated or cross-linked. + +## Open questions +Things that are unclear, missing, or contradictory in the source material. +Format each as a specific, answerable question. + +## Sources +Ticket URL, pages read, attachments read, knowledge base results used. + +## Unread attachments +[Omit this section if all attachments were read successfully.] +``` + +## Output + +`[workspace]/[TICKET-ID]/discover-feature.md` + +## Transition + +After writing the brief, summarize the key findings in 3–5 sentences and ask: + +> "Ready to plan the doc structure, or do you want to review the brief first?" + +**Stop here and wait for the writer's response before taking any further action.** + +## Rules + +* Only include information stated or directly supported by the source material. +* Do not invent product behavior. If something is unclear, put it in Open questions. +* If information is implied but not stated, note it in Open questions, not in the main sections. +* Terminology inconsistency is a factual error. Note exact phrasing from sources and use it consistently. diff --git a/.claude/skills/doc-review/SKILL.md b/.claude/skills/doc-review/SKILL.md new file mode 100644 index 0000000..3ddf316 --- /dev/null +++ b/.claude/skills/doc-review/SKILL.md @@ -0,0 +1,185 @@ +--- +name: doc-review +description: Perform a strict editorial review of a documentation file before publishing. +--- + +# doc-review + +Perform a strict editorial review of a documentation file before publishing. + +## When to use this skill + +Run this on any draft before it is published, whether AI-generated or human-written. Use it as a final pass before requesting peer review, or after incorporating feedback to verify all issues are resolved. + +## Inputs + +* File path of the document to review + +## Steps + +### Step 1: Run the mechanical linter (optional) + +A mechanical linter catches deterministic violations before the qualitative review: things like bare demonstrative pronouns, prohibited terms, sequential list numbering, and heading case. These are high-confidence findings that do not require judgment, so checking them programmatically first saves review time. + +If your project has a lint script, run it now: + +```bash +python [skills-dir]/doc-review/scripts/lint.py +``` + +Include lint findings in the report as Critical or Major severity based on the rule violated. + +**If you do not have a lint script yet, skip this step.** The qualitative review in Step 2 will catch most of the same issues. A lint script is worth adding once you have identified the style violations that appear most often in your project. At that point, automating them pays off. A minimal starting point: + +```python +import re +import sys + +def lint(filepath): + findings = [] + with open(filepath) as f: + lines = f.readlines() + + for i, line in enumerate(lines, 1): + # Em dashes + if "—" in line or " -- " in line: + findings.append((i, "Em dash found — use a period, colon, or restructure.")) + # Semicolons + if ";" in line and not line.strip().startswith("```"): + findings.append((i, "Semicolon found — split into two sentences.")) + # Bare demonstrative pronouns + if re.search(r'\b(This|These|That|Those)\s+(prevents|allows|enables|means|makes|shows|helps)', line): + findings.append((i, "Bare demonstrative pronoun — follow with a noun.")) + # Sequential list numbering (2., 3., etc.) + if re.match(r'^\s*[2-9]\d*\.', line): + findings.append((i, "Sequential list number — use '1.' for all items.")) + # Prohibited terms + for term in ["utilize", "leverage", "seamlessly", "robust", "unlock"]: + if term.lower() in line.lower(): + findings.append((i, f"Prohibited term: '{term}'.")) + + return findings + +if __name__ == "__main__": + issues = lint(sys.argv[1]) + if issues: + for lineno, msg in issues: + print(f"Line {lineno}: {msg}") + sys.exit(1) + else: + print("No lint errors found.") + sys.exit(0) +``` + +Extend this with rules specific to your style guide. Each rule should be deterministic. If you find yourself adding judgment calls to the script, those belong in the qualitative review instead. + +### Step 2: Qualitative review + +Read the full document and evaluate each dimension below. Flag genuine problems only. Do not flag hypothetical ones. + +**Concision** +Flag sentences that use more words than necessary. Setup phrases, hedging language, and redundant qualifiers are the most common culprits. Test: can the sentence be shortened without losing meaning? + +**Information density** +Flag sentences or paragraphs where little or no new information is delivered: restatements of what a heading already says, throat-clearing introductions, and transition sentences that describe what the next paragraph will say. + +**Scanability** +Flag: +* Paragraphs longer than 5 sentences that could be lists +* Sections with no visual break between dense prose blocks +* Missing or weak lead sentences that do not orient the reader + +**Redundancy** +Flag content that appears more than once. Note both locations. + +**Voice** +Flag passive constructions. Note when passive may be justified (actor is unknown or irrelevant). + +**Heading quality** +Flag headings that: +* Use title case instead of sentence case +* Are vague ("Overview," "More information," "Details") +* Do not match the content type. Task sections use action verbs. Concept sections use noun phrases. + +**Action clarity** +For procedural sections, flag instructions that are ambiguous, incomplete, or missing an explicit outcome. A good instruction tells the reader what to do and what to expect when they have done it. + +**Progressive disclosure** +Flag when information appears before the reader needs it. Background and context should follow actionable content, not precede it. + +**Style guide compliance** +Flag violations of your project's style guide. At minimum, check: +* No em dashes +* No semicolons +* No bare demonstrative pronouns ("This prevents..." becomes "This value prevents...") +* Sentence case for all headings +* Consistent list marker style + +**AI-sounding phrasing** +Flag phrases that signal generated text: "delve into", "it's worth noting", "comprehensive", "robust", "leverage", "seamlessly", "empower", "streamline", "unlock", "harness", "moreover", "furthermore", "take advantage of", "this allows you to", "this enables you to." + +### Step 3: Clarity sub-agent check + +Spawn a sub-agent with no context from this conversation. Give it only the document content and these three questions: + +1. What does this doc help you do? +2. Who is it written for? +3. What is the first thing you should do after reading it? + +If the sub-agent's answers do not match the doc's stated purpose, that is a finding. Report what it got wrong and which section caused the confusion. + +### Step 4: Write the report + +Write findings to `[workspace]/[TICKET-ID]/review.md` if inside the writing workflow, or output directly to the conversation if used standalone. + +Use this format for each finding: + +``` +### [Line number or section name]: [Issue type] + +Severity: Critical | Major | Minor +Confidence: High | Medium | Low +Problem: [What is wrong and why it hurts the reader] +Suggested rewrite: [Improved version, or "N/A: structural issue"] +``` + +Order findings by severity (Critical first), then by position in the document. + +End the report with a one-paragraph summary: overall quality assessment, the single most impactful change, and a count of findings by severity. + +## Example finding + +``` +### Introduction: AI-generated phrasing + style violation + +Severity: Critical +Confidence: High +Problem: "It's worth noting" is AI-generated filler and adds no information. +"Utilize" should be "use" per the style guide. The opening sentence is 38 words +and restates the page title without adding meaning. +Suggested rewrite: Use rate limiting to control how many requests the API accepts +within a given time window. +``` + +## Output + +`[workspace]/[TICKET-ID]/review.md` (or inline in conversation if standalone) + +## Severity definitions + +* **Critical:** Must fix before publish. Style guide violation or broken instruction. +* **Major:** Fix before publish. Significantly hurts clarity or consistency. +* **Minor:** Improvement opportunity. Writer's discretion. + +## Confidence definitions + +* **High:** Objectively wrong per the style guide. +* **Medium:** Clear pattern match, but context could justify the choice. +* **Low:** Judgment call. The writer may have good reason for it. + +## Rules + +* Do not verify factual accuracy. That is the writer's responsibility. +* Do not question structure or doc type decisions. Those were made in `plan-doc`. +* Do not rewrite large sections unprompted. Provide findings. Let the writer decide. +* If the writer asks for a rewrite of a specific section after seeing the findings, do it. diff --git a/.claude/skills/draft-doc/SKILL.md b/.claude/skills/draft-doc/SKILL.md new file mode 100644 index 0000000..96d1f45 --- /dev/null +++ b/.claude/skills/draft-doc/SKILL.md @@ -0,0 +1,91 @@ +--- +name: draft-doc +description: Write the documentation draft from the approved plan and research brief, flagging gaps inline. +--- + +# draft-doc + +Write the documentation draft from the approved plan and research brief. + +## When to use this skill + +Run this after `plan-doc` has produced a plan that the writer has approved. Do not draft without an approved plan. + +## Inputs + +* `[workspace]/[TICKET-ID]/plan.md` +* `[workspace]/[TICKET-ID]/discover-feature.md` + +If either file is missing, stop and ask the writer to run the appropriate preceding skill first. + +## Steps + +### Step 1: Extract verified content from sources + +Before writing anything, scan both input files and identify: + +* Key terms and their exact phrasing. Use these verbatim throughout the draft. Terminology inconsistency is a factual error. +* Specific values, settings, and defaults that are explicitly stated. +* Behaviors that are directly described vs. behaviors that are implied. + +### Step 2: Draft section by section + +Follow the section order from `plan.md` exactly. For each section: + +1. Re-read the section's Purpose and Content notes from the plan. +2. Identify which source material from the research brief covers that content. +3. Write the section using only that material. +4. Insert gap or verify markers wherever the sources fall short (see Markers below). + +Do not skip sections. A section with only a gap marker is more honest than a section with invented content. + +### Step 3: Apply writing standards + +* Lead with what the reader will do or understand. Do not lead with how the feature works internally. +* Do not restate what a UI label already says. Document what the reader needs to decide or understand, not what they can see. +* Do not use generic filler introductions ("This document describes how to..."). +* Procedures longer than seven steps need an intermediate checkpoint or verification step. +* Every sentence begins with the information it contains, not a preamble announcing that information is coming. + +### Step 4: Write the draft file + +Write the draft to the path specified in `plan.md` under File > Path. Use the front matter from the plan as the starting point. + +Also save a copy to `[workspace]/[TICKET-ID]/draft.md` as a working snapshot. + +## Markers + +Use these inline markers to flag content that needs writer attention. They render as HTML comments: visible in the source, invisible when the site builds. + +**Gap:** information the plan calls for that is not in the sources: +``` + +``` + +**Verify:** content that is inferred rather than directly stated in a source: +``` + +``` + +Insert markers at the exact location where missing or uncertain content belongs. Do not consolidate them at the bottom of the file. + +## Output + +* Draft written to the path in `plan.md` +* Working copy at `[workspace]/[TICKET-ID]/draft.md` + +## After drafting + +Count the gap and verify markers and report them to the writer: + +* How many `` markers exist and what they represent +* How many `` markers exist and what assumptions they contain + +Then say: "The draft is at `[file path]`. Review it and let me know what to change, or run `doc-review` for an editorial pass." + +## Rules + +* Only write what the sources in the research brief support. +* Do not invent product behavior, API parameters, default values, or UI labels. +* Do not skip sections from the plan. A missing section is always visible. +* Use exact terminology from the research brief throughout. Do not paraphrase technical terms. diff --git a/.claude/skills/plan-doc/SKILL.md b/.claude/skills/plan-doc/SKILL.md new file mode 100644 index 0000000..0451a75 --- /dev/null +++ b/.claude/skills/plan-doc/SKILL.md @@ -0,0 +1,105 @@ +--- +name: plan-doc +description: Produce a structured documentation outline from the research brief, for writer approval before any drafting begins. +--- + +# plan-doc + +Produce a structured documentation outline from the research brief, for writer approval before any drafting begins. + +## When to use this skill + +Run this after `discover-feature` has produced an approved research brief. Always plan before drafting. Changing structure after a draft exists is expensive. + +## Inputs + +* `[workspace]/[TICKET-ID]/discover-feature.md` + +If this file does not exist, ask the writer to run `discover-feature` first. + +## Steps + +### Step 1: Read the research brief + +Read the discover-feature brief. Identify the feature, the target audience, and what the reader will need to do after reading the documentation. + +### Step 2: Determine the doc type + +Use the Diataxis framework to select the appropriate doc type: + +| Type | Reader need | Shape | +|---|---|---| +| **How-to guide** | Complete a specific task | Numbered steps, minimal explanation | +| **Tutorial** | Learn by doing for the first time | Guided end-to-end sequence, hand-holding tone | +| **Concept** | Understand how something works | Prose explanation, no procedures | +| **Reference** | Look up a value, parameter, or behavior | Tables, lists, terse descriptions | + +Choose the type that matches what the reader will actually do with the doc. If the ticket requires more than one type, plan separate files. + +### Step 3: Apply outline principles + +Before writing headings, reason through these four dimensions: + +**Front-load value.** The most useful information comes first. A reader scanning the top of the page should immediately understand what the doc covers and whether it applies to them. Background follows actionable content. It does not precede it. + +**Optimize for scanning.** Readers rarely read linearly. Each heading should clearly signal the content beneath it. Avoid vague headings like "Overview" or "More information." + +**Separate concept from procedure.** Do not mix explanation and steps in the same section. If readers need to understand something before they can do something, that understanding belongs in its own section, not embedded inside a procedure. + +**Identify prerequisites.** What must the reader already know or have set up before this doc is useful? This belongs near the top. + +### Step 4: Determine the file path + +Based on the doc type and subject matter, identify where the file belongs in the content directory. Use existing files in the same area as a guide for naming conventions. If this is an update to an existing file, note that instead. + +### Step 5: Write the plan + +Write `[workspace]/[TICKET-ID]/plan.md` using this structure: + +```markdown +# Plan: [TICKET-ID] + +## Doc type +[Type]: [One sentence explaining why this type fits the reader need] + +## File +* Path: content/[path/to/file.md] +* Status: New file | Update to existing file + +## Front matter +title: [Proposed title] +description: [One sentence describing what the reader will learn or accomplish] + +## Prerequisite knowledge +[What the reader must already know. If none, say so.] + +## Outline + +### [Section heading] +Purpose: [What this section does for the reader, in one sentence] +Content: [Key points, decisions, or data this section must cover] + +### [Section heading] +Purpose: ... +Content: ... +``` + +## Output + +`[workspace]/[TICKET-ID]/plan.md` + +## Transition + +After writing the plan, show the outline to the writer as a summary (headings and purpose only). Ask: + +> "Does this structure look right, or do you want to adjust anything before drafting?" + +**Stop here and wait for the writer's response before taking any further action.** + +Once approved, offer to continue with `draft-doc`. + +## Rules + +* Do not start drafting until the plan is approved. +* If the research brief is missing information needed to plan a section, note it in that section's Content notes rather than inventing content. +* Choose the doc type based on reader need, not on what is easiest to write. diff --git a/.claude/skills/release-notes/SKILL.md b/.claude/skills/release-notes/SKILL.md new file mode 100644 index 0000000..b9f8a76 --- /dev/null +++ b/.claude/skills/release-notes/SKILL.md @@ -0,0 +1,147 @@ +--- +name: release-notes +description: Collect release items from the issue tracker, write a release notes blog post, and open a pull request in a single skill run. +--- + +# release-notes + +Collect release items from your issue tracker, write a release notes post, and open a pull request in a single skill run. + +## When to use this skill + +Run this each time you publish a release notes update. This skill handles the mechanical work: querying tickets, writing the post, and opening the PR. + +**Adapted for this repo:** this is a single-product project (the Task Manager API), so there is no multi-folder routing map. Every release note goes to one place: `blog/`, following the Docusaurus blog post convention. + +## Inputs + +* Release date: `YYYY-MM-DD` format + +## Steps + +### Step 1: Collect release items + +Query your issue tracker for tickets that are: +* Status: Ready for release (or your equivalent "done and approved" status) +* Release notes field: not empty + +For each ticket, collect: +* Ticket key +* Public-facing release notes text (the dedicated release notes field, not the description or title) + +Also query for tickets that are ready for release but have an empty release notes field. For each of these, draft suggested release notes text from the ticket description and present them to the writer for review before proceeding. Do not write anything to disk until the writer approves the suggested text. + +### Step 2: Write the release notes post + +Write `blog/[YYYY-MM-DD]-release-notes.md`. + +Before creating the file, check if a post for this date already exists. If it does, append entries to the appropriate section rather than overwrite. + +**File format (Docusaurus blog front matter):** + +```markdown +--- +slug: [YYYY-MM-DD]-release-notes +title: Release notes: [YYYY-MM-DD] +authors: [writetechhub] +tags: [release-notes] +--- + +#### New features + +* [Release note text] + +#### Updates and fixes + +* [Release note text] +``` + +**Section headings (use only what applies):** + +* `#### New features`: significant new capabilities +* `#### Updates and fixes`: updates, maintenance changes, and bug fixes +* `#### Fixes`: when all entries are bug fixes only +* `#### Deprecated`: features or items being deprecated + +**Writing rules:** + +* Use the release notes field text as the source. Do not rewrite the substance. +* Edit lightly for grammar and style: active voice, sentence case, no em dashes, no semicolons. +* Link feature or endpoint names to their documentation pages in `docs/api/` when you can confirm the page exists. Do not add links you cannot verify. + +### Step 3: Review before committing + +List all entries that will be added, with the ticket key and the release notes text each one produced. Ask the writer to confirm before proceeding. + +**Stop here and wait for the writer's confirmation.** + +### Step 4: Create the branch + +If not already on a feature branch, create one: + +```bash +git checkout -b release-notes-[YYYY-MM-DD] +``` + +### Step 5: Commit the changes + +Stage and commit only the release notes file: + +```bash +git add blog/[YYYY-MM-DD]-release-notes.md +git commit -m "Add release notes for [YYYY-MM-DD]" +``` + +Use the release date in the commit message, not today's date. + +### Step 6: Push and open a pull request + +```bash +git push -u origin [branch-name] +``` + +Open a pull request with: +* **Title:** `Add release notes for [YYYY-MM-DD]` +* **Body:** List of each ticket key included with a one-line summary of its release notes text + +**Stop and ask the writer for explicit confirmation before pushing or opening the PR.** Pushing a branch and opening a PR are visible to the rest of the team; do not do this automatically as part of a dry run or test. + +### Step 7: Report the PR URL + +Show the PR URL to the writer. + +## Output + +* A release notes post at `blog/[YYYY-MM-DD]-release-notes.md` +* A pull request with the changes + +## Example output + +Given a ticket with release notes text "Added comments support to the Tasks API, including add, list, and delete endpoints", the skill produces: + +```markdown +--- +slug: 2026-07-23-release-notes +title: Release notes: 2026-07-23 +authors: [writetechhub] +tags: [release-notes] +--- + +#### New features + +* Added [comments support](/docs/api/tasks#comments) to the Tasks API, including add, list, and delete endpoints. +``` + +The link is only added if the page exists. If it cannot be confirmed, the name appears as plain text. + +## Edge cases + +* If a ticket's release notes text contains internal jargon or is clearly not public-facing: ask the writer before including it. +* If the release date in the ticket title differs from today's date: use the date from the ticket, not today's date. + +## Rules + +* Use the release notes field text, not the ticket description or title. +* Do not invent release notes content for tickets that are missing it. Present drafts for writer approval. +* Do not link to documentation pages you have not confirmed exist. +* Always wait for writer confirmation in Step 3 before committing anything, and again in Step 6 before pushing or opening a PR. diff --git a/.claude/templates/skill.md b/.claude/templates/skill.md new file mode 100644 index 0000000..d90711a --- /dev/null +++ b/.claude/templates/skill.md @@ -0,0 +1,34 @@ +--- +name: skill-name +description: One sentence describing when to use this and what it does. +--- + +# skill-name + +One sentence describing what this skill does and when to use it. + +## When to use this skill +[What triggers it? What problem does it solve?] + +## Inputs +* [Input 1]: [description, format, where to find it] +* [Input 2]: [description, format, where to find it] + +## Steps + +Follow each step in order. Do not skip steps. + +### Step 1: [Name] +[Exact action. What to do, what to check, what edge cases to handle.] + +### Step 2: [Name] +[Continue for each step.] + +## Output +[What file or artifact is produced. Where it goes. What it contains.] + +## Edge cases +* If [condition]: [what to do] + +## Rules +[Things the agent must never do in this skill.] diff --git a/.claude/workspace/DOC-101/discover-feature.md b/.claude/workspace/DOC-101/discover-feature.md new file mode 100644 index 0000000..caf6ad6 --- /dev/null +++ b/.claude/workspace/DOC-101/discover-feature.md @@ -0,0 +1,86 @@ +# DOC-101: Document the task comments endpoints + +## What this feature does +The Tasks API now supports comments on a task. A user can add a comment to a +task, list all comments on a task, and delete a comment they authored. Admins +can also delete any comment, not just their own. This gives task collaborators +a way to discuss a task inline instead of relying on external channels. + +## What's changing +* New: `POST /api/tasks/:taskId/comments` — add a comment to a task. Body: + `{ "text": string }`. Returns 201 with the created comment (`id`, `text`, + `authorId`, `createdAt`). +* New: `GET /api/tasks/:taskId/comments` — list all comments on a task, + oldest first. Returns 200 with an array of comments. +* New: `DELETE /api/tasks/:taskId/comments/:commentId` — delete a comment. + Only the comment's author or an Admin can delete it. Returns 200 on + success, 403 if the requester is neither the author nor an Admin. +* Changed: none — this is additive to the existing Tasks API. +* Removed: nothing. + +## Target audience +Same audience as the rest of `docs/api/`: engineers integrating with the Task +Manager API, already familiar with the existing task CRUD and auth model +(JWT bearer token, Admin/Member roles). + +## Existing docs +* [docs/api/tasks.md](../../../docs/api/tasks.md) — needs to be updated. This is + the primary target: the comments endpoints follow the same + endpoint-table + numbered-section pattern already used here for task and + checklist endpoints (sections 1–8, plus the "Endpoints Overview" table and + "Common Error Responses" table at the bottom). +* [docs/api/authentication.md](../../../docs/api/authentication.md) — no update + needed; referenced only for the auth-header pattern (`Authorization: Bearer + `) reused in the new sections. +* [docs/api/users.md](../../../docs/api/users.md) — no update needed; referenced + only for Admin/Member role terminology consistency. +* No existing doc, test spec, or config file mentions "comment" — this is + entirely new content in this repo. + +## Open questions +* What HTTP status and error shape are returned when `text` is missing or + empty on `POST`? The ticket gives no 400 case for this endpoint (unlike the + existing task endpoints, which document 400 for invalid/missing fields). +* Is there a maximum length for `text`? Not stated in the ticket. +* Does the response body wrap the comment object (e.g. `{ "message": ..., + "comment": {...} }`, matching the pattern used by `POST /` and `PUT + /:taskId` in tasks.md) or return the comment bare (matching `GET /me` in + users.md)? The ticket says "Returns 201 with the created comment" without + specifying a wrapper. +* The ticket specifies the created-comment field as `id`, but every existing + resource in this API (tasks, users, checklist items) uses `_id` as the + identifier field. Is `id` intentional for comments, or should it be `_id` + for consistency? This is a terminology/shape discrepancy worth flagging + rather than silently normalizing. +* What does `DELETE` return in the body on success — a `message` string + (matching the pattern in tasks.md section 5, "Delete Task"), or something + else? +* What happens on `GET`/`DELETE` when the task itself doesn't exist, or when + the comment ID doesn't exist under that task? Existing task endpoints + document 404 for "Task not found" — is there an equivalent "Comment not + found" case? +* Is `GET /api/tasks/:taskId/comments` restricted by the same + visibility rule as `GET /:taskId` (Member can only see tasks they created + or are assigned to), or can any authenticated user with access to the + task ID read its comments? The ticket doesn't state a role restriction for + the list/read endpoint beyond "list all comments on a task." +* Can a Member add a comment to any task, or only tasks they created/are + assigned to (mirroring the task-level access model)? + +## Sources +* Ticket DOC-101, provided directly in the writer's request (title, + description, endpoint list, and acceptance criteria). No issue-tracker + integration (Jira/Linear/GitHub Issues) is configured in this environment, + so the ticket text quoted in the prompt is the sole source — nothing was + fetched externally. +* No linked tickets or linked documentation pages were provided. +* No internal knowledge base (Confluence/Notion/Glean) is configured in this + environment, so no search was performed there. +* Repo files read for existing pattern and terminology: `docs/api/tasks.md`, + `docs/api/authentication.md`, `docs/api/users.md`. +* Repo-wide search for "comment" (case-insensitive) across tracked content + turned up no existing documentation, config, or Doc Detective test spec + referencing task comments. + +## Unread attachments +None provided. diff --git a/.claude/workspace/DOC-101/draft.md b/.claude/workspace/DOC-101/draft.md new file mode 100644 index 0000000..5b8dbb5 --- /dev/null +++ b/.claude/workspace/DOC-101/draft.md @@ -0,0 +1,384 @@ +> **For AI agents:** A complete documentation index is available at [`/llms.txt`](https://task-manager-api-documentation.vercel.app/llms.txt). Markdown versions of all pages are available by appending `.md` to any URL. + +# Tasks API + +The Tasks API allows authenticated users to create, assign, update, track, and manage tasks. Tasks can include descriptions, due dates, assigned users, attachments, and progress tracking. + +Both **Admin** and **Member** roles can interact with tasks, but access levels differ: + +| Role | Permissions | +|------|-------------| +| **Admin** | Can view, create, update, and delete *any* task | +| **Member** | Can create tasks and only view or update tasks they created or are assigned to | + +--- + +## Base URL + +``` +/api/tasks +``` + +--- + +## Endpoints Overview + +| Method | Endpoint | Description | Auth Required | Role | +|--------|----------|-------------|---------------|------| +| POST | `/` | Create a new task | Yes | Admin / Member | +| GET | `/` | Get tasks visible to the user | Yes | Admin / Member | +| GET | `/:taskId` | Get details of a specific task | Yes | Admin / Member (if assigned) | +| PUT | `/:taskId` | Update a task | Yes | Admin / Member (if creator/assigned) | +| DELETE | `/:taskId` | Delete a task | Yes | Admin only | +| PATCH | `/:taskId/progress` | Update task progress (0–100%) | Yes | Admin / Member (if assigned) | +| POST | `/:taskId/checklist` | Add a checklist item | Yes | Admin / Member (if assigned) | +| PATCH | `/:taskId/checklist/:itemId` | Update a checklist item's completion state | Yes | Admin / Member (if assigned) | +| POST | `/:taskId/comments` | Add a comment to a task | Yes | Admin / Member | +| GET | `/:taskId/comments` | List all comments on a task | Yes | Admin / Member | +| DELETE | `/:taskId/comments/:commentId` | Delete a comment | Yes | Admin / Member (if author) | + + + +--- + +## Task Structure + +A task contains the following fields: + +```json +{ + "title": "Prepare Project Report", + "description": "Compile milestone achievements", + "priority": "High", + "status": "Pending", + "dueDate": "2025-01-20", + "assignedTo": [""], + "attachments": ["https://filelink.com/file.pdf"], + "todoChecklist": [ + { "text": "Gather docs", "completed": false } + ], + "progress": 40 +} +``` + +--- + +## 1. Create a Task + +**POST** `/` + +Creates a new task in the system. + +### Request Body + +```json +{ + "title": "Design Homepage UI", + "description": "Initial UI/UX layout", + "priority": "High", + "dueDate": "2025-01-29", + "assignedTo": ["65f93b8c9e9a2d52c3a421de"] +} +``` + +### Response (201 Created) + +```json +{ + "message": "Task created successfully", + "task": { + "_id": "65f94a9c19d23e", + "title": "Design Homepage UI", + "priority": "High", + "status": "Pending" + } +} +``` + +![Postman Sample](../assets/image-one.jpg) +--- + +## 2. Get Tasks (Filtered by Role) + +**GET** `/` + +Retrieves tasks based on the user's role: + +- **Admin** → Gets all tasks. +- **Member** → Gets only tasks they created or were assigned to. + +### Response (200 OK) + +```json +[ + { + "_id": "65f94a9c19d23e", + "title": "Design Homepage UI", + "status": "Pending", + "assignedTo": ["65f93b8c9e9a2d52c3a421de"], + "progress": 40 + } +] +``` + +--- + +## 3. Get Task by ID + +**GET** `/:taskId` + +Returns detailed information for a single task. + +### Response (200 OK) + +```json +{ + "_id": "65f94a9c19d23e", + "title": "Design Homepage UI", + "description": "Initial UI/UX layout", + "assignedTo": ["65f93b8c9e9a2d52c3a421de"], + "todoChecklist": [ + { "text": "Sketch wireframe", "completed": false } + ] +} +``` + +--- + +## 4. Update Task + +**PUT** `/:taskId` + +Updates task content including title, status, description, and other fields. + +### Request Body + +```json +{ + "status": "InProgress", + "description": "Working on visual layout" +} +``` + +### Response (200 OK) + +```json +{ + "message": "Task updated successfully", + "task": { + "_id": "65f94a9c19d23e", + "title": "Design Homepage UI", + "status": "InProgress", + "description": "Working on visual layout" + } +} +``` + +--- + +## 5. Delete Task (Admin Only) + +**DELETE** `/:taskId` + +Permanently removes a task from the system. Only admins can delete tasks. + +### Response (200 OK) + +```json +{ + "message": "Task deleted successfully" +} +``` + +--- + +## 6. Update Task Progress + +**PATCH** `/:taskId/progress` + +Updates the progress percentage of a task (0–100%). + +### Request Body + +```json +{ + "progress": 75 +} +``` + +### Response (200 OK) + +```json +{ + "message": "Progress updated", + "progress": 75 +} +``` + +--- + +## 7. Add Checklist Item + +**POST** `/:taskId/checklist` + +Adds a new item to the task's checklist. + +### Request Body + +```json +{ + "text": "Run accessibility audit" +} +``` + +### Response (201 Created) + +```json +{ + "message": "Checklist item added successfully", + "checklist": [ + { "_id": "65f95b2d3a1f34", "text": "Run accessibility audit", "completed": false } + ] +} +``` + +--- + +## 8. Update Checklist Completion + +**PATCH** `/:taskId/checklist/:itemId` + +Updates the completion status of a specific checklist item. + +### Request Body + +```json +{ + "completed": true +} +``` + +### Response (200 OK) + +```json +{ + "message": "Checklist item updated", + "item": { + "_id": "65f95b2d3a1f34", + "text": "Run accessibility audit", + "completed": true + } +} +``` + +--- + +## Comment Structure + +A comment contains the following fields: + +```json +{ + "id": "65f96a1c2b3d44", + "text": "Looks good, approving now.", + "authorId": "65f93b8c9e9a2d52c3a421de", + "createdAt": "2025-01-22T10:15:00.000Z" +} +``` + + + +--- + +## 9. Add a Comment + +**POST** `/:taskId/comments` + +Adds a comment to a task. + +### Request Body + +```json +{ + "text": "Looks good, approving now." +} +``` + + + +### Response (201 Created) + +```json +{ + "id": "65f96a1c2b3d44", + "text": "Looks good, approving now.", + "authorId": "65f93b8c9e9a2d52c3a421de", + "createdAt": "2025-01-22T10:15:00.000Z" +} +``` + + + +--- + +## 10. List Comments + +**GET** `/:taskId/comments` + +Retrieves all comments on a task, oldest first. + +### Response (200 OK) + +```json +[ + { + "id": "65f96a1c2b3d44", + "text": "Looks good, approving now.", + "authorId": "65f93b8c9e9a2d52c3a421de", + "createdAt": "2025-01-22T10:15:00.000Z" + } +] +``` + +--- + +## 11. Delete a Comment + +**DELETE** `/:taskId/comments/:commentId` + +Deletes a comment. Only the comment's author or an Admin can delete it. + +### Response (200 OK) + +```json +{ + "message": "Comment deleted successfully" +} +``` + + + +### Response (403 Forbidden) + +```json +{ + "message": "Access denied, not authorized to delete this comment" +} +``` + + + +--- + + + +## Common Error Responses + +| Status | Meaning | +|--------|---------| +| 400 | Invalid input or missing required fields | +| 401 | Missing or invalid token | +| 403 | User does not have permission | +| 404 | Task not found | + +--- diff --git a/.claude/workspace/DOC-101/plan.md b/.claude/workspace/DOC-101/plan.md new file mode 100644 index 0000000..5b41237 --- /dev/null +++ b/.claude/workspace/DOC-101/plan.md @@ -0,0 +1,54 @@ +# Plan: DOC-101 + +## Doc type +Reference: the reader needs to look up an endpoint's method, path, auth/role requirement, and request/response shape before calling it — not learn a workflow or a concept. This matches the existing `docs/api/tasks.md` reference style (endpoint table + numbered sections), which the acceptance criteria explicitly require reusing. + +## File +* Path: `docs/api/tasks.md` +* Status: Update to existing file. The comments endpoints are sub-resources of a task (`/api/tasks/:taskId/comments`), so they belong in the same file as the rest of the Tasks API rather than a new page. No new file is created; no front matter changes (the file currently has no front matter block to preserve or alter, and none is being added since that's outside this ticket's scope). + +## Prerequisite knowledge +Same as the rest of `docs/api/tasks.md`: the reader already knows the JWT bearer-token auth model (`docs/api/authentication.md`) and the Admin/Member role model used throughout this file. No new prerequisite is introduced by comments. + +## Outline + +### Endpoints Overview table (update) +Purpose: Let a reader scanning the top-of-file table see the three new endpoints alongside existing task endpoints, consistent with how checklist endpoints are already listed there. +Content: Add three rows after the existing checklist rows: +* `POST /:taskId/comments` — Add a comment to a task — Yes — Admin / Member +* `GET /:taskId/comments` — List all comments on a task — Yes — Admin / Member +* `DELETE /:taskId/comments/:commentId` — Delete a comment — Yes — Author / Admin + +### Comment Structure (new subsection, mirrors "Task Structure") +Purpose: Give the reader a single reference for the comment object shape before it appears in three separate endpoint examples, matching how "Task Structure" precedes the numbered task sections. +Content: Fields per the ticket: `text`, `authorId`, `createdAt`, plus an identifier field. + + +### 9. Add a Comment +Purpose: Tell the reader how to post a new comment and what they get back. +Content: +* `POST` `/:taskId/comments` +* Auth: required. Role: Admin / Member +* Request body: `{ "text": string }` +* Response: 201 with created comment (`id`/`_id`? — see GAP above, `text`, `authorId`, `createdAt`) +* No documented 400 case in the ticket for missing/empty `text`. Existing task endpoints document 400 for invalid/missing fields (see "Common Error Responses"). + +### 10. List Comments +Purpose: Tell the reader how to retrieve all comments on a task and what order to expect. +Content: +* `GET` `/:taskId/comments` +* Auth: required. Role: Admin / Member +* Response: 200 with an array of comment objects, oldest first +* No request body + +### 11. Delete a Comment +Purpose: Tell the reader who is allowed to delete a comment and what happens when they're not. +Content: +* `DELETE` `/:taskId/comments/:commentId` +* Auth: required. Role: comment author or Admin only +* Response: 200 on success +* 403 if requester is neither the author nor an Admin + +### Common Error Responses (existing table, no changes planned) +Purpose: Keep the file's single shared error table authoritative rather than duplicating error rows per section. +Content: The existing 400/401/403/404 rows already cover the cases stated in the ticket (403 for the delete-permission case). No new status code is confirmed by the ticket, so no row is added. diff --git a/.claude/workspace/DOC-101/review.md b/.claude/workspace/DOC-101/review.md new file mode 100644 index 0000000..d5d627e --- /dev/null +++ b/.claude/workspace/DOC-101/review.md @@ -0,0 +1,41 @@ +# Review: DOC-101 + +File reviewed: `docs/api/tasks.md` + +No lint script exists at `.claude/skills/doc-review/scripts/lint.py` in this repo, so Step 1 (mechanical lint) was skipped. Findings below come from the qualitative pass (Step 2) plus targeted regex checks for the deterministic rules the linter would otherwise cover (em dashes, semicolons, bare demonstrative pronouns), and the clarity sub-agent check (Step 3). + +## Findings + +### All headings (file-wide, including new "Comment Structure" / "9. Add a Comment" / "10. List Comments" / "11. Delete a Comment"): Heading case + +Severity: Major +Confidence: Medium +Problem: CLAUDE.md states "Sentence case for all headings," but every heading in this file — including the eight pre-existing ones (`## Task Structure`, `## 1. Create a Task`, `## 7. Add Checklist Item`, etc.) and the four new ones added for this ticket — uses title case. The new headings match the file's existing (non-compliant) convention exactly, so this is not a regression introduced by this draft, but it is a real, file-wide style guide violation. Confidence is Medium rather than High because CLAUDE.md also prioritizes "Consistency with existing docs" and "Minimal diffs" above stylistic rewrites not explicitly requested — normalizing only the four new headings to sentence case would make them inconsistent with the eight surrounding ones, which arguably hurts scanability more than it helps. +Suggested rewrite: N/A for this ticket. If the writer wants this fixed, it should be a single follow-up pass across the whole file (all 12 headings), not a partial fix scoped to the new content. + +### Line 320: Em dash inside a VERIFY marker + +Severity: Minor +Confidence: High +Problem: `— confirm whether comments follow that pattern instead.` uses an em dash, which the style guide prohibits. This has zero reader impact since HTML comments don't render on the published site, but it's a literal style-guide violation in the source and a lint script would flag it. +Suggested rewrite: `...envelope. Confirm whether comments follow that pattern instead.` + +### Lines 289 and 307: Semicolons inside GAP markers + +Severity: Minor +Confidence: High +Problem: Both lines use a semicolon to join two clauses (`...per the source ticket; confirm whether...` and `...missing or empty text; the source ticket does not confirm...`), which the style guide prohibits. Same as above: invisible to readers, but present in source. +Suggested rewrite: Line 289: split into two sentences at the semicolon. Line 307: same. + +## Clarity sub-agent check + +A context-free sub-agent was given only the document text and asked three questions. Its answers: +1. What the doc helps you do: correctly identified it as Tasks API reference covering CRUD, progress, checklists, and comments, with request/response shapes, roles, and error codes. +2. Audience: correctly identified engineers integrating with the API programmatically. +3. First action: correctly identified checking your role (Admin/Member) and consulting the Endpoints Overview table to find the right endpoint. + +All three answers match the doc's actual purpose and structure. No confusion was introduced by the new comments content — no finding here. + +## Summary + +The new comments content (Comment Structure section, sections 9–11, and the three added table rows) is consistent with the existing file's terminology, tone, and structural pattern, and the clarity check confirms the page still reads clearly with the addition. Every issue found here is Minor except one file-wide heading-case violation that predates this draft and isn't safe to fix in isolation without a broader normalization pass. The single most impactful change available right now is stripping the em dash (line 320) and two semicolons (lines 289, 307) from the marker comments, since those are unambiguous, zero-risk fixes. Findings: 1 Major, 2 Minor, 0 Critical. diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6b88dfe --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +.claude/workspace merge=ours diff --git a/.github/styles/Google/AMPM.yml b/.github/styles/Google/AMPM.yml new file mode 100644 index 0000000..37b49ed --- /dev/null +++ b/.github/styles/Google/AMPM.yml @@ -0,0 +1,9 @@ +extends: existence +message: "Use 'AM' or 'PM' (preceded by a space)." +link: "https://developers.google.com/style/word-list" +level: error +nonword: true +tokens: + - '\d{1,2}[AP]M\b' + - '\d{1,2} ?[ap]m\b' + - '\d{1,2} ?[aApP]\.[mM]\.' diff --git a/.github/styles/Google/Acronyms.yml b/.github/styles/Google/Acronyms.yml new file mode 100644 index 0000000..f41af01 --- /dev/null +++ b/.github/styles/Google/Acronyms.yml @@ -0,0 +1,64 @@ +extends: conditional +message: "Spell out '%s', if it's unfamiliar to the audience." +link: 'https://developers.google.com/style/abbreviations' +level: suggestion +ignorecase: false +# Ensures that the existence of 'first' implies the existence of 'second'. +first: '\b([A-Z]{3,5})\b' +second: '(?:\b[A-Z][a-z]+ )+\(([A-Z]{3,5})\)' +# ... with the exception of these: +exceptions: + - API + - ASP + - CLI + - CPU + - CSS + - CSV + - DEBUG + - DOM + - DPI + - FAQ + - GCC + - GDB + - GET + - GPU + - GTK + - GUI + - HTML + - HTTP + - HTTPS + - IDE + - JAR + - JSON + - JSX + - LESS + - LLDB + - NET + - NOTE + - NVDA + - OSS + - PATH + - PDF + - PHP + - POST + - RAM + - REPL + - RSA + - SCM + - SCSS + - SDK + - SQL + - SSH + - SSL + - SVG + - TBD + - TCP + - TODO + - URI + - URL + - USB + - UTF + - XML + - XSS + - YAML + - ZIP diff --git a/.github/styles/Google/Colons.yml b/.github/styles/Google/Colons.yml new file mode 100644 index 0000000..4a027c3 --- /dev/null +++ b/.github/styles/Google/Colons.yml @@ -0,0 +1,8 @@ +extends: existence +message: "'%s' should be in lowercase." +link: 'https://developers.google.com/style/colons' +nonword: true +level: warning +scope: sentence +tokens: + - '(?=1.0.0" +} diff --git a/.github/styles/Google/vocab.txt b/.github/styles/Google/vocab.txt new file mode 100644 index 0000000..e69de29 diff --git a/.github/styles/Vocab/accept.txt b/.github/styles/Vocab/accept.txt new file mode 100644 index 0000000..a3d5b17 --- /dev/null +++ b/.github/styles/Vocab/accept.txt @@ -0,0 +1,3 @@ +Tasker +Docusaurus +webhooks diff --git a/.github/styles/WriteTechHub/AvoidTerms.yml b/.github/styles/WriteTechHub/AvoidTerms.yml new file mode 100644 index 0000000..93f9294 --- /dev/null +++ b/.github/styles/WriteTechHub/AvoidTerms.yml @@ -0,0 +1,10 @@ +extends: substitution +message: "Use '%s' instead of '%s'." +level: error +ignorecase: true +swap: + utilize: use + leverage: use + seamlessly: "" + robust: "" + unlock: "" diff --git a/.github/workflows/ai-review.yml b/.github/workflows/ai-review.yml index e25fcad..b46680d 100644 --- a/.github/workflows/ai-review.yml +++ b/.github/workflows/ai-review.yml @@ -15,6 +15,8 @@ jobs: permissions: contents: read pull-requests: write + id-token: write + steps: - uses: anthropics/claude-code-action@beta with: diff --git a/.github/workflows/docs-linting.yml b/.github/workflows/docs-linting.yml new file mode 100644 index 0000000..1360cab --- /dev/null +++ b/.github/workflows/docs-linting.yml @@ -0,0 +1,37 @@ +name: Docs linting + +on: + pull_request: + branches: + - main + - toyibat + +jobs: + prose-lint: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get changed Markdown files + run: | + MODIFIED_FILES=$(git diff --diff-filter=AM --name-only \ + "${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" \ + -- '*.md') + MODIFIED_FILES_CSV=$(echo "$MODIFIED_FILES" | paste -sd "," -) + echo "MODIFIED_FILES_CSV=$MODIFIED_FILES_CSV" >> $GITHUB_ENV + + - name: Vale + if: ${{ env.MODIFIED_FILES_CSV != '' }} + uses: vale-cli/vale-action@v2.1.1 + with: + separator: "," + files: ${{ env.MODIFIED_FILES_CSV }} + reporter: github-pr-review + filter_mode: diff_context + level: error + fail_on_error: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/remind-review.yml b/.github/workflows/remind-review.yml new file mode 100644 index 0000000..d04a0b9 --- /dev/null +++ b/.github/workflows/remind-review.yml @@ -0,0 +1,38 @@ +name: Remind to review agent instructions + +on: + pull_request: + types: [opened, synchronize] + paths: + - "README.md" + +jobs: + remind: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/github-script@v7 + with: + script: | + const labels = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + const alreadyLabeled = labels.data.some(l => l.name === 'review-agent-instructions'); + if (!alreadyLabeled) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ['review-agent-instructions'], + }); + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: 'This PR touches the style guide or howtos. Check whether AGENTS.md and related instruction files still match. Remove the `review-agent-instructions` label once checked.', + }); + } diff --git a/.vale.ini b/.vale.ini new file mode 100644 index 0000000..e54c13b --- /dev/null +++ b/.vale.ini @@ -0,0 +1,8 @@ +StylesPath = .github/styles + +MinAlertLevel = error + +Packages = Google + +[*.md] +BasedOnStyles = Google, WriteTechHub diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..764d95b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,84 @@ +# Task Manager API Documentation + +## What this project is +Developer-facing API documentation for the Task Manager API: authentication, task +CRUD, user roles/permissions, and reporting endpoints. Audience is engineers +integrating with the API. Content is built with Docusaurus and deployed to +task-manager-api-documentation.vercel.app. + +## Primary goals +When editing documentation, prioritize: +1. Accuracy +2. Clarity +3. Consistency with existing docs +4. Minimal diffs + +Do not introduce stylistic rewrites unless explicitly asked. +Prefer small targeted edits over large rewrites. + +## Repository structure +* `docs/api/`: API reference pages (authentication.md, tasks.md, users.md) +* `docs/intro.md`: landing page for the docs site +* `docs/assets/`: images referenced from doc pages +* `docs/config.md`: project/config reference +* `blog/`: release-notes / announcement style posts +* `src/`: Docusaurus site source (theme, components) — not documentation content +* `tests/` and `.doc-detective/tests/`: Doc Detective test specs that validate + documented behavior against the live API/UI +* `.github/workflows/`: existing CI — `agent-docs.yml` (agent-friendliness check) + and `doc-detective.yml` (doc behavior tests). Do not duplicate these; new CI + added by this pipeline (Vale linting, PR quality summaries) is additive. + +## Writing style rules +* Sentence case for all headings +* Keep the existing table-heavy reference style for endpoint docs (Method / + Endpoint / Description / Auth Required / Role) — don't convert to prose +* Ordered lists: use 1. for every item, not sequential numbers +* No bare demonstrative pronouns: "The endpoint returns..." not "This returns..." +* No marketing language: avoid powerful, seamless, robust, unlock, leverage +* Do not use "utilize" — use "use" +* Do not use "allows you to" / "enables you to" — use direct action language + ("Creates a new task", not "This endpoint allows you to create a new task") + +> These are starting defaults inferred from the existing docs. Replace with your +> team's actual style guide once you have one — see 03-editor-prompts.md for +> where these rules also get enforced inline. + +## Front matter +Docusaurus front matter: `id`, `title`, `sidebar_position` (see `docs/intro.md` +for the pattern). Every page needs `id` and `title`. Do not remove or reorder +front matter fields. The agent may update `title` or `sidebar_position` only if +explicitly asked. + +## Special syntax +* Every doc page opens with this fixed callout — preserve it verbatim, do not + edit or remove it when drafting or reviewing: + ``` + > **For AI agents:** A complete documentation index is available at + [`/llms.txt`](https://task-manager-api-documentation.vercel.app/llms.txt). + Markdown versions of all pages are available by appending `.md` to any URL. + ``` +* Images are referenced with relative paths into `docs/assets/` + (e.g. `![Postman Sample](../assets/image-one.jpg)`) — keep this pattern for + new screenshots rather than absolute URLs. + +## What the agent may do without being asked +* Fix typos and grammar errors +* Apply the style rules listed above +* Normalize heading case to sentence case +* Keep the "For AI agents" callout and `llms.txt` reference intact when editing + a page + +## What the agent must not do without being asked +* Change endpoint paths, HTTP methods, parameter names, or response shapes +* Modify code/JSON examples +* Rewrite large sections or restructure a page's flow +* Remove or reorder front matter fields +* Add or remove Doc Detective test specs in `tests/` or `.doc-detective/tests/` + +## When uncertain +If product behavior is unclear from the source material, insert: +`` + +If information is missing and the doc cannot be completed without it: +`` diff --git a/README.md b/README.md index b28211a..26246f6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Website -This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. +This website is built using [Docusaurus](https://docusaurus.io/), which is a modern static website generator. ## Installation diff --git a/docs/api/tasks.md b/docs/api/tasks.md index 99b22be..5b8dbb5 100644 --- a/docs/api/tasks.md +++ b/docs/api/tasks.md @@ -33,6 +33,11 @@ Both **Admin** and **Member** roles can interact with tasks, but access levels d | PATCH | `/:taskId/progress` | Update task progress (0–100%) | Yes | Admin / Member (if assigned) | | POST | `/:taskId/checklist` | Add a checklist item | Yes | Admin / Member (if assigned) | | PATCH | `/:taskId/checklist/:itemId` | Update a checklist item's completion state | Yes | Admin / Member (if assigned) | +| POST | `/:taskId/comments` | Add a comment to a task | Yes | Admin / Member | +| GET | `/:taskId/comments` | List all comments on a task | Yes | Admin / Member | +| DELETE | `/:taskId/comments/:commentId` | Delete a comment | Yes | Admin / Member (if author) | + + --- @@ -268,6 +273,105 @@ Updates the completion status of a specific checklist item. --- +## Comment Structure + +A comment contains the following fields: + +```json +{ + "id": "65f96a1c2b3d44", + "text": "Looks good, approving now.", + "authorId": "65f93b8c9e9a2d52c3a421de", + "createdAt": "2025-01-22T10:15:00.000Z" +} +``` + + + +--- + +## 9. Add a Comment + +**POST** `/:taskId/comments` + +Adds a comment to a task. + +### Request Body + +```json +{ + "text": "Looks good, approving now." +} +``` + + + +### Response (201 Created) + +```json +{ + "id": "65f96a1c2b3d44", + "text": "Looks good, approving now.", + "authorId": "65f93b8c9e9a2d52c3a421de", + "createdAt": "2025-01-22T10:15:00.000Z" +} +``` + + + +--- + +## 10. List Comments + +**GET** `/:taskId/comments` + +Retrieves all comments on a task, oldest first. + +### Response (200 OK) + +```json +[ + { + "id": "65f96a1c2b3d44", + "text": "Looks good, approving now.", + "authorId": "65f93b8c9e9a2d52c3a421de", + "createdAt": "2025-01-22T10:15:00.000Z" + } +] +``` + +--- + +## 11. Delete a Comment + +**DELETE** `/:taskId/comments/:commentId` + +Deletes a comment. Only the comment's author or an Admin can delete it. + +### Response (200 OK) + +```json +{ + "message": "Comment deleted successfully" +} +``` + + + +### Response (403 Forbidden) + +```json +{ + "message": "Access denied, not authorized to delete this comment" +} +``` + + + +--- + + + ## Common Error Responses | Status | Meaning | diff --git a/scratch/content/Fr/intro.md b/scratch/content/Fr/intro.md new file mode 100644 index 0000000..7d31b41 --- /dev/null +++ b/scratch/content/Fr/intro.md @@ -0,0 +1,20 @@ +--- +id: intro +title: Bienvenue +sidebar_position: 1 +--- + +> **Pour les agents IA :** Un index complet de la documentation est disponible à [`/llms.txt`](https://task-manager-api-documentation.vercel.app/llms.txt). Des versions Markdown de toutes les pages sont disponibles en ajoutant `.md` à n'importe quelle URL. + +# Bienvenue dans la documentation de la Task Manager API + +Cette documentation vous aide à comprendre, intégrer et tester la **Task Manager API**, qui alimente les fonctionnalités d'authentification, de suivi des tâches, de rôles utilisateurs et de rapports. + +Vous pouvez explorer : + +- **Authentification** – Découvrez comment vous inscrire, vous connecter et sécuriser les requêtes. +- **Tâches** – Gérez les tâches avec des opérations CRUD, des priorités et un suivi de la progression. +- **Utilisateurs** – Comprenez les rôles et les permissions des utilisateurs. +- **Rapports** – Accédez aux points de terminaison de synthèse et d'analyse. + +👉 Commencez par consulter la section [Authentication API](./api/authentication). \ No newline at end of file diff --git a/scratch/content/en/intro.md b/scratch/content/en/intro.md new file mode 100644 index 0000000..663e42c --- /dev/null +++ b/scratch/content/en/intro.md @@ -0,0 +1,20 @@ +--- +id: intro +title: Welcome +sidebar_position: 1 +--- + +> **For AI agents:** A complete documentation index is available at [`/llms.txt`](https://task-manager-api-documentation.vercel.app/llms.txt). Markdown versions of all pages are available by appending `.md` to any URL. + +# Welcome to the Task Manager API Documentation + +This documentation helps you understand, integrate, and test the **Task Manager API**, which powers authentication, task tracking, user roles, and reporting features. + +You can explore: + +- **Authentication** – Learn how to register, log in, and secure requests. +- **Tasks** – Manage tasks with CRUD operations, priorities, and progress tracking. +- **Users** – Understand user roles and permissions. +- **Reports** – Access summary and analytics endpoints. + +👉 Start by checking the [Authentication API](./api/authentication) section. \ No newline at end of file diff --git a/scratch/content/ja/intro.md b/scratch/content/ja/intro.md new file mode 100644 index 0000000..65b1b36 --- /dev/null +++ b/scratch/content/ja/intro.md @@ -0,0 +1,20 @@ +--- +id: intro +title: ようこそ +sidebar_position: 1 +--- + +> **AIエージェント向け:** 完全なドキュメントインデックスは [`/llms.txt`](https://task-manager-api-documentation.vercel.app/llms.txt) でご覧いただけます。すべてのページのMarkdown版は、任意のURLに `.md` を追加することで利用できます。 + +# Task Manager API ドキュメントへようこそ + +このドキュメントは、認証、タスク管理、ユーザーロール、レポート機能を実現する **Task Manager API** の理解、統合、テストをサポートします。 + +以下の内容をご覧いただけます: + +- **Authentication** – 登録、ログイン、リクエストの保護方法について学びます。 +- **Tasks** – CRUD操作、優先度、進捗管理を用いたタスクの管理方法。 +- **Users** – ユーザーロールと権限について理解します。 +- **Reports** – サマリーおよび分析用エンドポイントへのアクセス。 + +👉 まずは [Authentication API](./api/authentication) セクションをご確認ください。 \ No newline at end of file diff --git a/scripts/translate/requirements.txt b/scripts/translate/requirements.txt new file mode 100644 index 0000000..8bdc4fa --- /dev/null +++ b/scripts/translate/requirements.txt @@ -0,0 +1,3 @@ +anthropic>=0.34.0 +tiktoken +pyyaml diff --git a/scripts/translate/translate.py b/scripts/translate/translate.py new file mode 100644 index 0000000..b89970d --- /dev/null +++ b/scripts/translate/translate.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python3 +""" +translate.py — AI documentation translation (Anthropic Claude version). + +Usage: + Translate changed files: python translate.py -c content/en/ + Translate new files: python translate.py -n content/en/ + Both: python translate.py -c -n content/en/ + Single file: python translate.py content/en/guides/rate-limiting.md + List only (test mode): python translate.py -t -c content/en/ +""" + +import os +import sys +import re +import csv +import argparse +import subprocess +from pathlib import Path +from anthropic import Anthropic + +# --- Configuration --- +SOURCE_LANG_DIR = "en" +TARGET_LANG_DIR = "ja" +TARGET_LANGUAGE = "Japanese" +MODEL = "claude-sonnet-5" +MAX_CHUNK_SIZE = 8192 + +PRESERVE_TERMS = ["API", "SDK", "OAuth", "webhook", "ID", "UUID", "REST", "JSON", "CLI"] +SKIP_DIRS = ["/misc", "/archive", "/drafts"] + +client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"], timeout=500) + + +# --- Change detection (git commit date comparison) --- + +def get_last_commit_date(file_path): + """Return epoch timestamp of the last commit touching this file.""" + result = subprocess.run( + ["git", "log", "-1", "--format=%ct", file_path], + capture_output=True, text=True + ) + if result.returncode == 0 and result.stdout.strip(): + return result.stdout.strip() + return None + + +def is_source_newer(source_path, target_path): + """True if source has a newer commit than target.""" + source_date = get_last_commit_date(source_path) + target_date = get_last_commit_date(target_path) + if source_date and target_date: + return source_date >= target_date + return True + + +def is_draft(file_path): + """True if the file has draft: true in front matter.""" + result = subprocess.run( + ["grep", "-q", "draft: true", file_path], + capture_output=True, text=True + ) + return result.returncode == 0 + + +def get_files_to_translate(source_dir, new_files=False, changed_files=False): + """Return list of source files that need translation.""" + files = [] + for root, dirs, filenames in os.walk(source_dir): + if any(skip in root for skip in SKIP_DIRS): + continue + for filename in filenames: + if not filename.endswith(".md"): + continue + source_path = os.path.join(root, filename).replace(os.sep, "/") + target_path = source_path.replace(f"{SOURCE_LANG_DIR}/", f"{TARGET_LANG_DIR}/") + target_exists = os.path.isfile(target_path) + + if is_draft(source_path): + continue + if not new_files and not changed_files: + files.append(source_path) + continue + if changed_files and (not target_exists or is_source_newer(source_path, target_path)): + files.append(source_path) + continue + if new_files and not target_exists: + files.append(source_path) + return files + + +# --- Chunking (split large files at heading boundaries) --- + +def chunk_content(content): + """Split content into chunks at heading boundaries.""" + chunks = [] + while len(content) > MAX_CHUNK_SIZE: + last_heading = 0 + for match in re.finditer(r"\n#{2,5} ", content[:MAX_CHUNK_SIZE]): + last_heading = match.start() + last_newline = content[:MAX_CHUNK_SIZE].rfind("\n") + split_point = last_heading if last_heading != 0 else last_newline + if split_point <= 0: + split_point = MAX_CHUNK_SIZE + chunks.append(content[:split_point + 1]) + content = content[split_point:] + chunks.append(content) + return chunks + + +# --- Translation --- + +def translate_chunk(chunk, target_language): + """Translate one chunk of Markdown via the AI API.""" + preserve_note = "" + if PRESERVE_TERMS: + preserve_note = f"Do not translate these terms, keep them in English: {', '.join(PRESERVE_TERMS)}." + + system_message = f"""You are a technical documentation translator from English to {target_language}. +Rules: +1. Preserve all Markdown formatting exactly: headings, lists, code blocks, bold, italic, links. +2. Do not translate content inside code blocks (``` or `). +3. In front matter (between --- delimiters), only translate values for 'title', 'linktitle', and 'description'. Do not translate field names, slugs, dates, or other metadata. +4. Do not translate URLs, file paths, or shortcode syntax (content inside {{{{ }}}}). +5. {preserve_note} +6. Maintain the same line structure and paragraph breaks. +7. Produce accurate, natural {target_language} technical writing.""" + + response = client.messages.create( + model=MODEL, + max_tokens=8192, + system=system_message, + messages=[{"role": "user", "content": chunk}] + ) + return next(block.text for block in response.content if block.type == "text") + + +def translate_file(source_path): + """Translate a full file, chunking if needed.""" + with open(source_path, "r", encoding="utf-8") as f: + content = f.read() + chunks = chunk_content(content) + translated = [] + for chunk in chunks: + translated.append(translate_chunk(chunk, TARGET_LANGUAGE)) + return "\n".join(translated) + + +# --- Post-processing --- + +def fix_internal_links(content, lang_prefix): + """Add language prefix to internal Markdown links.""" + link_pattern = re.compile(r'\[(.*?)\]\((/[^)]*)\)') + skip_extensions = ('.png', '.jpg', '.gif', '.jpeg', '.tgz', '.zip') + + def replace_link(match): + text = match.group(1) + url = match.group(2) + if url.startswith(f"/{lang_prefix}") or url.endswith(skip_extensions): + return match.group(0) + return f"[{text}](/{lang_prefix}{url})" + + return link_pattern.sub(replace_link, content) + + +def apply_word_fixes(content, csv_path): + """Apply terminology corrections from a word-fix CSV.""" + if not os.path.isfile(csv_path): + return content + with open(csv_path, "r", newline="") as f: + reader = csv.DictReader(f) + for row in reader: + if row.get("dst_old") and row.get("dst_new"): + content = content.replace(row["dst_old"], row["dst_new"]) + return content + + +# --- Main --- + +def main(): + parser = argparse.ArgumentParser(description="Translate documentation.") + parser.add_argument("source", help="Source file or directory") + parser.add_argument("-n", "--new", action="store_true", help="Only new files") + parser.add_argument("-c", "--changed", action="store_true", help="Only changed files") + parser.add_argument("-t", "--test", action="store_true", help="List files only") + args = parser.parse_args() + args.source = args.source.replace(os.sep, "/") + + if f"{SOURCE_LANG_DIR}/" not in args.source: + print(f"Source path must contain '{SOURCE_LANG_DIR}/'") + sys.exit(1) + + if os.path.isfile(args.source): + files = [args.source] + elif os.path.isdir(args.source): + files = get_files_to_translate(args.source, new_files=args.new, changed_files=args.changed) + else: + print("Source must be a file or directory") + sys.exit(1) + + if not files: + print("No files to translate.") + sys.exit(0) + + print(f"Files to translate: {len(files)}") + if args.test: + for f in files: + print(f" {f}") + sys.exit(0) + + # Word-fix CSV path (adjust for your repo) + word_fix_csv = os.path.join(os.path.dirname(__file__), f"en-{TARGET_LANG_DIR}.csv") + + success = 0 + for source_path in files: + print(f" {source_path}") + try: + translated = translate_file(source_path) + if translated: + # Post-process + translated = fix_internal_links(translated, TARGET_LANG_DIR) + translated = apply_word_fixes(translated, word_fix_csv) + + # Write to target + target_path = source_path.replace(f"{SOURCE_LANG_DIR}/", f"{TARGET_LANG_DIR}/") + os.makedirs(os.path.dirname(target_path), exist_ok=True) + with open(target_path, "w", encoding="utf-8") as f: + f.write(translated) + success += 1 + except Exception as e: + print(f" Failed: {e}") + + print(f"\nTranslated: {success}/{len(files)}") + + +if __name__ == "__main__": + main() diff --git a/vale-test.md b/vale-test.md new file mode 100644 index 0000000..f1f0118 --- /dev/null +++ b/vale-test.md @@ -0,0 +1 @@ +You can utilize this endpoint to leverage your data.