knowns 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3313,10 +3313,10 @@ var require_stringify = __commonJS({
3313
3313
  data = Object.assign({}, file3.data, data);
3314
3314
  const open = opts.delimiters[0];
3315
3315
  const close = opts.delimiters[1];
3316
- const matter9 = engine.stringify(data, options2).trim();
3316
+ const matter10 = engine.stringify(data, options2).trim();
3317
3317
  let buf = "";
3318
- if (matter9 !== "{}") {
3319
- buf = newline(open) + newline(matter9) + newline(close);
3318
+ if (matter10 !== "{}") {
3319
+ buf = newline(open) + newline(matter10) + newline(close);
3320
3320
  }
3321
3321
  if (typeof file3.excerpt === "string" && file3.excerpt !== "") {
3322
3322
  if (str2.indexOf(file3.excerpt.trim()) === -1) {
@@ -3422,19 +3422,19 @@ var require_gray_matter = __commonJS({
3422
3422
  var toFile = require_to_file();
3423
3423
  var parse4 = require_parse();
3424
3424
  var utils = require_utils();
3425
- function matter9(input, options2) {
3425
+ function matter10(input, options2) {
3426
3426
  if (input === "") {
3427
3427
  return { data: {}, content: input, excerpt: "", orig: input };
3428
3428
  }
3429
3429
  let file3 = toFile(input);
3430
- const cached2 = matter9.cache[file3.content];
3430
+ const cached2 = matter10.cache[file3.content];
3431
3431
  if (!options2) {
3432
3432
  if (cached2) {
3433
3433
  file3 = Object.assign({}, cached2);
3434
3434
  file3.orig = cached2.orig;
3435
3435
  return file3;
3436
3436
  }
3437
- matter9.cache[file3.content] = file3;
3437
+ matter10.cache[file3.content] = file3;
3438
3438
  }
3439
3439
  return parseMatter(file3, options2);
3440
3440
  }
@@ -3456,7 +3456,7 @@ var require_gray_matter = __commonJS({
3456
3456
  }
3457
3457
  str2 = str2.slice(openLen);
3458
3458
  const len = str2.length;
3459
- const language = matter9.language(str2, opts);
3459
+ const language = matter10.language(str2, opts);
3460
3460
  if (language.name) {
3461
3461
  file3.language = language.name;
3462
3462
  str2 = str2.slice(language.raw.length);
@@ -3491,24 +3491,24 @@ var require_gray_matter = __commonJS({
3491
3491
  }
3492
3492
  return file3;
3493
3493
  }
3494
- matter9.engines = engines2;
3495
- matter9.stringify = function(file3, data, options2) {
3496
- if (typeof file3 === "string") file3 = matter9(file3, options2);
3494
+ matter10.engines = engines2;
3495
+ matter10.stringify = function(file3, data, options2) {
3496
+ if (typeof file3 === "string") file3 = matter10(file3, options2);
3497
3497
  return stringify(file3, data, options2);
3498
3498
  };
3499
- matter9.read = function(filepath, options2) {
3499
+ matter10.read = function(filepath, options2) {
3500
3500
  const str2 = fs.readFileSync(filepath, "utf8");
3501
- const file3 = matter9(str2, options2);
3501
+ const file3 = matter10(str2, options2);
3502
3502
  file3.path = filepath;
3503
3503
  return file3;
3504
3504
  };
3505
- matter9.test = function(str2, options2) {
3505
+ matter10.test = function(str2, options2) {
3506
3506
  return utils.startsWith(str2, defaults(options2).delimiters[0]);
3507
3507
  };
3508
- matter9.language = function(str2, options2) {
3508
+ matter10.language = function(str2, options2) {
3509
3509
  const opts = defaults(options2);
3510
3510
  const open = opts.delimiters[0];
3511
- if (matter9.test(str2)) {
3511
+ if (matter10.test(str2)) {
3512
3512
  str2 = str2.slice(open.length);
3513
3513
  }
3514
3514
  const language = str2.slice(0, str2.search(/\r?\n/));
@@ -3517,11 +3517,11 @@ var require_gray_matter = __commonJS({
3517
3517
  name: language ? language.trim() : ""
3518
3518
  };
3519
3519
  };
3520
- matter9.cache = {};
3521
- matter9.clearCache = function() {
3522
- matter9.cache = {};
3520
+ matter10.cache = {};
3521
+ matter10.clearCache = function() {
3522
+ matter10.cache = {};
3523
3523
  };
3524
- module2.exports = matter9;
3524
+ module2.exports = matter10;
3525
3525
  }
3526
3526
  });
3527
3527
 
@@ -46167,6 +46167,22 @@ var FileStore = class {
46167
46167
  return null;
46168
46168
  }
46169
46169
  }
46170
+ /**
46171
+ * Skipped files due to parse errors (for graceful degradation)
46172
+ */
46173
+ skippedFiles = [];
46174
+ /**
46175
+ * Get list of skipped files from last load
46176
+ */
46177
+ getSkippedFiles() {
46178
+ return this.skippedFiles;
46179
+ }
46180
+ /**
46181
+ * Clear skipped files list
46182
+ */
46183
+ clearSkippedFiles() {
46184
+ this.skippedFiles = [];
46185
+ }
46170
46186
  /**
46171
46187
  * Get all tasks
46172
46188
  */
@@ -46175,24 +46191,42 @@ var FileStore = class {
46175
46191
  const files = await readdir(this.tasksPath);
46176
46192
  const taskFiles = files.filter((f) => f.startsWith("task-") && f.endsWith(".md"));
46177
46193
  const allTimeEntries = await this.loadTimeEntries();
46194
+ this.skippedFiles = [];
46178
46195
  const tasksMap = /* @__PURE__ */ new Map();
46179
46196
  for (const taskFile of taskFiles) {
46180
- const filePath = join2(this.tasksPath, taskFile);
46181
- const content = await file(filePath).text();
46182
- const taskData = parseTaskMarkdown(content);
46183
- if (taskData.id) {
46184
- const timeEntries = (allTimeEntries[taskData.id] || []).map((e) => ({
46185
- ...e,
46186
- startedAt: new Date(e.startedAt),
46187
- endedAt: e.endedAt ? new Date(e.endedAt) : void 0
46188
- }));
46189
- tasksMap.set(taskData.id, {
46190
- ...taskData,
46191
- subtasks: [],
46192
- timeEntries
46197
+ try {
46198
+ const filePath = join2(this.tasksPath, taskFile);
46199
+ const content = await file(filePath).text();
46200
+ const taskData = parseTaskMarkdown(content);
46201
+ if (taskData.id) {
46202
+ const timeEntries = (allTimeEntries[taskData.id] || []).map((e) => ({
46203
+ ...e,
46204
+ startedAt: new Date(e.startedAt),
46205
+ endedAt: e.endedAt ? new Date(e.endedAt) : void 0
46206
+ }));
46207
+ tasksMap.set(taskData.id, {
46208
+ ...taskData,
46209
+ subtasks: [],
46210
+ timeEntries
46211
+ });
46212
+ } else {
46213
+ this.skippedFiles.push({
46214
+ file: taskFile,
46215
+ error: "Missing task ID in frontmatter"
46216
+ });
46217
+ }
46218
+ } catch (parseError) {
46219
+ this.skippedFiles.push({
46220
+ file: taskFile,
46221
+ error: parseError instanceof Error ? parseError.message : String(parseError)
46193
46222
  });
46194
46223
  }
46195
46224
  }
46225
+ if (this.skippedFiles.length > 0) {
46226
+ console.warn(
46227
+ `\u26A0 Skipped ${this.skippedFiles.length} corrupted task file(s). Run "knowns task validate <id>" or "knowns task repair <id>" to fix.`
46228
+ );
46229
+ }
46196
46230
  for (const task of tasksMap.values()) {
46197
46231
  const subtasks = [];
46198
46232
  for (const otherTask of tasksMap.values()) {
@@ -46953,17 +46987,25 @@ var {
46953
46987
  // src/commands/init.ts
46954
46988
  var import_prompts2 = __toESM(require_prompts3(), 1);
46955
46989
 
46956
- // src/templates/knowns-guidelines-cli.md
46957
- var knowns_guidelines_cli_default = '<!-- KNOWNS GUIDELINES START -->\n# Knowns CLI Guidelines\n\n## Core Principles\n\n### 1. CLI-Only Operations\n**NEVER edit .md files directly. ALL operations MUST use CLI commands.**\n\nThis ensures data integrity, maintains proper change history, and prevents file corruption.\n\n### 2. Documentation-First (For AI Agents)\n**ALWAYS read project documentation BEFORE planning or coding.**\n\nAI agents must understand project context, conventions, and existing patterns before making any changes. This prevents rework and ensures consistency.\n\n---\n\n## AI Agent Guidelines\n\n> **CRITICAL**: Before performing ANY task, AI agents MUST read documentation to understand project context.\n\n### First-Time Initialization\n\nWhen starting a new session or working on an unfamiliar project:\n\n```bash\n# 1. List all available documentation\nknowns doc list --plain\n\n# 2. Read essential project docs (prioritize these)\nknowns doc "README" --plain # Project overview\nknowns doc "ARCHITECTURE" --plain # System design\nknowns doc "CONVENTIONS" --plain # Coding standards\nknowns doc "API" --plain # API specifications\n\n# 3. Review current task backlog\nknowns task list --plain\nknowns task list --status in-progress --plain\n```\n\n### Before Taking Any Task\n\n```bash\n# 1. View the task details\nknowns task <id> --plain\n\n# 2. Follow ALL refs in the task (see Reference System section)\n# @.knowns/tasks/task-44 - ... \u2192 knowns task 44 --plain\n# @.knowns/docs/patterns/module.md \u2192 knowns doc "patterns/module" --plain\n\n# 3. Search for additional related documentation\nknowns search "<keywords from task>" --type doc --plain\n\n# 4. Read ALL related docs before planning\nknowns doc "<related-doc>" --plain\n\n# 5. Check for similar completed tasks (learn from history)\nknowns search "<keywords>" --type task --status done --plain\n```\n\n### Why Documentation First?\n\n| Without Reading Docs | With Reading Docs |\n|---------------------|-------------------|\n| Reinvent existing patterns | Reuse established patterns |\n| Break conventions | Follow project standards |\n| Duplicate code | Use existing utilities |\n| Wrong architecture decisions | Align with system design |\n| Inconsistent naming | Match naming conventions |\n\n### Context Checklist for Agents\n\nBefore writing ANY code, ensure you can answer:\n\n- [ ] Have I followed ALL refs (`@.knowns/...`) in the task?\n- [ ] Have I followed nested refs recursively?\n- [ ] What is the project\'s overall architecture?\n- [ ] What coding conventions does this project follow?\n- [ ] Are there existing patterns/utilities I should reuse?\n- [ ] What are the testing requirements?\n- [ ] How should I structure my implementation?\n\n> **Remember**: A few minutes reading docs saves hours of rework. NEVER skip this step.\n\n---\n\n## Reference System (Refs)\n\nTasks and docs can contain **references** to other tasks/docs. AI agents MUST understand and follow these refs to gather complete context.\n\n### Reference Formats\n\n| Type | When Writing (Input) | When Reading (Output) | CLI Command |\n|------|---------------------|----------------------|-------------|\n| **Task ref** | `@task-<id>` | `@.knowns/tasks/task-<id> - <title>.md` | `knowns task <id> --plain` |\n| **Doc ref** | `@doc/<path>` | `@.knowns/docs/<path>.md` | `knowns doc <path> --plain` |\n\n> **CRITICAL for AI Agents**:\n> - When **WRITING** refs (in descriptions, plans, notes): Use `@task-<id>` and `@doc/<path>`\n> - When **READING** output from `--plain`: You\'ll see `@.knowns/tasks/...` and `@.knowns/docs/...`\n> - **NEVER write** the output format (`@.knowns/...`) - always use input format (`@task-<id>`, `@doc/<path>`)\n\n### How to Follow Refs\n\nWhen you read a task and see refs in system output format, follow them:\n\n```bash\n# Example: Task 42 output contains:\n# @.knowns/tasks/task-44 - CLI Task Create Command.md\n# @.knowns/docs/patterns/module.md\n\n# Follow task ref (extract ID from task-<id>)\nknowns task 44 --plain\n\n# Follow doc ref (extract path, remove .md)\nknowns doc "patterns/module" --plain\n```\n\n### Parsing Rules\n\n1. **Task refs**: `@.knowns/tasks/task-<id> - ...` \u2192 extract `<id>` \u2192 `knowns task <id> --plain`\n2. **Doc refs**: `@.knowns/docs/<path>.md` \u2192 extract `<path>` \u2192 `knowns doc "<path>" --plain`\n\n### Recursive Following\n\nRefs can be nested. Follow until complete context is gathered:\n\n```\nTask 42\n \u2192 @.knowns/docs/README.md\n \u2192 @.knowns/docs/patterns/module.md (found in README)\n \u2192 (read for full pattern details)\n```\n\n### When to Follow Refs\n\n| Situation | Action |\n|-----------|--------|\n| Refs in Description | ALWAYS follow - critical context |\n| Refs in Implementation Plan | Follow if implementing related work |\n| Refs in Notes | Optional - for historical context |\n| Dependency mentions | Follow if marked as blocker |\n\n### Example: Complete Ref Resolution\n\n```bash\n# 1. Read the task\n$ knowns task 42 --plain\n\n# Output contains:\n# @.knowns/tasks/task-44 - CLI Task Create Command.md\n# @.knowns/docs/README.md\n\n# 2. Follow task ref\n$ knowns task 44 --plain\n\n# 3. Follow doc ref\n$ knowns doc "README" --plain\n\n# 4. If README contains more refs, follow them too\n# @.knowns/docs/patterns/module.md \u2192 knowns doc "patterns/module" --plain\n\n# Now you have complete context\n```\n\n> **CRITICAL**: Never assume you understand a task fully without following its refs. Refs contain essential context that may change your implementation approach.\n\n---\n\n## Quick Start\n\n```bash\n# Initialize project\nknowns init [name]\n\n# Create task with acceptance criteria\nknowns task create "Title" -d "Description" --ac "Criterion 1" --ac "Criterion 2"\n\n# View task (ALWAYS use --plain for AI)\nknowns task <id> --plain # Shorthand\nknowns task view <id> --plain # Full command\n\n# View doc (ALWAYS use --plain for AI)\nknowns doc <path> --plain # Shorthand\nknowns doc view "<path>" --plain # Full command\n\n# List tasks\nknowns task list --plain\n\n# Search (tasks + docs)\nknowns search "query" --plain\n```\n\n---\n\n## End-to-End Example\n\nHere\'s a complete workflow for an AI agent implementing a feature:\n\n```bash\n# === AGENT SESSION START (Do this once per session) ===\n\n# 0a. List all available documentation\n$ knowns doc list --plain\n\n# Output:\n# DOC: README.md\n# DOC: ARCHITECTURE.md\n# DOC: CONVENTIONS.md\n# DOC: security-patterns.md\n# DOC: api-guidelines.md\n# DOC: email-templates.md\n\n# 0b. Read essential project docs\n$ knowns doc "README" --plain\n$ knowns doc "ARCHITECTURE" --plain\n$ knowns doc "CONVENTIONS" --plain\n\n# Now the agent understands project context and conventions\n\n# === TASK WORKFLOW ===\n\n# 1. Create the task\n$ knowns task create "Add password reset flow" \\\n -d "Users need ability to reset forgotten passwords via email" \\\n --ac "User can request password reset via email" \\\n --ac "Reset link expires after 1 hour" \\\n --ac "User can set new password via reset link" \\\n --ac "Unit tests cover all scenarios" \\\n --priority high \\\n -l "auth,feature"\n\n# Output: Created task AUTH-042\n\n# 2. Take the task and start timer (uses defaultAssignee or @me fallback)\n$ knowns task edit AUTH-042 -s in-progress -a $(knowns config get defaultAssignee --plain || echo "@me")\n$ knowns time start AUTH-042\n\n# Output: Timer started for AUTH-042\n\n# 3. Search for related documentation\n$ knowns search "password security" --type doc --plain\n\n# Output:\n# DOC: security-patterns.md (score: 0.92)\n# DOC: email-templates.md (score: 0.78)\n\n# 4. Read the documentation\n$ knowns doc "security-patterns" --plain\n\n# 5. Create implementation plan (SHARE WITH USER, WAIT FOR APPROVAL)\n$ knowns task edit AUTH-042 --plan $\'1. Review security patterns (see @doc/security-patterns)\n2. Design token generation with 1-hour expiry\n3. Create email template (see @doc/email-templates)\n4. Implement /forgot-password endpoint\n5. Implement /reset-password endpoint\n6. Add unit tests\n7. Update API documentation\'\n\n# 6. After approval, implement and check criteria as you go\n$ knowns task edit AUTH-042 --check-ac 1\n$ knowns task edit AUTH-042 --append-notes "\u2713 Implemented /forgot-password endpoint"\n\n$ knowns task edit AUTH-042 --check-ac 2\n$ knowns task edit AUTH-042 --append-notes "\u2713 Token expiry set to 1 hour"\n\n$ knowns task edit AUTH-042 --check-ac 3\n$ knowns task edit AUTH-042 --append-notes "\u2713 Implemented /reset-password endpoint"\n\n$ knowns task edit AUTH-042 --check-ac 4\n$ knowns task edit AUTH-042 --append-notes "\u2713 Added 12 unit tests, 100% coverage"\n\n# 7. Add final implementation notes\n$ knowns task edit AUTH-042 --notes $\'## Summary\nImplemented complete password reset flow with secure token generation.\n\n## Changes\n- Added POST /forgot-password endpoint\n- Added POST /reset-password endpoint\n- Created password_reset_tokens table\n- Added email template for reset link\n\n## Security\n- Tokens use crypto.randomBytes(32)\n- 1-hour expiry enforced at DB level\n- Rate limiting: 3 requests per hour per email\n\n## Tests\n- 12 unit tests added\n- Coverage: 100% for new code\n\n## Documentation\n- Updated API.md with new endpoints\'\n\n# 8. Stop timer and complete\n$ knowns time stop\n$ knowns task edit AUTH-042 -s done\n\n# Output: Task AUTH-042 marked as done\n```\n\n---\n\n## Task Workflow\n\n### Step 1: Take Task\n\n```bash\n# Assign using defaultAssignee from config (falls back to @me if not set)\nknowns task edit <id> -s in-progress -a $(knowns config get defaultAssignee --plain || echo "@me")\n```\n\n> **Note**: The `defaultAssignee` is configured in `.knowns/config.json` during `knowns init`. If not set, `@me` is used as fallback. To update: `knowns config set defaultAssignee "@username"`\n\n### Step 2: Start Time Tracking (REQUIRED)\n\n```bash\nknowns time start <id>\n```\n\n> **CRITICAL**: Time tracking is MANDATORY. Always start timer when taking a task and stop when done. This data is essential for:\n> - Accurate project estimation\n> - Identifying bottlenecks\n> - Resource planning\n> - Sprint retrospectives\n\n### Step 3: Read Related Documentation\n\n> **FOR AI AGENTS**: This step is MANDATORY, not optional. You must understand the codebase before planning.\n\n```bash\n# Search for related docs\nknowns search "authentication" --type doc --plain\n\n# View relevant documents\nknowns doc "API Guidelines" --plain\nknowns doc "Security Patterns" --plain\n\n# Also check for similar completed tasks\nknowns search "auth" --type task --status done --plain\n```\n\n> **CRITICAL**: ALWAYS read related documentation BEFORE planning! Understanding existing patterns and conventions prevents rework and ensures consistency.\n\n### Step 4: Create Implementation Plan\n\n```bash\nknowns task edit <id> --plan $\'1. Research patterns (see @doc/security-patterns)\n2. Design middleware\n3. Implement\n4. Add tests\n5. Update docs\'\n```\n\n> **CRITICAL**:\n> - Share plan with user and **WAIT for approval** before coding\n> - Include doc references using `@doc/<path>` format\n\n### Step 5: Implement\n\n```bash\n# Work through implementation plan step by step\n# IMPORTANT: Only check AC AFTER completing the work, not before\n\n# After completing work for AC #1:\nknowns task edit <id> --check-ac 1\nknowns task edit <id> --append-notes "\u2713 Completed: <brief description>"\n\n# After completing work for AC #2:\nknowns task edit <id> --check-ac 2\nknowns task edit <id> --append-notes "\u2713 Completed: <brief description>"\n```\n\n> **CRITICAL**: Never check an AC before the work is actually done. ACs represent completed outcomes, not intentions.\n\n### Step 6: Handle Dynamic Requests (During Implementation)\n\nIf the user adds new requirements during implementation:\n\n```bash\n# Add new acceptance criteria\nknowns task edit <id> --ac "New requirement from user"\n\n# Update implementation plan to include new steps\nknowns task edit <id> --plan $\'1. Original step 1\n2. Original step 2\n3. NEW: Handle user request for X\n4. Continue with remaining work\'\n\n# Append note about scope change\nknowns task edit <id> --append-notes "\u26A0\uFE0F Scope updated: Added requirement for X per user request"\n\n# Continue with Step 5 (Implement) for new requirements\n```\n\n> **Note**: Always document scope changes. This helps track why a task took longer than expected.\n\n### Step 7: Add Implementation Notes\n\n```bash\n# Add comprehensive notes (suitable for PR description)\nknowns task edit <id> --notes $\'## Summary\n\nImplemented JWT auth.\n\n## Changes\n- Added middleware\n- Added tests\'\n\n# OR append progressively (recommended)\nknowns task edit <id> --append-notes "\u2713 Implemented middleware"\nknowns task edit <id> --append-notes "\u2713 Added tests"\n```\n\n### Step 8: Stop Time Tracking (REQUIRED)\n\n```bash\nknowns time stop\n```\n\n> **CRITICAL**: Never forget to stop the timer. If you forget, use manual entry: `knowns time add <id> <duration> -n "Forgot to stop timer"`\n\n### Step 9: Complete Task\n\n```bash\nknowns task edit <id> -s done\n```\n\n### Step 10: Handle Post-Completion Changes (If Applicable)\n\nIf the user requests changes or updates AFTER task is marked done:\n\n```bash\n# 1. Reopen task - set back to in-progress\nknowns task edit <id> -s in-progress\n\n# 2. Restart time tracking (REQUIRED)\nknowns time start <id>\n\n# 3. Add new AC for the changes requested\nknowns task edit <id> --ac "Post-completion fix: <description>"\n\n# 4. Document the reopen reason\nknowns task edit <id> --append-notes "\u{1F504} Reopened: User requested changes - <reason>"\n\n# 5. Follow Step 5-9 again (Implement \u2192 Notes \u2192 Stop Timer \u2192 Done)\n```\n\n> **CRITICAL**: Treat post-completion changes as a mini-workflow. Always:\n> - Reopen task (in-progress)\n> - Start timer again\n> - Add AC for traceability\n> - Document why it was reopened\n> - Follow the same completion process\n\n### Step 11: Knowledge Extraction (Post-Completion)\n\nAfter completing a task, extract reusable knowledge to docs:\n\n```bash\n# Search if similar pattern already documented\nknowns search "<pattern/concept>" --type doc --plain\n\n# If new knowledge, create a doc for future reference\nknowns doc create "Pattern: <Name>" \\\n -d "Reusable pattern discovered during task implementation" \\\n -t "pattern,<domain>" \\\n -f "patterns"\n\n# Or append to existing doc\nknowns doc edit "<existing-doc>" -a "## New Section\\n\\nLearned from task <id>: ..."\n\n# Reference the source task\nknowns doc edit "<doc-name>" -a "\\n\\n> Source: @task-<id>"\n```\n\n**When to extract knowledge:**\n- New patterns/conventions discovered\n- Common error solutions\n- Reusable code snippets or approaches\n- Integration patterns with external services\n- Performance optimization techniques\n\n> **CRITICAL**: Only extract **generalizable** knowledge. Task-specific details belong in implementation notes, not docs.\n\n---\n\n## Essential Commands\n\n### Task Management\n\n```bash\n# Create task\nknowns task create "Title" -d "Description" --ac "Criterion" -l "labels" --priority high\n\n# Edit task\nknowns task edit <id> -t "New title"\nknowns task edit <id> -d "New description"\nknowns task edit <id> -s in-progress\nknowns task edit <id> --priority high\nknowns task edit <id> -a <assignee> # $(knowns config get defaultAssignee --plain || echo "@me")\n\n# Acceptance Criteria\nknowns task edit <id> --ac "New criterion" # Add\nknowns task edit <id> --check-ac 1 --check-ac 2 # Check (1-indexed)\nknowns task edit <id> --uncheck-ac 2 # Uncheck\nknowns task edit <id> --remove-ac 3 # Remove\n\n# Implementation Plan & Notes\nknowns task edit <id> --plan $\'1. Step\\n2. Step\'\nknowns task edit <id> --notes "Implementation summary"\nknowns task edit <id> --append-notes "Progress update"\n\n# View & List\nknowns task <id> --plain # Shorthand (ALWAYS use --plain)\nknowns task view <id> --plain # Full command\nknowns task list --plain\nknowns task list --status in-progress --plain\nknowns task list --assignee <assignee> --plain # $(knowns config get defaultAssignee --plain || echo "@me")\nknowns task list --tree --plain # Tree hierarchy\n```\n\n### Time Tracking\n\n```bash\n# Timer\nknowns time start <id>\nknowns time stop\nknowns time pause\nknowns time resume\nknowns time status\n\n# Manual entry\nknowns time add <id> 2h -n "Note" -d "2025-12-25"\n\n# Reports\nknowns time report --from "2025-12-01" --to "2025-12-31"\nknowns time report --by-label --csv > report.csv\n```\n\n### Documentation\n\n```bash\n# List & View\nknowns doc list --plain\nknowns doc list --tag architecture --plain\nknowns doc <path> --plain # Shorthand (ALWAYS use --plain)\nknowns doc view "<path>" --plain # Full command\n\n# Create (with optional folder)\nknowns doc create "Title" -d "Description" -t "tags"\nknowns doc create "Title" -d "Description" -t "tags" -f "folder/path"\n\n# Edit metadata\nknowns doc edit "Doc Name" -t "New Title" --tags "new,tags"\n\n# Edit content\nknowns doc edit "Doc Name" -c "New content" # Replace content\nknowns doc edit "Doc Name" -a "Appended content" # Append to content\n```\n\n### Search\n\n```bash\n# Search everything\nknowns search "query" --plain\n\n# Search specific type\nknowns search "auth" --type task --plain\nknowns search "patterns" --type doc --plain\n\n# Filter\nknowns search "bug" --status in-progress --priority high --plain\n```\n\n---\n\n## Task Structure\n\n### Title\n\nClear summary (WHAT needs to be done).\n\n| Bad | Good |\n|-----|------|\n| Do auth stuff | Add JWT authentication |\n| Fix bug | Fix login timeout on slow networks |\n| Update docs | Document rate limiting in API.md |\n\n### Description\n\nExplains WHY and WHAT (not HOW). **Link related docs using `@doc/<path>`**\n\n```markdown\nWe need JWT authentication because sessions don\'t scale for our microservices architecture.\n\nRelated docs: @doc/security-patterns, @doc/api-guidelines\n```\n\n### Acceptance Criteria\n\n**Outcome-oriented**, testable criteria. NOT implementation steps.\n\n| Bad (Implementation details) | Good (Outcomes) |\n|------------------------------|-----------------|\n| Add function handleLogin() in auth.ts | User can login and receive JWT token |\n| Use bcrypt for hashing | Passwords are securely hashed |\n| Add try-catch blocks | Errors return appropriate HTTP status codes |\n\n### Implementation Plan\n\nHOW to solve. Added AFTER taking task, BEFORE coding.\n\n```markdown\n1. Research JWT libraries (see @doc/security-patterns)\n2. Design token structure (access + refresh tokens)\n3. Implement auth middleware\n4. Add unit tests (aim for 90%+ coverage)\n5. Update API.md with new endpoints\n```\n\n### Implementation Notes\n\nSummary for PR description. Added AFTER completion.\n\n```markdown\n## Summary\nImplemented JWT auth using jsonwebtoken library.\n\n## Changes\n- Added auth middleware in src/middleware/auth.ts\n- Added /login and /refresh endpoints\n- Created JWT utility functions\n\n## Tests\n- Added 15 unit tests\n- Coverage: 94%\n\n## Documentation\n- Updated API.md with authentication section\n```\n\n---\n\n## Error Handling\n\n### Common Errors and Solutions\n\n| Error | Cause | Solution |\n|-------|-------|----------|\n| `Error: Task not found` | Invalid task ID | Run `knowns task list --plain` to find correct ID |\n| `Error: No active timer` | Calling `time stop` without active timer | Start timer first: `knowns time start <id>` |\n| `Error: Timer already running` | Starting timer when one is active | Stop current: `knowns time stop` |\n| `Error: Invalid status` | Wrong status format | Use lowercase with hyphens: `in-progress`, not `In Progress` |\n| `Error: AC index out of range` | Checking non-existent criterion | View task first: `knowns task <id> --plain` |\n| `Error: Document not found` | Wrong document name | Run `knowns doc list --plain` to find correct name |\n| `Error: Not initialized` | Running commands without init | Run `knowns init` first |\n\n### Debugging Commands\n\n```bash\n# Check CLI version\nknowns --version\n\n# Verify project is initialized\nknowns status\n\n# View raw task data (for debugging)\nknowns task <id> --json\n\n# Check timer status\nknowns time status\n```\n\n---\n\n## Definition of Done\n\nA task is **Done** ONLY when **ALL** criteria are met:\n\n### Via CLI (Required)\n\n- [ ] All acceptance criteria checked: `--check-ac <index>` (only after work is actually done)\n- [ ] Implementation notes added: `--notes "..."`\n- [ ] \u23F1\uFE0F Timer stopped: `knowns time stop` (MANDATORY - do not skip!)\n- [ ] Status set to done: `-s done`\n- [ ] Knowledge extracted to docs (if applicable)\n\n### Via Code (Required)\n\n- [ ] All tests pass\n- [ ] Documentation updated\n- [ ] Code reviewed (linting, formatting)\n- [ ] No regressions introduced\n\n---\n\n## Status & Priority Reference\n\n### Status Values\n\nUse **lowercase with hyphens**:\n\n| Status | Description | When to Use |\n|--------|-------------|-------------|\n| `todo` | Not started | Default for new tasks |\n| `in-progress` | Currently working | After taking task |\n| `in-review` | In code review | PR submitted |\n| `blocked` | Waiting on dependency | External blocker |\n| `done` | Completed | All criteria met |\n\n### Priority Values\n\n| Priority | Description |\n|----------|-------------|\n| `low` | Can wait, nice-to-have |\n| `medium` | Normal priority (default) |\n| `high` | Urgent, time-sensitive |\n\n---\n\n## Common Mistakes\n\n| Wrong | Right |\n|-------|-------|\n| Edit .md files directly | Use `knowns task edit` |\n| Change `- [ ]` to `- [x]` in file | Use `--check-ac <index>` |\n| Check AC before completing work | Only check AC AFTER work is actually done |\n| Skip time tracking | ALWAYS use `time start` and `time stop` |\n| Start coding without reading docs | Read ALL related docs FIRST |\n| Skip `knowns doc list` on new project | Always list docs when starting |\n| Assume you know the conventions | Read CONVENTIONS/ARCHITECTURE docs |\n| Plan without checking docs | Read docs before planning |\n| Ignore similar completed tasks | Search done tasks for patterns |\n| Missing doc links in description/plan | Link docs using `@doc/<path>` |\n| Write refs as `@.knowns/docs/...` or `@.knowns/tasks/...` | Use input format: `@doc/<path>`, `@task-<id>` |\n| Forget `--plain` flag | Always use `--plain` for AI |\n| Code before plan approval | Share plan, WAIT for approval |\n| Mark done without all criteria | Check ALL criteria first |\n| Write implementation steps in AC | Write outcome-oriented criteria |\n| Use `"In Progress"` or `"Done"` | Use `in-progress`, `done` |\n| Use `@yourself` or unknown assignee | Use `$(knowns config get defaultAssignee --plain \\|\\| echo "@me")` |\n| Ignore refs in task description | Follow ALL refs (`@.knowns/...`) before planning |\n| See `@.knowns/docs/...` but don\'t read | Use `knowns doc "<path>" --plain` |\n| See `@.knowns/tasks/task-X` but don\'t check | Use `knowns task X --plain` for context |\n| Follow only first-level refs | Recursively follow nested refs until complete |\n\n---\n\n## Platform-Specific Notes\n\n### Multi-line Input\n\nDifferent shells handle multi-line strings differently:\n\n**Bash / Zsh (Recommended)**\n```bash\nknowns task edit <id> --plan $\'1. First step\\n2. Second step\\n3. Third step\'\n```\n\n**PowerShell**\n```powershell\nknowns task edit <id> --plan "1. First step`n2. Second step`n3. Third step"\n```\n\n**Cross-platform (Using printf)**\n```bash\nknowns task edit <id> --plan "$(printf \'1. First step\\n2. Second step\\n3. Third step\')"\n```\n\n**Using heredoc (for long content)**\n```bash\nknowns task edit <id> --plan "$(cat <<EOF\n1. First step\n2. Second step\n3. Third step\nEOF\n)"\n```\n\n### Path Separators\n\n- **Unix/macOS**: Use forward slashes: `./docs/api.md`\n- **Windows**: Both work, but prefer forward slashes for consistency\n\n---\n\n## Best Practices Checklist\n\n### For AI Agents: Session Start\n\n- [ ] List all docs: `knowns doc list --plain`\n- [ ] Read README/ARCHITECTURE docs\n- [ ] Understand coding conventions\n- [ ] Review current task backlog\n\n### Before Starting Work\n\n- [ ] Task has clear acceptance criteria\n- [ ] ALL refs in task followed (`@.knowns/...`)\n- [ ] Nested refs recursively followed until complete context gathered\n- [ ] Related docs searched: `knowns search "keyword" --type doc --plain`\n- [ ] ALL relevant docs read: `knowns doc "Doc Name" --plain`\n- [ ] Similar done tasks reviewed for patterns\n- [ ] Task assigned to self: `-a $(knowns config get defaultAssignee --plain || echo "@me")`\n- [ ] Status set to in-progress: `-s in-progress`\n- [ ] Timer started: `knowns time start <id>`\n\n### During Work\n\n- [ ] Implementation plan created and approved\n- [ ] Doc links included in plan: `@doc/<path>`\n- [ ] Criteria checked as completed: `--check-ac <index>`\n- [ ] Progress notes appended: `--append-notes "\u2713 ..."`\n\n### After Work\n\n- [ ] All acceptance criteria checked (only after work is done)\n- [ ] Implementation notes added: `--notes "..."`\n- [ ] Timer stopped: `knowns time stop`\n- [ ] Tests passing\n- [ ] Documentation updated\n- [ ] Status set to done: `-s done`\n- [ ] Knowledge extracted to docs (if applicable): patterns, solutions, conventions\n\n---\n\n## Quick Reference Card\n\n```bash\n# === AGENT INITIALIZATION (Once per session) ===\nknowns doc list --plain\nknowns doc "README" --plain\nknowns doc "ARCHITECTURE" --plain\nknowns doc "CONVENTIONS" --plain\n\n# === FULL WORKFLOW ===\nknowns task create "Title" -d "Description" --ac "Criterion"\nknowns task edit <id> -s in-progress -a $(knowns config get defaultAssignee --plain || echo "@me")\nknowns time start <id> # \u23F1\uFE0F REQUIRED: Start timer\nknowns search "keyword" --type doc --plain\nknowns doc "Doc Name" --plain\nknowns search "keyword" --type task --status done --plain # Learn from history\nknowns task edit <id> --plan $\'1. Step (see @doc/file)\\n2. Step\'\n# ... wait for approval, then implement ...\n# Only check AC AFTER completing the work:\nknowns task edit <id> --check-ac 1\nknowns task edit <id> --append-notes "\u2713 Completed: feature X"\nknowns task edit <id> --check-ac 2\nknowns task edit <id> --append-notes "\u2713 Completed: feature Y"\nknowns time stop # \u23F1\uFE0F REQUIRED: Stop timer\nknowns task edit <id> -s done\n# Optional: Extract knowledge to docs if generalizable patterns found\n\n# === VIEW & SEARCH ===\nknowns task <id> --plain # Shorthand for view\nknowns task list --plain\nknowns task list --status in-progress --assignee $(knowns config get defaultAssignee --plain || echo "@me") --plain\nknowns search "query" --plain\nknowns search "bug" --type task --status in-progress --plain\n\n# === TIME TRACKING ===\nknowns time start <id>\nknowns time stop\nknowns time status\nknowns time report --from "2025-12-01" --to "2025-12-31"\n\n# === DOCUMENTATION ===\nknowns doc list --plain\nknowns doc "path/doc-name" --plain # Shorthand for view\nknowns doc create "Title" -d "Description" -t "tags" -f "folder"\nknowns doc edit "doc-name" -c "New content"\nknowns doc edit "doc-name" -a "Appended content"\n```\n\n---\n\n**Maintained By**: Knowns CLI Team\n\n<!-- KNOWNS GUIDELINES END -->\n';
46958
-
46959
- // src/templates/knowns-guidelines-mcp.md
46960
- var knowns_guidelines_mcp_default = '<!-- KNOWNS GUIDELINES START -->\n# Knowns MCP Guidelines\n\n## Core Principles\n\n### 1. MCP Tool Operations\n**Use MCP tools for ALL Knowns operations. NEVER edit .md files directly.**\n\nThis ensures data integrity, maintains proper change history, and prevents file corruption.\n\n### 2. Documentation-First (For AI Agents)\n**ALWAYS read project documentation BEFORE planning or coding.**\n\nAI agents must understand project context, conventions, and existing patterns before making any changes. This prevents rework and ensures consistency.\n\n---\n\n## AI Agent Guidelines\n\n> **CRITICAL**: Before performing ANY task, AI agents MUST read documentation to understand project context.\n\n### First-Time Initialization\n\nWhen starting a new session or working on an unfamiliar project:\n\n```\n# 1. List all available documentation\nmcp__knowns__list_docs({})\n\n# 2. Read essential project docs (prioritize these)\nmcp__knowns__get_doc({ path: "README" })\nmcp__knowns__get_doc({ path: "ARCHITECTURE" })\nmcp__knowns__get_doc({ path: "CONVENTIONS" })\nmcp__knowns__get_doc({ path: "API" })\n\n# 3. Review current task backlog\nmcp__knowns__list_tasks({})\nmcp__knowns__list_tasks({ status: "in-progress" })\n```\n\n### Before Taking Any Task\n\n```\n# 1. View the task details\nmcp__knowns__get_task({ taskId: "<id>" })\n\n# 2. Follow ALL refs in the task (see Reference System section)\n# @.knowns/tasks/task-44 - ... \u2192 mcp__knowns__get_task({ taskId: "44" })\n# @.knowns/docs/patterns/module.md \u2192 mcp__knowns__get_doc({ path: "patterns/module" })\n\n# 3. Search for additional related documentation\nmcp__knowns__search_docs({ query: "<keywords from task>" })\n\n# 4. Read ALL related docs before planning\nmcp__knowns__get_doc({ path: "<related-doc>" })\n\n# 5. Check for similar completed tasks (learn from history)\nmcp__knowns__search_tasks({ query: "<keywords>", status: "done" })\n```\n\n### Why Documentation First?\n\n| Without Reading Docs | With Reading Docs |\n|---------------------|-------------------|\n| Reinvent existing patterns | Reuse established patterns |\n| Break conventions | Follow project standards |\n| Duplicate code | Use existing utilities |\n| Wrong architecture decisions | Align with system design |\n| Inconsistent naming | Match naming conventions |\n\n### Context Checklist for Agents\n\nBefore writing ANY code, ensure you can answer:\n\n- [ ] Have I followed ALL refs (`@.knowns/...`) in the task?\n- [ ] Have I followed nested refs recursively?\n- [ ] What is the project\'s overall architecture?\n- [ ] What coding conventions does this project follow?\n- [ ] Are there existing patterns/utilities I should reuse?\n- [ ] What are the testing requirements?\n- [ ] How should I structure my implementation?\n\n> **Remember**: A few minutes reading docs saves hours of rework. NEVER skip this step.\n\n---\n\n## Reference System (Refs)\n\nTasks and docs can contain **references** to other tasks/docs. AI agents MUST understand and follow these refs to gather complete context.\n\n### Reference Formats\n\n| Type | When Writing (Input) | When Reading (Output) | MCP Tool |\n|------|---------------------|----------------------|----------|\n| **Task ref** | `@task-<id>` | `@.knowns/tasks/task-<id> - <title>.md` | `mcp__knowns__get_task({ taskId: "<id>" })` |\n| **Doc ref** | `@doc/<path>` | `@.knowns/docs/<path>.md` | `mcp__knowns__get_doc({ path: "<path>" })` |\n\n> **CRITICAL for AI Agents**:\n> - When **WRITING** refs (in descriptions, plans, notes): Use `@task-<id>` and `@doc/<path>`\n> - When **READING** output: You\'ll see `@.knowns/tasks/...` and `@.knowns/docs/...`\n> - **NEVER write** the output format (`@.knowns/...`) - always use input format\n\n### How to Follow Refs\n\nWhen you read a task and see refs in system output format, follow them:\n\n```\n# Example: Task 42 output contains:\n# @.knowns/tasks/task-44 - CLI Task Create Command.md\n# @.knowns/docs/patterns/module.md\n\n# Follow task ref (extract ID from task-<id>)\nmcp__knowns__get_task({ taskId: "44" })\n\n# Follow doc ref (extract path, remove .md)\nmcp__knowns__get_doc({ path: "patterns/module" })\n```\n\n### Recursive Following\n\nRefs can be nested. Follow until complete context is gathered:\n\n```\nTask 42\n \u2192 @.knowns/docs/README.md\n \u2192 @.knowns/docs/patterns/module.md (found in README)\n \u2192 (read for full pattern details)\n```\n\n> **CRITICAL**: Never assume you understand a task fully without following its refs. Refs contain essential context that may change your implementation approach.\n\n---\n\n## Quick Start\n\n```\n# Initialize project (use CLI for this)\nknowns init [name]\n\n# Create task with acceptance criteria\nmcp__knowns__create_task({\n title: "Title",\n description: "Description",\n priority: "high",\n labels: ["label1", "label2"]\n})\n\n# View task\nmcp__knowns__get_task({ taskId: "<id>" })\n\n# List tasks\nmcp__knowns__list_tasks({})\n\n# Search (tasks + docs)\nmcp__knowns__search_tasks({ query: "query" })\nmcp__knowns__search_docs({ query: "query" })\n```\n\n---\n\n## End-to-End Example\n\nHere\'s a complete workflow for an AI agent implementing a feature:\n\n```\n# === AGENT SESSION START (Do this once per session) ===\n\n# 0a. List all available documentation\nmcp__knowns__list_docs({})\n\n# 0b. Read essential project docs\nmcp__knowns__get_doc({ path: "README" })\nmcp__knowns__get_doc({ path: "ARCHITECTURE" })\nmcp__knowns__get_doc({ path: "CONVENTIONS" })\n\n# Now the agent understands project context and conventions\n\n# === TASK WORKFLOW ===\n\n# 1. Create the task\nmcp__knowns__create_task({\n title: "Add password reset flow",\n description: "Users need ability to reset forgotten passwords via email",\n priority: "high",\n labels: ["auth", "feature"]\n})\n\n# Output: Created task 42\n\n# 2. Take the task and start timer\nmcp__knowns__update_task({\n taskId: "42",\n status: "in-progress",\n assignee: "@howznguyen"\n})\nmcp__knowns__start_time({ taskId: "42" })\n\n# 3. Search for related documentation\nmcp__knowns__search_docs({ query: "password security" })\n\n# 4. Read the documentation\nmcp__knowns__get_doc({ path: "security-patterns" })\n\n# 5. Create implementation plan (SHARE WITH USER, WAIT FOR APPROVAL)\nmcp__knowns__update_task({\n taskId: "42",\n plan: "1. Review security patterns (see @doc/security-patterns)\\n2. Design token generation with 1-hour expiry\\n3. Implement /forgot-password endpoint\\n4. Add unit tests"\n})\n\n# 6. After approval, implement and update task progressively\nmcp__knowns__update_task({\n taskId: "42",\n appendNotes: "\u2713 Implemented /forgot-password endpoint"\n})\n\n# 7. Add final implementation notes\nmcp__knowns__update_task({\n taskId: "42",\n notes: "## Summary\\nImplemented complete password reset flow.\\n\\n## Changes\\n- Added POST /forgot-password endpoint\\n- Added POST /reset-password endpoint"\n})\n\n# 8. Stop timer and complete\nmcp__knowns__stop_time({ taskId: "42" })\nmcp__knowns__update_task({\n taskId: "42",\n status: "done"\n})\n```\n\n---\n\n## Task Workflow\n\n### Step 1: Take Task\n\n```\n# Update task status and assign to self\nmcp__knowns__update_task({\n taskId: "<id>",\n status: "in-progress",\n assignee: "@<your-username>"\n})\n```\n\n> **Note**: Use your username as configured in the project. Check project config for `defaultAssignee`.\n\n### Step 2: Start Time Tracking (REQUIRED)\n\n```\nmcp__knowns__start_time({ taskId: "<id>" })\n```\n\n> **CRITICAL**: Time tracking is MANDATORY. Always start timer when taking a task and stop when done. This data is essential for:\n> - Accurate project estimation\n> - Identifying bottlenecks\n> - Resource planning\n> - Sprint retrospectives\n\n### Step 3: Read Related Documentation\n\n> **FOR AI AGENTS**: This step is MANDATORY, not optional. You must understand the codebase before planning.\n\n```\n# Search for related docs\nmcp__knowns__search_docs({ query: "authentication" })\n\n# View relevant documents\nmcp__knowns__get_doc({ path: "API Guidelines" })\nmcp__knowns__get_doc({ path: "Security Patterns" })\n\n# Also check for similar completed tasks\nmcp__knowns__search_tasks({ query: "auth", status: "done" })\n```\n\n> **CRITICAL**: ALWAYS read related documentation BEFORE planning!\n\n### Step 4: Create Implementation Plan\n\n```\nmcp__knowns__update_task({\n taskId: "<id>",\n plan: "1. Research patterns (see @doc/security-patterns)\\n2. Design middleware\\n3. Implement\\n4. Add tests\\n5. Update docs"\n})\n```\n\n> **CRITICAL**:\n> - Share plan with user and **WAIT for approval** before coding\n> - Include doc references using `@doc/<path>` format\n\n### Step 5: Implement\n\n```\n# Work through implementation plan step by step\n# IMPORTANT: Only update task AFTER completing the work, not before\n\n# After completing work, append notes:\nmcp__knowns__update_task({\n taskId: "<id>",\n appendNotes: "\u2713 Completed: <brief description>"\n})\n```\n\n> **CRITICAL**: Never claim work is done before it\'s actually completed.\n\n### Step 6: Handle Dynamic Requests (During Implementation)\n\nIf the user adds new requirements during implementation:\n\n```\n# Append note about scope change\nmcp__knowns__update_task({\n taskId: "<id>",\n appendNotes: "\u26A0\uFE0F Scope updated: Added requirement for X per user request"\n})\n\n# Continue with Step 5 (Implement) for new requirements\n```\n\n> **Note**: Always document scope changes. This helps track why a task took longer than expected.\n\n### Step 7: Add Implementation Notes\n\n```\n# Add comprehensive notes (suitable for PR description)\nmcp__knowns__update_task({\n taskId: "<id>",\n notes: "## Summary\\n\\nImplemented JWT auth.\\n\\n## Changes\\n- Added middleware\\n- Added tests"\n})\n\n# OR append progressively (recommended)\nmcp__knowns__update_task({\n taskId: "<id>",\n appendNotes: "\u2713 Implemented middleware"\n})\n```\n\n### Step 8: Stop Time Tracking (REQUIRED)\n\n```\nmcp__knowns__stop_time({ taskId: "<id>" })\n```\n\n> **CRITICAL**: Never forget to stop the timer. If you forget, use manual entry:\n> `mcp__knowns__add_time({ taskId: "<id>", duration: "2h", note: "Forgot to stop timer" })`\n\n### Step 9: Complete Task\n\n```\nmcp__knowns__update_task({\n taskId: "<id>",\n status: "done"\n})\n```\n\n### Step 10: Handle Post-Completion Changes (If Applicable)\n\nIf the user requests changes or updates AFTER task is marked done:\n\n```\n# 1. Reopen task - set back to in-progress\nmcp__knowns__update_task({\n taskId: "<id>",\n status: "in-progress"\n})\n\n# 2. Restart time tracking (REQUIRED)\nmcp__knowns__start_time({ taskId: "<id>" })\n\n# 3. Document the reopen reason\nmcp__knowns__update_task({\n taskId: "<id>",\n appendNotes: "\u{1F504} Reopened: User requested changes - <reason>"\n})\n\n# 4. Follow Step 5-9 again (Implement \u2192 Notes \u2192 Stop Timer \u2192 Done)\n```\n\n> **CRITICAL**: Treat post-completion changes as a mini-workflow. Always:\n> - Reopen task (in-progress)\n> - Start timer again\n> - Document why it was reopened\n> - Follow the same completion process\n\n### Step 11: Knowledge Extraction (Post-Completion)\n\nAfter completing a task, extract reusable knowledge to docs:\n\n```\n# Search if similar pattern already documented\nmcp__knowns__search_docs({ query: "<pattern/concept>" })\n\n# If new knowledge, create a doc for future reference\nmcp__knowns__create_doc({\n title: "Pattern: <Name>",\n description: "Reusable pattern discovered during task implementation",\n tags: ["pattern", "<domain>"],\n folder: "patterns"\n})\n\n# Or append to existing doc\nmcp__knowns__update_doc({\n path: "<existing-doc>",\n appendContent: "## New Section\\n\\nLearned from task <id>: ..."\n})\n```\n\n**When to extract knowledge:**\n- New patterns/conventions discovered\n- Common error solutions\n- Reusable code snippets or approaches\n- Integration patterns with external services\n- Performance optimization techniques\n\n> **CRITICAL**: Only extract **generalizable** knowledge. Task-specific details belong in implementation notes, not docs.\n\n---\n\n## Essential MCP Tools\n\n### Task Management\n\n```\n# Create task\nmcp__knowns__create_task({\n title: "Title",\n description: "Description",\n priority: "high", # low, medium, high\n labels: ["label1"],\n status: "todo", # todo, in-progress, in-review, done, blocked\n assignee: "@username"\n})\n\n# Get task\nmcp__knowns__get_task({ taskId: "<id>" })\n\n# Update task\nmcp__knowns__update_task({\n taskId: "<id>",\n title: "New title",\n description: "New description",\n status: "in-progress",\n priority: "high",\n assignee: "@username",\n labels: ["new", "labels"],\n plan: "Implementation plan...",\n notes: "Implementation notes...",\n appendNotes: "Append to existing notes..."\n})\n\n# List tasks\nmcp__knowns__list_tasks({})\nmcp__knowns__list_tasks({ status: "in-progress" })\nmcp__knowns__list_tasks({ assignee: "@username" })\nmcp__knowns__list_tasks({ priority: "high" })\nmcp__knowns__list_tasks({ label: "feature" })\n\n# Search tasks\nmcp__knowns__search_tasks({ query: "auth" })\n```\n\n### Time Tracking\n\n```\n# Start timer\nmcp__knowns__start_time({ taskId: "<id>" })\n\n# Stop timer\nmcp__knowns__stop_time({ taskId: "<id>" })\n\n# Manual entry\nmcp__knowns__add_time({\n taskId: "<id>",\n duration: "2h", # e.g., "2h", "30m", "1h30m"\n note: "Optional note",\n date: "2025-12-25" # Optional, defaults to now\n})\n\n# Reports\nmcp__knowns__get_time_report({})\nmcp__knowns__get_time_report({\n from: "2025-12-01",\n to: "2025-12-31",\n groupBy: "task" # task, label, status\n})\n```\n\n### Documentation\n\n```\n# List docs\nmcp__knowns__list_docs({})\nmcp__knowns__list_docs({ tag: "architecture" })\n\n# Get doc\nmcp__knowns__get_doc({ path: "README" })\nmcp__knowns__get_doc({ path: "patterns/module" })\n\n# Create doc\nmcp__knowns__create_doc({\n title: "Title",\n description: "Description",\n tags: ["tag1", "tag2"],\n folder: "folder/path", # Optional\n content: "Initial content..."\n})\n\n# Update doc\nmcp__knowns__update_doc({\n path: "doc-name",\n title: "New Title",\n description: "New description",\n tags: ["new", "tags"],\n content: "Replace content...",\n appendContent: "Append to content..."\n})\n\n# Search docs\nmcp__knowns__search_docs({ query: "patterns" })\nmcp__knowns__search_docs({ query: "auth", tag: "security" })\n```\n\n### Board\n\n```\n# Get kanban board view\nmcp__knowns__get_board({})\n```\n\n---\n\n## Task Structure\n\n### Title\n\nClear summary (WHAT needs to be done).\n\n| Bad | Good |\n|-----|------|\n| Do auth stuff | Add JWT authentication |\n| Fix bug | Fix login timeout on slow networks |\n| Update docs | Document rate limiting in API.md |\n\n### Description\n\nExplains WHY and WHAT (not HOW). **Link related docs using `@doc/<path>`**\n\n```\nWe need JWT authentication because sessions don\'t scale for our microservices architecture.\n\nRelated docs: @doc/security-patterns, @doc/api-guidelines\n```\n\n### Acceptance Criteria\n\n**Outcome-oriented**, testable criteria. NOT implementation steps.\n\n| Bad (Implementation details) | Good (Outcomes) |\n|------------------------------|-----------------|\n| Add function handleLogin() in auth.ts | User can login and receive JWT token |\n| Use bcrypt for hashing | Passwords are securely hashed |\n| Add try-catch blocks | Errors return appropriate HTTP status codes |\n\n---\n\n## Definition of Done\n\nA task is **Done** ONLY when **ALL** criteria are met:\n\n### Via MCP Tools (Required)\n\n- [ ] All work completed and verified\n- [ ] Implementation notes added via `update_task`\n- [ ] \u23F1\uFE0F Timer stopped: `mcp__knowns__stop_time` (MANDATORY - do not skip!)\n- [ ] Status set to done via `update_task`\n- [ ] Knowledge extracted to docs (if applicable)\n\n### Via Code (Required)\n\n- [ ] All tests pass\n- [ ] Documentation updated\n- [ ] Code reviewed (linting, formatting)\n- [ ] No regressions introduced\n\n---\n\n## Status & Priority Reference\n\n### Status Values\n\n| Status | Description | When to Use |\n|--------|-------------|-------------|\n| `todo` | Not started | Default for new tasks |\n| `in-progress` | Currently working | After taking task |\n| `in-review` | In code review | PR submitted |\n| `blocked` | Waiting on dependency | External blocker |\n| `done` | Completed | All criteria met |\n\n### Priority Values\n\n| Priority | Description |\n|----------|-------------|\n| `low` | Can wait, nice-to-have |\n| `medium` | Normal priority (default) |\n| `high` | Urgent, time-sensitive |\n\n---\n\n## Common Mistakes\n\n| Wrong | Right |\n|-------|-------|\n| Edit .md files directly | Use MCP tools |\n| Skip time tracking | ALWAYS use `start_time` and `stop_time` |\n| Start coding without reading docs | Read ALL related docs FIRST |\n| Plan without checking docs | Read docs before planning |\n| Code before plan approval | Share plan, WAIT for approval |\n| Mark done without all criteria | Verify ALL criteria first |\n| Ignore refs in task description | Follow ALL refs before planning |\n| Follow only first-level refs | Recursively follow nested refs |\n\n---\n\n## Best Practices Checklist\n\n### For AI Agents: Session Start\n\n- [ ] List all docs: `mcp__knowns__list_docs({})`\n- [ ] Read README/ARCHITECTURE docs\n- [ ] Understand coding conventions\n- [ ] Review current task backlog\n\n### Before Starting Work\n\n- [ ] Task details retrieved: `mcp__knowns__get_task`\n- [ ] ALL refs in task followed\n- [ ] Nested refs recursively followed\n- [ ] Related docs searched and read\n- [ ] Similar done tasks reviewed for patterns\n- [ ] Task assigned to self via `update_task`\n- [ ] Status set to in-progress\n- [ ] Timer started: `mcp__knowns__start_time`\n\n### During Work\n\n- [ ] Implementation plan created and approved\n- [ ] Doc links included in plan: `@doc/<path>`\n- [ ] Progress notes appended: `appendNotes`\n\n### After Work\n\n- [ ] All work verified complete\n- [ ] Implementation notes added\n- [ ] Timer stopped: `mcp__knowns__stop_time`\n- [ ] Tests passing\n- [ ] Documentation updated\n- [ ] Status set to done\n- [ ] Knowledge extracted to docs (if applicable)\n\n---\n\n## Quick Reference\n\n```\n# === AGENT INITIALIZATION (Once per session) ===\nmcp__knowns__list_docs({})\nmcp__knowns__get_doc({ path: "README" })\nmcp__knowns__get_doc({ path: "ARCHITECTURE" })\nmcp__knowns__get_doc({ path: "CONVENTIONS" })\n\n# === FULL WORKFLOW ===\nmcp__knowns__create_task({ title: "Title", description: "Description" })\nmcp__knowns__update_task({ taskId: "<id>", status: "in-progress", assignee: "@me" })\nmcp__knowns__start_time({ taskId: "<id>" }) # \u23F1\uFE0F REQUIRED\nmcp__knowns__search_docs({ query: "keyword" })\nmcp__knowns__get_doc({ path: "Doc Name" })\nmcp__knowns__search_tasks({ query: "keyword", status: "done" }) # Learn from history\nmcp__knowns__update_task({ taskId: "<id>", plan: "1. Step\\n2. Step" })\n# ... wait for approval, then implement ...\nmcp__knowns__update_task({ taskId: "<id>", appendNotes: "\u2713 Completed: feature X" })\nmcp__knowns__stop_time({ taskId: "<id>" }) # \u23F1\uFE0F REQUIRED\nmcp__knowns__update_task({ taskId: "<id>", status: "done" })\n# Optional: Extract knowledge to docs if generalizable patterns found\n\n# === VIEW & SEARCH ===\nmcp__knowns__get_task({ taskId: "<id>" })\nmcp__knowns__list_tasks({})\nmcp__knowns__list_tasks({ status: "in-progress", assignee: "@me" })\nmcp__knowns__search_tasks({ query: "bug" })\nmcp__knowns__search_docs({ query: "pattern" })\n\n# === TIME TRACKING ===\nmcp__knowns__start_time({ taskId: "<id>" })\nmcp__knowns__stop_time({ taskId: "<id>" })\nmcp__knowns__add_time({ taskId: "<id>", duration: "2h" })\nmcp__knowns__get_time_report({})\n\n# === DOCUMENTATION ===\nmcp__knowns__list_docs({})\nmcp__knowns__get_doc({ path: "path/doc-name" })\nmcp__knowns__create_doc({ title: "Title", description: "Desc", tags: ["tag"] })\nmcp__knowns__update_doc({ path: "doc-name", appendContent: "New content" })\n```\n\n---\n\n**Maintained By**: Knowns CLI Team\n\n<!-- KNOWNS GUIDELINES END -->\n';
46961
-
46962
46990
  // src/commands/agents.ts
46963
46991
  import { existsSync } from "node:fs";
46964
46992
  import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
46965
46993
  import { dirname, join as join3 } from "node:path";
46966
46994
  var import_prompts = __toESM(require_prompts3(), 1);
46995
+
46996
+ // src/templates/cli/gemini.md
46997
+ var gemini_default = '<!-- KNOWNS GUIDELINES START -->\n# Knowns CLI - Gemini Quick Reference\n\n## RULES\n- NEVER edit .md files directly - use CLI only\n- ALWAYS use `--plain` flag\n- Read docs BEFORE coding\n- Start timer when taking task, stop when done\n\n## SESSION START\n```bash\nknowns doc list --plain\nknowns doc "README" --plain\nknowns task list --plain\n```\n\n## TASK WORKFLOW\n\n### 1. Take Task\n```bash\nknowns task <id> --plain # View task\nknowns task edit <id> -s in-progress -a @me\nknowns time start <id>\n```\n\n### 2. Read Context\n```bash\nknowns doc list "guides/" --plain # List by folder\nknowns doc "path/name" --plain # View doc\nknowns search "keyword" --type doc --plain\n```\n\n### 3. Plan & Implement\n```bash\nknowns task edit <id> --plan $\'1. Step one\\n2. Step two\'\n# Wait for approval, then code\nknowns task edit <id> --check-ac 1 # Check criteria after done\nknowns task edit <id> --append-notes "Done: feature X"\n```\n\n### 4. Complete\n```bash\nknowns time stop\nknowns task edit <id> -s done\n```\n\n## COMMANDS CHEATSHEET\n\n### Task\n```bash\nknowns task list --plain\nknowns task list --status in-progress --plain\nknowns task <id> --plain\nknowns task create "Title" -d "Desc" --ac "Criterion" --priority high\nknowns task edit <id> -s <status> -a @me\nknowns task edit <id> --check-ac 1 --check-ac 2\nknowns task edit <id> --plan "..."\nknowns task edit <id> --notes "..."\nknowns task edit <id> --append-notes "..."\n```\n\n### Doc\n```bash\nknowns doc list --plain\nknowns doc list "folder/" --plain\nknowns doc "name" --plain\nknowns doc create "Title" -d "Desc" -t "tags" -f "folder"\nknowns doc edit "name" -c "content"\nknowns doc edit "name" -a "append"\nknowns doc edit "name" --content-file ./file.md\nknowns doc edit "name" --append-file ./file.md\nknowns doc search-in "name" "query" --plain\nknowns doc replace "name" "old" "new"\n```\n\n### Time\n```bash\nknowns time start <id>\nknowns time stop\nknowns time status\nknowns time add <id> 2h -n "Note"\n```\n\n### Search\n```bash\nknowns search "query" --plain\nknowns search "query" --type doc --plain\nknowns search "query" --type task --plain\n```\n\n## REFS\n\n### Reading (output format)\n- `@.knowns/tasks/task-X - Title.md` \u2192 `knowns task X --plain`\n- `@.knowns/docs/path/name.md` \u2192 `knowns doc "path/name" --plain`\n\n### Writing (input format)\n- Task: `@task-X`\n- Doc: `@doc/path/name`\n\n## STATUS & PRIORITY\n\n**Status:** `todo`, `in-progress`, `in-review`, `blocked`, `done`\n**Priority:** `low`, `medium`, `high`\n\n## LONG CONTENT\n\nWindows has ~8191 char limit. Use:\n\n```bash\n# Append in chunks\nknowns doc edit "name" -a "Section 1..."\nknowns doc edit "name" -a "Section 2..."\n\n# Or file-based\nknowns doc edit "name" --content-file ./content.md\nknowns doc edit "name" --append-file ./more.md\n```\n\n## VALIDATE & REPAIR\n\n```bash\nknowns doc validate "name" --plain\nknowns doc repair "name" --plain\nknowns task validate <id> --plain\nknowns task repair <id> --plain\n```\n<!-- KNOWNS GUIDELINES END -->\n';
46998
+
46999
+ // src/templates/cli/general.md
47000
+ var general_default = '<!-- KNOWNS GUIDELINES START -->\n# Knowns CLI Guidelines\n\n## Core Principles\n\n### 1. CLI-Only Operations\n**NEVER edit .md files directly. ALL operations MUST use CLI commands.**\n\nThis ensures data integrity, maintains proper change history, and prevents file corruption.\n\n### 2. Documentation-First (For AI Agents)\n**ALWAYS read project documentation BEFORE planning or coding.**\n\nAI agents must understand project context, conventions, and existing patterns before making any changes. This prevents rework and ensures consistency.\n\n---\n\n## AI Agent Guidelines\n\n> **CRITICAL**: Before performing ANY task, AI agents MUST read documentation to understand project context.\n\n### First-Time Initialization\n\nWhen starting a new session or working on an unfamiliar project:\n\n```bash\n# 1. List all available documentation\nknowns doc list --plain\n\n# 2. Read essential project docs (prioritize these)\nknowns doc "README" --plain # Project overview\nknowns doc "ARCHITECTURE" --plain # System design\nknowns doc "CONVENTIONS" --plain # Coding standards\nknowns doc "API" --plain # API specifications\n\n# 3. Review current task backlog\nknowns task list --plain\nknowns task list --status in-progress --plain\n```\n\n### Before Taking Any Task\n\n```bash\n# 1. View the task details\nknowns task <id> --plain\n\n# 2. Follow ALL refs in the task (see Reference System section)\n# @.knowns/tasks/task-44 - ... \u2192 knowns task 44 --plain\n# @.knowns/docs/patterns/module.md \u2192 knowns doc "patterns/module" --plain\n\n# 3. Search for additional related documentation\nknowns search "<keywords from task>" --type doc --plain\n\n# 4. Read ALL related docs before planning\nknowns doc "<related-doc>" --plain\n\n# 5. Check for similar completed tasks (learn from history)\nknowns search "<keywords>" --type task --status done --plain\n```\n\n### Why Documentation First?\n\n| Without Reading Docs | With Reading Docs |\n|---------------------|-------------------|\n| Reinvent existing patterns | Reuse established patterns |\n| Break conventions | Follow project standards |\n| Duplicate code | Use existing utilities |\n| Wrong architecture decisions | Align with system design |\n| Inconsistent naming | Match naming conventions |\n\n### Context Checklist for Agents\n\nBefore writing ANY code, ensure you can answer:\n\n- [ ] Have I followed ALL refs (`@.knowns/...`) in the task?\n- [ ] Have I followed nested refs recursively?\n- [ ] What is the project\'s overall architecture?\n- [ ] What coding conventions does this project follow?\n- [ ] Are there existing patterns/utilities I should reuse?\n- [ ] What are the testing requirements?\n- [ ] How should I structure my implementation?\n\n> **Remember**: A few minutes reading docs saves hours of rework. NEVER skip this step.\n\n---\n\n## Reference System (Refs)\n\nTasks and docs can contain **references** to other tasks/docs. AI agents MUST understand and follow these refs to gather complete context.\n\n### Reference Formats\n\n| Type | When Writing (Input) | When Reading (Output) | CLI Command |\n|------|---------------------|----------------------|-------------|\n| **Task ref** | `@task-<id>` | `@.knowns/tasks/task-<id> - <title>.md` | `knowns task <id> --plain` |\n| **Doc ref** | `@doc/<path>` | `@.knowns/docs/<path>.md` | `knowns doc <path> --plain` |\n\n> **CRITICAL for AI Agents**:\n> - When **WRITING** refs (in descriptions, plans, notes): Use `@task-<id>` and `@doc/<path>`\n> - When **READING** output from `--plain`: You\'ll see `@.knowns/tasks/...` and `@.knowns/docs/...`\n> - **NEVER write** the output format (`@.knowns/...`) - always use input format (`@task-<id>`, `@doc/<path>`)\n\n### How to Follow Refs\n\nWhen you read a task and see refs in system output format, follow them:\n\n```bash\n# Example: Task 42 output contains:\n# @.knowns/tasks/task-44 - CLI Task Create Command.md\n# @.knowns/docs/patterns/module.md\n\n# Follow task ref (extract ID from task-<id>)\nknowns task 44 --plain\n\n# Follow doc ref (extract path, remove .md)\nknowns doc "patterns/module" --plain\n```\n\n### Parsing Rules\n\n1. **Task refs**: `@.knowns/tasks/task-<id> - ...` \u2192 extract `<id>` \u2192 `knowns task <id> --plain`\n2. **Doc refs**: `@.knowns/docs/<path>.md` \u2192 extract `<path>` \u2192 `knowns doc "<path>" --plain`\n\n### Recursive Following\n\nRefs can be nested. Follow until complete context is gathered:\n\n```\nTask 42\n \u2192 @.knowns/docs/README.md\n \u2192 @.knowns/docs/patterns/module.md (found in README)\n \u2192 (read for full pattern details)\n```\n\n### When to Follow Refs\n\n| Situation | Action |\n|-----------|--------|\n| Refs in Description | ALWAYS follow - critical context |\n| Refs in Implementation Plan | Follow if implementing related work |\n| Refs in Notes | Optional - for historical context |\n| Dependency mentions | Follow if marked as blocker |\n\n### Example: Complete Ref Resolution\n\n```bash\n# 1. Read the task\n$ knowns task 42 --plain\n\n# Output contains:\n# @.knowns/tasks/task-44 - CLI Task Create Command.md\n# @.knowns/docs/README.md\n\n# 2. Follow task ref\n$ knowns task 44 --plain\n\n# 3. Follow doc ref\n$ knowns doc "README" --plain\n\n# 4. If README contains more refs, follow them too\n# @.knowns/docs/patterns/module.md \u2192 knowns doc "patterns/module" --plain\n\n# Now you have complete context\n```\n\n> **CRITICAL**: Never assume you understand a task fully without following its refs. Refs contain essential context that may change your implementation approach.\n\n---\n\n## Quick Start\n\n```bash\n# Initialize project\nknowns init [name]\n\n# Create task with acceptance criteria\nknowns task create "Title" -d "Description" --ac "Criterion 1" --ac "Criterion 2"\n\n# View task (ALWAYS use --plain for AI)\nknowns task <id> --plain # Shorthand\nknowns task view <id> --plain # Full command\n\n# View doc (ALWAYS use --plain for AI)\nknowns doc <path> --plain # Shorthand\nknowns doc view "<path>" --plain # Full command\n\n# List tasks\nknowns task list --plain\n\n# Search (tasks + docs)\nknowns search "query" --plain\n```\n\n---\n\n## End-to-End Example\n\nHere\'s a complete workflow for an AI agent implementing a feature:\n\n```bash\n# === AGENT SESSION START (Do this once per session) ===\n\n# 0a. List all available documentation\n$ knowns doc list --plain\n\n# Output:\n# DOC: README.md\n# DOC: ARCHITECTURE.md\n# DOC: CONVENTIONS.md\n# DOC: security-patterns.md\n# DOC: api-guidelines.md\n# DOC: email-templates.md\n\n# 0b. Read essential project docs\n$ knowns doc "README" --plain\n$ knowns doc "ARCHITECTURE" --plain\n$ knowns doc "CONVENTIONS" --plain\n\n# Now the agent understands project context and conventions\n\n# === TASK WORKFLOW ===\n\n# 1. Create the task\n$ knowns task create "Add password reset flow" \\\n -d "Users need ability to reset forgotten passwords via email" \\\n --ac "User can request password reset via email" \\\n --ac "Reset link expires after 1 hour" \\\n --ac "User can set new password via reset link" \\\n --ac "Unit tests cover all scenarios" \\\n --priority high \\\n -l "auth,feature"\n\n# Output: Created task AUTH-042\n\n# 2. Take the task and start timer (uses defaultAssignee or @me fallback)\n$ knowns task edit AUTH-042 -s in-progress -a $(knowns config get defaultAssignee --plain || echo "@me")\n$ knowns time start AUTH-042\n\n# Output: Timer started for AUTH-042\n\n# 3. Search for related documentation\n$ knowns search "password security" --type doc --plain\n\n# Output:\n# DOC: security-patterns.md (score: 0.92)\n# DOC: email-templates.md (score: 0.78)\n\n# 4. Read the documentation\n$ knowns doc "security-patterns" --plain\n\n# 5. Create implementation plan (SHARE WITH USER, WAIT FOR APPROVAL)\n$ knowns task edit AUTH-042 --plan $\'1. Review security patterns (see @doc/security-patterns)\n2. Design token generation with 1-hour expiry\n3. Create email template (see @doc/email-templates)\n4. Implement /forgot-password endpoint\n5. Implement /reset-password endpoint\n6. Add unit tests\n7. Update API documentation\'\n\n# 6. After approval, implement and check criteria as you go\n$ knowns task edit AUTH-042 --check-ac 1\n$ knowns task edit AUTH-042 --append-notes "\u2713 Implemented /forgot-password endpoint"\n\n$ knowns task edit AUTH-042 --check-ac 2\n$ knowns task edit AUTH-042 --append-notes "\u2713 Token expiry set to 1 hour"\n\n$ knowns task edit AUTH-042 --check-ac 3\n$ knowns task edit AUTH-042 --append-notes "\u2713 Implemented /reset-password endpoint"\n\n$ knowns task edit AUTH-042 --check-ac 4\n$ knowns task edit AUTH-042 --append-notes "\u2713 Added 12 unit tests, 100% coverage"\n\n# 7. Add final implementation notes\n$ knowns task edit AUTH-042 --notes $\'## Summary\nImplemented complete password reset flow with secure token generation.\n\n## Changes\n- Added POST /forgot-password endpoint\n- Added POST /reset-password endpoint\n- Created password_reset_tokens table\n- Added email template for reset link\n\n## Security\n- Tokens use crypto.randomBytes(32)\n- 1-hour expiry enforced at DB level\n- Rate limiting: 3 requests per hour per email\n\n## Tests\n- 12 unit tests added\n- Coverage: 100% for new code\n\n## Documentation\n- Updated API.md with new endpoints\'\n\n# 8. Stop timer and complete\n$ knowns time stop\n$ knowns task edit AUTH-042 -s done\n\n# Output: Task AUTH-042 marked as done\n```\n\n---\n\n## Task Workflow\n\n### Step 1: Take Task\n\n```bash\n# Assign using defaultAssignee from config (falls back to @me if not set)\nknowns task edit <id> -s in-progress -a $(knowns config get defaultAssignee --plain || echo "@me")\n```\n\n> **Note**: The `defaultAssignee` is configured in `.knowns/config.json` during `knowns init`. If not set, `@me` is used as fallback. To update: `knowns config set defaultAssignee "@username"`\n\n### Step 2: Start Time Tracking (REQUIRED)\n\n```bash\nknowns time start <id>\n```\n\n> **CRITICAL**: Time tracking is MANDATORY. Always start timer when taking a task and stop when done. This data is essential for:\n> - Accurate project estimation\n> - Identifying bottlenecks\n> - Resource planning\n> - Sprint retrospectives\n\n### Step 3: Read Related Documentation\n\n> **FOR AI AGENTS**: This step is MANDATORY, not optional. You must understand the codebase before planning.\n\n```bash\n# Search for related docs\nknowns search "authentication" --type doc --plain\n\n# View relevant documents\nknowns doc "API Guidelines" --plain\nknowns doc "Security Patterns" --plain\n\n# Also check for similar completed tasks\nknowns search "auth" --type task --status done --plain\n```\n\n> **CRITICAL**: ALWAYS read related documentation BEFORE planning! Understanding existing patterns and conventions prevents rework and ensures consistency.\n\n### Step 4: Create Implementation Plan\n\n```bash\nknowns task edit <id> --plan $\'1. Research patterns (see @doc/security-patterns)\n2. Design middleware\n3. Implement\n4. Add tests\n5. Update docs\'\n```\n\n> **CRITICAL**:\n> - Share plan with user and **WAIT for approval** before coding\n> - Include doc references using `@doc/<path>` format\n\n### Step 5: Implement\n\n```bash\n# Work through implementation plan step by step\n# IMPORTANT: Only check AC AFTER completing the work, not before\n\n# After completing work for AC #1:\nknowns task edit <id> --check-ac 1\nknowns task edit <id> --append-notes "\u2713 Completed: <brief description>"\n\n# After completing work for AC #2:\nknowns task edit <id> --check-ac 2\nknowns task edit <id> --append-notes "\u2713 Completed: <brief description>"\n```\n\n> **CRITICAL**: Never check an AC before the work is actually done. ACs represent completed outcomes, not intentions.\n\n### Step 6: Handle Dynamic Requests (During Implementation)\n\nIf the user adds new requirements during implementation:\n\n```bash\n# Add new acceptance criteria\nknowns task edit <id> --ac "New requirement from user"\n\n# Update implementation plan to include new steps\nknowns task edit <id> --plan $\'1. Original step 1\n2. Original step 2\n3. NEW: Handle user request for X\n4. Continue with remaining work\'\n\n# Append note about scope change\nknowns task edit <id> --append-notes "\u26A0\uFE0F Scope updated: Added requirement for X per user request"\n\n# Continue with Step 5 (Implement) for new requirements\n```\n\n> **Note**: Always document scope changes. This helps track why a task took longer than expected.\n\n### Step 7: Add Implementation Notes\n\n```bash\n# Add comprehensive notes (suitable for PR description)\nknowns task edit <id> --notes $\'## Summary\n\nImplemented JWT auth.\n\n## Changes\n- Added middleware\n- Added tests\'\n\n# OR append progressively (recommended)\nknowns task edit <id> --append-notes "\u2713 Implemented middleware"\nknowns task edit <id> --append-notes "\u2713 Added tests"\n```\n\n### Step 8: Stop Time Tracking (REQUIRED)\n\n```bash\nknowns time stop\n```\n\n> **CRITICAL**: Never forget to stop the timer. If you forget, use manual entry: `knowns time add <id> <duration> -n "Forgot to stop timer"`\n\n### Step 9: Complete Task\n\n```bash\nknowns task edit <id> -s done\n```\n\n### Step 10: Handle Post-Completion Changes (If Applicable)\n\nIf the user requests changes or updates AFTER task is marked done:\n\n```bash\n# 1. Reopen task - set back to in-progress\nknowns task edit <id> -s in-progress\n\n# 2. Restart time tracking (REQUIRED)\nknowns time start <id>\n\n# 3. Add new AC for the changes requested\nknowns task edit <id> --ac "Post-completion fix: <description>"\n\n# 4. Document the reopen reason\nknowns task edit <id> --append-notes "\u{1F504} Reopened: User requested changes - <reason>"\n\n# 5. Follow Step 5-9 again (Implement \u2192 Notes \u2192 Stop Timer \u2192 Done)\n```\n\n> **CRITICAL**: Treat post-completion changes as a mini-workflow. Always:\n> - Reopen task (in-progress)\n> - Start timer again\n> - Add AC for traceability\n> - Document why it was reopened\n> - Follow the same completion process\n\n### Step 11: Knowledge Extraction (Post-Completion)\n\nAfter completing a task, extract reusable knowledge to docs:\n\n```bash\n# Search if similar pattern already documented\nknowns search "<pattern/concept>" --type doc --plain\n\n# If new knowledge, create a doc for future reference\nknowns doc create "Pattern: <Name>" \\\n -d "Reusable pattern discovered during task implementation" \\\n -t "pattern,<domain>" \\\n -f "patterns"\n\n# Or append to existing doc\nknowns doc edit "<existing-doc>" -a "## New Section\\n\\nLearned from task <id>: ..."\n\n# Reference the source task\nknowns doc edit "<doc-name>" -a "\\n\\n> Source: @task-<id>"\n```\n\n**When to extract knowledge:**\n- New patterns/conventions discovered\n- Common error solutions\n- Reusable code snippets or approaches\n- Integration patterns with external services\n- Performance optimization techniques\n\n> **CRITICAL**: Only extract **generalizable** knowledge. Task-specific details belong in implementation notes, not docs.\n\n---\n\n## Essential Commands\n\n### Task Management\n\n```bash\n# Create task\nknowns task create "Title" -d "Description" --ac "Criterion" -l "labels" --priority high\n\n# Edit task\nknowns task edit <id> -t "New title"\nknowns task edit <id> -d "New description"\nknowns task edit <id> -s in-progress\nknowns task edit <id> --priority high\nknowns task edit <id> -a <assignee> # $(knowns config get defaultAssignee --plain || echo "@me")\n\n# Acceptance Criteria\nknowns task edit <id> --ac "New criterion" # Add\nknowns task edit <id> --check-ac 1 --check-ac 2 # Check (1-indexed)\nknowns task edit <id> --uncheck-ac 2 # Uncheck\nknowns task edit <id> --remove-ac 3 # Remove\n\n# Implementation Plan & Notes\nknowns task edit <id> --plan $\'1. Step\\n2. Step\'\nknowns task edit <id> --notes "Implementation summary"\nknowns task edit <id> --append-notes "Progress update"\n\n# View & List\nknowns task <id> --plain # Shorthand (ALWAYS use --plain)\nknowns task view <id> --plain # Full command\nknowns task list --plain\nknowns task list --status in-progress --plain\nknowns task list --assignee <assignee> --plain # $(knowns config get defaultAssignee --plain || echo "@me")\nknowns task list --tree --plain # Tree hierarchy\n```\n\n### Time Tracking\n\n```bash\n# Timer\nknowns time start <id>\nknowns time stop\nknowns time pause\nknowns time resume\nknowns time status\n\n# Manual entry\nknowns time add <id> 2h -n "Note" -d "2025-12-25"\n\n# Reports\nknowns time report --from "2025-12-01" --to "2025-12-31"\nknowns time report --by-label --csv > report.csv\n```\n\n### Documentation\n\n```bash\n# List & View\nknowns doc list --plain\nknowns doc list --tag architecture --plain\nknowns doc <path> --plain # Shorthand (ALWAYS use --plain)\nknowns doc view "<path>" --plain # Full command\n\n# Create (with optional folder)\nknowns doc create "Title" -d "Description" -t "tags"\nknowns doc create "Title" -d "Description" -t "tags" -f "folder/path"\n\n# Edit metadata\nknowns doc edit "Doc Name" -t "New Title" --tags "new,tags"\n\n# Edit content\nknowns doc edit "Doc Name" -c "New content" # Replace content\nknowns doc edit "Doc Name" -a "Appended content" # Append to content\n```\n\n### Search\n\n```bash\n# Search everything\nknowns search "query" --plain\n\n# Search specific type\nknowns search "auth" --type task --plain\nknowns search "patterns" --type doc --plain\n\n# Filter\nknowns search "bug" --status in-progress --priority high --plain\n```\n\n---\n\n## Task Structure\n\n### Title\n\nClear summary (WHAT needs to be done).\n\n| Bad | Good |\n|-----|------|\n| Do auth stuff | Add JWT authentication |\n| Fix bug | Fix login timeout on slow networks |\n| Update docs | Document rate limiting in API.md |\n\n### Description\n\nExplains WHY and WHAT (not HOW). **Link related docs using `@doc/<path>`**\n\n```markdown\nWe need JWT authentication because sessions don\'t scale for our microservices architecture.\n\nRelated docs: @doc/security-patterns, @doc/api-guidelines\n```\n\n### Acceptance Criteria\n\n**Outcome-oriented**, testable criteria. NOT implementation steps.\n\n| Bad (Implementation details) | Good (Outcomes) |\n|------------------------------|-----------------|\n| Add function handleLogin() in auth.ts | User can login and receive JWT token |\n| Use bcrypt for hashing | Passwords are securely hashed |\n| Add try-catch blocks | Errors return appropriate HTTP status codes |\n\n### Implementation Plan\n\nHOW to solve. Added AFTER taking task, BEFORE coding.\n\n```markdown\n1. Research JWT libraries (see @doc/security-patterns)\n2. Design token structure (access + refresh tokens)\n3. Implement auth middleware\n4. Add unit tests (aim for 90%+ coverage)\n5. Update API.md with new endpoints\n```\n\n### Implementation Notes\n\nSummary for PR description. Added AFTER completion.\n\n```markdown\n## Summary\nImplemented JWT auth using jsonwebtoken library.\n\n## Changes\n- Added auth middleware in src/middleware/auth.ts\n- Added /login and /refresh endpoints\n- Created JWT utility functions\n\n## Tests\n- Added 15 unit tests\n- Coverage: 94%\n\n## Documentation\n- Updated API.md with authentication section\n```\n\n---\n\n## Error Handling\n\n### Common Errors and Solutions\n\n| Error | Cause | Solution |\n|-------|-------|----------|\n| `Error: Task not found` | Invalid task ID | Run `knowns task list --plain` to find correct ID |\n| `Error: No active timer` | Calling `time stop` without active timer | Start timer first: `knowns time start <id>` |\n| `Error: Timer already running` | Starting timer when one is active | Stop current: `knowns time stop` |\n| `Error: Invalid status` | Wrong status format | Use lowercase with hyphens: `in-progress`, not `In Progress` |\n| `Error: AC index out of range` | Checking non-existent criterion | View task first: `knowns task <id> --plain` |\n| `Error: Document not found` | Wrong document name | Run `knowns doc list --plain` to find correct name |\n| `Error: Not initialized` | Running commands without init | Run `knowns init` first |\n\n### Debugging Commands\n\n```bash\n# Check CLI version\nknowns --version\n\n# Verify project is initialized\nknowns status\n\n# View raw task data (for debugging)\nknowns task <id> --json\n\n# Check timer status\nknowns time status\n```\n\n---\n\n## Definition of Done\n\nA task is **Done** ONLY when **ALL** criteria are met:\n\n### Via CLI (Required)\n\n- [ ] All acceptance criteria checked: `--check-ac <index>` (only after work is actually done)\n- [ ] Implementation notes added: `--notes "..."`\n- [ ] \u23F1\uFE0F Timer stopped: `knowns time stop` (MANDATORY - do not skip!)\n- [ ] Status set to done: `-s done`\n- [ ] Knowledge extracted to docs (if applicable)\n\n### Via Code (Required)\n\n- [ ] All tests pass\n- [ ] Documentation updated\n- [ ] Code reviewed (linting, formatting)\n- [ ] No regressions introduced\n\n---\n\n## Status & Priority Reference\n\n### Status Values\n\nUse **lowercase with hyphens**:\n\n| Status | Description | When to Use |\n|--------|-------------|-------------|\n| `todo` | Not started | Default for new tasks |\n| `in-progress` | Currently working | After taking task |\n| `in-review` | In code review | PR submitted |\n| `blocked` | Waiting on dependency | External blocker |\n| `done` | Completed | All criteria met |\n\n### Priority Values\n\n| Priority | Description |\n|----------|-------------|\n| `low` | Can wait, nice-to-have |\n| `medium` | Normal priority (default) |\n| `high` | Urgent, time-sensitive |\n\n---\n\n## Common Mistakes\n\n| Wrong | Right |\n|-------|-------|\n| Edit .md files directly | Use `knowns task edit` |\n| Change `- [ ]` to `- [x]` in file | Use `--check-ac <index>` |\n| Check AC before completing work | Only check AC AFTER work is actually done |\n| Skip time tracking | ALWAYS use `time start` and `time stop` |\n| Start coding without reading docs | Read ALL related docs FIRST |\n| Skip `knowns doc list` on new project | Always list docs when starting |\n| Assume you know the conventions | Read CONVENTIONS/ARCHITECTURE docs |\n| Plan without checking docs | Read docs before planning |\n| Ignore similar completed tasks | Search done tasks for patterns |\n| Missing doc links in description/plan | Link docs using `@doc/<path>` |\n| Write refs as `@.knowns/docs/...` or `@.knowns/tasks/...` | Use input format: `@doc/<path>`, `@task-<id>` |\n| Forget `--plain` flag | Always use `--plain` for AI |\n| Code before plan approval | Share plan, WAIT for approval |\n| Mark done without all criteria | Check ALL criteria first |\n| Write implementation steps in AC | Write outcome-oriented criteria |\n| Use `"In Progress"` or `"Done"` | Use `in-progress`, `done` |\n| Use `@yourself` or unknown assignee | Use `$(knowns config get defaultAssignee --plain \\|\\| echo "@me")` |\n| Ignore refs in task description | Follow ALL refs (`@.knowns/...`) before planning |\n| See `@.knowns/docs/...` but don\'t read | Use `knowns doc "<path>" --plain` |\n| See `@.knowns/tasks/task-X` but don\'t check | Use `knowns task X --plain` for context |\n| Follow only first-level refs | Recursively follow nested refs until complete |\n\n---\n\n## Platform-Specific Notes\n\n### Multi-line Input\n\nDifferent shells handle multi-line strings differently:\n\n**Bash / Zsh (Recommended)**\n```bash\nknowns task edit <id> --plan $\'1. First step\\n2. Second step\\n3. Third step\'\n```\n\n**PowerShell**\n```powershell\nknowns task edit <id> --plan "1. First step`n2. Second step`n3. Third step"\n```\n\n**Cross-platform (Using printf)**\n```bash\nknowns task edit <id> --plan "$(printf \'1. First step\\n2. Second step\\n3. Third step\')"\n```\n\n**Using heredoc (for long content)**\n```bash\nknowns task edit <id> --plan "$(cat <<EOF\n1. First step\n2. Second step\n3. Third step\nEOF\n)"\n```\n\n### Path Separators\n\n- **Unix/macOS**: Use forward slashes: `./docs/api.md`\n- **Windows**: Both work, but prefer forward slashes for consistency\n\n### Windows Command Line Limit\n\nWindows has ~8191 character limit. For long content, append in chunks:\n\n```bash\n# 1. Create or reset with short content\nknowns doc edit "doc-name" -c "## Overview\\n\\nShort intro."\n\n# 2. Append each section separately\nknowns doc edit "doc-name" -a "## Section 1\\n\\nContent..."\nknowns doc edit "doc-name" -a "## Section 2\\n\\nMore content..."\n```\n\nOr use file-based options:\n\n```bash\nknowns doc edit "doc-name" --content-file ./content.md\nknowns doc edit "doc-name" --append-file ./more.md\n```\n\n---\n\n## Best Practices Checklist\n\n### For AI Agents: Session Start\n\n- [ ] List all docs: `knowns doc list --plain`\n- [ ] Read README/ARCHITECTURE docs\n- [ ] Understand coding conventions\n- [ ] Review current task backlog\n\n### Before Starting Work\n\n- [ ] Task has clear acceptance criteria\n- [ ] ALL refs in task followed (`@.knowns/...`)\n- [ ] Nested refs recursively followed until complete context gathered\n- [ ] Related docs searched: `knowns search "keyword" --type doc --plain`\n- [ ] ALL relevant docs read: `knowns doc "Doc Name" --plain`\n- [ ] Similar done tasks reviewed for patterns\n- [ ] Task assigned to self: `-a $(knowns config get defaultAssignee --plain || echo "@me")`\n- [ ] Status set to in-progress: `-s in-progress`\n- [ ] Timer started: `knowns time start <id>`\n\n### During Work\n\n- [ ] Implementation plan created and approved\n- [ ] Doc links included in plan: `@doc/<path>`\n- [ ] Criteria checked as completed: `--check-ac <index>`\n- [ ] Progress notes appended: `--append-notes "\u2713 ..."`\n\n### After Work\n\n- [ ] All acceptance criteria checked (only after work is done)\n- [ ] Implementation notes added: `--notes "..."`\n- [ ] Timer stopped: `knowns time stop`\n- [ ] Tests passing\n- [ ] Documentation updated\n- [ ] Status set to done: `-s done`\n- [ ] Knowledge extracted to docs (if applicable): patterns, solutions, conventions\n\n---\n\n## Quick Reference Card\n\n```bash\n# === AGENT INITIALIZATION (Once per session) ===\nknowns doc list --plain\nknowns doc "README" --plain\nknowns doc "ARCHITECTURE" --plain\nknowns doc "CONVENTIONS" --plain\n\n# === FULL WORKFLOW ===\nknowns task create "Title" -d "Description" --ac "Criterion"\nknowns task edit <id> -s in-progress -a $(knowns config get defaultAssignee --plain || echo "@me")\nknowns time start <id> # \u23F1\uFE0F REQUIRED: Start timer\nknowns search "keyword" --type doc --plain\nknowns doc "Doc Name" --plain\nknowns search "keyword" --type task --status done --plain # Learn from history\nknowns task edit <id> --plan $\'1. Step (see @doc/file)\\n2. Step\'\n# ... wait for approval, then implement ...\n# Only check AC AFTER completing the work:\nknowns task edit <id> --check-ac 1\nknowns task edit <id> --append-notes "\u2713 Completed: feature X"\nknowns task edit <id> --check-ac 2\nknowns task edit <id> --append-notes "\u2713 Completed: feature Y"\nknowns time stop # \u23F1\uFE0F REQUIRED: Stop timer\nknowns task edit <id> -s done\n# Optional: Extract knowledge to docs if generalizable patterns found\n\n# === VIEW & SEARCH ===\nknowns task <id> --plain # Shorthand for view\nknowns task list --plain\nknowns task list --status in-progress --assignee $(knowns config get defaultAssignee --plain || echo "@me") --plain\nknowns search "query" --plain\nknowns search "bug" --type task --status in-progress --plain\n\n# === TIME TRACKING ===\nknowns time start <id>\nknowns time stop\nknowns time status\nknowns time report --from "2025-12-01" --to "2025-12-31"\n\n# === DOCUMENTATION ===\nknowns doc list --plain\nknowns doc "path/doc-name" --plain # Shorthand for view\nknowns doc create "Title" -d "Description" -t "tags" -f "folder"\nknowns doc edit "doc-name" -c "New content"\nknowns doc edit "doc-name" -a "Appended content"\n```\n\n---\n\n**Maintained By**: Knowns CLI Team\n\n<!-- KNOWNS GUIDELINES END -->\n';
47001
+
47002
+ // src/templates/mcp/gemini.md
47003
+ var gemini_default2 = '<!-- KNOWNS GUIDELINES START -->\n# Knowns MCP - Gemini Quick Reference\n\n## RULES\n- NEVER edit .md files directly - use MCP tools only\n- Read docs BEFORE coding\n- Start timer when taking task, stop when done\n\n## SESSION START\n```\nmcp__knowns__list_docs({})\nmcp__knowns__get_doc({ path: "README" })\nmcp__knowns__list_tasks({})\n```\n\n## TASK WORKFLOW\n\n### 1. Take Task\n```\nmcp__knowns__get_task({ taskId: "<id>" })\nmcp__knowns__update_task({ taskId: "<id>", status: "in-progress", assignee: "@me" })\nmcp__knowns__start_time({ taskId: "<id>" })\n```\n\n### 2. Read Context\n```\nmcp__knowns__list_docs({ tag: "guides" })\nmcp__knowns__get_doc({ path: "path/name" })\nmcp__knowns__search_docs({ query: "keyword" })\n```\n\n### 3. Plan & Implement\n```\nmcp__knowns__update_task({ taskId: "<id>", description: "Updated with plan..." })\n// Wait for approval, then code\nmcp__knowns__update_task({ taskId: "<id>", labels: ["done-ac-1"] })\n```\n\n### 4. Complete\n```\nmcp__knowns__stop_time({ taskId: "<id>" })\nmcp__knowns__update_task({ taskId: "<id>", status: "done" })\n```\n\n## MCP TOOLS CHEATSHEET\n\n### Task\n```\nmcp__knowns__list_tasks({})\nmcp__knowns__list_tasks({ status: "in-progress" })\nmcp__knowns__get_task({ taskId: "<id>" })\nmcp__knowns__create_task({ title: "Title", description: "Desc", priority: "high" })\nmcp__knowns__update_task({ taskId: "<id>", status: "<status>", assignee: "@me" })\nmcp__knowns__search_tasks({ query: "keyword" })\n```\n\n### Doc\n```\nmcp__knowns__list_docs({})\nmcp__knowns__list_docs({ tag: "patterns" })\nmcp__knowns__get_doc({ path: "name" })\nmcp__knowns__create_doc({ title: "Title", description: "Desc", tags: ["tag1"] })\nmcp__knowns__update_doc({ path: "name", content: "new content" })\nmcp__knowns__update_doc({ path: "name", appendContent: "more content" })\nmcp__knowns__search_docs({ query: "keyword" })\n```\n\n### Time\n```\nmcp__knowns__start_time({ taskId: "<id>" })\nmcp__knowns__stop_time({ taskId: "<id>" })\nmcp__knowns__add_time({ taskId: "<id>", duration: "2h", note: "Note" })\nmcp__knowns__get_time_report({})\n```\n\n### Board\n```\nmcp__knowns__get_board({})\n```\n\n## REFS\n\n### Reading (output format)\n- `@.knowns/tasks/task-X - Title.md` \u2192 `mcp__knowns__get_task({ taskId: "X" })`\n- `@.knowns/docs/path/name.md` \u2192 `mcp__knowns__get_doc({ path: "path/name" })`\n\n### Writing (input format)\n- Task: `@task-X`\n- Doc: `@doc/path/name`\n\n## STATUS & PRIORITY\n\n**Status:** `todo`, `in-progress`, `in-review`, `blocked`, `done`\n**Priority:** `low`, `medium`, `high`\n\n## LONG CONTENT\n\nFor large docs, append in chunks:\n```\n# Create with initial content\nmcp__knowns__create_doc({ title: "Title", content: "## Overview\\n\\nIntro." })\n\n# Append sections\nmcp__knowns__update_doc({ path: "name", appendContent: "## Section 1\\n\\n..." })\nmcp__knowns__update_doc({ path: "name", appendContent: "## Section 2\\n\\n..." })\n```\n<!-- KNOWNS GUIDELINES END -->\n';
47004
+
47005
+ // src/templates/mcp/general.md
47006
+ var general_default2 = '<!-- KNOWNS GUIDELINES START -->\n# Knowns MCP Guidelines\n\n## Core Principles\n\n### 1. MCP Tool Operations\n**Use MCP tools for ALL Knowns operations. NEVER edit .md files directly.**\n\nThis ensures data integrity, maintains proper change history, and prevents file corruption.\n\n### 2. Documentation-First (For AI Agents)\n**ALWAYS read project documentation BEFORE planning or coding.**\n\nAI agents must understand project context, conventions, and existing patterns before making any changes. This prevents rework and ensures consistency.\n\n---\n\n## AI Agent Guidelines\n\n> **CRITICAL**: Before performing ANY task, AI agents MUST read documentation to understand project context.\n\n### First-Time Initialization\n\nWhen starting a new session or working on an unfamiliar project:\n\n```\n# 1. List all available documentation\nmcp__knowns__list_docs({})\n\n# 2. Read essential project docs (prioritize these)\nmcp__knowns__get_doc({ path: "README" })\nmcp__knowns__get_doc({ path: "ARCHITECTURE" })\nmcp__knowns__get_doc({ path: "CONVENTIONS" })\nmcp__knowns__get_doc({ path: "API" })\n\n# 3. Review current task backlog\nmcp__knowns__list_tasks({})\nmcp__knowns__list_tasks({ status: "in-progress" })\n```\n\n### Before Taking Any Task\n\n```\n# 1. View the task details\nmcp__knowns__get_task({ taskId: "<id>" })\n\n# 2. Follow ALL refs in the task (see Reference System section)\n# @.knowns/tasks/task-44 - ... \u2192 mcp__knowns__get_task({ taskId: "44" })\n# @.knowns/docs/patterns/module.md \u2192 mcp__knowns__get_doc({ path: "patterns/module" })\n\n# 3. Search for additional related documentation\nmcp__knowns__search_docs({ query: "<keywords from task>" })\n\n# 4. Read ALL related docs before planning\nmcp__knowns__get_doc({ path: "<related-doc>" })\n\n# 5. Check for similar completed tasks (learn from history)\nmcp__knowns__search_tasks({ query: "<keywords>", status: "done" })\n```\n\n### Why Documentation First?\n\n| Without Reading Docs | With Reading Docs |\n|---------------------|-------------------|\n| Reinvent existing patterns | Reuse established patterns |\n| Break conventions | Follow project standards |\n| Duplicate code | Use existing utilities |\n| Wrong architecture decisions | Align with system design |\n| Inconsistent naming | Match naming conventions |\n\n### Context Checklist for Agents\n\nBefore writing ANY code, ensure you can answer:\n\n- [ ] Have I followed ALL refs (`@.knowns/...`) in the task?\n- [ ] Have I followed nested refs recursively?\n- [ ] What is the project\'s overall architecture?\n- [ ] What coding conventions does this project follow?\n- [ ] Are there existing patterns/utilities I should reuse?\n- [ ] What are the testing requirements?\n- [ ] How should I structure my implementation?\n\n> **Remember**: A few minutes reading docs saves hours of rework. NEVER skip this step.\n\n---\n\n## Reference System (Refs)\n\nTasks and docs can contain **references** to other tasks/docs. AI agents MUST understand and follow these refs to gather complete context.\n\n### Reference Formats\n\n| Type | When Writing (Input) | When Reading (Output) | MCP Tool |\n|------|---------------------|----------------------|----------|\n| **Task ref** | `@task-<id>` | `@.knowns/tasks/task-<id> - <title>.md` | `mcp__knowns__get_task({ taskId: "<id>" })` |\n| **Doc ref** | `@doc/<path>` | `@.knowns/docs/<path>.md` | `mcp__knowns__get_doc({ path: "<path>" })` |\n\n> **CRITICAL for AI Agents**:\n> - When **WRITING** refs (in descriptions, plans, notes): Use `@task-<id>` and `@doc/<path>`\n> - When **READING** output: You\'ll see `@.knowns/tasks/...` and `@.knowns/docs/...`\n> - **NEVER write** the output format (`@.knowns/...`) - always use input format\n\n### How to Follow Refs\n\nWhen you read a task and see refs in system output format, follow them:\n\n```\n# Example: Task 42 output contains:\n# @.knowns/tasks/task-44 - CLI Task Create Command.md\n# @.knowns/docs/patterns/module.md\n\n# Follow task ref (extract ID from task-<id>)\nmcp__knowns__get_task({ taskId: "44" })\n\n# Follow doc ref (extract path, remove .md)\nmcp__knowns__get_doc({ path: "patterns/module" })\n```\n\n### Recursive Following\n\nRefs can be nested. Follow until complete context is gathered:\n\n```\nTask 42\n \u2192 @.knowns/docs/README.md\n \u2192 @.knowns/docs/patterns/module.md (found in README)\n \u2192 (read for full pattern details)\n```\n\n> **CRITICAL**: Never assume you understand a task fully without following its refs. Refs contain essential context that may change your implementation approach.\n\n---\n\n## Quick Start\n\n```\n# Initialize project (use CLI for this)\nknowns init [name]\n\n# Create task with acceptance criteria\nmcp__knowns__create_task({\n title: "Title",\n description: "Description",\n priority: "high",\n labels: ["label1", "label2"]\n})\n\n# View task\nmcp__knowns__get_task({ taskId: "<id>" })\n\n# List tasks\nmcp__knowns__list_tasks({})\n\n# Search (tasks + docs)\nmcp__knowns__search_tasks({ query: "query" })\nmcp__knowns__search_docs({ query: "query" })\n```\n\n---\n\n## End-to-End Example\n\nHere\'s a complete workflow for an AI agent implementing a feature:\n\n```\n# === AGENT SESSION START (Do this once per session) ===\n\n# 0a. List all available documentation\nmcp__knowns__list_docs({})\n\n# 0b. Read essential project docs\nmcp__knowns__get_doc({ path: "README" })\nmcp__knowns__get_doc({ path: "ARCHITECTURE" })\nmcp__knowns__get_doc({ path: "CONVENTIONS" })\n\n# Now the agent understands project context and conventions\n\n# === TASK WORKFLOW ===\n\n# 1. Create the task\nmcp__knowns__create_task({\n title: "Add password reset flow",\n description: "Users need ability to reset forgotten passwords via email",\n priority: "high",\n labels: ["auth", "feature"]\n})\n\n# Output: Created task 42\n\n# 2. Take the task and start timer\nmcp__knowns__update_task({\n taskId: "42",\n status: "in-progress",\n assignee: "@howznguyen"\n})\nmcp__knowns__start_time({ taskId: "42" })\n\n# 3. Search for related documentation\nmcp__knowns__search_docs({ query: "password security" })\n\n# 4. Read the documentation\nmcp__knowns__get_doc({ path: "security-patterns" })\n\n# 5. Create implementation plan (SHARE WITH USER, WAIT FOR APPROVAL)\nmcp__knowns__update_task({\n taskId: "42",\n plan: "1. Review security patterns (see @doc/security-patterns)\\n2. Design token generation with 1-hour expiry\\n3. Implement /forgot-password endpoint\\n4. Add unit tests"\n})\n\n# 6. After approval, implement and update task progressively\nmcp__knowns__update_task({\n taskId: "42",\n appendNotes: "\u2713 Implemented /forgot-password endpoint"\n})\n\n# 7. Add final implementation notes\nmcp__knowns__update_task({\n taskId: "42",\n notes: "## Summary\\nImplemented complete password reset flow.\\n\\n## Changes\\n- Added POST /forgot-password endpoint\\n- Added POST /reset-password endpoint"\n})\n\n# 8. Stop timer and complete\nmcp__knowns__stop_time({ taskId: "42" })\nmcp__knowns__update_task({\n taskId: "42",\n status: "done"\n})\n```\n\n---\n\n## Task Workflow\n\n### Step 1: Take Task\n\n```\n# Update task status and assign to self\nmcp__knowns__update_task({\n taskId: "<id>",\n status: "in-progress",\n assignee: "@<your-username>"\n})\n```\n\n> **Note**: Use your username as configured in the project. Check project config for `defaultAssignee`.\n\n### Step 2: Start Time Tracking (REQUIRED)\n\n```\nmcp__knowns__start_time({ taskId: "<id>" })\n```\n\n> **CRITICAL**: Time tracking is MANDATORY. Always start timer when taking a task and stop when done. This data is essential for:\n> - Accurate project estimation\n> - Identifying bottlenecks\n> - Resource planning\n> - Sprint retrospectives\n\n### Step 3: Read Related Documentation\n\n> **FOR AI AGENTS**: This step is MANDATORY, not optional. You must understand the codebase before planning.\n\n```\n# Search for related docs\nmcp__knowns__search_docs({ query: "authentication" })\n\n# View relevant documents\nmcp__knowns__get_doc({ path: "API Guidelines" })\nmcp__knowns__get_doc({ path: "Security Patterns" })\n\n# Also check for similar completed tasks\nmcp__knowns__search_tasks({ query: "auth", status: "done" })\n```\n\n> **CRITICAL**: ALWAYS read related documentation BEFORE planning!\n\n### Step 4: Create Implementation Plan\n\n```\nmcp__knowns__update_task({\n taskId: "<id>",\n plan: "1. Research patterns (see @doc/security-patterns)\\n2. Design middleware\\n3. Implement\\n4. Add tests\\n5. Update docs"\n})\n```\n\n> **CRITICAL**:\n> - Share plan with user and **WAIT for approval** before coding\n> - Include doc references using `@doc/<path>` format\n\n### Step 5: Implement\n\n```\n# Work through implementation plan step by step\n# IMPORTANT: Only update task AFTER completing the work, not before\n\n# After completing work, append notes:\nmcp__knowns__update_task({\n taskId: "<id>",\n appendNotes: "\u2713 Completed: <brief description>"\n})\n```\n\n> **CRITICAL**: Never claim work is done before it\'s actually completed.\n\n### Step 6: Handle Dynamic Requests (During Implementation)\n\nIf the user adds new requirements during implementation:\n\n```\n# Append note about scope change\nmcp__knowns__update_task({\n taskId: "<id>",\n appendNotes: "\u26A0\uFE0F Scope updated: Added requirement for X per user request"\n})\n\n# Continue with Step 5 (Implement) for new requirements\n```\n\n> **Note**: Always document scope changes. This helps track why a task took longer than expected.\n\n### Step 7: Add Implementation Notes\n\n```\n# Add comprehensive notes (suitable for PR description)\nmcp__knowns__update_task({\n taskId: "<id>",\n notes: "## Summary\\n\\nImplemented JWT auth.\\n\\n## Changes\\n- Added middleware\\n- Added tests"\n})\n\n# OR append progressively (recommended)\nmcp__knowns__update_task({\n taskId: "<id>",\n appendNotes: "\u2713 Implemented middleware"\n})\n```\n\n### Step 8: Stop Time Tracking (REQUIRED)\n\n```\nmcp__knowns__stop_time({ taskId: "<id>" })\n```\n\n> **CRITICAL**: Never forget to stop the timer. If you forget, use manual entry:\n> `mcp__knowns__add_time({ taskId: "<id>", duration: "2h", note: "Forgot to stop timer" })`\n\n### Step 9: Complete Task\n\n```\nmcp__knowns__update_task({\n taskId: "<id>",\n status: "done"\n})\n```\n\n### Step 10: Handle Post-Completion Changes (If Applicable)\n\nIf the user requests changes or updates AFTER task is marked done:\n\n```\n# 1. Reopen task - set back to in-progress\nmcp__knowns__update_task({\n taskId: "<id>",\n status: "in-progress"\n})\n\n# 2. Restart time tracking (REQUIRED)\nmcp__knowns__start_time({ taskId: "<id>" })\n\n# 3. Document the reopen reason\nmcp__knowns__update_task({\n taskId: "<id>",\n appendNotes: "\u{1F504} Reopened: User requested changes - <reason>"\n})\n\n# 4. Follow Step 5-9 again (Implement \u2192 Notes \u2192 Stop Timer \u2192 Done)\n```\n\n> **CRITICAL**: Treat post-completion changes as a mini-workflow. Always:\n> - Reopen task (in-progress)\n> - Start timer again\n> - Document why it was reopened\n> - Follow the same completion process\n\n### Step 11: Knowledge Extraction (Post-Completion)\n\nAfter completing a task, extract reusable knowledge to docs:\n\n```\n# Search if similar pattern already documented\nmcp__knowns__search_docs({ query: "<pattern/concept>" })\n\n# If new knowledge, create a doc for future reference\nmcp__knowns__create_doc({\n title: "Pattern: <Name>",\n description: "Reusable pattern discovered during task implementation",\n tags: ["pattern", "<domain>"],\n folder: "patterns"\n})\n\n# Or append to existing doc\nmcp__knowns__update_doc({\n path: "<existing-doc>",\n appendContent: "## New Section\\n\\nLearned from task <id>: ..."\n})\n```\n\n**When to extract knowledge:**\n- New patterns/conventions discovered\n- Common error solutions\n- Reusable code snippets or approaches\n- Integration patterns with external services\n- Performance optimization techniques\n\n> **CRITICAL**: Only extract **generalizable** knowledge. Task-specific details belong in implementation notes, not docs.\n\n---\n\n## Essential MCP Tools\n\n### Task Management\n\n```\n# Create task\nmcp__knowns__create_task({\n title: "Title",\n description: "Description",\n priority: "high", # low, medium, high\n labels: ["label1"],\n status: "todo", # todo, in-progress, in-review, done, blocked\n assignee: "@username"\n})\n\n# Get task\nmcp__knowns__get_task({ taskId: "<id>" })\n\n# Update task\nmcp__knowns__update_task({\n taskId: "<id>",\n title: "New title",\n description: "New description",\n status: "in-progress",\n priority: "high",\n assignee: "@username",\n labels: ["new", "labels"],\n plan: "Implementation plan...",\n notes: "Implementation notes...",\n appendNotes: "Append to existing notes..."\n})\n\n# List tasks\nmcp__knowns__list_tasks({})\nmcp__knowns__list_tasks({ status: "in-progress" })\nmcp__knowns__list_tasks({ assignee: "@username" })\nmcp__knowns__list_tasks({ priority: "high" })\nmcp__knowns__list_tasks({ label: "feature" })\n\n# Search tasks\nmcp__knowns__search_tasks({ query: "auth" })\n```\n\n### Time Tracking\n\n```\n# Start timer\nmcp__knowns__start_time({ taskId: "<id>" })\n\n# Stop timer\nmcp__knowns__stop_time({ taskId: "<id>" })\n\n# Manual entry\nmcp__knowns__add_time({\n taskId: "<id>",\n duration: "2h", # e.g., "2h", "30m", "1h30m"\n note: "Optional note",\n date: "2025-12-25" # Optional, defaults to now\n})\n\n# Reports\nmcp__knowns__get_time_report({})\nmcp__knowns__get_time_report({\n from: "2025-12-01",\n to: "2025-12-31",\n groupBy: "task" # task, label, status\n})\n```\n\n### Documentation\n\n```\n# List docs\nmcp__knowns__list_docs({})\nmcp__knowns__list_docs({ tag: "architecture" })\n\n# Get doc\nmcp__knowns__get_doc({ path: "README" })\nmcp__knowns__get_doc({ path: "patterns/module" })\n\n# Create doc\nmcp__knowns__create_doc({\n title: "Title",\n description: "Description",\n tags: ["tag1", "tag2"],\n folder: "folder/path", # Optional\n content: "Initial content..."\n})\n\n# Update doc\nmcp__knowns__update_doc({\n path: "doc-name",\n title: "New Title",\n description: "New description",\n tags: ["new", "tags"],\n content: "Replace content...",\n appendContent: "Append to content..."\n})\n\n# Search docs\nmcp__knowns__search_docs({ query: "patterns" })\nmcp__knowns__search_docs({ query: "auth", tag: "security" })\n```\n\n### Board\n\n```\n# Get kanban board view\nmcp__knowns__get_board({})\n```\n\n---\n\n## Task Structure\n\n### Title\n\nClear summary (WHAT needs to be done).\n\n| Bad | Good |\n|-----|------|\n| Do auth stuff | Add JWT authentication |\n| Fix bug | Fix login timeout on slow networks |\n| Update docs | Document rate limiting in API.md |\n\n### Description\n\nExplains WHY and WHAT (not HOW). **Link related docs using `@doc/<path>`**\n\n```\nWe need JWT authentication because sessions don\'t scale for our microservices architecture.\n\nRelated docs: @doc/security-patterns, @doc/api-guidelines\n```\n\n### Acceptance Criteria\n\n**Outcome-oriented**, testable criteria. NOT implementation steps.\n\n| Bad (Implementation details) | Good (Outcomes) |\n|------------------------------|-----------------|\n| Add function handleLogin() in auth.ts | User can login and receive JWT token |\n| Use bcrypt for hashing | Passwords are securely hashed |\n| Add try-catch blocks | Errors return appropriate HTTP status codes |\n\n---\n\n## Definition of Done\n\nA task is **Done** ONLY when **ALL** criteria are met:\n\n### Via MCP Tools (Required)\n\n- [ ] All work completed and verified\n- [ ] Implementation notes added via `update_task`\n- [ ] \u23F1\uFE0F Timer stopped: `mcp__knowns__stop_time` (MANDATORY - do not skip!)\n- [ ] Status set to done via `update_task`\n- [ ] Knowledge extracted to docs (if applicable)\n\n### Via Code (Required)\n\n- [ ] All tests pass\n- [ ] Documentation updated\n- [ ] Code reviewed (linting, formatting)\n- [ ] No regressions introduced\n\n---\n\n## Status & Priority Reference\n\n### Status Values\n\n| Status | Description | When to Use |\n|--------|-------------|-------------|\n| `todo` | Not started | Default for new tasks |\n| `in-progress` | Currently working | After taking task |\n| `in-review` | In code review | PR submitted |\n| `blocked` | Waiting on dependency | External blocker |\n| `done` | Completed | All criteria met |\n\n### Priority Values\n\n| Priority | Description |\n|----------|-------------|\n| `low` | Can wait, nice-to-have |\n| `medium` | Normal priority (default) |\n| `high` | Urgent, time-sensitive |\n\n---\n\n## Common Mistakes\n\n| Wrong | Right |\n|-------|-------|\n| Edit .md files directly | Use MCP tools |\n| Skip time tracking | ALWAYS use `start_time` and `stop_time` |\n| Start coding without reading docs | Read ALL related docs FIRST |\n| Plan without checking docs | Read docs before planning |\n| Code before plan approval | Share plan, WAIT for approval |\n| Mark done without all criteria | Verify ALL criteria first |\n| Ignore refs in task description | Follow ALL refs before planning |\n| Follow only first-level refs | Recursively follow nested refs |\n\n---\n\n## Long Content Handling\n\nFor long documentation content, append in chunks:\n\n```\n# 1. Create doc with initial content\nmcp__knowns__create_doc({\n title: "Doc Title",\n content: "## Overview\\n\\nShort intro."\n})\n\n# 2. Append each section separately\nmcp__knowns__update_doc({\n path: "doc-title",\n appendContent: "## Section 1\\n\\nContent for section 1..."\n})\n\nmcp__knowns__update_doc({\n path: "doc-title",\n appendContent: "## Section 2\\n\\nContent for section 2..."\n})\n```\n\n> **Tip**: Each `appendContent` adds content after existing content. Use this for large docs to avoid context limits.\n\n---\n\n## Best Practices Checklist\n\n### For AI Agents: Session Start\n\n- [ ] List all docs: `mcp__knowns__list_docs({})`\n- [ ] Read README/ARCHITECTURE docs\n- [ ] Understand coding conventions\n- [ ] Review current task backlog\n\n### Before Starting Work\n\n- [ ] Task details retrieved: `mcp__knowns__get_task`\n- [ ] ALL refs in task followed\n- [ ] Nested refs recursively followed\n- [ ] Related docs searched and read\n- [ ] Similar done tasks reviewed for patterns\n- [ ] Task assigned to self via `update_task`\n- [ ] Status set to in-progress\n- [ ] Timer started: `mcp__knowns__start_time`\n\n### During Work\n\n- [ ] Implementation plan created and approved\n- [ ] Doc links included in plan: `@doc/<path>`\n- [ ] Progress notes appended: `appendNotes`\n\n### After Work\n\n- [ ] All work verified complete\n- [ ] Implementation notes added\n- [ ] Timer stopped: `mcp__knowns__stop_time`\n- [ ] Tests passing\n- [ ] Documentation updated\n- [ ] Status set to done\n- [ ] Knowledge extracted to docs (if applicable)\n\n---\n\n## Quick Reference\n\n```\n# === AGENT INITIALIZATION (Once per session) ===\nmcp__knowns__list_docs({})\nmcp__knowns__get_doc({ path: "README" })\nmcp__knowns__get_doc({ path: "ARCHITECTURE" })\nmcp__knowns__get_doc({ path: "CONVENTIONS" })\n\n# === FULL WORKFLOW ===\nmcp__knowns__create_task({ title: "Title", description: "Description" })\nmcp__knowns__update_task({ taskId: "<id>", status: "in-progress", assignee: "@me" })\nmcp__knowns__start_time({ taskId: "<id>" }) # \u23F1\uFE0F REQUIRED\nmcp__knowns__search_docs({ query: "keyword" })\nmcp__knowns__get_doc({ path: "Doc Name" })\nmcp__knowns__search_tasks({ query: "keyword", status: "done" }) # Learn from history\nmcp__knowns__update_task({ taskId: "<id>", plan: "1. Step\\n2. Step" })\n# ... wait for approval, then implement ...\nmcp__knowns__update_task({ taskId: "<id>", appendNotes: "\u2713 Completed: feature X" })\nmcp__knowns__stop_time({ taskId: "<id>" }) # \u23F1\uFE0F REQUIRED\nmcp__knowns__update_task({ taskId: "<id>", status: "done" })\n# Optional: Extract knowledge to docs if generalizable patterns found\n\n# === VIEW & SEARCH ===\nmcp__knowns__get_task({ taskId: "<id>" })\nmcp__knowns__list_tasks({})\nmcp__knowns__list_tasks({ status: "in-progress", assignee: "@me" })\nmcp__knowns__search_tasks({ query: "bug" })\nmcp__knowns__search_docs({ query: "pattern" })\n\n# === TIME TRACKING ===\nmcp__knowns__start_time({ taskId: "<id>" })\nmcp__knowns__stop_time({ taskId: "<id>" })\nmcp__knowns__add_time({ taskId: "<id>", duration: "2h" })\nmcp__knowns__get_time_report({})\n\n# === DOCUMENTATION ===\nmcp__knowns__list_docs({})\nmcp__knowns__get_doc({ path: "path/doc-name" })\nmcp__knowns__create_doc({ title: "Title", description: "Desc", tags: ["tag"] })\nmcp__knowns__update_doc({ path: "doc-name", appendContent: "New content" })\n```\n\n---\n\n**Maintained By**: Knowns CLI Team\n\n<!-- KNOWNS GUIDELINES END -->\n';
47007
+
47008
+ // src/commands/agents.ts
46967
47009
  var PROJECT_ROOT = process.cwd();
46968
47010
  var INSTRUCTION_FILES = [
46969
47011
  { path: "CLAUDE.md", name: "Claude Code", selected: true },
@@ -46971,8 +47013,11 @@ var INSTRUCTION_FILES = [
46971
47013
  { path: "GEMINI.md", name: "Gemini", selected: false },
46972
47014
  { path: ".github/copilot-instructions.md", name: "GitHub Copilot", selected: false }
46973
47015
  ];
46974
- function getGuidelines(version2) {
46975
- return version2 === "mcp" ? knowns_guidelines_mcp_default : knowns_guidelines_cli_default;
47016
+ function getGuidelines(type, variant = "general") {
47017
+ if (type === "mcp") {
47018
+ return variant === "gemini" ? gemini_default2 : general_default2;
47019
+ }
47020
+ return variant === "gemini" ? gemini_default : general_default;
46976
47021
  }
46977
47022
  async function updateInstructionFile(filePath, guidelines) {
46978
47023
  const fullPath = join3(PROJECT_ROOT, filePath);
@@ -47003,11 +47048,12 @@ ${guidelines}
47003
47048
  await writeFile2(fullPath, newContent, "utf-8");
47004
47049
  return { success: true, action: "updated" };
47005
47050
  }
47006
- var agentsCommand = new Command("agents").description("Manage agent instruction files (CLAUDE.md, GEMINI.md, etc.)").option("--update-instructions", "Update agent instruction files (non-interactive)").option("--type <type>", "Guidelines type: cli or mcp", "cli").option("--files <files>", "Comma-separated list of files to update").action(async (options2) => {
47051
+ var agentsCommand = new Command("agents").description("Manage agent instruction files (CLAUDE.md, GEMINI.md, etc.)").enablePositionalOptions().passThroughOptions().option("--update-instructions", "Update agent instruction files (non-interactive)").option("--type <type>", "Guidelines type: cli or mcp", "cli").option("--gemini", "Use compact Gemini variant (smaller context)").option("--files <files>", "Comma-separated list of files to update").action(async (options2) => {
47007
47052
  try {
47008
47053
  if (options2.updateInstructions) {
47009
- const version2 = options2.type === "mcp" ? "mcp" : "cli";
47010
- const guidelines2 = getGuidelines(version2);
47054
+ const type = options2.type === "mcp" ? "mcp" : "cli";
47055
+ const variant = options2.gemini ? "gemini" : "general";
47056
+ const guidelines2 = getGuidelines(type, variant);
47011
47057
  let filesToUpdate = INSTRUCTION_FILES;
47012
47058
  if (options2.files) {
47013
47059
  const requestedFiles = options2.files.split(",").map((f) => f.trim());
@@ -47015,32 +47061,55 @@ var agentsCommand = new Command("agents").description("Manage agent instruction
47015
47061
  (f) => requestedFiles.includes(f.path) || requestedFiles.includes(f.name)
47016
47062
  );
47017
47063
  }
47064
+ const label2 = `${type.toUpperCase()}${variant === "gemini" ? " (Gemini)" : ""}`;
47018
47065
  console.log(source_default.bold(`
47019
- Updating agent instruction files (${version2.toUpperCase()} version)...
47066
+ Updating agent instruction files (${label2})...
47020
47067
  `));
47021
47068
  await updateFiles(filesToUpdate, guidelines2);
47022
47069
  return;
47023
47070
  }
47024
47071
  console.log(source_default.bold("\n\u{1F916} Agent Instructions Manager\n"));
47025
- const versionResponse = await (0, import_prompts.default)({
47072
+ const typeResponse = await (0, import_prompts.default)({
47026
47073
  type: "select",
47027
- name: "version",
47028
- message: "Select guidelines version:",
47074
+ name: "type",
47075
+ message: "Select guidelines type:",
47029
47076
  choices: [
47030
47077
  {
47031
47078
  title: "CLI",
47032
47079
  value: "cli",
47033
- description: "Use CLI commands (knowns task edit, knowns doc view, etc.)"
47080
+ description: "CLI commands (knowns task edit, knowns doc view, etc.)"
47034
47081
  },
47035
47082
  {
47036
47083
  title: "MCP",
47037
47084
  value: "mcp",
47038
- description: "Use MCP tools (mcp__knowns__update_task, mcp__knowns__get_doc, etc.)"
47085
+ description: "MCP tools (mcp__knowns__update_task, etc.)"
47086
+ }
47087
+ ],
47088
+ initial: 0
47089
+ });
47090
+ if (!typeResponse.type) {
47091
+ console.log(source_default.yellow("\n\u26A0\uFE0F Cancelled"));
47092
+ return;
47093
+ }
47094
+ const variantResponse = await (0, import_prompts.default)({
47095
+ type: "select",
47096
+ name: "variant",
47097
+ message: "Select variant:",
47098
+ choices: [
47099
+ {
47100
+ title: "General (Full)",
47101
+ value: "general",
47102
+ description: "Complete guidelines for Claude, GPT, etc."
47103
+ },
47104
+ {
47105
+ title: "Gemini (Compact)",
47106
+ value: "gemini",
47107
+ description: "Condensed version for Gemini 2.5 Flash (smaller context)"
47039
47108
  }
47040
47109
  ],
47041
47110
  initial: 0
47042
47111
  });
47043
- if (!versionResponse.version) {
47112
+ if (!variantResponse.variant) {
47044
47113
  console.log(source_default.yellow("\n\u26A0\uFE0F Cancelled"));
47045
47114
  return;
47046
47115
  }
@@ -47059,19 +47128,23 @@ Updating agent instruction files (${version2.toUpperCase()} version)...
47059
47128
  console.log(source_default.yellow("\n\u26A0\uFE0F No files selected"));
47060
47129
  return;
47061
47130
  }
47131
+ const label = `${typeResponse.type.toUpperCase()}${variantResponse.variant === "gemini" ? " (Gemini)" : ""}`;
47062
47132
  const confirmResponse = await (0, import_prompts.default)({
47063
47133
  type: "confirm",
47064
47134
  name: "confirm",
47065
- message: `Update ${filesResponse.files.length} file(s) with ${versionResponse.version.toUpperCase()} guidelines?`,
47135
+ message: `Update ${filesResponse.files.length} file(s) with ${label} guidelines?`,
47066
47136
  initial: true
47067
47137
  });
47068
47138
  if (!confirmResponse.confirm) {
47069
47139
  console.log(source_default.yellow("\n\u26A0\uFE0F Cancelled"));
47070
47140
  return;
47071
47141
  }
47072
- const guidelines = getGuidelines(versionResponse.version);
47142
+ const guidelines = getGuidelines(
47143
+ typeResponse.type,
47144
+ variantResponse.variant
47145
+ );
47073
47146
  console.log(source_default.bold(`
47074
- Updating files with ${versionResponse.version.toUpperCase()} guidelines...
47147
+ Updating files with ${label} guidelines...
47075
47148
  `));
47076
47149
  await updateFiles(filesResponse.files, guidelines);
47077
47150
  } catch (error46) {
@@ -47122,6 +47195,23 @@ async function updateFiles(files, guidelines) {
47122
47195
  }
47123
47196
  console.log();
47124
47197
  }
47198
+ var syncCommand = new Command("sync").description("Sync/update all agent instruction files with latest guidelines").option("--type <type>", "Guidelines type: cli or mcp", "cli").option("--gemini", "Use compact Gemini variant (smaller context)").option("--all", "Update all instruction files (including Gemini, Copilot)").action(async (options2) => {
47199
+ try {
47200
+ const type = options2.type === "mcp" ? "mcp" : "cli";
47201
+ const variant = options2.gemini ? "gemini" : "general";
47202
+ const guidelines = getGuidelines(type, variant);
47203
+ const filesToUpdate = options2.all ? INSTRUCTION_FILES : INSTRUCTION_FILES.filter((f) => f.selected);
47204
+ const label = `${type.toUpperCase()}${variant === "gemini" ? " (Gemini)" : ""}`;
47205
+ console.log(source_default.bold(`
47206
+ Syncing agent instructions (${label})...
47207
+ `));
47208
+ await updateFiles(filesToUpdate, guidelines);
47209
+ } catch (error46) {
47210
+ console.error(source_default.red("Error:"), error46 instanceof Error ? error46.message : String(error46));
47211
+ process.exit(1);
47212
+ }
47213
+ });
47214
+ agentsCommand.addCommand(syncCommand);
47125
47215
 
47126
47216
  // src/commands/init.ts
47127
47217
  async function checkAndInitGit(projectRoot) {
@@ -47251,8 +47341,8 @@ async function runWizard() {
47251
47341
  },
47252
47342
  {
47253
47343
  type: "select",
47254
- name: "guidelinesVersion",
47255
- message: "AI Guidelines version",
47344
+ name: "guidelinesType",
47345
+ message: "AI Guidelines type",
47256
47346
  choices: [
47257
47347
  { title: "CLI", value: "cli", description: "Use CLI commands (knowns task edit, knowns doc view)" },
47258
47348
  { title: "MCP", value: "mcp", description: "Use MCP tools (mcp__knowns__update_task, etc.)" }
@@ -47289,7 +47379,7 @@ async function runWizard() {
47289
47379
  defaultPriority: response.defaultPriority,
47290
47380
  defaultLabels: response.defaultLabels?.filter((l) => l.trim()) || [],
47291
47381
  timeFormat: response.timeFormat,
47292
- guidelinesVersion: response.guidelinesVersion || "cli",
47382
+ guidelinesType: response.guidelinesType || "cli",
47293
47383
  agentFiles: response.agentFiles || []
47294
47384
  };
47295
47385
  }
@@ -47322,7 +47412,7 @@ var initCommand = new Command("init").description("Initialize .knowns/ folder in
47322
47412
  defaultPriority: "medium",
47323
47413
  defaultLabels: [],
47324
47414
  timeFormat: "24h",
47325
- guidelinesVersion: "cli",
47415
+ guidelinesType: "cli",
47326
47416
  agentFiles: INSTRUCTION_FILES.filter((f) => f.selected)
47327
47417
  };
47328
47418
  }
@@ -47347,8 +47437,8 @@ var initCommand = new Command("init").description("Initialize .knowns/ folder in
47347
47437
  console.log(source_default.gray(` Time Format: ${config2.timeFormat}`));
47348
47438
  console.log();
47349
47439
  if (config2.agentFiles.length > 0) {
47350
- const guidelines = config2.guidelinesVersion === "mcp" ? knowns_guidelines_mcp_default : knowns_guidelines_cli_default;
47351
- console.log(source_default.bold(`Updating AI instruction files (${config2.guidelinesVersion.toUpperCase()} version)...`));
47440
+ const guidelines = getGuidelines(config2.guidelinesType);
47441
+ console.log(source_default.bold(`Updating AI instruction files (${config2.guidelinesType.toUpperCase()} version)...`));
47352
47442
  console.log();
47353
47443
  let syncedCount = 0;
47354
47444
  for (const file3 of config2.agentFiles) {
@@ -47383,7 +47473,7 @@ var initCommand = new Command("init").description("Initialize .knowns/ folder in
47383
47473
  });
47384
47474
 
47385
47475
  // src/commands/task.ts
47386
- import { mkdir as mkdir4, readdir as readdir2, unlink as unlink3 } from "node:fs/promises";
47476
+ import { mkdir as mkdir4, readFile as readFile4, readdir as readdir2, unlink as unlink3 } from "node:fs/promises";
47387
47477
  import { join as join8 } from "node:path";
47388
47478
 
47389
47479
  // src/utils/doc-links.ts
@@ -47582,6 +47672,402 @@ async function notifyTimeUpdate(active) {
47582
47672
  }
47583
47673
  }
47584
47674
 
47675
+ // src/utils/validate.ts
47676
+ var import_gray_matter2 = __toESM(require_gray_matter(), 1);
47677
+ import { existsSync as existsSync6 } from "node:fs";
47678
+ import { copyFile, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
47679
+ var DOC_REQUIRED_FIELDS = ["title", "createdAt", "updatedAt"];
47680
+ function validateDoc(content) {
47681
+ const errors = [];
47682
+ const warnings = [];
47683
+ let data;
47684
+ let bodyContent;
47685
+ try {
47686
+ const parsed = (0, import_gray_matter2.default)(content);
47687
+ data = parsed.data;
47688
+ bodyContent = parsed.content;
47689
+ } catch (error46) {
47690
+ errors.push({
47691
+ field: "frontmatter",
47692
+ message: `Invalid YAML frontmatter: ${error46 instanceof Error ? error46.message : String(error46)}`,
47693
+ fixable: false
47694
+ });
47695
+ return { valid: false, errors, warnings };
47696
+ }
47697
+ for (const field of DOC_REQUIRED_FIELDS) {
47698
+ if (!data[field]) {
47699
+ errors.push({
47700
+ field,
47701
+ message: `Missing required field: ${field}`,
47702
+ fixable: true
47703
+ });
47704
+ }
47705
+ }
47706
+ if (data.title && typeof data.title !== "string") {
47707
+ errors.push({
47708
+ field: "title",
47709
+ message: "Title must be a string",
47710
+ fixable: true
47711
+ });
47712
+ }
47713
+ if (data.createdAt && !isValidISODate(data.createdAt)) {
47714
+ errors.push({
47715
+ field: "createdAt",
47716
+ message: "createdAt must be a valid ISO date",
47717
+ fixable: true
47718
+ });
47719
+ }
47720
+ if (data.updatedAt && !isValidISODate(data.updatedAt)) {
47721
+ errors.push({
47722
+ field: "updatedAt",
47723
+ message: "updatedAt must be a valid ISO date",
47724
+ fixable: true
47725
+ });
47726
+ }
47727
+ if (data.tags !== void 0) {
47728
+ if (typeof data.tags === "string") {
47729
+ warnings.push({
47730
+ field: "tags",
47731
+ message: "Tags should be an array, not a string"
47732
+ });
47733
+ } else if (!Array.isArray(data.tags)) {
47734
+ errors.push({
47735
+ field: "tags",
47736
+ message: "Tags must be an array of strings",
47737
+ fixable: true
47738
+ });
47739
+ }
47740
+ }
47741
+ if (!bodyContent.trim()) {
47742
+ warnings.push({
47743
+ field: "content",
47744
+ message: "Document has no content"
47745
+ });
47746
+ }
47747
+ return {
47748
+ valid: errors.length === 0,
47749
+ errors,
47750
+ warnings
47751
+ };
47752
+ }
47753
+ async function repairDoc(filePath) {
47754
+ const fixes = [];
47755
+ const repairErrors = [];
47756
+ if (!existsSync6(filePath)) {
47757
+ return {
47758
+ success: false,
47759
+ errors: ["File not found"],
47760
+ fixes: []
47761
+ };
47762
+ }
47763
+ const backupPath = `${filePath}.bak`;
47764
+ try {
47765
+ await copyFile(filePath, backupPath);
47766
+ } catch (error46) {
47767
+ return {
47768
+ success: false,
47769
+ errors: [`Failed to create backup: ${error46 instanceof Error ? error46.message : String(error46)}`],
47770
+ fixes: []
47771
+ };
47772
+ }
47773
+ let content;
47774
+ try {
47775
+ content = await readFile3(filePath, "utf-8");
47776
+ } catch (error46) {
47777
+ return {
47778
+ success: false,
47779
+ backupPath,
47780
+ errors: [`Failed to read file: ${error46 instanceof Error ? error46.message : String(error46)}`],
47781
+ fixes: []
47782
+ };
47783
+ }
47784
+ let data;
47785
+ let bodyContent;
47786
+ try {
47787
+ const parsed = (0, import_gray_matter2.default)(content);
47788
+ data = parsed.data;
47789
+ bodyContent = parsed.content;
47790
+ } catch {
47791
+ const lines = content.split("\n");
47792
+ const titleMatch = lines.find((l) => l.startsWith("# "));
47793
+ const title = titleMatch ? titleMatch.replace("# ", "").trim() : "Untitled";
47794
+ const now2 = (/* @__PURE__ */ new Date()).toISOString();
47795
+ data = {
47796
+ title,
47797
+ createdAt: now2,
47798
+ updatedAt: now2
47799
+ };
47800
+ const frontmatterEnd = content.indexOf("---", 3);
47801
+ bodyContent = frontmatterEnd > 0 ? content.substring(frontmatterEnd + 3).trim() : content.replace(/^---[\s\S]*?---/, "").trim();
47802
+ fixes.push("Rebuilt corrupted frontmatter");
47803
+ }
47804
+ const now = (/* @__PURE__ */ new Date()).toISOString();
47805
+ if (!data.title) {
47806
+ const titleMatch = bodyContent.match(/^#\s+(.+)$/m);
47807
+ data.title = titleMatch ? titleMatch[1] : "Untitled Document";
47808
+ fixes.push(`Added missing title: "${data.title}"`);
47809
+ }
47810
+ if (!data.createdAt || !isValidISODate(data.createdAt)) {
47811
+ data.createdAt = now;
47812
+ fixes.push("Fixed createdAt date");
47813
+ }
47814
+ if (!data.updatedAt || !isValidISODate(data.updatedAt)) {
47815
+ data.updatedAt = now;
47816
+ fixes.push("Fixed updatedAt date");
47817
+ }
47818
+ if (typeof data.tags === "string") {
47819
+ data.tags = data.tags.split(",").map((t) => t.trim());
47820
+ fixes.push("Converted tags from string to array");
47821
+ }
47822
+ if (data.tags && !Array.isArray(data.tags)) {
47823
+ data.tags = [];
47824
+ fixes.push("Reset invalid tags to empty array");
47825
+ }
47826
+ try {
47827
+ const repairedContent = import_gray_matter2.default.stringify(bodyContent, data);
47828
+ await writeFile3(filePath, repairedContent, "utf-8");
47829
+ } catch (error46) {
47830
+ repairErrors.push(`Failed to write repaired file: ${error46 instanceof Error ? error46.message : String(error46)}`);
47831
+ return {
47832
+ success: false,
47833
+ backupPath,
47834
+ errors: repairErrors,
47835
+ fixes
47836
+ };
47837
+ }
47838
+ return {
47839
+ success: true,
47840
+ backupPath,
47841
+ fixes,
47842
+ errors: repairErrors
47843
+ };
47844
+ }
47845
+ var TASK_REQUIRED_FIELDS = ["id", "title", "status", "priority", "createdAt", "updatedAt"];
47846
+ var VALID_STATUSES = ["todo", "in-progress", "in-review", "done", "blocked", "on-hold"];
47847
+ var VALID_PRIORITIES = ["low", "medium", "high"];
47848
+ function validateTask(content) {
47849
+ const errors = [];
47850
+ const warnings = [];
47851
+ let data;
47852
+ let bodyContent;
47853
+ try {
47854
+ const parsed = (0, import_gray_matter2.default)(content);
47855
+ data = parsed.data;
47856
+ bodyContent = parsed.content;
47857
+ } catch (error46) {
47858
+ errors.push({
47859
+ field: "frontmatter",
47860
+ message: `Invalid YAML frontmatter: ${error46 instanceof Error ? error46.message : String(error46)}`,
47861
+ fixable: false
47862
+ });
47863
+ return { valid: false, errors, warnings };
47864
+ }
47865
+ for (const field of TASK_REQUIRED_FIELDS) {
47866
+ if (data[field] === void 0) {
47867
+ errors.push({
47868
+ field,
47869
+ message: `Missing required field: ${field}`,
47870
+ fixable: field !== "id"
47871
+ // ID can't be auto-fixed
47872
+ });
47873
+ }
47874
+ }
47875
+ if (data.id && !/^\d+(\.\d+)*$/.test(data.id)) {
47876
+ errors.push({
47877
+ field: "id",
47878
+ message: "Invalid ID format (expected: number or hierarchical like 7.1.2)",
47879
+ fixable: false
47880
+ });
47881
+ }
47882
+ if (data.status && !VALID_STATUSES.includes(data.status)) {
47883
+ errors.push({
47884
+ field: "status",
47885
+ message: `Invalid status: ${data.status}. Expected one of: ${VALID_STATUSES.join(", ")}`,
47886
+ fixable: true
47887
+ });
47888
+ }
47889
+ if (data.priority && !VALID_PRIORITIES.includes(data.priority)) {
47890
+ errors.push({
47891
+ field: "priority",
47892
+ message: `Invalid priority: ${data.priority}. Expected one of: ${VALID_PRIORITIES.join(", ")}`,
47893
+ fixable: true
47894
+ });
47895
+ }
47896
+ if (data.createdAt && !isValidISODate(data.createdAt)) {
47897
+ errors.push({
47898
+ field: "createdAt",
47899
+ message: "createdAt must be a valid ISO date",
47900
+ fixable: true
47901
+ });
47902
+ }
47903
+ if (data.updatedAt && !isValidISODate(data.updatedAt)) {
47904
+ errors.push({
47905
+ field: "updatedAt",
47906
+ message: "updatedAt must be a valid ISO date",
47907
+ fixable: true
47908
+ });
47909
+ }
47910
+ if (data.labels !== void 0) {
47911
+ if (typeof data.labels === "string") {
47912
+ warnings.push({
47913
+ field: "labels",
47914
+ message: "Labels should be an array, not a string"
47915
+ });
47916
+ } else if (!Array.isArray(data.labels)) {
47917
+ errors.push({
47918
+ field: "labels",
47919
+ message: "Labels must be an array of strings",
47920
+ fixable: true
47921
+ });
47922
+ }
47923
+ }
47924
+ if (data.timeSpent !== void 0 && (typeof data.timeSpent !== "number" || data.timeSpent < 0)) {
47925
+ errors.push({
47926
+ field: "timeSpent",
47927
+ message: "timeSpent must be a non-negative number",
47928
+ fixable: true
47929
+ });
47930
+ }
47931
+ if (!bodyContent.includes("# ")) {
47932
+ warnings.push({
47933
+ field: "content",
47934
+ message: "Missing title heading in body"
47935
+ });
47936
+ }
47937
+ return {
47938
+ valid: errors.length === 0,
47939
+ errors,
47940
+ warnings
47941
+ };
47942
+ }
47943
+ async function repairTask(filePath, extractedId) {
47944
+ const fixes = [];
47945
+ const repairErrors = [];
47946
+ if (!existsSync6(filePath)) {
47947
+ return {
47948
+ success: false,
47949
+ errors: ["File not found"],
47950
+ fixes: []
47951
+ };
47952
+ }
47953
+ const backupPath = `${filePath}.bak`;
47954
+ try {
47955
+ await copyFile(filePath, backupPath);
47956
+ } catch (error46) {
47957
+ return {
47958
+ success: false,
47959
+ errors: [`Failed to create backup: ${error46 instanceof Error ? error46.message : String(error46)}`],
47960
+ fixes: []
47961
+ };
47962
+ }
47963
+ let content;
47964
+ try {
47965
+ content = await readFile3(filePath, "utf-8");
47966
+ } catch (error46) {
47967
+ return {
47968
+ success: false,
47969
+ backupPath,
47970
+ errors: [`Failed to read file: ${error46 instanceof Error ? error46.message : String(error46)}`],
47971
+ fixes: []
47972
+ };
47973
+ }
47974
+ let data;
47975
+ let bodyContent;
47976
+ try {
47977
+ const parsed = (0, import_gray_matter2.default)(content);
47978
+ data = parsed.data;
47979
+ bodyContent = parsed.content;
47980
+ } catch {
47981
+ const titleMatch = content.match(/^#\s+(.+)$/m);
47982
+ const title = titleMatch ? titleMatch[1] : "Untitled Task";
47983
+ const now2 = (/* @__PURE__ */ new Date()).toISOString();
47984
+ data = {
47985
+ id: extractedId,
47986
+ title,
47987
+ status: "todo",
47988
+ priority: "medium",
47989
+ labels: [],
47990
+ createdAt: now2,
47991
+ updatedAt: now2,
47992
+ timeSpent: 0
47993
+ };
47994
+ const frontmatterEnd = content.indexOf("---", 3);
47995
+ bodyContent = frontmatterEnd > 0 ? content.substring(frontmatterEnd + 3).trim() : content.replace(/^---[\s\S]*?---/, "").trim();
47996
+ fixes.push("Rebuilt corrupted frontmatter");
47997
+ }
47998
+ const now = (/* @__PURE__ */ new Date()).toISOString();
47999
+ if (!data.id && extractedId) {
48000
+ data.id = extractedId;
48001
+ fixes.push(`Set ID from filename: ${extractedId}`);
48002
+ }
48003
+ if (!data.title) {
48004
+ const titleMatch = bodyContent.match(/^#\s+(.+)$/m);
48005
+ data.title = titleMatch ? titleMatch[1] : "Untitled Task";
48006
+ fixes.push(`Added missing title: "${data.title}"`);
48007
+ }
48008
+ if (!data.status || !VALID_STATUSES.includes(data.status)) {
48009
+ data.status = "todo";
48010
+ fixes.push("Set status to 'todo'");
48011
+ }
48012
+ if (!data.priority || !VALID_PRIORITIES.includes(data.priority)) {
48013
+ data.priority = "medium";
48014
+ fixes.push("Set priority to 'medium'");
48015
+ }
48016
+ if (!data.createdAt || !isValidISODate(data.createdAt)) {
48017
+ data.createdAt = now;
48018
+ fixes.push("Fixed createdAt date");
48019
+ }
48020
+ if (!data.updatedAt || !isValidISODate(data.updatedAt)) {
48021
+ data.updatedAt = now;
48022
+ fixes.push("Fixed updatedAt date");
48023
+ }
48024
+ if (typeof data.labels === "string") {
48025
+ data.labels = data.labels.split(",").map((l) => l.trim());
48026
+ fixes.push("Converted labels from string to array");
48027
+ }
48028
+ if (!Array.isArray(data.labels)) {
48029
+ data.labels = [];
48030
+ fixes.push("Reset invalid labels to empty array");
48031
+ }
48032
+ if (typeof data.timeSpent !== "number" || data.timeSpent < 0) {
48033
+ data.timeSpent = 0;
48034
+ fixes.push("Reset timeSpent to 0");
48035
+ }
48036
+ if (!bodyContent.includes("# ") && data.title) {
48037
+ bodyContent = `# ${data.title}
48038
+
48039
+ ${bodyContent}`;
48040
+ fixes.push("Added title heading to body");
48041
+ }
48042
+ try {
48043
+ const repairedContent = import_gray_matter2.default.stringify(bodyContent, data);
48044
+ await writeFile3(filePath, repairedContent, "utf-8");
48045
+ } catch (error46) {
48046
+ repairErrors.push(`Failed to write repaired file: ${error46 instanceof Error ? error46.message : String(error46)}`);
48047
+ return {
48048
+ success: false,
48049
+ backupPath,
48050
+ errors: repairErrors,
48051
+ fixes
48052
+ };
48053
+ }
48054
+ return {
48055
+ success: true,
48056
+ backupPath,
48057
+ fixes,
48058
+ errors: repairErrors
48059
+ };
48060
+ }
48061
+ function isValidISODate(dateString) {
48062
+ if (typeof dateString !== "string") return false;
48063
+ const date5 = new Date(dateString);
48064
+ return !Number.isNaN(date5.getTime());
48065
+ }
48066
+ function extractTaskIdFromFilename(filename) {
48067
+ const match = filename.match(/^task-(\d+(?:\.\d+)*)\s*-/);
48068
+ return match ? match[1] : void 0;
48069
+ }
48070
+
47585
48071
  // src/commands/task.ts
47586
48072
  function getFileStore() {
47587
48073
  const projectRoot = findProjectRoot();
@@ -48649,7 +49135,151 @@ var restoreCommand = new Command("restore").description("Restore task to a previ
48649
49135
  process.exit(1);
48650
49136
  }
48651
49137
  });
48652
- var taskCommand = new Command("task").description("Manage tasks").argument("[id]", "Task ID (shorthand for 'task view <id>')").option("--plain", "Plain text output for AI").action(async (id, options2) => {
49138
+ var validateCommand = new Command("validate").description("Validate a task file format").argument("<id>", "Task ID to validate").option("--plain", "Plain text output for AI").action(async (id, options2) => {
49139
+ try {
49140
+ const projectRoot = findProjectRoot();
49141
+ if (!projectRoot) {
49142
+ console.error(source_default.red("\u2717 Not a knowns project"));
49143
+ process.exit(1);
49144
+ }
49145
+ const tasksPath = join8(projectRoot, ".knowns", "tasks");
49146
+ const files = await readdir2(tasksPath);
49147
+ const taskFile = files.find((f) => f.startsWith(`task-${id} -`));
49148
+ if (!taskFile) {
49149
+ console.error(source_default.red(`\u2717 Task ${id} not found`));
49150
+ process.exit(1);
49151
+ }
49152
+ const filePath = join8(tasksPath, taskFile);
49153
+ const content = await readFile4(filePath, "utf-8");
49154
+ const result = validateTask(content);
49155
+ if (options2.plain) {
49156
+ console.log(`Validating: task-${id}`);
49157
+ console.log(`Valid: ${result.valid}`);
49158
+ if (result.errors.length > 0) {
49159
+ console.log("\nErrors:");
49160
+ for (const error46 of result.errors) {
49161
+ console.log(` \u2717 ${error46.field}: ${error46.message}${error46.fixable ? " (fixable)" : ""}`);
49162
+ }
49163
+ }
49164
+ if (result.warnings.length > 0) {
49165
+ console.log("\nWarnings:");
49166
+ for (const warning of result.warnings) {
49167
+ console.log(` \u26A0 ${warning.field}: ${warning.message}`);
49168
+ }
49169
+ }
49170
+ if (result.valid && result.warnings.length === 0) {
49171
+ console.log("No issues found.");
49172
+ }
49173
+ } else {
49174
+ console.log(source_default.bold(`
49175
+ \u{1F4CB} Validation: Task ${id}
49176
+ `));
49177
+ if (result.valid) {
49178
+ console.log(source_default.green("\u2713 Task is valid"));
49179
+ } else {
49180
+ console.log(source_default.red("\u2717 Task has errors"));
49181
+ }
49182
+ if (result.errors.length > 0) {
49183
+ console.log(source_default.red("\nErrors:"));
49184
+ for (const error46 of result.errors) {
49185
+ const fixable = error46.fixable ? source_default.gray(" (fixable)") : "";
49186
+ console.log(source_default.red(` \u2717 ${error46.field}: ${error46.message}${fixable}`));
49187
+ }
49188
+ }
49189
+ if (result.warnings.length > 0) {
49190
+ console.log(source_default.yellow("\nWarnings:"));
49191
+ for (const warning of result.warnings) {
49192
+ console.log(source_default.yellow(` \u26A0 ${warning.field}: ${warning.message}`));
49193
+ }
49194
+ }
49195
+ if (result.valid && result.warnings.length === 0) {
49196
+ console.log(source_default.gray("\nNo issues found."));
49197
+ }
49198
+ console.log();
49199
+ }
49200
+ process.exit(result.valid ? 0 : 1);
49201
+ } catch (error46) {
49202
+ console.error(source_default.red("\u2717 Failed to validate task"));
49203
+ if (error46 instanceof Error) {
49204
+ console.error(source_default.red(` ${error46.message}`));
49205
+ }
49206
+ process.exit(1);
49207
+ }
49208
+ });
49209
+ var repairCommand = new Command("repair").description("Repair a corrupted task file").argument("<id>", "Task ID to repair").option("--plain", "Plain text output for AI").action(async (id, options2) => {
49210
+ try {
49211
+ const projectRoot = findProjectRoot();
49212
+ if (!projectRoot) {
49213
+ console.error(source_default.red("\u2717 Not a knowns project"));
49214
+ process.exit(1);
49215
+ }
49216
+ const tasksPath = join8(projectRoot, ".knowns", "tasks");
49217
+ const files = await readdir2(tasksPath);
49218
+ const taskFile = files.find((f) => f.startsWith(`task-${id} -`));
49219
+ if (!taskFile) {
49220
+ console.error(source_default.red(`\u2717 Task ${id} not found`));
49221
+ process.exit(1);
49222
+ }
49223
+ const filePath = join8(tasksPath, taskFile);
49224
+ const extractedId = extractTaskIdFromFilename(taskFile);
49225
+ const result = await repairTask(filePath, extractedId);
49226
+ if (options2.plain) {
49227
+ console.log(`Repairing: task-${id}`);
49228
+ console.log(`Success: ${result.success}`);
49229
+ if (result.backupPath) {
49230
+ console.log(`Backup: ${result.backupPath}`);
49231
+ }
49232
+ if (result.fixes.length > 0) {
49233
+ console.log("\nFixes applied:");
49234
+ for (const fix of result.fixes) {
49235
+ console.log(` \u2713 ${fix}`);
49236
+ }
49237
+ }
49238
+ if (result.errors.length > 0) {
49239
+ console.log("\nErrors:");
49240
+ for (const err of result.errors) {
49241
+ console.log(` \u2717 ${err}`);
49242
+ }
49243
+ }
49244
+ } else {
49245
+ console.log(source_default.bold(`
49246
+ \u{1F527} Repair: Task ${id}
49247
+ `));
49248
+ if (result.success) {
49249
+ console.log(source_default.green("\u2713 Task repaired successfully"));
49250
+ } else {
49251
+ console.log(source_default.red("\u2717 Repair failed"));
49252
+ }
49253
+ if (result.backupPath) {
49254
+ console.log(source_default.gray(` Backup created: ${result.backupPath}`));
49255
+ }
49256
+ if (result.fixes.length > 0) {
49257
+ console.log(source_default.green("\nFixes applied:"));
49258
+ for (const fix of result.fixes) {
49259
+ console.log(source_default.green(` \u2713 ${fix}`));
49260
+ }
49261
+ }
49262
+ if (result.errors.length > 0) {
49263
+ console.log(source_default.red("\nErrors:"));
49264
+ for (const err of result.errors) {
49265
+ console.log(source_default.red(` \u2717 ${err}`));
49266
+ }
49267
+ }
49268
+ console.log();
49269
+ }
49270
+ if (result.success) {
49271
+ await notifyTaskUpdate(id);
49272
+ }
49273
+ process.exit(result.success ? 0 : 1);
49274
+ } catch (error46) {
49275
+ console.error(source_default.red("\u2717 Failed to repair task"));
49276
+ if (error46 instanceof Error) {
49277
+ console.error(source_default.red(` ${error46.message}`));
49278
+ }
49279
+ process.exit(1);
49280
+ }
49281
+ });
49282
+ var taskCommand = new Command("task").description("Manage tasks").argument("[id]", "Task ID (shorthand for 'task view <id>')").option("--plain", "Plain text output for AI").enablePositionalOptions().passThroughOptions().action(async (id, options2) => {
48653
49283
  if (!id) {
48654
49284
  taskCommand.help();
48655
49285
  return;
@@ -48679,6 +49309,8 @@ taskCommand.addCommand(unarchiveCommand);
48679
49309
  taskCommand.addCommand(historyCommand);
48680
49310
  taskCommand.addCommand(diffCommand);
48681
49311
  taskCommand.addCommand(restoreCommand);
49312
+ taskCommand.addCommand(validateCommand);
49313
+ taskCommand.addCommand(repairCommand);
48682
49314
 
48683
49315
  // src/commands/board.ts
48684
49316
  function getFileStore2() {
@@ -48840,10 +49472,10 @@ var boardCommand = new Command("board").description("Display Kanban board").opti
48840
49472
  );
48841
49473
 
48842
49474
  // src/commands/search.ts
48843
- import { existsSync as existsSync6 } from "node:fs";
48844
- import { readFile as readFile3, readdir as readdir3 } from "node:fs/promises";
49475
+ import { existsSync as existsSync7 } from "node:fs";
49476
+ import { readFile as readFile5, readdir as readdir3 } from "node:fs/promises";
48845
49477
  import { join as join9 } from "node:path";
48846
- var import_gray_matter2 = __toESM(require_gray_matter(), 1);
49478
+ var import_gray_matter3 = __toESM(require_gray_matter(), 1);
48847
49479
  function getFileStore3() {
48848
49480
  const projectRoot = findProjectRoot();
48849
49481
  if (!projectRoot) {
@@ -48895,7 +49527,7 @@ function calculateDocScore(doc, query) {
48895
49527
  }
48896
49528
  async function searchDocs(query, projectRoot) {
48897
49529
  const docsDir = join9(projectRoot, ".knowns", "docs");
48898
- if (!existsSync6(docsDir)) {
49530
+ if (!existsSync7(docsDir)) {
48899
49531
  return [];
48900
49532
  }
48901
49533
  try {
@@ -48903,8 +49535,8 @@ async function searchDocs(query, projectRoot) {
48903
49535
  const mdFiles = files.filter((f) => f.endsWith(".md"));
48904
49536
  const results = [];
48905
49537
  for (const file3 of mdFiles) {
48906
- const content = await readFile3(join9(docsDir, file3), "utf-8");
48907
- const { data, content: docContent } = (0, import_gray_matter2.default)(content);
49538
+ const content = await readFile5(join9(docsDir, file3), "utf-8");
49539
+ const { data, content: docContent } = (0, import_gray_matter3.default)(content);
48908
49540
  const metadata = data;
48909
49541
  const doc = {
48910
49542
  filename: file3,
@@ -49507,13 +50139,13 @@ timeCommand.addCommand(addCommand);
49507
50139
  timeCommand.addCommand(reportCommand);
49508
50140
 
49509
50141
  // src/commands/browser.ts
49510
- import { existsSync as existsSync12 } from "node:fs";
49511
- import { mkdir as mkdir6, readFile as readFile8, writeFile as writeFile6 } from "node:fs/promises";
50142
+ import { existsSync as existsSync13 } from "node:fs";
50143
+ import { mkdir as mkdir6, readFile as readFile10, writeFile as writeFile7 } from "node:fs/promises";
49512
50144
  import { join as join16 } from "node:path";
49513
50145
 
49514
50146
  // src/server/index.ts
49515
50147
  import { spawn } from "node:child_process";
49516
- import { existsSync as existsSync11, realpathSync } from "node:fs";
50148
+ import { existsSync as existsSync12, realpathSync } from "node:fs";
49517
50149
  import { createServer } from "node:http";
49518
50150
  import { basename as basename2, dirname as dirname3, join as join15 } from "node:path";
49519
50151
  import { fileURLToPath } from "node:url";
@@ -49577,8 +50209,8 @@ function createActivityRoutes(ctx) {
49577
50209
 
49578
50210
  // src/server/routes/config.ts
49579
50211
  var import_express2 = __toESM(require_express2(), 1);
49580
- import { existsSync as existsSync7 } from "node:fs";
49581
- import { readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
50212
+ import { existsSync as existsSync8 } from "node:fs";
50213
+ import { readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
49582
50214
  import { join as join10 } from "node:path";
49583
50215
  function createConfigRoutes(ctx) {
49584
50216
  const router = (0, import_express2.Router)();
@@ -49586,7 +50218,7 @@ function createConfigRoutes(ctx) {
49586
50218
  const configPath = join10(store.projectRoot, ".knowns", "config.json");
49587
50219
  router.get("/", async (_req, res) => {
49588
50220
  try {
49589
- if (!existsSync7(configPath)) {
50221
+ if (!existsSync8(configPath)) {
49590
50222
  res.json({
49591
50223
  config: {
49592
50224
  name: "Knowns",
@@ -49598,7 +50230,7 @@ function createConfigRoutes(ctx) {
49598
50230
  });
49599
50231
  return;
49600
50232
  }
49601
- const content = await readFile4(configPath, "utf-8");
50233
+ const content = await readFile6(configPath, "utf-8");
49602
50234
  const data = JSON.parse(content);
49603
50235
  const settings = data.settings || {};
49604
50236
  const config2 = {
@@ -49620,8 +50252,8 @@ function createConfigRoutes(ctx) {
49620
50252
  try {
49621
50253
  const config2 = req.body;
49622
50254
  let existingData = {};
49623
- if (existsSync7(configPath)) {
49624
- const content = await readFile4(configPath, "utf-8");
50255
+ if (existsSync8(configPath)) {
50256
+ const content = await readFile6(configPath, "utf-8");
49625
50257
  existingData = JSON.parse(content);
49626
50258
  }
49627
50259
  const { name, ...settings } = config2;
@@ -49630,7 +50262,7 @@ function createConfigRoutes(ctx) {
49630
50262
  name: name || existingData.name,
49631
50263
  settings
49632
50264
  };
49633
- await writeFile3(configPath, JSON.stringify(merged, null, 2), "utf-8");
50265
+ await writeFile4(configPath, JSON.stringify(merged, null, 2), "utf-8");
49634
50266
  res.json({ success: true });
49635
50267
  } catch (error46) {
49636
50268
  console.error("Error saving config:", error46);
@@ -49642,9 +50274,9 @@ function createConfigRoutes(ctx) {
49642
50274
 
49643
50275
  // src/server/routes/docs.ts
49644
50276
  var import_express3 = __toESM(require_express2(), 1);
49645
- var import_gray_matter3 = __toESM(require_gray_matter(), 1);
49646
- import { existsSync as existsSync8 } from "node:fs";
49647
- import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
50277
+ var import_gray_matter4 = __toESM(require_gray_matter(), 1);
50278
+ import { existsSync as existsSync9 } from "node:fs";
50279
+ import { mkdir as mkdir5, readFile as readFile7, writeFile as writeFile5 } from "node:fs/promises";
49648
50280
  import { join as join12 } from "node:path";
49649
50281
 
49650
50282
  // src/server/utils/markdown.ts
@@ -49673,7 +50305,7 @@ function createDocRoutes(ctx) {
49673
50305
  const docsDir = join12(store.projectRoot, ".knowns", "docs");
49674
50306
  router.get("/", async (_req, res) => {
49675
50307
  try {
49676
- if (!existsSync8(docsDir)) {
50308
+ if (!existsSync9(docsDir)) {
49677
50309
  res.json({ docs: [] });
49678
50310
  return;
49679
50311
  }
@@ -49681,8 +50313,8 @@ function createDocRoutes(ctx) {
49681
50313
  const docs = await Promise.all(
49682
50314
  mdFiles.map(async (relativePath) => {
49683
50315
  const fullPath = join12(docsDir, relativePath);
49684
- const content = await readFile5(fullPath, "utf-8");
49685
- const { data, content: docContent } = (0, import_gray_matter3.default)(content);
50316
+ const content = await readFile7(fullPath, "utf-8");
50317
+ const { data, content: docContent } = (0, import_gray_matter4.default)(content);
49686
50318
  const pathParts = relativePath.split("/");
49687
50319
  const filename = pathParts[pathParts.length - 1];
49688
50320
  const folder = pathParts.length > 1 ? pathParts.slice(0, -1).join("/") : "";
@@ -49709,12 +50341,12 @@ function createDocRoutes(ctx) {
49709
50341
  res.status(400).json({ error: "Invalid path" });
49710
50342
  return;
49711
50343
  }
49712
- if (!existsSync8(fullPath)) {
50344
+ if (!existsSync9(fullPath)) {
49713
50345
  res.status(404).json({ error: "Document not found" });
49714
50346
  return;
49715
50347
  }
49716
- const content = await readFile5(fullPath, "utf-8");
49717
- const { data, content: docContent } = (0, import_gray_matter3.default)(content);
50348
+ const content = await readFile7(fullPath, "utf-8");
50349
+ const { data, content: docContent } = (0, import_gray_matter4.default)(content);
49718
50350
  const pathParts = docPath.split("/");
49719
50351
  const filename = pathParts[pathParts.length - 1];
49720
50352
  const folder = pathParts.length > 1 ? pathParts.slice(0, -1).join("/") : "";
@@ -49736,7 +50368,7 @@ function createDocRoutes(ctx) {
49736
50368
  });
49737
50369
  router.post("/", async (req, res) => {
49738
50370
  try {
49739
- if (!existsSync8(docsDir)) {
50371
+ if (!existsSync9(docsDir)) {
49740
50372
  await mkdir5(docsDir, { recursive: true });
49741
50373
  }
49742
50374
  const data = req.body;
@@ -49756,10 +50388,10 @@ function createDocRoutes(ctx) {
49756
50388
  targetDir = docsDir;
49757
50389
  filepath = join12(docsDir, filename);
49758
50390
  }
49759
- if (!existsSync8(targetDir)) {
50391
+ if (!existsSync9(targetDir)) {
49760
50392
  await mkdir5(targetDir, { recursive: true });
49761
50393
  }
49762
- if (existsSync8(filepath)) {
50394
+ if (existsSync9(filepath)) {
49763
50395
  res.status(409).json({ error: "Document with this title already exists in this folder" });
49764
50396
  return;
49765
50397
  }
@@ -49771,8 +50403,8 @@ function createDocRoutes(ctx) {
49771
50403
  updatedAt: now,
49772
50404
  tags: tags || []
49773
50405
  };
49774
- const markdown = import_gray_matter3.default.stringify(content || "", frontmatter);
49775
- await writeFile4(filepath, markdown, "utf-8");
50406
+ const markdown = import_gray_matter4.default.stringify(content || "", frontmatter);
50407
+ await writeFile5(filepath, markdown, "utf-8");
49776
50408
  res.status(201).json({
49777
50409
  success: true,
49778
50410
  filename,
@@ -49793,14 +50425,14 @@ function createDocRoutes(ctx) {
49793
50425
  res.status(400).json({ error: "Invalid path" });
49794
50426
  return;
49795
50427
  }
49796
- if (!existsSync8(fullPath)) {
50428
+ if (!existsSync9(fullPath)) {
49797
50429
  res.status(404).json({ error: "Document not found" });
49798
50430
  return;
49799
50431
  }
49800
50432
  const data = req.body;
49801
50433
  const { content, title, description, tags } = data;
49802
- const existingContent = await readFile5(fullPath, "utf-8");
49803
- const { data: existingData } = (0, import_gray_matter3.default)(existingContent);
50434
+ const existingContent = await readFile7(fullPath, "utf-8");
50435
+ const { data: existingData } = (0, import_gray_matter4.default)(existingContent);
49804
50436
  const now = (/* @__PURE__ */ new Date()).toISOString();
49805
50437
  const updatedFrontmatter = {
49806
50438
  ...existingData,
@@ -49809,8 +50441,8 @@ function createDocRoutes(ctx) {
49809
50441
  tags: tags ?? existingData.tags,
49810
50442
  updatedAt: now
49811
50443
  };
49812
- const newFileContent = import_gray_matter3.default.stringify(content ?? "", updatedFrontmatter);
49813
- await writeFile4(fullPath, newFileContent, "utf-8");
50444
+ const newFileContent = import_gray_matter4.default.stringify(content ?? "", updatedFrontmatter);
50445
+ await writeFile5(fullPath, newFileContent, "utf-8");
49814
50446
  const pathParts = docPath.split("/");
49815
50447
  const filename = pathParts[pathParts.length - 1];
49816
50448
  const folder = pathParts.length > 1 ? pathParts.slice(0, -1).join("/") : "";
@@ -49878,9 +50510,9 @@ function createNotifyRoutes(ctx) {
49878
50510
 
49879
50511
  // src/server/routes/search.ts
49880
50512
  var import_express5 = __toESM(require_express2(), 1);
49881
- var import_gray_matter4 = __toESM(require_gray_matter(), 1);
49882
- import { existsSync as existsSync9 } from "node:fs";
49883
- import { readFile as readFile6 } from "node:fs/promises";
50513
+ var import_gray_matter5 = __toESM(require_gray_matter(), 1);
50514
+ import { existsSync as existsSync10 } from "node:fs";
50515
+ import { readFile as readFile8 } from "node:fs/promises";
49884
50516
  import { join as join13 } from "node:path";
49885
50517
  function createSearchRoutes(ctx) {
49886
50518
  const router = (0, import_express5.Router)();
@@ -49908,12 +50540,12 @@ function createSearchRoutes(ctx) {
49908
50540
  });
49909
50541
  const docsDir = join13(store.projectRoot, ".knowns", "docs");
49910
50542
  const docResults = [];
49911
- if (existsSync9(docsDir)) {
50543
+ if (existsSync10(docsDir)) {
49912
50544
  const mdFiles = await findMarkdownFiles(docsDir, docsDir);
49913
50545
  for (const relativePath of mdFiles) {
49914
50546
  const fullPath = join13(docsDir, relativePath);
49915
- const content = await readFile6(fullPath, "utf-8");
49916
- const { data, content: docContent } = (0, import_gray_matter4.default)(content);
50547
+ const content = await readFile8(fullPath, "utf-8");
50548
+ const { data, content: docContent } = (0, import_gray_matter5.default)(content);
49917
50549
  const searchText = `${data.title || ""} ${data.description || ""} ${data.tags?.join(" ") || ""} ${docContent}`.toLowerCase();
49918
50550
  if (searchText.includes(q)) {
49919
50551
  const pathParts = relativePath.split("/");
@@ -50037,22 +50669,22 @@ function createTaskRoutes(ctx) {
50037
50669
 
50038
50670
  // src/server/routes/time.ts
50039
50671
  var import_express7 = __toESM(require_express2(), 1);
50040
- import { existsSync as existsSync10 } from "node:fs";
50041
- import { readFile as readFile7, writeFile as writeFile5 } from "node:fs/promises";
50672
+ import { existsSync as existsSync11 } from "node:fs";
50673
+ import { readFile as readFile9, writeFile as writeFile6 } from "node:fs/promises";
50042
50674
  import { join as join14 } from "node:path";
50043
50675
  function createTimeRoutes(ctx) {
50044
50676
  const router = (0, import_express7.Router)();
50045
50677
  const { store, broadcast } = ctx;
50046
50678
  const timePath = join14(store.projectRoot, ".knowns", "time.json");
50047
50679
  async function loadTimeData2() {
50048
- if (!existsSync10(timePath)) {
50680
+ if (!existsSync11(timePath)) {
50049
50681
  return { active: null };
50050
50682
  }
50051
- const content = await readFile7(timePath, "utf-8");
50683
+ const content = await readFile9(timePath, "utf-8");
50052
50684
  return JSON.parse(content);
50053
50685
  }
50054
50686
  async function saveTimeData2(data) {
50055
- await writeFile5(timePath, JSON.stringify(data, null, 2), "utf-8");
50687
+ await writeFile6(timePath, JSON.stringify(data, null, 2), "utf-8");
50056
50688
  }
50057
50689
  router.get("/status", async (_req, res) => {
50058
50690
  try {
@@ -50241,7 +50873,7 @@ async function startServer(options2) {
50241
50873
  packageRoot = join15(currentDir, "..", "..");
50242
50874
  }
50243
50875
  const uiDistPath = join15(packageRoot, "dist", "ui");
50244
- if (!existsSync11(join15(uiDistPath, "index.html"))) {
50876
+ if (!existsSync12(join15(uiDistPath, "index.html"))) {
50245
50877
  throw new Error(`UI build not found at ${uiDistPath}. Run 'bun run build:ui' first.`);
50246
50878
  }
50247
50879
  const app = (0, import_express9.default)();
@@ -50272,7 +50904,7 @@ async function startServer(options2) {
50272
50904
  app.use(errorHandler);
50273
50905
  app.get("/{*path}", (_req, res) => {
50274
50906
  const indexPath = join15(uiDistPath, "index.html");
50275
- if (existsSync11(indexPath)) {
50907
+ if (existsSync12(indexPath)) {
50276
50908
  res.sendFile("index.html", { root: uiDistPath });
50277
50909
  } else {
50278
50910
  res.status(404).send("Not Found");
@@ -50323,19 +50955,19 @@ var CONFIG_FILE = ".knowns/config.json";
50323
50955
  async function saveServerPort(projectRoot, port) {
50324
50956
  const configPath = join16(projectRoot, CONFIG_FILE);
50325
50957
  const knownsDir = join16(projectRoot, ".knowns");
50326
- if (!existsSync12(knownsDir)) {
50958
+ if (!existsSync13(knownsDir)) {
50327
50959
  await mkdir6(knownsDir, { recursive: true });
50328
50960
  }
50329
50961
  try {
50330
50962
  let config2 = {};
50331
- if (existsSync12(configPath)) {
50332
- const content = await readFile8(configPath, "utf-8");
50963
+ if (existsSync13(configPath)) {
50964
+ const content = await readFile10(configPath, "utf-8");
50333
50965
  config2 = JSON.parse(content);
50334
50966
  }
50335
50967
  const settings = config2.settings || {};
50336
50968
  settings.serverPort = port;
50337
50969
  config2.settings = settings;
50338
- await writeFile6(configPath, JSON.stringify(config2, null, 2), "utf-8");
50970
+ await writeFile7(configPath, JSON.stringify(config2, null, 2), "utf-8");
50339
50971
  } catch {
50340
50972
  }
50341
50973
  }
@@ -50365,10 +50997,10 @@ var browserCommand = new Command("browser").description("Open web UI for task ma
50365
50997
  });
50366
50998
 
50367
50999
  // src/commands/doc.ts
50368
- import { existsSync as existsSync13 } from "node:fs";
50369
- import { mkdir as mkdir7, readFile as readFile9, readdir as readdir5, writeFile as writeFile7 } from "node:fs/promises";
51000
+ import { existsSync as existsSync14 } from "node:fs";
51001
+ import { mkdir as mkdir7, readFile as readFile11, readdir as readdir5, writeFile as writeFile8 } from "node:fs/promises";
50370
51002
  import { join as join17 } from "node:path";
50371
- var import_gray_matter5 = __toESM(require_gray_matter(), 1);
51003
+ var import_gray_matter6 = __toESM(require_gray_matter(), 1);
50372
51004
  var DOCS_DIR = join17(process.cwd(), ".knowns", "docs");
50373
51005
  async function getAllMdFiles(dir, basePath = "") {
50374
51006
  const files = [];
@@ -50386,7 +51018,7 @@ async function getAllMdFiles(dir, basePath = "") {
50386
51018
  return files;
50387
51019
  }
50388
51020
  async function ensureDocsDir() {
50389
- if (!existsSync13(DOCS_DIR)) {
51021
+ if (!existsSync14(DOCS_DIR)) {
50390
51022
  await mkdir7(DOCS_DIR, { recursive: true });
50391
51023
  }
50392
51024
  }
@@ -50397,11 +51029,11 @@ async function resolveDocPath(name) {
50397
51029
  await ensureDocsDir();
50398
51030
  let filename = name.endsWith(".md") ? name : `${name}.md`;
50399
51031
  let filepath = join17(DOCS_DIR, filename);
50400
- if (!existsSync13(filepath)) {
51032
+ if (!existsSync14(filepath)) {
50401
51033
  filename = `${titleToFilename(name)}.md`;
50402
51034
  filepath = join17(DOCS_DIR, filename);
50403
51035
  }
50404
- if (!existsSync13(filepath)) {
51036
+ if (!existsSync14(filepath)) {
50405
51037
  const allFiles = await getAllMdFiles(DOCS_DIR);
50406
51038
  const searchName = name.toLowerCase().replace(/\.md$/, "");
50407
51039
  const matchingFile = allFiles.find((file3) => {
@@ -50414,7 +51046,7 @@ async function resolveDocPath(name) {
50414
51046
  filepath = join17(DOCS_DIR, matchingFile);
50415
51047
  }
50416
51048
  }
50417
- if (!existsSync13(filepath)) {
51049
+ if (!existsSync14(filepath)) {
50418
51050
  return null;
50419
51051
  }
50420
51052
  return { filepath, filename };
@@ -50429,12 +51061,12 @@ var createCommand3 = new Command("create").description("Create a new documentati
50429
51061
  const folderPath = options2.folder.replace(/^\/|\/$/g, "");
50430
51062
  targetDir = join17(DOCS_DIR, folderPath);
50431
51063
  relativePath = join17(folderPath, filename);
50432
- if (!existsSync13(targetDir)) {
51064
+ if (!existsSync14(targetDir)) {
50433
51065
  await mkdir7(targetDir, { recursive: true });
50434
51066
  }
50435
51067
  }
50436
51068
  const filepath = join17(targetDir, filename);
50437
- if (existsSync13(filepath)) {
51069
+ if (existsSync14(filepath)) {
50438
51070
  console.error(source_default.red(`\u2717 Document already exists: ${relativePath}`));
50439
51071
  process.exit(1);
50440
51072
  }
@@ -50450,8 +51082,8 @@ var createCommand3 = new Command("create").description("Create a new documentati
50450
51082
  if (options2.tags) {
50451
51083
  metadata.tags = options2.tags.split(",").map((t) => t.trim());
50452
51084
  }
50453
- const content = import_gray_matter5.default.stringify("# Content\n\nWrite your documentation here.\n", metadata);
50454
- await writeFile7(filepath, content, "utf-8");
51085
+ const content = import_gray_matter6.default.stringify("# Content\n\nWrite your documentation here.\n", metadata);
51086
+ await writeFile8(filepath, content, "utf-8");
50455
51087
  await notifyDocUpdate(relativePath);
50456
51088
  if (options2.plain) {
50457
51089
  console.log(`Created: ${relativePath}`);
@@ -50464,7 +51096,7 @@ var createCommand3 = new Command("create").description("Create a new documentati
50464
51096
  process.exit(1);
50465
51097
  }
50466
51098
  });
50467
- var listCommand2 = new Command("list").description("List all documentation files").option("--plain", "Plain text output for AI").option("-t, --tag <tag>", "Filter by tag").action(async (options2) => {
51099
+ var listCommand2 = new Command("list").description("List all documentation files").argument("[path]", "Filter by path (e.g., 'guides/' or 'patterns/')").option("--plain", "Plain text output for AI").option("-t, --tag <tag>", "Filter by tag").action(async (path, options2) => {
50468
51100
  try {
50469
51101
  await ensureDocsDir();
50470
51102
  const mdFiles = await getAllMdFiles(DOCS_DIR);
@@ -50479,55 +51111,107 @@ var listCommand2 = new Command("list").description("List all documentation files
50479
51111
  }
50480
51112
  const docs = [];
50481
51113
  for (const file3 of mdFiles) {
50482
- const content = await readFile9(join17(DOCS_DIR, file3), "utf-8");
50483
- const { data } = (0, import_gray_matter5.default)(content);
51114
+ const content = await readFile11(join17(DOCS_DIR, file3), "utf-8");
51115
+ const { data } = (0, import_gray_matter6.default)(content);
50484
51116
  docs.push({
50485
51117
  filename: file3,
50486
51118
  metadata: data
50487
51119
  });
50488
51120
  }
50489
51121
  let filteredDocs = docs;
51122
+ if (path) {
51123
+ const normalizedPath = path.endsWith("/") ? path : `${path}/`;
51124
+ filteredDocs = docs.filter((doc) => doc.filename.startsWith(normalizedPath));
51125
+ }
50490
51126
  if (options2.tag) {
50491
- filteredDocs = docs.filter((doc) => doc.metadata.tags?.includes(options2.tag));
51127
+ filteredDocs = filteredDocs.filter((doc) => doc.metadata.tags?.includes(options2.tag));
50492
51128
  }
50493
51129
  if (filteredDocs.length === 0) {
51130
+ const filterMsg = path ? `path: ${path}` : options2.tag ? `tag: ${options2.tag}` : "";
50494
51131
  console.log(
50495
- options2.plain ? "No documentation found" : source_default.yellow(`No documentation found with tag: ${options2.tag}`)
51132
+ options2.plain ? "No documentation found" : source_default.yellow(`No documentation found${filterMsg ? ` with ${filterMsg}` : ""}`)
50496
51133
  );
50497
51134
  return;
50498
51135
  }
50499
51136
  if (options2.plain) {
50500
- const border = "=".repeat(50);
50501
- console.log(`Documentation Files (${filteredDocs.length})`);
50502
- console.log(border);
50503
- console.log();
51137
+ const folders = /* @__PURE__ */ new Map();
51138
+ const rootDocs = [];
50504
51139
  for (const doc of filteredDocs) {
50505
- console.log(`${doc.filename} - ${doc.metadata.title}`);
50506
- if (doc.metadata.description) {
50507
- console.log(` ${doc.metadata.description}`);
51140
+ const parts = doc.filename.split("/");
51141
+ if (parts.length === 1) {
51142
+ rootDocs.push({
51143
+ name: parts[0].replace(/\.md$/, ""),
51144
+ title: doc.metadata.title
51145
+ });
51146
+ } else {
51147
+ const folder = parts.slice(0, -1).join("/");
51148
+ const name = parts[parts.length - 1].replace(/\.md$/, "");
51149
+ if (!folders.has(folder)) {
51150
+ folders.set(folder, []);
51151
+ }
51152
+ folders.get(folder)?.push({ name, title: doc.metadata.title });
50508
51153
  }
50509
- console.log(` Created: ${doc.metadata.createdAt}`);
50510
- if (doc.metadata.tags && doc.metadata.tags.length > 0) {
50511
- console.log(` Tags: ${doc.metadata.tags.join(", ")}`);
51154
+ }
51155
+ const sortedFolders = Array.from(folders.keys()).sort();
51156
+ for (const folder of sortedFolders) {
51157
+ console.log(`${folder}/`);
51158
+ const docs2 = folders.get(folder)?.sort((a, b) => a.name.localeCompare(b.name));
51159
+ for (const doc of docs2) {
51160
+ console.log(` ${doc.name} - ${doc.title}`);
51161
+ }
51162
+ }
51163
+ if (rootDocs.length > 0) {
51164
+ rootDocs.sort((a, b) => a.name.localeCompare(b.name));
51165
+ for (const doc of rootDocs) {
51166
+ console.log(`${doc.name} - ${doc.title}`);
50512
51167
  }
50513
- console.log();
50514
51168
  }
50515
51169
  } else {
50516
- console.log(source_default.bold("\n\u{1F4DA} Documentation\n"));
51170
+ const folders = /* @__PURE__ */ new Map();
51171
+ const rootDocs = [];
50517
51172
  for (const doc of filteredDocs) {
50518
- console.log(source_default.cyan(` ${doc.metadata.title}`));
50519
- if (doc.metadata.description) {
50520
- console.log(source_default.gray(` ${doc.metadata.description}`));
51173
+ const parts = doc.filename.split("/");
51174
+ if (parts.length === 1) {
51175
+ rootDocs.push(doc);
51176
+ } else {
51177
+ const folder = parts.slice(0, -1).join("/");
51178
+ if (!folders.has(folder)) {
51179
+ folders.set(folder, []);
51180
+ }
51181
+ folders.get(folder)?.push(doc);
50521
51182
  }
50522
- console.log(source_default.gray(` File: ${doc.filename}`));
50523
- if (doc.metadata.tags && doc.metadata.tags.length > 0) {
50524
- console.log(source_default.gray(` Tags: ${doc.metadata.tags.join(", ")}`));
51183
+ }
51184
+ console.log(source_default.bold(`
51185
+ Documentation (${filteredDocs.length})
51186
+ `));
51187
+ const sortedFolders = Array.from(folders.keys()).sort();
51188
+ for (const folder of sortedFolders) {
51189
+ console.log(source_default.cyan.bold(`${folder}/`));
51190
+ const docs2 = folders.get(folder)?.sort((a, b) => a.metadata.title.localeCompare(b.metadata.title));
51191
+ for (const doc of docs2) {
51192
+ console.log(source_default.white(` ${doc.metadata.title}`));
51193
+ if (doc.metadata.description) {
51194
+ console.log(source_default.gray(` ${doc.metadata.description}`));
51195
+ }
51196
+ if (doc.metadata.tags && doc.metadata.tags.length > 0) {
51197
+ console.log(source_default.gray(` Tags: ${doc.metadata.tags.join(", ")}`));
51198
+ }
50525
51199
  }
50526
- console.log(source_default.gray(` Updated: ${new Date(doc.metadata.updatedAt).toLocaleString()}`));
50527
51200
  console.log();
50528
51201
  }
50529
- console.log(source_default.gray(`Total: ${filteredDocs.length} document(s)
50530
- `));
51202
+ if (rootDocs.length > 0) {
51203
+ rootDocs.sort((a, b) => a.metadata.title.localeCompare(b.metadata.title));
51204
+ for (const doc of rootDocs) {
51205
+ console.log(source_default.white(`${doc.metadata.title}`));
51206
+ if (doc.metadata.description) {
51207
+ console.log(source_default.gray(` ${doc.metadata.description}`));
51208
+ }
51209
+ if (doc.metadata.tags && doc.metadata.tags.length > 0) {
51210
+ console.log(source_default.gray(` Tags: ${doc.metadata.tags.join(", ")}`));
51211
+ }
51212
+ console.log();
51213
+ }
51214
+ }
50531
51215
  }
50532
51216
  } catch (error46) {
50533
51217
  console.error(source_default.red("Error listing documentation:"), error46 instanceof Error ? error46.message : String(error46));
@@ -50539,11 +51223,11 @@ var viewCommand2 = new Command("view").description("View a documentation file").
50539
51223
  await ensureDocsDir();
50540
51224
  let filename = name.endsWith(".md") ? name : `${name}.md`;
50541
51225
  let filepath = join17(DOCS_DIR, filename);
50542
- if (!existsSync13(filepath)) {
51226
+ if (!existsSync14(filepath)) {
50543
51227
  filename = `${titleToFilename(name)}.md`;
50544
51228
  filepath = join17(DOCS_DIR, filename);
50545
51229
  }
50546
- if (!existsSync13(filepath)) {
51230
+ if (!existsSync14(filepath)) {
50547
51231
  const allFiles = await getAllMdFiles(DOCS_DIR);
50548
51232
  const searchName = name.toLowerCase().replace(/\.md$/, "");
50549
51233
  const matchingFile = allFiles.find((file3) => {
@@ -50556,12 +51240,12 @@ var viewCommand2 = new Command("view").description("View a documentation file").
50556
51240
  filepath = join17(DOCS_DIR, matchingFile);
50557
51241
  }
50558
51242
  }
50559
- if (!existsSync13(filepath)) {
51243
+ if (!existsSync14(filepath)) {
50560
51244
  console.error(source_default.red(`\u2717 Documentation not found: ${name}`));
50561
51245
  process.exit(1);
50562
51246
  }
50563
- const fileContent = await readFile9(filepath, "utf-8");
50564
- const { data, content } = (0, import_gray_matter5.default)(fileContent);
51247
+ const fileContent = await readFile11(filepath, "utf-8");
51248
+ const { data, content } = (0, import_gray_matter6.default)(fileContent);
50565
51249
  const metadata = data;
50566
51250
  if (options2.plain) {
50567
51251
  const border = "-".repeat(50);
@@ -50642,18 +51326,18 @@ var viewCommand2 = new Command("view").description("View a documentation file").
50642
51326
  process.exit(1);
50643
51327
  }
50644
51328
  });
50645
- var editCommand2 = new Command("edit").description("Edit a documentation file (metadata and content)").argument("<name>", "Document name or path (e.g., guides/my-doc)").option("-t, --title <text>", "New title").option("-d, --description <text>", "New description").option("--tags <tags>", "Comma-separated tags").option("-c, --content <text>", "Replace content").option("-a, --append <text>", "Append to content").option("--plain", "Plain text output for AI").action(
51329
+ var editCommand2 = new Command("edit").description("Edit a documentation file (metadata and content)").argument("<name>", "Document name or path (e.g., guides/my-doc)").option("-t, --title <text>", "New title").option("-d, --description <text>", "New description").option("--tags <tags>", "Comma-separated tags").option("-c, --content <text>", "Replace content").option("-a, --append <text>", "Append to content").option("--content-file <path>", "Replace content with file contents").option("--append-file <path>", "Append file contents to document").option("--plain", "Plain text output for AI").action(
50646
51330
  async (name, options2) => {
50647
51331
  try {
50648
51332
  await ensureDocsDir();
50649
51333
  let filename = name.endsWith(".md") ? name : `${name}.md`;
50650
51334
  let filepath = join17(DOCS_DIR, filename);
50651
- if (!existsSync13(filepath)) {
51335
+ if (!existsSync14(filepath)) {
50652
51336
  const baseName = name.includes("/") ? name : titleToFilename(name);
50653
51337
  filename = baseName.endsWith(".md") ? baseName : `${baseName}.md`;
50654
51338
  filepath = join17(DOCS_DIR, filename);
50655
51339
  }
50656
- if (!existsSync13(filepath)) {
51340
+ if (!existsSync14(filepath)) {
50657
51341
  const allFiles = await getAllMdFiles(DOCS_DIR);
50658
51342
  const searchName = name.toLowerCase().replace(/\.md$/, "");
50659
51343
  const matchingFile = allFiles.find((file3) => {
@@ -50666,33 +51350,57 @@ var editCommand2 = new Command("edit").description("Edit a documentation file (m
50666
51350
  filepath = join17(DOCS_DIR, matchingFile);
50667
51351
  }
50668
51352
  }
50669
- if (!existsSync13(filepath)) {
51353
+ if (!existsSync14(filepath)) {
50670
51354
  console.error(source_default.red(`\u2717 Documentation not found: ${name}`));
50671
51355
  process.exit(1);
50672
51356
  }
50673
- const fileContent = await readFile9(filepath, "utf-8");
50674
- const { data, content } = (0, import_gray_matter5.default)(fileContent);
51357
+ const fileContent = await readFile11(filepath, "utf-8");
51358
+ const { data, content } = (0, import_gray_matter6.default)(fileContent);
50675
51359
  const metadata = data;
50676
51360
  if (options2.title) metadata.title = options2.title;
50677
51361
  if (options2.description) metadata.description = normalizeRefs(options2.description);
50678
51362
  if (options2.tags) metadata.tags = options2.tags.split(",").map((t) => t.trim());
50679
51363
  metadata.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
50680
51364
  let updatedContent = content;
50681
- if (options2.content) {
51365
+ let sourceFile;
51366
+ if (options2.contentFile) {
51367
+ if (!existsSync14(options2.contentFile)) {
51368
+ console.error(source_default.red(`\u2717 File not found: ${options2.contentFile}`));
51369
+ process.exit(1);
51370
+ }
51371
+ const fileData = await readFile11(options2.contentFile, "utf-8");
51372
+ updatedContent = normalizeRefs(fileData);
51373
+ sourceFile = options2.contentFile;
51374
+ } else if (options2.appendFile) {
51375
+ if (!existsSync14(options2.appendFile)) {
51376
+ console.error(source_default.red(`\u2717 File not found: ${options2.appendFile}`));
51377
+ process.exit(1);
51378
+ }
51379
+ const fileData = await readFile11(options2.appendFile, "utf-8");
51380
+ updatedContent = `${content.trimEnd()}
51381
+
51382
+ ${normalizeRefs(fileData)}`;
51383
+ sourceFile = options2.appendFile;
51384
+ } else if (options2.content) {
50682
51385
  updatedContent = normalizeRefs(options2.content);
50683
- }
50684
- if (options2.append) {
51386
+ } else if (options2.append) {
50685
51387
  updatedContent = `${content.trimEnd()}
50686
51388
 
50687
51389
  ${normalizeRefs(options2.append)}`;
50688
51390
  }
50689
- const newFileContent = import_gray_matter5.default.stringify(updatedContent, metadata);
50690
- await writeFile7(filepath, newFileContent, "utf-8");
51391
+ const newFileContent = import_gray_matter6.default.stringify(updatedContent, metadata);
51392
+ await writeFile8(filepath, newFileContent, "utf-8");
50691
51393
  await notifyDocUpdate(filename);
50692
51394
  if (options2.plain) {
50693
51395
  console.log(`Updated: ${filename}`);
51396
+ if (sourceFile) {
51397
+ console.log(`Content from: ${sourceFile}`);
51398
+ }
50694
51399
  } else {
50695
51400
  console.log(source_default.green(`\u2713 Updated documentation: ${source_default.bold(filename)}`));
51401
+ if (sourceFile) {
51402
+ console.log(source_default.gray(` Content from: ${sourceFile}`));
51403
+ }
50696
51404
  }
50697
51405
  } catch (error46) {
50698
51406
  console.error(
@@ -50703,7 +51411,285 @@ ${normalizeRefs(options2.append)}`;
50703
51411
  }
50704
51412
  }
50705
51413
  );
50706
- var docCommand = new Command("doc").description("Manage documentation").argument("[name]", "Document name (shorthand for 'doc view <name>')").option("--plain", "Plain text output for AI").action(async (name, options2) => {
51414
+ var validateCommand2 = new Command("validate").description("Validate a documentation file format").argument("<name>", "Document name or path").option("--plain", "Plain text output for AI").action(async (name, options2) => {
51415
+ try {
51416
+ const resolved = await resolveDocPath(name);
51417
+ if (!resolved) {
51418
+ console.error(source_default.red(`\u2717 Documentation not found: ${name}`));
51419
+ process.exit(1);
51420
+ }
51421
+ const content = await readFile11(resolved.filepath, "utf-8");
51422
+ const result = validateDoc(content);
51423
+ if (options2.plain) {
51424
+ console.log(`Validating: ${resolved.filename}`);
51425
+ console.log(`Valid: ${result.valid}`);
51426
+ if (result.errors.length > 0) {
51427
+ console.log("\nErrors:");
51428
+ for (const error46 of result.errors) {
51429
+ console.log(` \u2717 ${error46.field}: ${error46.message}${error46.fixable ? " (fixable)" : ""}`);
51430
+ }
51431
+ }
51432
+ if (result.warnings.length > 0) {
51433
+ console.log("\nWarnings:");
51434
+ for (const warning of result.warnings) {
51435
+ console.log(` \u26A0 ${warning.field}: ${warning.message}`);
51436
+ }
51437
+ }
51438
+ if (result.valid && result.warnings.length === 0) {
51439
+ console.log("No issues found.");
51440
+ }
51441
+ } else {
51442
+ console.log(source_default.bold(`
51443
+ \u{1F4CB} Validation: ${resolved.filename}
51444
+ `));
51445
+ if (result.valid) {
51446
+ console.log(source_default.green("\u2713 Document is valid"));
51447
+ } else {
51448
+ console.log(source_default.red("\u2717 Document has errors"));
51449
+ }
51450
+ if (result.errors.length > 0) {
51451
+ console.log(source_default.red("\nErrors:"));
51452
+ for (const error46 of result.errors) {
51453
+ const fixable = error46.fixable ? source_default.gray(" (fixable)") : "";
51454
+ console.log(source_default.red(` \u2717 ${error46.field}: ${error46.message}${fixable}`));
51455
+ }
51456
+ }
51457
+ if (result.warnings.length > 0) {
51458
+ console.log(source_default.yellow("\nWarnings:"));
51459
+ for (const warning of result.warnings) {
51460
+ console.log(source_default.yellow(` \u26A0 ${warning.field}: ${warning.message}`));
51461
+ }
51462
+ }
51463
+ if (result.valid && result.warnings.length === 0) {
51464
+ console.log(source_default.gray("\nNo issues found."));
51465
+ }
51466
+ console.log();
51467
+ }
51468
+ process.exit(result.valid ? 0 : 1);
51469
+ } catch (error46) {
51470
+ console.error(
51471
+ source_default.red("Error validating documentation:"),
51472
+ error46 instanceof Error ? error46.message : String(error46)
51473
+ );
51474
+ process.exit(1);
51475
+ }
51476
+ });
51477
+ var repairCommand2 = new Command("repair").description("Repair a corrupted documentation file").argument("<name>", "Document name or path").option("--plain", "Plain text output for AI").action(async (name, options2) => {
51478
+ try {
51479
+ const resolved = await resolveDocPath(name);
51480
+ if (!resolved) {
51481
+ console.error(source_default.red(`\u2717 Documentation not found: ${name}`));
51482
+ process.exit(1);
51483
+ }
51484
+ const result = await repairDoc(resolved.filepath);
51485
+ if (options2.plain) {
51486
+ console.log(`Repairing: ${resolved.filename}`);
51487
+ console.log(`Success: ${result.success}`);
51488
+ if (result.backupPath) {
51489
+ console.log(`Backup: ${result.backupPath}`);
51490
+ }
51491
+ if (result.fixes.length > 0) {
51492
+ console.log("\nFixes applied:");
51493
+ for (const fix of result.fixes) {
51494
+ console.log(` \u2713 ${fix}`);
51495
+ }
51496
+ }
51497
+ if (result.errors.length > 0) {
51498
+ console.log("\nErrors:");
51499
+ for (const error46 of result.errors) {
51500
+ console.log(` \u2717 ${error46}`);
51501
+ }
51502
+ }
51503
+ } else {
51504
+ console.log(source_default.bold(`
51505
+ \u{1F527} Repair: ${resolved.filename}
51506
+ `));
51507
+ if (result.success) {
51508
+ console.log(source_default.green("\u2713 Document repaired successfully"));
51509
+ } else {
51510
+ console.log(source_default.red("\u2717 Repair failed"));
51511
+ }
51512
+ if (result.backupPath) {
51513
+ console.log(source_default.gray(` Backup created: ${result.backupPath}`));
51514
+ }
51515
+ if (result.fixes.length > 0) {
51516
+ console.log(source_default.green("\nFixes applied:"));
51517
+ for (const fix of result.fixes) {
51518
+ console.log(source_default.green(` \u2713 ${fix}`));
51519
+ }
51520
+ }
51521
+ if (result.errors.length > 0) {
51522
+ console.log(source_default.red("\nErrors:"));
51523
+ for (const error46 of result.errors) {
51524
+ console.log(source_default.red(` \u2717 ${error46}`));
51525
+ }
51526
+ }
51527
+ console.log();
51528
+ }
51529
+ if (result.success) {
51530
+ await notifyDocUpdate(resolved.filename);
51531
+ }
51532
+ process.exit(result.success ? 0 : 1);
51533
+ } catch (error46) {
51534
+ console.error(
51535
+ source_default.red("Error repairing documentation:"),
51536
+ error46 instanceof Error ? error46.message : String(error46)
51537
+ );
51538
+ process.exit(1);
51539
+ }
51540
+ });
51541
+ var searchInCommand = new Command("search-in").description("Search text within a specific document").argument("<name>", "Document name or path").argument("<query>", "Text to search for").option("--plain", "Plain text output for AI").option("-i, --ignore-case", "Case insensitive search").action(async (name, query, options2) => {
51542
+ try {
51543
+ const resolved = await resolveDocPath(name);
51544
+ if (!resolved) {
51545
+ console.error(source_default.red(`\u2717 Documentation not found: ${name}`));
51546
+ process.exit(1);
51547
+ }
51548
+ const fileContent = await readFile11(resolved.filepath, "utf-8");
51549
+ const { content } = (0, import_gray_matter6.default)(fileContent);
51550
+ const lines = content.split("\n");
51551
+ const matches = [];
51552
+ const searchQuery = options2.ignoreCase ? query.toLowerCase() : query;
51553
+ for (let i = 0; i < lines.length; i++) {
51554
+ const line = lines[i];
51555
+ const searchLine = options2.ignoreCase ? line.toLowerCase() : line;
51556
+ if (searchLine.includes(searchQuery)) {
51557
+ const contextStart = Math.max(0, i - 1);
51558
+ const contextEnd = Math.min(lines.length - 1, i + 1);
51559
+ const context = lines.slice(contextStart, contextEnd + 1).join("\n");
51560
+ matches.push({
51561
+ lineNum: i + 1,
51562
+ // 1-indexed
51563
+ line,
51564
+ context
51565
+ });
51566
+ }
51567
+ }
51568
+ if (options2.plain) {
51569
+ console.log(`Searching in: ${resolved.filename}`);
51570
+ console.log(`Query: "${query}"`);
51571
+ console.log(`Found: ${matches.length} match(es)`);
51572
+ console.log();
51573
+ for (const match of matches) {
51574
+ console.log(`Line ${match.lineNum}: ${match.line.trim()}`);
51575
+ }
51576
+ } else {
51577
+ console.log(source_default.bold(`
51578
+ \u{1F50D} Search in: ${resolved.filename}
51579
+ `));
51580
+ console.log(source_default.gray(`Query: "${query}"`));
51581
+ console.log(source_default.gray(`Found: ${matches.length} match(es)
51582
+ `));
51583
+ for (const match of matches) {
51584
+ console.log(source_default.cyan(`Line ${match.lineNum}:`));
51585
+ console.log(source_default.white(` ${match.line.trim()}`));
51586
+ console.log();
51587
+ }
51588
+ }
51589
+ } catch (error46) {
51590
+ console.error(source_default.red("Error searching document:"), error46 instanceof Error ? error46.message : String(error46));
51591
+ process.exit(1);
51592
+ }
51593
+ });
51594
+ var replaceCommand = new Command("replace").description("Replace text in a document").argument("<name>", "Document name or path").argument("<old-text>", "Text to find").argument("<new-text>", "Text to replace with").option("--plain", "Plain text output for AI").option("-a, --all", "Replace all occurrences (default: first only)").action(async (name, oldText, newText, options2) => {
51595
+ try {
51596
+ const resolved = await resolveDocPath(name);
51597
+ if (!resolved) {
51598
+ console.error(source_default.red(`\u2717 Documentation not found: ${name}`));
51599
+ process.exit(1);
51600
+ }
51601
+ const fileContent = await readFile11(resolved.filepath, "utf-8");
51602
+ const { data, content } = (0, import_gray_matter6.default)(fileContent);
51603
+ if (!content.includes(oldText)) {
51604
+ if (options2.plain) {
51605
+ console.log(`Text not found: "${oldText}"`);
51606
+ } else {
51607
+ console.log(source_default.yellow(`\u26A0 Text not found: "${oldText}"`));
51608
+ }
51609
+ process.exit(1);
51610
+ }
51611
+ let newContent;
51612
+ let count = 0;
51613
+ if (options2.all) {
51614
+ const parts = content.split(oldText);
51615
+ count = parts.length - 1;
51616
+ newContent = parts.join(newText);
51617
+ } else {
51618
+ newContent = content.replace(oldText, newText);
51619
+ count = 1;
51620
+ }
51621
+ const metadata = data;
51622
+ metadata.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
51623
+ const updatedFileContent = import_gray_matter6.default.stringify(newContent, data);
51624
+ await writeFile8(resolved.filepath, updatedFileContent, "utf-8");
51625
+ await notifyDocUpdate(resolved.filename);
51626
+ if (options2.plain) {
51627
+ console.log(`Updated: ${resolved.filename}`);
51628
+ console.log(`Replaced: ${count} occurrence(s)`);
51629
+ } else {
51630
+ console.log(source_default.green(`\u2713 Updated: ${resolved.filename}`));
51631
+ console.log(source_default.gray(` Replaced ${count} occurrence(s)`));
51632
+ }
51633
+ } catch (error46) {
51634
+ console.error(source_default.red("Error replacing text:"), error46 instanceof Error ? error46.message : String(error46));
51635
+ process.exit(1);
51636
+ }
51637
+ });
51638
+ var replaceSectionCommand = new Command("replace-section").description("Replace an entire section by its header").argument("<name>", "Document name or path").argument("<header>", "Section header (e.g., '## Section Name')").argument("<content>", "New section content (without header)").option("--plain", "Plain text output for AI").action(async (name, header, newSectionContent, options2) => {
51639
+ try {
51640
+ const resolved = await resolveDocPath(name);
51641
+ if (!resolved) {
51642
+ console.error(source_default.red(`\u2717 Documentation not found: ${name}`));
51643
+ process.exit(1);
51644
+ }
51645
+ const fileContent = await readFile11(resolved.filepath, "utf-8");
51646
+ const { data, content } = (0, import_gray_matter6.default)(fileContent);
51647
+ const headerLevel = (header.match(/^#+/) || ["##"])[0];
51648
+ const headerPattern = new RegExp(`^${header.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*$`, "m");
51649
+ const headerMatch = content.match(headerPattern);
51650
+ if (!headerMatch) {
51651
+ if (options2.plain) {
51652
+ console.log(`Section not found: "${header}"`);
51653
+ } else {
51654
+ console.log(source_default.yellow(`\u26A0 Section not found: "${header}"`));
51655
+ }
51656
+ process.exit(1);
51657
+ }
51658
+ const headerIndex = content.indexOf(headerMatch[0]);
51659
+ const afterHeader = content.substring(headerIndex + headerMatch[0].length);
51660
+ const nextHeaderPattern = new RegExp(`^#{1,${headerLevel.length}}\\s+`, "m");
51661
+ const nextHeaderMatch = afterHeader.match(nextHeaderPattern);
51662
+ let sectionEnd;
51663
+ if (nextHeaderMatch) {
51664
+ sectionEnd = headerIndex + headerMatch[0].length + afterHeader.indexOf(nextHeaderMatch[0]);
51665
+ } else {
51666
+ sectionEnd = content.length;
51667
+ }
51668
+ const beforeSection = content.substring(0, headerIndex);
51669
+ const afterSection = content.substring(sectionEnd);
51670
+ const newContent = `${beforeSection}${header}
51671
+
51672
+ ${newSectionContent}
51673
+
51674
+ ${afterSection.trimStart()}`;
51675
+ const metadata = data;
51676
+ metadata.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
51677
+ const updatedFileContent = import_gray_matter6.default.stringify(newContent.trim(), data);
51678
+ await writeFile8(resolved.filepath, updatedFileContent, "utf-8");
51679
+ await notifyDocUpdate(resolved.filename);
51680
+ if (options2.plain) {
51681
+ console.log(`Updated: ${resolved.filename}`);
51682
+ console.log(`Replaced section: "${header}"`);
51683
+ } else {
51684
+ console.log(source_default.green(`\u2713 Updated: ${resolved.filename}`));
51685
+ console.log(source_default.gray(` Replaced section: "${header}"`));
51686
+ }
51687
+ } catch (error46) {
51688
+ console.error(source_default.red("Error replacing section:"), error46 instanceof Error ? error46.message : String(error46));
51689
+ process.exit(1);
51690
+ }
51691
+ });
51692
+ var docCommand = new Command("doc").description("Manage documentation").argument("[name]", "Document name (shorthand for 'doc view <name>')").option("--plain", "Plain text output for AI").enablePositionalOptions().passThroughOptions().action(async (name, options2) => {
50707
51693
  if (!name) {
50708
51694
  docCommand.help();
50709
51695
  return;
@@ -50715,8 +51701,8 @@ var docCommand = new Command("doc").description("Manage documentation").argument
50715
51701
  process.exit(1);
50716
51702
  }
50717
51703
  const { filepath, filename } = resolved;
50718
- const fileContent = await readFile9(filepath, "utf-8");
50719
- const { data, content } = (0, import_gray_matter5.default)(fileContent);
51704
+ const fileContent = await readFile11(filepath, "utf-8");
51705
+ const { data, content } = (0, import_gray_matter6.default)(fileContent);
50720
51706
  const metadata = data;
50721
51707
  if (options2.plain) {
50722
51708
  const border = "-".repeat(50);
@@ -50801,10 +51787,15 @@ docCommand.addCommand(createCommand3);
50801
51787
  docCommand.addCommand(listCommand2);
50802
51788
  docCommand.addCommand(viewCommand2);
50803
51789
  docCommand.addCommand(editCommand2);
51790
+ docCommand.addCommand(validateCommand2);
51791
+ docCommand.addCommand(repairCommand2);
51792
+ docCommand.addCommand(searchInCommand);
51793
+ docCommand.addCommand(replaceCommand);
51794
+ docCommand.addCommand(replaceSectionCommand);
50804
51795
 
50805
51796
  // src/commands/config.ts
50806
- import { existsSync as existsSync14 } from "node:fs";
50807
- import { mkdir as mkdir8, readFile as readFile10, writeFile as writeFile8 } from "node:fs/promises";
51797
+ import { existsSync as existsSync15 } from "node:fs";
51798
+ import { mkdir as mkdir8, readFile as readFile12, writeFile as writeFile9 } from "node:fs/promises";
50808
51799
  import { join as join18 } from "node:path";
50809
51800
 
50810
51801
  // node_modules/zod/v4/classic/external.js
@@ -64363,11 +65354,11 @@ function getProjectRoot2() {
64363
65354
  }
64364
65355
  async function loadConfig(projectRoot) {
64365
65356
  const configPath = join18(projectRoot, CONFIG_FILE2);
64366
- if (!existsSync14(configPath)) {
65357
+ if (!existsSync15(configPath)) {
64367
65358
  return { ...DEFAULT_CONFIG };
64368
65359
  }
64369
65360
  try {
64370
- const content = await readFile10(configPath, "utf-8");
65361
+ const content = await readFile12(configPath, "utf-8");
64371
65362
  const data = JSON.parse(content);
64372
65363
  const settings = data.settings || {};
64373
65364
  const validated = ConfigSchema.parse(settings);
@@ -64383,20 +65374,20 @@ async function loadConfig(projectRoot) {
64383
65374
  async function saveConfig(projectRoot, config2) {
64384
65375
  const configPath = join18(projectRoot, CONFIG_FILE2);
64385
65376
  const knownsDir = join18(projectRoot, ".knowns");
64386
- if (!existsSync14(knownsDir)) {
65377
+ if (!existsSync15(knownsDir)) {
64387
65378
  await mkdir8(knownsDir, { recursive: true });
64388
65379
  }
64389
65380
  try {
64390
65381
  let existingData = {};
64391
- if (existsSync14(configPath)) {
64392
- const content = await readFile10(configPath, "utf-8");
65382
+ if (existsSync15(configPath)) {
65383
+ const content = await readFile12(configPath, "utf-8");
64393
65384
  existingData = JSON.parse(content);
64394
65385
  }
64395
65386
  const merged = {
64396
65387
  ...existingData,
64397
65388
  settings: config2
64398
65389
  };
64399
- await writeFile8(configPath, JSON.stringify(merged, null, 2), "utf-8");
65390
+ await writeFile9(configPath, JSON.stringify(merged, null, 2), "utf-8");
64400
65391
  } catch (error46) {
64401
65392
  console.error(source_default.red("\u2717 Failed to save config"));
64402
65393
  if (error46 instanceof Error) {
@@ -64538,8 +65529,8 @@ var resetCommand = new Command("reset").description("Reset configuration to defa
64538
65529
  var configCommand = new Command("config").description("Manage configuration settings").addCommand(listCommand3).addCommand(getCommand).addCommand(setCommand).addCommand(resetCommand);
64539
65530
 
64540
65531
  // src/mcp/server.ts
64541
- import { existsSync as existsSync16 } from "node:fs";
64542
- import { readFile as readFile13 } from "node:fs/promises";
65532
+ import { existsSync as existsSync17 } from "node:fs";
65533
+ import { readFile as readFile15 } from "node:fs/promises";
64543
65534
  import { join as join21 } from "node:path";
64544
65535
 
64545
65536
  // node_modules/zod/v3/helpers/util.js
@@ -71600,12 +72591,12 @@ var StdioServerTransport = class {
71600
72591
  };
71601
72592
 
71602
72593
  // src/mcp/server.ts
71603
- var import_gray_matter8 = __toESM(require_gray_matter(), 1);
72594
+ var import_gray_matter9 = __toESM(require_gray_matter(), 1);
71604
72595
 
71605
72596
  // src/mcp/utils.ts
71606
- import { readFile as readFile11 } from "node:fs/promises";
72597
+ import { readFile as readFile13 } from "node:fs/promises";
71607
72598
  import { join as join19 } from "node:path";
71608
- var import_gray_matter6 = __toESM(require_gray_matter(), 1);
72599
+ var import_gray_matter7 = __toESM(require_gray_matter(), 1);
71609
72600
  function parseDuration2(durationStr) {
71610
72601
  let totalSeconds = 0;
71611
72602
  const hoursMatch = durationStr.match(/(\d+)h/);
@@ -71646,8 +72637,8 @@ async function fetchLinkedDocs(task) {
71646
72637
  try {
71647
72638
  const filename = ref.resolvedPath.replace("@.knowns/docs/", "");
71648
72639
  const filepath = join19(docsDir, filename);
71649
- const fileContent = await readFile11(filepath, "utf-8");
71650
- const { data, content } = (0, import_gray_matter6.default)(fileContent);
72640
+ const fileContent = await readFile13(filepath, "utf-8");
72641
+ const { data, content } = (0, import_gray_matter7.default)(fileContent);
71651
72642
  linkedDocs.push({
71652
72643
  path: ref.resolvedPath,
71653
72644
  title: data.title || ref.text,
@@ -72208,10 +73199,10 @@ async function handleGetBoard(fileStore2) {
72208
73199
  }
72209
73200
 
72210
73201
  // src/mcp/handlers/doc.ts
72211
- import { existsSync as existsSync15 } from "node:fs";
72212
- import { mkdir as mkdir9, readFile as readFile12, readdir as readdir6, writeFile as writeFile9 } from "node:fs/promises";
73202
+ import { existsSync as existsSync16 } from "node:fs";
73203
+ import { mkdir as mkdir9, readFile as readFile14, readdir as readdir6, writeFile as writeFile10 } from "node:fs/promises";
72213
73204
  import { join as join20 } from "node:path";
72214
- var import_gray_matter7 = __toESM(require_gray_matter(), 1);
73205
+ var import_gray_matter8 = __toESM(require_gray_matter(), 1);
72215
73206
  var DOCS_DIR2 = join20(process.cwd(), ".knowns", "docs");
72216
73207
  var listDocsSchema = external_exports.object({
72217
73208
  tag: external_exports.string().optional()
@@ -72329,7 +73320,7 @@ var docTools = [
72329
73320
  }
72330
73321
  ];
72331
73322
  async function ensureDocsDir2() {
72332
- if (!existsSync15(DOCS_DIR2)) {
73323
+ if (!existsSync16(DOCS_DIR2)) {
72333
73324
  await mkdir9(DOCS_DIR2, { recursive: true });
72334
73325
  }
72335
73326
  }
@@ -72338,7 +73329,7 @@ function titleToFilename2(title) {
72338
73329
  }
72339
73330
  async function getAllMdFiles2(dir, basePath = "") {
72340
73331
  const files = [];
72341
- if (!existsSync15(dir)) {
73332
+ if (!existsSync16(dir)) {
72342
73333
  return files;
72343
73334
  }
72344
73335
  const entries = await readdir6(dir, { withFileTypes: true });
@@ -72358,12 +73349,12 @@ async function resolveDocPath2(name) {
72358
73349
  await ensureDocsDir2();
72359
73350
  let filename = name.endsWith(".md") ? name : `${name}.md`;
72360
73351
  let filepath = join20(DOCS_DIR2, filename);
72361
- if (existsSync15(filepath)) {
73352
+ if (existsSync16(filepath)) {
72362
73353
  return { filepath, filename };
72363
73354
  }
72364
73355
  filename = `${titleToFilename2(name)}.md`;
72365
73356
  filepath = join20(DOCS_DIR2, filename);
72366
- if (existsSync15(filepath)) {
73357
+ if (existsSync16(filepath)) {
72367
73358
  return { filepath, filename };
72368
73359
  }
72369
73360
  const allFiles = await getAllMdFiles2(DOCS_DIR2);
@@ -72394,8 +73385,8 @@ async function handleListDocs(args) {
72394
73385
  }
72395
73386
  const docs = [];
72396
73387
  for (const file3 of mdFiles) {
72397
- const content = await readFile12(join20(DOCS_DIR2, file3), "utf-8");
72398
- const { data } = (0, import_gray_matter7.default)(content);
73388
+ const content = await readFile14(join20(DOCS_DIR2, file3), "utf-8");
73389
+ const { data } = (0, import_gray_matter8.default)(content);
72399
73390
  const metadata = data;
72400
73391
  if (input.tag && !metadata.tags?.includes(input.tag)) {
72401
73392
  continue;
@@ -72419,8 +73410,8 @@ async function handleGetDoc(args) {
72419
73410
  if (!resolved) {
72420
73411
  return errorResponse(`Documentation not found: ${input.path}`);
72421
73412
  }
72422
- const fileContent = await readFile12(resolved.filepath, "utf-8");
72423
- const { data, content } = (0, import_gray_matter7.default)(fileContent);
73413
+ const fileContent = await readFile14(resolved.filepath, "utf-8");
73414
+ const { data, content } = (0, import_gray_matter8.default)(fileContent);
72424
73415
  const metadata = data;
72425
73416
  return successResponse({
72426
73417
  doc: {
@@ -72444,12 +73435,12 @@ async function handleCreateDoc(args) {
72444
73435
  const folderPath = input.folder.replace(/^\/|\/$/g, "");
72445
73436
  targetDir = join20(DOCS_DIR2, folderPath);
72446
73437
  relativePath = join20(folderPath, filename);
72447
- if (!existsSync15(targetDir)) {
73438
+ if (!existsSync16(targetDir)) {
72448
73439
  await mkdir9(targetDir, { recursive: true });
72449
73440
  }
72450
73441
  }
72451
73442
  const filepath = join20(targetDir, filename);
72452
- if (existsSync15(filepath)) {
73443
+ if (existsSync16(filepath)) {
72453
73444
  return errorResponse(`Document already exists: ${relativePath}`);
72454
73445
  }
72455
73446
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -72465,8 +73456,8 @@ async function handleCreateDoc(args) {
72465
73456
  metadata.tags = input.tags;
72466
73457
  }
72467
73458
  const initialContent = input.content || "# Content\n\nWrite your documentation here.";
72468
- const fileContent = import_gray_matter7.default.stringify(initialContent, metadata);
72469
- await writeFile9(filepath, fileContent, "utf-8");
73459
+ const fileContent = import_gray_matter8.default.stringify(initialContent, metadata);
73460
+ await writeFile10(filepath, fileContent, "utf-8");
72470
73461
  await notifyDocUpdate(relativePath);
72471
73462
  return successResponse({
72472
73463
  message: `Created documentation: ${relativePath}`,
@@ -72484,8 +73475,8 @@ async function handleUpdateDoc(args) {
72484
73475
  if (!resolved) {
72485
73476
  return errorResponse(`Documentation not found: ${input.path}`);
72486
73477
  }
72487
- const fileContent = await readFile12(resolved.filepath, "utf-8");
72488
- const { data, content } = (0, import_gray_matter7.default)(fileContent);
73478
+ const fileContent = await readFile14(resolved.filepath, "utf-8");
73479
+ const { data, content } = (0, import_gray_matter8.default)(fileContent);
72489
73480
  const metadata = data;
72490
73481
  if (input.title) metadata.title = input.title;
72491
73482
  if (input.description) metadata.description = input.description;
@@ -72500,8 +73491,8 @@ async function handleUpdateDoc(args) {
72500
73491
 
72501
73492
  ${input.appendContent}`;
72502
73493
  }
72503
- const newFileContent = import_gray_matter7.default.stringify(updatedContent, metadata);
72504
- await writeFile9(resolved.filepath, newFileContent, "utf-8");
73494
+ const newFileContent = import_gray_matter8.default.stringify(updatedContent, metadata);
73495
+ await writeFile10(resolved.filepath, newFileContent, "utf-8");
72505
73496
  await notifyDocUpdate(resolved.filename);
72506
73497
  return successResponse({
72507
73498
  message: `Updated documentation: ${resolved.filename}`,
@@ -72521,8 +73512,8 @@ async function handleSearchDocs(args) {
72521
73512
  const query = input.query.toLowerCase();
72522
73513
  const results = [];
72523
73514
  for (const file3 of mdFiles) {
72524
- const fileContent = await readFile12(join20(DOCS_DIR2, file3), "utf-8");
72525
- const { data, content } = (0, import_gray_matter7.default)(fileContent);
73515
+ const fileContent = await readFile14(join20(DOCS_DIR2, file3), "utf-8");
73516
+ const { data, content } = (0, import_gray_matter8.default)(fileContent);
72526
73517
  const metadata = data;
72527
73518
  if (input.tag && !metadata.tags?.includes(input.tag)) {
72528
73519
  continue;
@@ -72630,7 +73621,7 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => {
72630
73621
  description: `Task #${task.id}: ${task.title}`
72631
73622
  }));
72632
73623
  const docResources = [];
72633
- if (existsSync16(docsDir)) {
73624
+ if (existsSync17(docsDir)) {
72634
73625
  const { readdir: readdir7 } = await import("node:fs/promises");
72635
73626
  async function getAllMdFiles3(dir, basePath = "") {
72636
73627
  const files = [];
@@ -72650,8 +73641,8 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => {
72650
73641
  const mdFiles = await getAllMdFiles3(docsDir);
72651
73642
  for (const file3 of mdFiles) {
72652
73643
  const filepath = join21(docsDir, file3);
72653
- const content = await readFile13(filepath, "utf-8");
72654
- const { data } = (0, import_gray_matter8.default)(content);
73644
+ const content = await readFile15(filepath, "utf-8");
73645
+ const { data } = (0, import_gray_matter9.default)(content);
72655
73646
  docResources.push({
72656
73647
  uri: `knowns://doc/${file3.replace(/\.md$/, "")}`,
72657
73648
  name: data.title || file3.replace(/\.md$/, ""),
@@ -72688,11 +73679,11 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
72688
73679
  const docPath = docMatch[1];
72689
73680
  const docsDir = join21(process.cwd(), ".knowns", "docs");
72690
73681
  const filepath = join21(docsDir, `${docPath}.md`);
72691
- if (!existsSync16(filepath)) {
73682
+ if (!existsSync17(filepath)) {
72692
73683
  throw new Error(`Documentation ${docPath} not found`);
72693
73684
  }
72694
- const content = await readFile13(filepath, "utf-8");
72695
- const { data, content: docContent } = (0, import_gray_matter8.default)(content);
73685
+ const content = await readFile15(filepath, "utf-8");
73686
+ const { data, content: docContent } = (0, import_gray_matter9.default)(content);
72696
73687
  return {
72697
73688
  contents: [
72698
73689
  {
@@ -72795,7 +73786,7 @@ function showConfigInfo() {
72795
73786
  // package.json
72796
73787
  var package_default = {
72797
73788
  name: "knowns",
72798
- version: "0.3.1",
73789
+ version: "0.4.0",
72799
73790
  description: "CLI tool for dev teams to manage tasks and documentation",
72800
73791
  module: "index.ts",
72801
73792
  type: "module",
@@ -72928,7 +73919,7 @@ function showBanner() {
72928
73919
  console.log();
72929
73920
  }
72930
73921
  var program2 = new Command();
72931
- program2.name("knowns").description("CLI tool for dev teams to manage tasks, track time, and sync").version(package_default.version);
73922
+ program2.name("knowns").description("CLI tool for dev teams to manage tasks, track time, and sync").version(package_default.version).enablePositionalOptions();
72932
73923
  program2.addCommand(initCommand);
72933
73924
  program2.addCommand(taskCommand);
72934
73925
  program2.addCommand(boardCommand);