knowns 0.10.1 → 0.10.3

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
@@ -58829,7 +58829,7 @@ function evaluateCondition(condition, context) {
58829
58829
  var commands_reference_default = '{{#if mcp}}\n# MCP Tools Reference\n\n## Task Tools\n\n### mcp__knowns__create_task\n\n```json\n{\n "title": "Task title",\n "description": "Task description",\n "status": "todo",\n "priority": "medium",\n "labels": ["label1"],\n "assignee": "@me",\n "parent": "parent-id"\n}\n```\n\n### mcp__knowns__update_task\n\n```json\n{\n "taskId": "<id>",\n "status": "in-progress",\n "assignee": "@me",\n "addAc": ["Criterion 1", "Criterion 2"],\n "checkAc": [1, 2],\n "uncheckAc": [3],\n "removeAc": [4],\n "plan": "1. Step one\\n2. Step two",\n "notes": "Implementation notes",\n "appendNotes": "Additional notes"\n}\n```\n\n| Field | Purpose |\n|-------|---------|\n| `addAc` | Add new acceptance criteria |\n| `checkAc` | Mark AC done (1-based index) |\n| `uncheckAc` | Unmark AC (1-based index) |\n| `removeAc` | Remove AC (1-based index) |\n| `plan` | Set implementation plan |\n| `notes` | Replace implementation notes |\n| `appendNotes` | Append to notes |\n\n### mcp__knowns__get_task\n\n```json\n{ "taskId": "<id>" }\n```\n\n### mcp__knowns__list_tasks\n\n```json\n{ "status": "in-progress", "assignee": "@me" }\n```\n\n### mcp__knowns__search_tasks\n\n```json\n{ "query": "keyword" }\n```\n\n---\n\n## Doc Tools\n\n### mcp__knowns__get_doc\n\n**ALWAYS use `smart: true`** - auto-handles small/large docs:\n\n```json\n{ "path": "readme", "smart": true }\n```\n\nIf large, returns TOC. Then read section:\n```json\n{ "path": "readme", "section": "3" }\n```\n\n### mcp__knowns__list_docs\n\n```json\n{ "tag": "api" }\n```\n\n### mcp__knowns__create_doc\n\n```json\n{\n "title": "Doc Title",\n "description": "Description",\n "tags": ["tag1"],\n "folder": "guides",\n "content": "Initial content"\n}\n```\n\n### mcp__knowns__update_doc\n\n```json\n{\n "path": "readme",\n "content": "Replace content",\n "section": "2"\n}\n```\n\n### mcp__knowns__search_docs\n\n```json\n{ "query": "keyword", "tag": "api" }\n```\n\n### mcp__knowns__search (Unified)\n\n```json\n{\n "query": "keyword",\n "type": "all",\n "status": "in-progress",\n "priority": "high",\n "assignee": "@me",\n "label": "feature",\n "tag": "api",\n "limit": 20\n}\n```\n\n| Field | Purpose |\n|-------|---------|\n| `type` | "all", "task", or "doc" |\n| `status/priority/assignee/label` | Task filters |\n| `tag` | Doc filter |\n| `limit` | Max results (default: 20) |\n\n---\n\n## Time Tools\n\n### mcp__knowns__start_time\n\n```json\n{ "taskId": "<id>" }\n```\n\n### mcp__knowns__stop_time\n\n```json\n{ "taskId": "<id>" }\n```\n\n### mcp__knowns__add_time\n\n```json\n{\n "taskId": "<id>",\n "duration": "2h30m",\n "note": "Note",\n "date": "2025-01-15"\n}\n```\n\n### mcp__knowns__get_time_report\n\n```json\n{ "from": "2025-01-01", "to": "2025-01-31", "groupBy": "task" }\n```\n\n---\n\n## Template Tools\n\n### mcp__knowns__list_templates\n\n```json\n{}\n```\n\n### mcp__knowns__get_template\n\n```json\n{ "name": "template-name" }\n```\n\n### mcp__knowns__run_template\n\n```json\n{\n "name": "template-name",\n "variables": { "name": "MyComponent" },\n "dryRun": true\n}\n```\n\n### mcp__knowns__create_template\n\n```json\n{\n "name": "my-template",\n "description": "Description",\n "doc": "patterns/my-pattern"\n}\n```\n\n---\n\n## Other\n\n### mcp__knowns__get_board\n\n```json\n{}\n```\n\n{{else}}\n# CLI Commands Reference\n\n## task create\n\n```bash\nknowns task create <title> [options]\n```\n\n| Flag | Short | Purpose |\n|------|-------|---------|\n| `--description` | `-d` | Task description |\n| `--ac` | | Acceptance criterion (repeatable) |\n| `--labels` | `-l` | Comma-separated labels |\n| `--assignee` | `-a` | Assign to user |\n| `--priority` | | low/medium/high |\n| `--parent` | | Parent task ID (raw ID only!) |\n\n**`-a` = assignee, NOT acceptance criteria! Use `--ac` for AC.**\n\n---\n\n## task edit\n\n```bash\nknowns task edit <id> [options]\n```\n\n| Flag | Short | Purpose |\n|------|-------|---------|\n| `--status` | `-s` | Change status |\n| `--assignee` | `-a` | Assign user |\n| `--ac` | | Add acceptance criterion |\n| `--check-ac` | | Mark AC done (1-indexed) |\n| `--uncheck-ac` | | Unmark AC |\n| `--plan` | | Set implementation plan |\n| `--notes` | | Replace notes |\n| `--append-notes` | | Add to notes |\n\n---\n\n## task view/list\n\n```bash\nknowns task <id> --plain\nknowns task list --plain\nknowns task list --status in-progress --plain\nknowns task list --tree --plain\n```\n\n---\n\n## doc create\n\n```bash\nknowns doc create <title> [options]\n```\n\n| Flag | Short | Purpose |\n|------|-------|---------|\n| `--description` | `-d` | Description |\n| `--tags` | `-t` | Comma-separated tags |\n| `--folder` | `-f` | Folder path |\n\n---\n\n## doc edit\n\n```bash\nknowns doc edit <name> [options]\n```\n\n| Flag | Short | Purpose |\n|------|-------|---------|\n| `--content` | `-c` | Replace content |\n| `--append` | `-a` | Append content |\n| `--section` | | Target section (use with -c) |\n\n**In doc edit, `-a` = append content, NOT assignee!**\n\n---\n\n## doc view/list\n\n**ALWAYS use `--smart`** - auto-handles small/large docs:\n\n```bash\nknowns doc <path> --plain --smart\n```\n\nIf large, returns TOC. Then read section:\n```bash\nknowns doc <path> --plain --section 3\n```\n\n```bash\nknowns doc list --plain\nknowns doc list --tag api --plain\n```\n\n---\n\n## time\n\n```bash\nknowns time start <id> # REQUIRED when taking task\nknowns time stop # REQUIRED when completing\nknowns time status\nknowns time add <id> <duration> -n "Note"\n```\n\n---\n\n## search\n\n```bash\nknowns search "query" --plain\nknowns search "auth" --type task --plain\nknowns search "api" --type doc --plain\n```\n\n---\n\n## template\n\n```bash\nknowns template list\nknowns template info <name>\nknowns template run <name> --name "X" --dry-run\nknowns template create <name>\n```\n\n---\n\n## Multi-line Input\n\n```bash\nknowns task edit <id> --plan $\'1. Step\\n2. Step\\n3. Step\'\n```\n{{/if}}\n';
58830
58830
 
58831
58831
  // src/instructions/guidelines/unified/common-mistakes.md
58832
- var common_mistakes_default = '# Common Mistakes\n\n{{#unless mcp}}\n## CRITICAL: The -a Flag\n\n| Command | `-a` Means | NOT This! |\n|---------|------------|-----------|\n| `task create/edit` | `--assignee` | ~~acceptance criteria~~ |\n| `doc edit` | `--append` | ~~assignee~~ |\n\n```bash\n# WRONG (sets assignee to garbage!)\nknowns task edit 35 -a "Criterion text"\n\n# CORRECT (use --ac)\nknowns task edit 35 --ac "Criterion text"\n```\n\n---\n{{/unless}}\n\n## Quick Reference\n\n| DON\'T | DO |\n|-------|-----|\n{{#if mcp}}\n| Edit .md files directly | Use MCP tools |\n{{else}}\n| Edit .md files directly | Use CLI commands |\n| `-a "criterion"` | `--ac "criterion"` |\n| `--parent task-48` | `--parent 48` (raw ID) |\n| `--plain` with create/edit | `--plain` only for view/list |\n{{/if}}\n| Check AC before work done | Check AC AFTER work done |\n| Code before plan approval | Wait for user approval |\n| Code before reading docs | Read docs FIRST |\n| Skip time tracking | Always start/stop timer |\n| Ignore refs | Follow ALL `@task-xxx`, `@doc/xxx`, `@template/xxx` refs |\n\n{{#if mcp}}\n---\n\n## MCP Task Operations\n\nAll task operations are available via MCP:\n\n| Operation | MCP Field |\n|-----------|-----------|\n| Add acceptance criteria | `addAc: ["criterion"]` |\n| Check AC | `checkAc: [1, 2]` (1-based) |\n| Uncheck AC | `uncheckAc: [1]` (1-based) |\n| Remove AC | `removeAc: [1]` (1-based) |\n| Set plan | `plan: "..."` |\n| Set notes | `notes: "..."` |\n| Append notes | `appendNotes: "..."` |\n| Change status | `status: "in-progress"` |\n| Assign | `assignee: "@me"` |\n{{/if}}\n\n---\n\n## Error Recovery\n\n| Problem | Solution |\n|---------|----------|\n{{#if mcp}}\n| Forgot to stop timer | `mcp__knowns__add_time` with duration |\n| Wrong status | `mcp__knowns__update_task` to fix |\n| Task not found | `mcp__knowns__list_tasks` to find ID |\n| Need to uncheck AC | `mcp__knowns__update_task` with `uncheckAc: [N]` |\n| Checked AC too early | `mcp__knowns__update_task` with `uncheckAc: [N]` |\n{{else}}\n| Set assignee to AC text | `knowns task edit <id> -a @me` |\n| Forgot to stop timer | `knowns time add <id> <duration>` |\n| Checked AC too early | `knowns task edit <id> --uncheck-ac N` |\n| Task not found | `knowns task list --plain` |\n{{/if}}\n';
58832
+ var common_mistakes_default = '# Common Mistakes\n\n{{#unless mcp}}\n## CRITICAL: The -a Flag\n\n| Command | `-a` Means | NOT This! |\n|---------|------------|-----------|\n| `task create/edit` | `--assignee` | ~~acceptance criteria~~ |\n| `doc edit` | `--append` | ~~assignee~~ |\n\n```bash\n# WRONG (sets assignee to garbage!)\nknowns task edit 35 -a "Criterion text"\n\n# CORRECT (use --ac)\nknowns task edit 35 --ac "Criterion text"\n```\n\n---\n{{/unless}}\n\n## Quick Reference\n\n| DON\'T | DO |\n|-------|-----|\n{{#if mcp}}\n| Edit .md files directly | Use MCP tools |\n{{else}}\n| Edit .md files directly | Use CLI commands |\n| `-a "criterion"` | `--ac "criterion"` |\n| `--parent task-48` | `--parent 48` (raw ID) |\n| `--plain` with create/edit | `--plain` only for view/list |\n{{/if}}\n| Check AC before work done | Check AC AFTER work done |\n| Code before plan approval | Wait for user approval |\n| Code before reading docs | Read docs FIRST |\n| Skip time tracking | Always start/stop timer |\n| Ignore refs | Follow ALL `@task-xxx`, `@doc/xxx`, `@template/xxx` refs |\n\n{{#if mcp}}\n---\n\n## MCP Task Operations\n\nAll task operations are available via MCP:\n\n| Operation | MCP Field |\n|-----------|-----------|\n| Add acceptance criteria | `addAc: ["criterion"]` |\n| Check AC | `checkAc: [1, 2]` (1-based) |\n| Uncheck AC | `uncheckAc: [1]` (1-based) |\n| Remove AC | `removeAc: [1]` (1-based) |\n| Set plan | `plan: "..."` |\n| Set notes | `notes: "..."` |\n| Append notes | `appendNotes: "..."` |\n| Change status | `status: "in-progress"` |\n| Assign | `assignee: "@me"` |\n{{/if}}\n\n---\n\n## Template Syntax Pitfalls\n\nWhen writing `.hbs` templates, **NEVER** create `$` followed by triple-brace - Handlebars interprets triple-brace as unescaped output:\n\n```\n// \u274C WRONG - Parse error!\nthis.logger.log(`Created: $` + `{` + `{` + `{camelCase entity}.id}`);\n\n// \u2705 CORRECT - Add space between ${ and double-brace, use ~ to trim whitespace\nthis.logger.log(`Created: ${ \\{{~camelCase entity~}}.id}`);\n```\n\n| DON\'T | DO |\n|-------|-----|\n| `$` + triple-brace | `${ \\{{~helper~}}}` (space + escaped) |\n\n**Rules:**\n- Add space between `${` and double-brace\n- Use `~` (tilde) to trim whitespace in output\n- Escape literal braces with backslash\n\n---\n\n## Error Recovery\n\n| Problem | Solution |\n|---------|----------|\n{{#if mcp}}\n| Forgot to stop timer | `mcp__knowns__add_time` with duration |\n| Wrong status | `mcp__knowns__update_task` to fix |\n| Task not found | `mcp__knowns__list_tasks` to find ID |\n| Need to uncheck AC | `mcp__knowns__update_task` with `uncheckAc: [N]` |\n| Checked AC too early | `mcp__knowns__update_task` with `uncheckAc: [N]` |\n{{else}}\n| Set assignee to AC text | `knowns task edit <id> -a @me` |\n| Forgot to stop timer | `knowns time add <id> <duration>` |\n| Checked AC too early | `knowns task edit <id> --uncheck-ac N` |\n| Task not found | `knowns task list --plain` |\n{{/if}}\n';
58833
58833
 
58834
58834
  // src/instructions/guidelines/unified/context-optimization.md
58835
58835
  var context_optimization_default = '# Context Optimization\n\nOptimize your context usage to work more efficiently within token limits.\n\n---\n\n{{#unless mcp}}\n## Output Format\n\n```bash\n# Verbose output\nknowns task 42 --json\n\n# Compact output (always use --plain)\nknowns task 42 --plain\n```\n\n---\n{{/unless}}\n\n## Search Before Read\n\n{{#if mcp}}\n```json\n// DON\'T: Read all docs hoping to find info\nmcp__knowns__get_doc({ "path": "doc1" })\nmcp__knowns__get_doc({ "path": "doc2" })\n\n// DO: Search first, then read only relevant docs\nmcp__knowns__search_docs({ "query": "authentication" })\nmcp__knowns__get_doc({ "path": "security-patterns" })\n```\n{{else}}\n```bash\n# DON\'T: Read all docs hoping to find info\nknowns doc "doc1" --plain\nknowns doc "doc2" --plain\n\n# DO: Search first, then read only relevant docs\nknowns search "authentication" --type doc --plain\nknowns doc "security-patterns" --plain\n```\n{{/if}}\n\n---\n\n{{#if mcp}}\n## Use Filters\n\n```json\n// DON\'T: List all then filter manually\nmcp__knowns__list_tasks({})\n\n// DO: Use filters in the query\nmcp__knowns__list_tasks({\n "status": "in-progress",\n "assignee": "@me"\n})\n```\n\n---\n{{/if}}\n\n## Reading Documents\n\n{{#if mcp}}\n**ALWAYS use `smart: true`** - auto-handles both small and large docs:\n\n```json\n// DON\'T: Read without smart\nmcp__knowns__get_doc({ "path": "readme" })\n\n// DO: Always use smart\nmcp__knowns__get_doc({ "path": "readme", "smart": true })\n// Small doc \u2192 full content\n// Large doc \u2192 stats + TOC\n\n// If large, read specific section:\nmcp__knowns__get_doc({ "path": "readme", "section": "3" })\n```\n{{else}}\n**ALWAYS use `--smart`** - auto-handles both small and large docs:\n\n```bash\n# DON\'T: Read without --smart\nknowns doc readme --plain\n\n# DO: Always use --smart\nknowns doc readme --plain --smart\n# Small doc \u2192 full content\n# Large doc \u2192 stats + TOC\n\n# If large, read specific section:\nknowns doc readme --plain --section 3\n```\n{{/if}}\n\n**Behavior:**\n- **\u22642000 tokens**: Returns full content automatically\n- **>2000 tokens**: Returns stats + TOC, then use section parameter\n\n---\n\n## Compact Notes\n\n```bash\n# DON\'T: Verbose notes\nknowns task edit 42 --append-notes "I have successfully completed the implementation..."\n\n# DO: Compact notes\nknowns task edit 42 --append-notes "Done: Auth middleware + JWT validation"\n```\n\n---\n\n## Avoid Redundant Operations\n\n| Don\'t | Do Instead |\n|-------|------------|\n| Re-read files already in context | Reference from memory |\n| List tasks/docs multiple times | List once, remember results |\n| Quote entire file contents | Summarize key points |\n\n---\n\n## Efficient Workflow\n\n| Phase | Context-Efficient Approach |\n|-------|---------------------------|\n| **Research** | Search \u2192 Read only matches |\n| **Planning** | Brief plan, not detailed prose |\n| **Coding** | Read only files being modified |\n| **Notes** | Bullet points, not paragraphs |\n| **Completion** | Summary, not full log |\n\n---\n\n## Quick Rules\n\n{{#if mcp}}\n1. **Always `smart: true`** - Auto-handles doc size\n{{else}}\n1. **Always `--plain`** - Never use `--json` unless needed\n2. **Always `--smart`** - Auto-handles doc size\n{{/if}}\n3. **Search first** - Don\'t read all docs hoping to find info\n4. **Read selectively** - Only fetch what you need\n5. **Write concise** - Compact notes, not essays\n6. **Don\'t repeat** - Reference context already loaded\n';
@@ -59011,7 +59011,7 @@ var SKILL_default9 = '---\nname: knowns.task.reopen\ndescription: Use when reope
59011
59011
  var SKILL_default10 = '---\nname: knowns.task\ndescription: Use when working on a Knowns task - view task details and decide next action\n---\n\n# Working on a Task\n\nView task details and determine the appropriate next action.\n\n**Announce at start:** "I\'m using the knowns.task skill to view task [ID]."\n\n**Core principle:** VIEW AND ROUTE - analyze state, suggest next skill.\n\n## The Process\n\n### Step 1: View Task\n\n{{#if mcp}}\n```json\nmcp__knowns__get_task({ "taskId": "$ARGUMENTS" })\n```\n{{else}}\n```bash\nknowns task $ARGUMENTS --plain\n```\n{{/if}}\n\n### Step 2: Analyze State\n\nCheck:\n- **Status**: todo, in-progress, done?\n- **Assignee**: Assigned to someone?\n- **AC**: Any checked? All checked?\n- **Plan**: Has implementation plan?\n- **Refs**: Any `@doc/` or `@task-` references?\n\n### Step 3: Suggest Next Action\n\nBased on task state, recommend the appropriate skill:\n\n| State | Next Skill |\n|-------|------------|\n| `todo`, not started | `knowns.task.plan` |\n| `in-progress`, no plan | `knowns.task.plan` |\n| `in-progress`, has plan | `knowns.task.implement` |\n| `done`, needs changes | `knowns.task.reopen` |\n| Requirements unclear | `knowns.task.brainstorm` |\n\n### Step 4: Follow Refs (if needed)\n\nIf task has references, follow them for context:\n\n{{#if mcp}}\n```json\n// Doc ref: @doc/path \u2192\nmcp__knowns__get_doc({ "path": "<path>", "smart": true })\n\n// Task ref: @task-<id> \u2192\nmcp__knowns__get_task({ "taskId": "<id>" })\n```\n{{else}}\n```bash\n# Doc ref: @doc/path \u2192\nknowns doc "<path>" --plain\n\n# Task ref: @task-<id> \u2192\nknowns task <id> --plain\n```\n{{/if}}\n\n## Quick Actions\n\n**Start planning (includes taking ownership):**\n```\n/knowns.task.plan $ARGUMENTS\n```\n\n**Continue implementing:**\n```\n/knowns.task.implement $ARGUMENTS\n```\n\n**Requirements unclear:**\n```\n/knowns.task.brainstorm $ARGUMENTS\n```\n\n**Reopen completed task:**\n```\n/knowns.task.reopen $ARGUMENTS\n```\n\n## Remember\n\n- This skill is for viewing and routing\n- Use `plan` to start a new task (takes ownership, starts timer)\n- Use `implement` to continue/complete in-progress tasks\n- Always follow refs for full context\n';
59012
59012
 
59013
59013
  // src/instructions/skills/knowns.template/SKILL.md
59014
- var SKILL_default11 = '---\nname: knowns.template\ndescription: Use when generating code from templates - list, run, or create templates\n---\n\n# Working with Templates\n\nGenerate code from predefined templates stored in `.knowns/templates/`.\n\n**Announce at start:** "I\'m using the knowns.template skill to work with templates."\n\n**Core principle:** USE TEMPLATES FOR CONSISTENT CODE GENERATION.\n\n## The Process\n\n### Step 1: List Available Templates\n\n{{#if mcp}}\n```json\nmcp__knowns__list_templates({})\n```\n{{else}}\n```bash\nknowns template list\n```\n{{/if}}\n\n### Step 2: Get Template Details\n\n{{#if mcp}}\n```json\nmcp__knowns__get_template({ "name": "<template-name>" })\n```\n{{else}}\n```bash\nknowns template info <template-name>\n```\n{{/if}}\n\nCheck:\n- Required variables (prompts)\n- Linked documentation (`doc:`)\n- Files that will be generated\n\n### Step 3: Read Linked Documentation\n\nIf template has a `doc:` field, read it first:\n\n{{#if mcp}}\n```json\nmcp__knowns__get_doc({ "path": "<doc-path>", "smart": true })\n```\n{{else}}\n```bash\nknowns doc "<doc-path>" --plain\n```\n{{/if}}\n\n### Step 4: Run Template\n\n{{#if mcp}}\n```json\n// Dry run first (preview)\nmcp__knowns__run_template({\n "name": "<template-name>",\n "variables": { "name": "MyComponent", "type": "page" },\n "dryRun": true\n})\n\n// Then run for real\nmcp__knowns__run_template({\n "name": "<template-name>",\n "variables": { "name": "MyComponent", "type": "page" },\n "dryRun": false\n})\n```\n{{else}}\n```bash\n# Dry run (preview)\nknowns template run <template-name> --name "MyComponent" --dry-run\n\n# Run for real\nknowns template run <template-name> --name "MyComponent"\n```\n{{/if}}\n\n### Step 5: Create New Template\n\n{{#if mcp}}\n```json\nmcp__knowns__create_template({\n "name": "<template-name>",\n "description": "Template description",\n "doc": "patterns/<related-doc>" // Optional: link to documentation\n})\n```\n{{else}}\n```bash\nknowns template create <template-name>\n```\n{{/if}}\n\nThis creates:\n```\n.knowns/templates/<template-name>/\n \u251C\u2500\u2500 _template.yaml # Config\n \u2514\u2500\u2500 example.ts.hbs # Example file\n```\n\n## Template Config (`_template.yaml`)\n\n```yaml\nname: react-component\ndescription: Create a React component with tests\ndoc: patterns/react-component # Link to documentation\n\nprompts:\n - name: name\n message: Component name?\n validate: required\n\n - name: type\n message: Component type?\n type: select\n choices:\n - page\n - component\n - layout\n\nfiles:\n - template: "{{name}}.tsx.hbs"\n destination: "src/components/{{pascalCase name}}/{{pascalCase name}}.tsx"\n\n - template: "{{name}}.test.tsx.hbs"\n destination: "src/components/{{pascalCase name}}/{{pascalCase name}}.test.tsx"\n condition: "{{includeTests}}"\n```\n\n## Template-Doc Linking\n\nTemplates can reference docs and vice versa:\n\n**In `_template.yaml`:**\n```yaml\ndoc: patterns/react-component\n```\n\n**In doc (markdown):**\n```markdown\nUse @template/react-component to generate.\n```\n\n**AI workflow:**\n1. Get template config\n2. Follow `doc:` link to understand patterns\n3. Run template with appropriate variables\n\n## Handlebars Helpers\n\nTemplates use Handlebars with built-in helpers:\n\n| Helper | Example | Output |\n|--------|---------|--------|\n| `camelCase` | `{{camelCase "my name"}}` | `myName` |\n| `pascalCase` | `{{pascalCase "my name"}}` | `MyName` |\n| `kebabCase` | `{{kebabCase "MyName"}}` | `my-name` |\n| `snakeCase` | `{{snakeCase "MyName"}}` | `my_name` |\n| `upperCase` | `{{upperCase "name"}}` | `NAME` |\n| `lowerCase` | `{{lowerCase "NAME"}}` | `name` |\n\n## When to Use Templates\n\n| Scenario | Action |\n|----------|--------|\n| Creating new component | Run `react-component` template |\n| Adding API endpoint | Run `api-endpoint` template |\n| Setting up new feature | Run `feature-module` template |\n| Consistent file structure | Use template instead of copy-paste |\n\n## Integrated Workflows\n\n### During Implementation (Use Template)\n\n```\nTask \u2192 Read Context \u2192 Find Template \u2192 Generate Code \u2192 Customize\n```\n\n1. Read task and understand requirements\n2. List templates to find applicable one\n3. Get template details and read linked doc\n4. Run template (dry run first, then real)\n5. Customize generated code as needed\n6. Continue with remaining implementation\n\n**Benefits:**\n- Reduces context (no need to generate boilerplate)\n- Ensures consistency with project patterns\n- Faster implementation\n\n### During Extract (Create Template)\n\n```\nContext \u2192 Identify Pattern \u2192 Create Doc \u2192 Create Template \u2192 Link Both\n```\n\n1. Identify repeatable code pattern\n2. Create doc with `/knowns.extract`\n3. Create template with `knowns template create <name>`\n4. Link template to doc: `doc: patterns/<name>`\n5. Link doc to template: `@template/<name>`\n\n**When to create template:**\n- Pattern will be used multiple times\n- Has consistent file structure\n- Can be parameterized\n\n## Checklist\n\n- [ ] Listed available templates\n- [ ] Got template details (prompts, files)\n- [ ] Read linked documentation (if any)\n- [ ] Understood required variables\n- [ ] Ran dry run first\n- [ ] Ran template with correct inputs\n- [ ] Verified generated files\n\n## Remember\n\n- Always dry run first before writing files\n- Check `doc:` link in template for context\n- Templates ensure consistent code structure\n- Create new templates for repeated patterns\n';
59014
+ var SKILL_default11 = '---\nname: knowns.template\ndescription: Use when generating code from templates - list, run, or create templates\n---\n\n# Working with Templates\n\nGenerate code from predefined templates stored in `.knowns/templates/`.\n\n**Announce at start:** "I\'m using the knowns.template skill to work with templates."\n\n**Core principle:** USE TEMPLATES FOR CONSISTENT CODE GENERATION.\n\n## The Process\n\n### Step 1: List Available Templates\n\n{{#if mcp}}\n```json\nmcp__knowns__list_templates({})\n```\n{{else}}\n```bash\nknowns template list\n```\n{{/if}}\n\n### Step 2: Get Template Details\n\n{{#if mcp}}\n```json\nmcp__knowns__get_template({ "name": "<template-name>" })\n```\n{{else}}\n```bash\nknowns template info <template-name>\n```\n{{/if}}\n\nCheck:\n- Required variables (prompts)\n- Linked documentation (`doc:`)\n- Files that will be generated\n\n### Step 3: Read Linked Documentation\n\nIf template has a `doc:` field, read it first:\n\n{{#if mcp}}\n```json\nmcp__knowns__get_doc({ "path": "<doc-path>", "smart": true })\n```\n{{else}}\n```bash\nknowns doc "<doc-path>" --plain\n```\n{{/if}}\n\n### Step 4: Run Template\n\n{{#if mcp}}\n```json\n// Dry run first (preview)\nmcp__knowns__run_template({\n "name": "<template-name>",\n "variables": { "name": "MyComponent", "type": "page" },\n "dryRun": true\n})\n\n// Then run for real\nmcp__knowns__run_template({\n "name": "<template-name>",\n "variables": { "name": "MyComponent", "type": "page" },\n "dryRun": false\n})\n```\n{{else}}\n```bash\n# Dry run (preview)\nknowns template run <template-name> --name "MyComponent" --dry-run\n\n# Run for real\nknowns template run <template-name> --name "MyComponent"\n```\n{{/if}}\n\n### Step 5: Create New Template\n\n{{#if mcp}}\n```json\nmcp__knowns__create_template({\n "name": "<template-name>",\n "description": "Template description",\n "doc": "patterns/<related-doc>" // Optional: link to documentation\n})\n```\n{{else}}\n```bash\nknowns template create <template-name>\n```\n{{/if}}\n\nThis creates:\n```\n.knowns/templates/<template-name>/\n \u251C\u2500\u2500 _template.yaml # Config\n \u2514\u2500\u2500 example.ts.hbs # Example file\n```\n\n## Template Config (`_template.yaml`)\n\n```yaml\nname: react-component\ndescription: Create a React component with tests\ndoc: patterns/react-component # Link to documentation\n\nprompts:\n - name: name\n message: Component name?\n validate: required\n\n - name: type\n message: Component type?\n type: select\n choices:\n - page\n - component\n - layout\n\nfiles:\n - template: "{{name}}.tsx.hbs"\n destination: "src/components/{{pascalCase name}}/{{pascalCase name}}.tsx"\n\n - template: "{{name}}.test.tsx.hbs"\n destination: "src/components/{{pascalCase name}}/{{pascalCase name}}.test.tsx"\n condition: "{{includeTests}}"\n```\n\n## Template-Doc Linking\n\nTemplates can reference docs and vice versa:\n\n**In `_template.yaml`:**\n```yaml\ndoc: patterns/react-component\n```\n\n**In doc (markdown):**\n```markdown\nUse @template/react-component to generate.\n```\n\n**AI workflow:**\n1. Get template config\n2. Follow `doc:` link to understand patterns\n3. Run template with appropriate variables\n\n## Handlebars Helpers\n\nTemplates use Handlebars with built-in helpers:\n\n| Helper | Example | Output |\n|--------|---------|--------|\n| `camelCase` | `{{camelCase "my name"}}` | `myName` |\n| `pascalCase` | `{{pascalCase "my name"}}` | `MyName` |\n| `kebabCase` | `{{kebabCase "MyName"}}` | `my-name` |\n| `snakeCase` | `{{snakeCase "MyName"}}` | `my_name` |\n| `upperCase` | `{{upperCase "name"}}` | `NAME` |\n| `lowerCase` | `{{lowerCase "NAME"}}` | `name` |\n\n## CRITICAL: Template Syntax Pitfalls\n\n### JavaScript Template Literals + Handlebars\n\n**NEVER write `$` followed by triple-brace** - Handlebars interprets triple-brace as unescaped output:\n\n```\n// \u274C WRONG - Parse error!\nthis.logger.log(`Created: $` + `\\{{\\{camelCase entity}.id}`);\n\n// \u2705 CORRECT - Add space, use ~ to trim whitespace\nthis.logger.log(`Created: ${ \\{{~camelCase entity~}}.id}`);\n// Output: this.logger.log(`Created: ${product.id}`);\n```\n\n**Rules when writing .hbs templates:**\n1. Never `$` + triple-brace - always add space: `${ \\{{`\n2. Use `~` (tilde) to trim whitespace: `\\{{~helper~}}`\n3. For literal braces, escape with backslash\n\n## When to Use Templates\n\n| Scenario | Action |\n|----------|--------|\n| Creating new component | Run `react-component` template |\n| Adding API endpoint | Run `api-endpoint` template |\n| Setting up new feature | Run `feature-module` template |\n| Consistent file structure | Use template instead of copy-paste |\n\n## Integrated Workflows\n\n### During Implementation (Use Template)\n\n```\nTask \u2192 Read Context \u2192 Find Template \u2192 Generate Code \u2192 Customize\n```\n\n1. Read task and understand requirements\n2. List templates to find applicable one\n3. Get template details and read linked doc\n4. Run template (dry run first, then real)\n5. Customize generated code as needed\n6. Continue with remaining implementation\n\n**Benefits:**\n- Reduces context (no need to generate boilerplate)\n- Ensures consistency with project patterns\n- Faster implementation\n\n### During Extract (Create Template)\n\n```\nContext \u2192 Identify Pattern \u2192 Create Doc \u2192 Create Template \u2192 Link Both\n```\n\n1. Identify repeatable code pattern\n2. Create doc with `/knowns.extract`\n3. Create template with `knowns template create <name>`\n4. Link template to doc: `doc: patterns/<name>`\n5. Link doc to template: `@template/<name>`\n\n**When to create template:**\n- Pattern will be used multiple times\n- Has consistent file structure\n- Can be parameterized\n\n## Checklist\n\n- [ ] Listed available templates\n- [ ] Got template details (prompts, files)\n- [ ] Read linked documentation (if any)\n- [ ] Understood required variables\n- [ ] Ran dry run first\n- [ ] Ran template with correct inputs\n- [ ] Verified generated files\n\n## Remember\n\n- Always dry run first before writing files\n- Check `doc:` link in template for context\n- Templates ensure consistent code structure\n- Create new templates for repeated patterns\n- **NEVER write `$` + triple-brace** - use `${ \\{{~helper~}}` instead (add space, use tilde)\n';
59015
59015
 
59016
59016
  // src/instructions/skills/index.ts
59017
59017
  function parseSkillFrontmatter(content) {
@@ -61849,22 +61849,25 @@ var searchCommand = new Command("search").description("Search tasks and document
61849
61849
  const pathGroups = {};
61850
61850
  for (const doc of docResults) {
61851
61851
  const parts = doc.filename.split("/");
61852
- const folder = parts.length > 1 ? `${parts.slice(0, -1).join("/")}/` : "(root)";
61852
+ const folder = parts.length > 1 ? `${parts.slice(0, -1).join("/")}/` : "";
61853
61853
  if (!pathGroups[folder]) {
61854
61854
  pathGroups[folder] = [];
61855
61855
  }
61856
61856
  pathGroups[folder].push(doc);
61857
61857
  }
61858
61858
  const sortedPaths = Object.keys(pathGroups).sort((a, b) => {
61859
- if (a === "(root)") return -1;
61860
- if (b === "(root)") return 1;
61859
+ if (a === "") return -1;
61860
+ if (b === "") return 1;
61861
61861
  return a.localeCompare(b);
61862
61862
  });
61863
61863
  for (const path3 of sortedPaths) {
61864
- console.log(` ${path3}:`);
61864
+ if (path3) {
61865
+ console.log(` ${path3}:`);
61866
+ }
61867
+ const indent = path3 ? " " : " ";
61865
61868
  for (const doc of pathGroups[path3]) {
61866
61869
  const filename = doc.filename.split("/").pop() || doc.filename;
61867
- console.log(` ${filename} - ${doc.metadata.title}`);
61870
+ console.log(`${indent}${filename} - ${doc.metadata.title}`);
61868
61871
  }
61869
61872
  }
61870
61873
  }
@@ -62482,6 +62485,7 @@ function createConfigRoutes(ctx) {
62482
62485
  name: data.name,
62483
62486
  id: data.id,
62484
62487
  createdAt: data.createdAt,
62488
+ imports: data.imports,
62485
62489
  ...settings
62486
62490
  };
62487
62491
  if (!config2.visibleColumns) {
@@ -62501,10 +62505,13 @@ function createConfigRoutes(ctx) {
62501
62505
  const content = await readFile7(configPath, "utf-8");
62502
62506
  existingData = JSON.parse(content);
62503
62507
  }
62504
- const { name, ...settings } = config2;
62508
+ const { name, imports, id, createdAt, ...settings } = config2;
62505
62509
  const merged = {
62506
62510
  ...existingData,
62507
62511
  name: name || existingData.name,
62512
+ id: id || existingData.id,
62513
+ createdAt: createdAt || existingData.createdAt,
62514
+ imports: imports !== void 0 ? imports : existingData.imports,
62508
62515
  settings
62509
62516
  };
62510
62517
  await writeFile4(configPath, JSON.stringify(merged, null, 2), "utf-8");
@@ -63966,7 +63973,7 @@ async function importSource(projectRoot, source, options2 = {}) {
63966
63973
  if (!nameValidation.valid) {
63967
63974
  throw new ImportError(nameValidation.error || "Invalid name", "NAME_CONFLICT" /* NAME_CONFLICT */);
63968
63975
  }
63969
- if (!options2.force && await importExists(projectRoot, name)) {
63976
+ if (!options2.force && !options2.isSync && await importExists(projectRoot, name)) {
63970
63977
  throw new ImportError(
63971
63978
  `Import "${name}" already exists`,
63972
63979
  "NAME_CONFLICT" /* NAME_CONFLICT */,
@@ -64144,8 +64151,10 @@ async function syncImport(projectRoot, name, options2 = {}) {
64144
64151
  exclude: config2.exclude,
64145
64152
  force: options2.force,
64146
64153
  dryRun: options2.dryRun,
64147
- noSave: true
64154
+ noSave: true,
64148
64155
  // Don't update config on sync
64156
+ isSync: true
64157
+ // Bypass "already exists" check
64149
64158
  });
64150
64159
  }
64151
64160
  async function syncAllImports(projectRoot, options2 = {}) {
@@ -64153,7 +64162,7 @@ async function syncAllImports(projectRoot, options2 = {}) {
64153
64162
  const configs = await getImportConfigs2(projectRoot);
64154
64163
  const results = [];
64155
64164
  for (const config2 of configs) {
64156
- if (config2.autoSync === false && !options2.force) {
64165
+ if (options2.autoOnly && config2.autoSync === false) {
64157
64166
  continue;
64158
64167
  }
64159
64168
  try {
@@ -64197,7 +64206,38 @@ import { existsSync as existsSync14 } from "node:fs";
64197
64206
  import { readdir as readdir7 } from "node:fs/promises";
64198
64207
  import { join as join17 } from "node:path";
64199
64208
  var KNOWNS_DIR5 = ".knowns";
64209
+ var TEMPLATES_DIR2 = "templates";
64200
64210
  var DOCS_DIR2 = "docs";
64211
+ async function getTemplateDirectories(projectRoot) {
64212
+ const results = [];
64213
+ const localTemplates = join17(projectRoot, KNOWNS_DIR5, TEMPLATES_DIR2);
64214
+ if (existsSync14(localTemplates)) {
64215
+ results.push({
64216
+ path: localTemplates,
64217
+ source: "local",
64218
+ isImported: false
64219
+ });
64220
+ }
64221
+ const importsDir = getImportsDir(projectRoot);
64222
+ if (existsSync14(importsDir)) {
64223
+ try {
64224
+ const entries = await readdir7(importsDir, { withFileTypes: true });
64225
+ for (const entry of entries) {
64226
+ if (!entry.isDirectory()) continue;
64227
+ const importedTemplates = join17(importsDir, entry.name, TEMPLATES_DIR2);
64228
+ if (existsSync14(importedTemplates)) {
64229
+ results.push({
64230
+ path: importedTemplates,
64231
+ source: entry.name,
64232
+ isImported: true
64233
+ });
64234
+ }
64235
+ }
64236
+ } catch {
64237
+ }
64238
+ }
64239
+ return results;
64240
+ }
64201
64241
  async function getDocDirectories(projectRoot) {
64202
64242
  const results = [];
64203
64243
  const localDocs = join17(projectRoot, KNOWNS_DIR5, DOCS_DIR2);
@@ -64300,8 +64340,36 @@ async function resolveDocWithContext(projectRoot, docPath, context) {
64300
64340
  }
64301
64341
  return null;
64302
64342
  }
64343
+ async function listAllTemplates(projectRoot) {
64344
+ const directories = await getTemplateDirectories(projectRoot);
64345
+ const importConfigs = await getImportConfigs(projectRoot);
64346
+ const sourceUrlMap = new Map(importConfigs.map((c) => [c.name, c.source]));
64347
+ const results = [];
64348
+ for (const dir of directories) {
64349
+ try {
64350
+ const entries = await readdir7(dir.path, { withFileTypes: true });
64351
+ for (const entry of entries) {
64352
+ if (!entry.isDirectory()) continue;
64353
+ if (entry.name.startsWith(".")) continue;
64354
+ const ref = dir.isImported ? `${dir.source}/${entry.name}` : entry.name;
64355
+ results.push({
64356
+ name: entry.name,
64357
+ ref,
64358
+ source: dir.source,
64359
+ sourceUrl: dir.isImported ? sourceUrlMap.get(dir.source) : void 0,
64360
+ path: join17(dir.path, entry.name),
64361
+ isImported: dir.isImported
64362
+ });
64363
+ }
64364
+ } catch {
64365
+ }
64366
+ }
64367
+ return results.sort((a, b) => a.ref.localeCompare(b.ref));
64368
+ }
64303
64369
  async function listAllDocs(projectRoot) {
64304
64370
  const directories = await getDocDirectories(projectRoot);
64371
+ const importConfigs = await getImportConfigs(projectRoot);
64372
+ const sourceUrlMap = new Map(importConfigs.map((c) => [c.name, c.source]));
64305
64373
  const results = [];
64306
64374
  async function scanDir(baseDir, relativePath, source, isImported) {
64307
64375
  const currentDir = join17(baseDir, relativePath);
@@ -64319,6 +64387,7 @@ async function listAllDocs(projectRoot) {
64319
64387
  name: docPath,
64320
64388
  ref,
64321
64389
  source,
64390
+ sourceUrl: isImported ? sourceUrlMap.get(source) : void 0,
64322
64391
  fullPath: join17(currentDir, entry.name),
64323
64392
  isImported
64324
64393
  });
@@ -87092,131 +87161,190 @@ var createCommand3 = new Command("create").description("Create a new documentati
87092
87161
  }
87093
87162
  }
87094
87163
  );
87095
- 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 (path3, options2) => {
87096
- try {
87097
- await ensureDocsDir();
87098
- const mdFiles = await getAllMdFiles(DOCS_DIR3);
87099
- if (mdFiles.length === 0) {
87100
- if (options2.plain) {
87101
- console.log("No documentation found");
87102
- } else {
87103
- console.log(source_default.yellow("No documentation files found."));
87104
- console.log(source_default.gray(`Create one with: knowns doc create "Title"`));
87105
- }
87106
- return;
87107
- }
87108
- const docs = [];
87109
- for (const file3 of mdFiles) {
87110
- const fileContent = await readFile18(join29(DOCS_DIR3, file3), "utf-8");
87111
- const { data, content } = (0, import_gray_matter7.default)(fileContent);
87112
- const stats = calculateDocStats(content);
87113
- docs.push({
87114
- filename: file3,
87115
- metadata: data,
87116
- tokens: stats.estimatedTokens
87117
- });
87118
- }
87119
- let filteredDocs = docs;
87120
- if (path3) {
87121
- const normalizedPath = path3.endsWith("/") ? path3 : `${path3}/`;
87122
- filteredDocs = docs.filter((doc) => doc.filename.startsWith(normalizedPath));
87123
- }
87124
- if (options2.tag) {
87125
- filteredDocs = filteredDocs.filter((doc) => doc.metadata.tags?.includes(options2.tag));
87126
- }
87127
- if (filteredDocs.length === 0) {
87128
- const filterMsg = path3 ? `path: ${path3}` : options2.tag ? `tag: ${options2.tag}` : "";
87129
- console.log(
87130
- options2.plain ? "No documentation found" : source_default.yellow(`No documentation found${filterMsg ? ` with ${filterMsg}` : ""}`)
87131
- );
87132
- return;
87133
- }
87134
- if (options2.plain) {
87135
- const folders = /* @__PURE__ */ new Map();
87136
- const rootDocs = [];
87137
- for (const doc of filteredDocs) {
87138
- const parts = doc.filename.split("/");
87139
- if (parts.length === 1) {
87140
- rootDocs.push({
87141
- name: parts[0].replace(/\.md$/, ""),
87142
- title: doc.metadata.title,
87143
- tokens: doc.tokens
87144
- });
87164
+ var listCommand2 = new Command("list").description("List all documentation files (local + imported)").argument("[path]", "Filter by path (e.g., 'guides/' or 'patterns/')").option("--plain", "Plain text output for AI").option("-t, --tag <tag>", "Filter by tag").option("--local", "Show only local docs").option("--imported", "Show only imported docs").action(
87165
+ async (path3, options2) => {
87166
+ try {
87167
+ await ensureDocsDir();
87168
+ const projectRoot = await findProjectRoot() || process.cwd();
87169
+ const allDocs = await listAllDocs(projectRoot);
87170
+ if (allDocs.length === 0) {
87171
+ if (options2.plain) {
87172
+ console.log("No documentation found");
87145
87173
  } else {
87146
- const folder = parts.slice(0, -1).join("/");
87147
- const name = parts[parts.length - 1].replace(/\.md$/, "");
87148
- if (!folders.has(folder)) {
87149
- folders.set(folder, []);
87150
- }
87151
- folders.get(folder)?.push({ name, title: doc.metadata.title, tokens: doc.tokens });
87174
+ console.log(source_default.yellow("No documentation files found."));
87175
+ console.log(source_default.gray(`Create one with: knowns doc create "Title"`));
87152
87176
  }
87177
+ return;
87153
87178
  }
87154
- const sortedFolders = Array.from(folders.keys()).sort();
87155
- for (const folder of sortedFolders) {
87156
- console.log(`${folder}/`);
87157
- const docs2 = folders.get(folder)?.sort((a, b) => a.name.localeCompare(b.name));
87158
- for (const doc of docs2) {
87159
- console.log(` ${doc.name} - ${doc.title} (~${doc.tokens} tokens)`);
87179
+ const docs = [];
87180
+ for (const doc of allDocs) {
87181
+ try {
87182
+ const fileContent = await readFile18(doc.fullPath, "utf-8");
87183
+ const { data, content } = (0, import_gray_matter7.default)(fileContent);
87184
+ const stats = calculateDocStats(content);
87185
+ docs.push({
87186
+ ref: doc.ref,
87187
+ name: doc.name,
87188
+ source: doc.source,
87189
+ sourceUrl: doc.sourceUrl,
87190
+ isImported: doc.isImported,
87191
+ fullPath: doc.fullPath,
87192
+ metadata: data,
87193
+ tokens: stats.estimatedTokens
87194
+ });
87195
+ } catch {
87160
87196
  }
87161
87197
  }
87162
- if (rootDocs.length > 0) {
87163
- rootDocs.sort((a, b) => a.name.localeCompare(b.name));
87164
- for (const doc of rootDocs) {
87165
- console.log(`${doc.name} - ${doc.title} (~${doc.tokens} tokens)`);
87166
- }
87198
+ let filteredDocs = docs;
87199
+ if (options2.local) {
87200
+ filteredDocs = docs.filter((doc) => !doc.isImported);
87201
+ } else if (options2.imported) {
87202
+ filteredDocs = docs.filter((doc) => doc.isImported);
87167
87203
  }
87168
- } else {
87169
- const folders = /* @__PURE__ */ new Map();
87170
- const rootDocs = [];
87171
- for (const doc of filteredDocs) {
87172
- const parts = doc.filename.split("/");
87173
- if (parts.length === 1) {
87174
- rootDocs.push(doc);
87175
- } else {
87176
- const folder = parts.slice(0, -1).join("/");
87177
- if (!folders.has(folder)) {
87178
- folders.set(folder, []);
87204
+ if (path3) {
87205
+ const normalizedPath = path3.endsWith("/") ? path3 : `${path3}/`;
87206
+ filteredDocs = filteredDocs.filter(
87207
+ (doc) => doc.ref.startsWith(normalizedPath) || doc.name.startsWith(normalizedPath)
87208
+ );
87209
+ }
87210
+ if (options2.tag) {
87211
+ filteredDocs = filteredDocs.filter((doc) => doc.metadata.tags?.includes(options2.tag));
87212
+ }
87213
+ if (filteredDocs.length === 0) {
87214
+ const filterMsg = path3 ? `path: ${path3}` : options2.tag ? `tag: ${options2.tag}` : "";
87215
+ console.log(
87216
+ options2.plain ? "No documentation found" : source_default.yellow(`No documentation found${filterMsg ? ` with ${filterMsg}` : ""}`)
87217
+ );
87218
+ return;
87219
+ }
87220
+ if (options2.plain) {
87221
+ const sources = /* @__PURE__ */ new Map();
87222
+ for (const doc of filteredDocs) {
87223
+ const sourceKey = doc.isImported ? `[${doc.source}]` : "[local]";
87224
+ if (!sources.has(sourceKey)) {
87225
+ sources.set(sourceKey, []);
87226
+ }
87227
+ sources.get(sourceKey)?.push(doc);
87228
+ }
87229
+ const sortedSources = Array.from(sources.keys()).sort((a, b) => {
87230
+ if (a === "[local]") return -1;
87231
+ if (b === "[local]") return 1;
87232
+ return a.localeCompare(b);
87233
+ });
87234
+ for (const sourceKey of sortedSources) {
87235
+ const sourceDocs = sources.get(sourceKey) || [];
87236
+ const sourceUrl = sourceDocs[0]?.sourceUrl;
87237
+ if (sourceUrl) {
87238
+ console.log(`${sourceKey} (${sourceUrl})`);
87239
+ } else {
87240
+ console.log(`${sourceKey}`);
87241
+ }
87242
+ const folders = /* @__PURE__ */ new Map();
87243
+ const rootDocs = [];
87244
+ for (const doc of sourceDocs) {
87245
+ const parts = doc.name.split("/");
87246
+ if (parts.length === 1) {
87247
+ rootDocs.push({
87248
+ name: parts[0],
87249
+ title: doc.metadata.title || parts[0],
87250
+ tokens: doc.tokens
87251
+ });
87252
+ } else {
87253
+ const folder = parts.slice(0, -1).join("/");
87254
+ const name = parts[parts.length - 1];
87255
+ if (!folders.has(folder)) {
87256
+ folders.set(folder, []);
87257
+ }
87258
+ folders.get(folder)?.push({ name, title: doc.metadata.title || name, tokens: doc.tokens });
87259
+ }
87260
+ }
87261
+ const sortedFolders = Array.from(folders.keys()).sort();
87262
+ for (const folder of sortedFolders) {
87263
+ console.log(` ${folder}/`);
87264
+ const folderDocs = folders.get(folder)?.sort((a, b) => a.name.localeCompare(b.name));
87265
+ for (const doc of folderDocs || []) {
87266
+ console.log(` ${doc.name} - ${doc.title} (~${doc.tokens} tokens)`);
87267
+ }
87268
+ }
87269
+ if (rootDocs.length > 0) {
87270
+ rootDocs.sort((a, b) => a.name.localeCompare(b.name));
87271
+ for (const doc of rootDocs) {
87272
+ console.log(` ${doc.name} - ${doc.title} (~${doc.tokens} tokens)`);
87273
+ }
87179
87274
  }
87180
- folders.get(folder)?.push(doc);
87181
87275
  }
87182
- }
87183
- console.log(source_default.bold(`
87276
+ } else {
87277
+ const sources = /* @__PURE__ */ new Map();
87278
+ for (const doc of filteredDocs) {
87279
+ const sourceKey = doc.isImported ? doc.source : "local";
87280
+ if (!sources.has(sourceKey)) {
87281
+ sources.set(sourceKey, []);
87282
+ }
87283
+ sources.get(sourceKey)?.push(doc);
87284
+ }
87285
+ const sortedSources = Array.from(sources.keys()).sort((a, b) => {
87286
+ if (a === "local") return -1;
87287
+ if (b === "local") return 1;
87288
+ return a.localeCompare(b);
87289
+ });
87290
+ console.log(source_default.bold(`
87184
87291
  Documentation (${filteredDocs.length})
87185
87292
  `));
87186
- const sortedFolders = Array.from(folders.keys()).sort();
87187
- for (const folder of sortedFolders) {
87188
- console.log(source_default.cyan.bold(`${folder}/`));
87189
- const docs2 = folders.get(folder)?.sort((a, b) => a.metadata.title.localeCompare(b.metadata.title));
87190
- for (const doc of docs2) {
87191
- console.log(source_default.white(` ${doc.metadata.title}`));
87192
- if (doc.metadata.description) {
87193
- console.log(source_default.gray(` ${doc.metadata.description}`));
87194
- }
87195
- if (doc.metadata.tags && doc.metadata.tags.length > 0) {
87196
- console.log(source_default.gray(` Tags: ${doc.metadata.tags.join(", ")}`));
87293
+ for (const sourceKey of sortedSources) {
87294
+ const sourceDocs = sources.get(sourceKey) || [];
87295
+ const sourceUrl = sourceDocs[0]?.sourceUrl;
87296
+ const sourceLabel = sourceKey === "local" ? "Local" : `Import: ${sourceKey}`;
87297
+ if (sourceUrl) {
87298
+ console.log(source_default.magenta.bold(`[${sourceLabel}]`) + source_default.gray(` ${sourceUrl}`));
87299
+ } else {
87300
+ console.log(source_default.magenta.bold(`[${sourceLabel}]`));
87301
+ }
87302
+ const folders = /* @__PURE__ */ new Map();
87303
+ const rootDocs = [];
87304
+ for (const doc of sourceDocs) {
87305
+ const parts = doc.name.split("/");
87306
+ if (parts.length === 1) {
87307
+ rootDocs.push(doc);
87308
+ } else {
87309
+ const folder = parts.slice(0, -1).join("/");
87310
+ if (!folders.has(folder)) {
87311
+ folders.set(folder, []);
87312
+ }
87313
+ folders.get(folder)?.push(doc);
87314
+ }
87197
87315
  }
87198
- }
87199
- console.log();
87200
- }
87201
- if (rootDocs.length > 0) {
87202
- rootDocs.sort((a, b) => a.metadata.title.localeCompare(b.metadata.title));
87203
- for (const doc of rootDocs) {
87204
- console.log(source_default.white(`${doc.metadata.title}`));
87205
- if (doc.metadata.description) {
87206
- console.log(source_default.gray(` ${doc.metadata.description}`));
87316
+ const sortedFolders = Array.from(folders.keys()).sort();
87317
+ for (const folder of sortedFolders) {
87318
+ console.log(source_default.cyan.bold(` ${folder}/`));
87319
+ const folderDocs = folders.get(folder)?.sort((a, b) => (a.metadata.title || "").localeCompare(b.metadata.title || ""));
87320
+ for (const doc of folderDocs || []) {
87321
+ console.log(source_default.white(` ${doc.metadata.title || doc.name}`));
87322
+ if (doc.metadata.description) {
87323
+ console.log(source_default.gray(` ${doc.metadata.description}`));
87324
+ }
87325
+ }
87207
87326
  }
87208
- if (doc.metadata.tags && doc.metadata.tags.length > 0) {
87209
- console.log(source_default.gray(` Tags: ${doc.metadata.tags.join(", ")}`));
87327
+ if (rootDocs.length > 0) {
87328
+ rootDocs.sort((a, b) => (a.metadata.title || "").localeCompare(b.metadata.title || ""));
87329
+ for (const doc of rootDocs) {
87330
+ console.log(source_default.white(` ${doc.metadata.title || doc.name}`));
87331
+ if (doc.metadata.description) {
87332
+ console.log(source_default.gray(` ${doc.metadata.description}`));
87333
+ }
87334
+ }
87210
87335
  }
87211
87336
  console.log();
87212
87337
  }
87213
87338
  }
87339
+ } catch (error48) {
87340
+ console.error(
87341
+ source_default.red("Error listing documentation:"),
87342
+ error48 instanceof Error ? error48.message : String(error48)
87343
+ );
87344
+ process.exit(1);
87214
87345
  }
87215
- } catch (error48) {
87216
- console.error(source_default.red("Error listing documentation:"), error48 instanceof Error ? error48.message : String(error48));
87217
- process.exit(1);
87218
87346
  }
87219
- });
87347
+ );
87220
87348
  var viewCommand2 = new Command("view").description("View a documentation file").argument("<name>", "Document name (filename or title or path)").option("--plain", "Plain text output for AI").option("--info", "Show document stats (size, tokens, headings) without content").option("--toc", "Show table of contents only").option("--section <title>", "Show specific section by heading title or number (e.g., '2. Overview' or '2')").option("--smart", "Smart mode: auto-return full content if small, or stats+TOC if large (>2000 tokens)").action(
87221
87349
  async (name, options2) => {
87222
87350
  try {
@@ -96471,8 +96599,9 @@ async function resolveDocPath2(name) {
96471
96599
  async function handleListDocs(args2) {
96472
96600
  const input = listDocsSchema.parse(args2);
96473
96601
  await ensureDocsDir2();
96474
- const mdFiles = await getAllMdFiles2(DOCS_DIR4);
96475
- if (mdFiles.length === 0) {
96602
+ const projectRoot = process.cwd();
96603
+ const allDocs = await listAllDocs(projectRoot);
96604
+ if (allDocs.length === 0) {
96476
96605
  return successResponse({
96477
96606
  count: 0,
96478
96607
  docs: [],
@@ -96480,22 +96609,29 @@ async function handleListDocs(args2) {
96480
96609
  });
96481
96610
  }
96482
96611
  const docs = [];
96483
- for (const file3 of mdFiles) {
96484
- const fileContent = await readFile21(join33(DOCS_DIR4, file3), "utf-8");
96485
- const { data, content } = (0, import_gray_matter9.default)(fileContent);
96486
- const metadata = data;
96487
- const stats = calculateDocStats(content);
96488
- if (input.tag && !metadata.tags?.includes(input.tag)) {
96489
- continue;
96612
+ for (const doc of allDocs) {
96613
+ try {
96614
+ const fileContent = await readFile21(doc.fullPath, "utf-8");
96615
+ const { data, content } = (0, import_gray_matter9.default)(fileContent);
96616
+ const metadata = data;
96617
+ const stats = calculateDocStats(content);
96618
+ if (input.tag && !metadata.tags?.includes(input.tag)) {
96619
+ continue;
96620
+ }
96621
+ docs.push({
96622
+ path: doc.ref,
96623
+ // Use full ref path (includes import prefix if imported)
96624
+ title: metadata.title || doc.name,
96625
+ description: metadata.description,
96626
+ tags: metadata.tags,
96627
+ tokens: stats.estimatedTokens,
96628
+ updatedAt: metadata.updatedAt,
96629
+ source: doc.source,
96630
+ sourceUrl: doc.sourceUrl,
96631
+ isImported: doc.isImported
96632
+ });
96633
+ } catch {
96490
96634
  }
96491
- docs.push({
96492
- path: file3.replace(/\.md$/, ""),
96493
- title: metadata.title || file3.replace(/\.md$/, ""),
96494
- description: metadata.description,
96495
- tags: metadata.tags,
96496
- tokens: stats.estimatedTokens,
96497
- updatedAt: metadata.updatedAt
96498
- });
96499
96635
  }
96500
96636
  return successResponse({
96501
96637
  count: docs.length,
@@ -96803,7 +96939,7 @@ async function handleGetGuideline(args2) {
96803
96939
  import { existsSync as existsSync29 } from "node:fs";
96804
96940
  import { mkdir as mkdir18, writeFile as writeFile16 } from "node:fs/promises";
96805
96941
  import { join as join34 } from "node:path";
96806
- var TEMPLATES_DIR2 = join34(process.cwd(), ".knowns", "templates");
96942
+ var TEMPLATES_DIR3 = join34(process.cwd(), ".knowns", "templates");
96807
96943
  var listTemplatesSchema = external_exports.object({});
96808
96944
  var getTemplateSchema = external_exports.object({
96809
96945
  name: external_exports.string()
@@ -96896,30 +97032,45 @@ var templateTools = [
96896
97032
  ];
96897
97033
  async function handleListTemplates(_args) {
96898
97034
  listTemplatesSchema.parse(_args);
96899
- if (!existsSync29(TEMPLATES_DIR2)) {
96900
- return successResponse({
96901
- count: 0,
96902
- templates: [],
96903
- message: "No templates directory found. Create templates in .knowns/templates/"
96904
- });
96905
- }
97035
+ const projectRoot = process.cwd();
96906
97036
  try {
96907
- const templates = await listTemplates(TEMPLATES_DIR2);
96908
- if (templates.length === 0) {
97037
+ const allTemplates = await listAllTemplates(projectRoot);
97038
+ if (allTemplates.length === 0) {
96909
97039
  return successResponse({
96910
97040
  count: 0,
96911
97041
  templates: [],
96912
- message: "No templates found in .knowns/templates/"
97042
+ message: "No templates found. Create templates in .knowns/templates/"
96913
97043
  });
96914
97044
  }
96915
- const templateList = templates.map((t) => ({
96916
- name: t.name,
96917
- description: t.description,
96918
- doc: t.doc,
96919
- // Linked documentation
96920
- promptCount: t.prompts?.length || 0,
96921
- fileCount: t.files?.length || 0
96922
- }));
97045
+ const templateList = [];
97046
+ for (const t of allTemplates) {
97047
+ try {
97048
+ const loaded = await listTemplates(join34(t.path, ".."));
97049
+ const match2 = loaded.find((l) => l.name === t.name);
97050
+ templateList.push({
97051
+ name: t.name,
97052
+ ref: t.ref,
97053
+ description: match2?.description || "No description",
97054
+ doc: match2?.doc,
97055
+ promptCount: match2?.prompts?.length || 0,
97056
+ fileCount: match2?.files?.length || 0,
97057
+ source: t.source,
97058
+ sourceUrl: t.sourceUrl,
97059
+ isImported: t.isImported
97060
+ });
97061
+ } catch {
97062
+ templateList.push({
97063
+ name: t.name,
97064
+ ref: t.ref,
97065
+ description: "No description",
97066
+ promptCount: 0,
97067
+ fileCount: 0,
97068
+ source: t.source,
97069
+ sourceUrl: t.sourceUrl,
97070
+ isImported: t.isImported
97071
+ });
97072
+ }
97073
+ }
96923
97074
  return successResponse({
96924
97075
  count: templateList.length,
96925
97076
  templates: templateList
@@ -96930,27 +97081,37 @@ async function handleListTemplates(_args) {
96930
97081
  }
96931
97082
  async function handleGetTemplate(args2) {
96932
97083
  const input = getTemplateSchema.parse(args2);
96933
- if (!existsSync29(TEMPLATES_DIR2)) {
97084
+ if (!existsSync29(TEMPLATES_DIR3)) {
96934
97085
  return errorResponse("No templates directory found");
96935
97086
  }
96936
97087
  try {
96937
- const template = await loadTemplateByName(input.name, TEMPLATES_DIR2);
97088
+ const template = await loadTemplateByName(TEMPLATES_DIR3, input.name);
96938
97089
  if (!template) {
96939
97090
  return errorResponse(`Template not found: ${input.name}`);
96940
97091
  }
96941
97092
  const prompts4 = template.config.prompts?.map((p) => ({
96942
97093
  name: p.name,
96943
97094
  message: p.message,
96944
- type: p.type || "input",
97095
+ type: p.type || "text",
96945
97096
  required: p.validate === "required",
96946
- default: p.default,
97097
+ default: p.initial,
96947
97098
  choices: p.choices
96948
97099
  }));
96949
- const files = template.config.files?.map((f) => ({
96950
- template: f.template,
96951
- destination: f.destination,
96952
- condition: f.condition
96953
- }));
97100
+ const actions = template.config.actions?.map((a) => {
97101
+ if (a.type === "add") {
97102
+ return { type: a.type, template: a.template, path: a.path, skipIfExists: a.skipIfExists };
97103
+ }
97104
+ if (a.type === "addMany") {
97105
+ return { type: a.type, source: a.source, destination: a.destination, globPattern: a.globPattern };
97106
+ }
97107
+ if (a.type === "modify") {
97108
+ return { type: a.type, path: a.path, pattern: a.pattern };
97109
+ }
97110
+ if (a.type === "append") {
97111
+ return { type: a.type, path: a.path, unique: a.unique };
97112
+ }
97113
+ return a;
97114
+ });
96954
97115
  return successResponse({
96955
97116
  template: {
96956
97117
  name: template.config.name,
@@ -96958,7 +97119,7 @@ async function handleGetTemplate(args2) {
96958
97119
  doc: template.config.doc,
96959
97120
  // Linked documentation - AI should read this
96960
97121
  prompts: prompts4 || [],
96961
- files: files || [],
97122
+ actions: actions || [],
96962
97123
  messages: template.config.messages
96963
97124
  },
96964
97125
  hint: template.config.doc ? `This template links to @doc/${template.config.doc}. Read the doc for context before running.` : void 0
@@ -96970,11 +97131,11 @@ async function handleGetTemplate(args2) {
96970
97131
  async function handleRunTemplate(args2) {
96971
97132
  const input = runTemplateSchema.parse(args2);
96972
97133
  const dryRun = input.dryRun !== false;
96973
- if (!existsSync29(TEMPLATES_DIR2)) {
97134
+ if (!existsSync29(TEMPLATES_DIR3)) {
96974
97135
  return errorResponse("No templates directory found");
96975
97136
  }
96976
97137
  try {
96977
- const template = await loadTemplateByName(input.name, TEMPLATES_DIR2);
97138
+ const template = await loadTemplateByName(TEMPLATES_DIR3, input.name);
96978
97139
  if (!template) {
96979
97140
  return errorResponse(`Template not found: ${input.name}`);
96980
97141
  }
@@ -96989,8 +97150,8 @@ async function handleRunTemplate(args2) {
96989
97150
  for (const prompt of template.config.prompts || []) {
96990
97151
  if (input.variables?.[prompt.name]) {
96991
97152
  values[prompt.name] = input.variables[prompt.name];
96992
- } else if (prompt.default) {
96993
- values[prompt.name] = String(prompt.default);
97153
+ } else if (prompt.initial !== void 0) {
97154
+ values[prompt.name] = String(prompt.initial);
96994
97155
  }
96995
97156
  }
96996
97157
  const result = await runTemplate(template, {
@@ -97001,19 +97162,18 @@ async function handleRunTemplate(args2) {
97001
97162
  if (!result.success) {
97002
97163
  return errorResponse(`Template failed: ${result.error}`);
97003
97164
  }
97004
- const filesCreated = result.files?.map((f) => ({
97005
- path: f.path,
97006
- action: f.action,
97007
- skipped: f.skipped,
97008
- skipReason: f.skipReason
97009
- }));
97165
+ const totalCreated = result.created?.length || 0;
97166
+ const totalModified = result.modified?.length || 0;
97167
+ const totalSkipped = result.skipped?.length || 0;
97010
97168
  return successResponse({
97011
97169
  success: true,
97012
97170
  dryRun,
97013
97171
  template: input.name,
97014
97172
  variables: values,
97015
- files: filesCreated || [],
97016
- message: dryRun ? `Dry run complete. ${filesCreated?.length || 0} files would be created. Set dryRun: false to write files.` : `Template executed. ${filesCreated?.filter((f) => !f.skipped).length || 0} files created.`
97173
+ created: result.created || [],
97174
+ modified: result.modified || [],
97175
+ skipped: result.skipped || [],
97176
+ message: dryRun ? `Dry run complete. ${totalCreated} files would be created, ${totalModified} modified. Set dryRun: false to write files.` : `Template executed. ${totalCreated} files created, ${totalModified} modified, ${totalSkipped} skipped.`
97017
97177
  });
97018
97178
  } catch (error48) {
97019
97179
  return errorResponse(`Failed to run template: ${error48 instanceof Error ? error48.message : String(error48)}`);
@@ -97022,10 +97182,10 @@ async function handleRunTemplate(args2) {
97022
97182
  async function handleCreateTemplate(args2) {
97023
97183
  const input = createTemplateSchema.parse(args2);
97024
97184
  try {
97025
- if (!existsSync29(TEMPLATES_DIR2)) {
97026
- await mkdir18(TEMPLATES_DIR2, { recursive: true });
97185
+ if (!existsSync29(TEMPLATES_DIR3)) {
97186
+ await mkdir18(TEMPLATES_DIR3, { recursive: true });
97027
97187
  }
97028
- const templateDir = join34(TEMPLATES_DIR2, input.name);
97188
+ const templateDir = join34(TEMPLATES_DIR3, input.name);
97029
97189
  if (existsSync29(templateDir)) {
97030
97190
  return errorResponse(`Template "${input.name}" already exists`);
97031
97191
  }
@@ -97645,7 +97805,7 @@ function showConfigInfo() {
97645
97805
  import { existsSync as existsSync33 } from "node:fs";
97646
97806
  import { mkdir as mkdir19, writeFile as writeFile17 } from "node:fs/promises";
97647
97807
  import { join as join38 } from "node:path";
97648
- var TEMPLATES_DIR3 = ".knowns/templates";
97808
+ var TEMPLATES_DIR4 = ".knowns/templates";
97649
97809
  function getProjectRoot3() {
97650
97810
  const projectRoot = findProjectRoot();
97651
97811
  if (!projectRoot) {
@@ -97656,7 +97816,7 @@ function getProjectRoot3() {
97656
97816
  return projectRoot;
97657
97817
  }
97658
97818
  function getTemplatesDir(projectRoot) {
97659
- return join38(projectRoot, TEMPLATES_DIR3);
97819
+ return join38(projectRoot, TEMPLATES_DIR4);
97660
97820
  }
97661
97821
  async function ensureTemplatesDir(projectRoot) {
97662
97822
  const templatesDir = getTemplatesDir(projectRoot);
@@ -97666,20 +97826,16 @@ async function ensureTemplatesDir(projectRoot) {
97666
97826
  return templatesDir;
97667
97827
  }
97668
97828
  var templateCommand = new Command("template").description("Manage code generation templates").enablePositionalOptions();
97669
- var listCommand4 = new Command("list").description("List available templates").option("--plain", "Plain text output for AI").action(async (options2) => {
97829
+ var listCommand4 = new Command("list").description("List available templates (local + imported)").option("--plain", "Plain text output for AI").option("--local", "Show only local templates").option("--imported", "Show only imported templates").action(async (options2) => {
97670
97830
  try {
97671
97831
  const projectRoot = getProjectRoot3();
97672
- const templatesDir = getTemplatesDir(projectRoot);
97673
- if (!existsSync33(templatesDir)) {
97674
- if (options2.plain) {
97675
- console.log("No templates found");
97676
- } else {
97677
- console.log(source_default.yellow("No templates found"));
97678
- console.log(source_default.gray(" Create one with: knowns template create <name>"));
97679
- }
97680
- return;
97832
+ const allTemplates = await listAllTemplates(projectRoot);
97833
+ let templates = allTemplates;
97834
+ if (options2.local) {
97835
+ templates = allTemplates.filter((t) => !t.isImported);
97836
+ } else if (options2.imported) {
97837
+ templates = allTemplates.filter((t) => t.isImported);
97681
97838
  }
97682
- const templates = await listTemplates(templatesDir);
97683
97839
  if (templates.length === 0) {
97684
97840
  if (options2.plain) {
97685
97841
  console.log("No templates found");
@@ -97689,21 +97845,88 @@ var listCommand4 = new Command("list").description("List available templates").o
97689
97845
  }
97690
97846
  return;
97691
97847
  }
97848
+ const templatesWithDesc = [];
97849
+ for (const t of templates) {
97850
+ try {
97851
+ const loaded = await listTemplates(join38(t.path, ".."));
97852
+ const match2 = loaded.find((l) => l.name === t.name);
97853
+ templatesWithDesc.push({
97854
+ ref: t.ref,
97855
+ name: t.name,
97856
+ source: t.source,
97857
+ sourceUrl: t.sourceUrl,
97858
+ isImported: t.isImported,
97859
+ description: match2?.description || "No description"
97860
+ });
97861
+ } catch {
97862
+ templatesWithDesc.push({
97863
+ ref: t.ref,
97864
+ name: t.name,
97865
+ source: t.source,
97866
+ sourceUrl: t.sourceUrl,
97867
+ isImported: t.isImported,
97868
+ description: "No description"
97869
+ });
97870
+ }
97871
+ }
97692
97872
  if (options2.plain) {
97693
- for (const template of templates) {
97694
- console.log(`${template.name} - ${template.description || "No description"}`);
97873
+ const sources = /* @__PURE__ */ new Map();
97874
+ for (const t of templatesWithDesc) {
97875
+ const sourceKey = t.isImported ? `[${t.source}]` : "[local]";
97876
+ if (!sources.has(sourceKey)) {
97877
+ sources.set(sourceKey, []);
97878
+ }
97879
+ sources.get(sourceKey)?.push(t);
97880
+ }
97881
+ const sortedSources = Array.from(sources.keys()).sort((a, b) => {
97882
+ if (a === "[local]") return -1;
97883
+ if (b === "[local]") return 1;
97884
+ return a.localeCompare(b);
97885
+ });
97886
+ for (const sourceKey of sortedSources) {
97887
+ const sourceTemplates = sources.get(sourceKey) || [];
97888
+ const sourceUrl = sourceTemplates[0]?.sourceUrl;
97889
+ if (sourceUrl) {
97890
+ console.log(`${sourceKey} (${sourceUrl})`);
97891
+ } else {
97892
+ console.log(sourceKey);
97893
+ }
97894
+ for (const t of sourceTemplates) {
97895
+ console.log(` ${t.name} - ${t.description}`);
97896
+ }
97695
97897
  }
97696
97898
  } else {
97697
97899
  console.log(source_default.bold("\nTemplates:\n"));
97698
- const maxNameLen = Math.max(...templates.map((t) => t.name.length), 4);
97699
- console.log(source_default.gray(`${"Name".padEnd(maxNameLen + 2)}Description`));
97700
- console.log(source_default.gray("\u2500".repeat(60)));
97701
- for (const template of templates) {
97702
- const name = source_default.cyan(template.name.padEnd(maxNameLen + 2));
97703
- const desc = template.description || source_default.gray("No description");
97704
- console.log(`${name}${desc}`);
97900
+ const sources = /* @__PURE__ */ new Map();
97901
+ for (const t of templatesWithDesc) {
97902
+ const sourceKey = t.isImported ? t.source : "local";
97903
+ if (!sources.has(sourceKey)) {
97904
+ sources.set(sourceKey, []);
97905
+ }
97906
+ sources.get(sourceKey)?.push(t);
97907
+ }
97908
+ const sortedSources = Array.from(sources.keys()).sort((a, b) => {
97909
+ if (a === "local") return -1;
97910
+ if (b === "local") return 1;
97911
+ return a.localeCompare(b);
97912
+ });
97913
+ for (const sourceKey of sortedSources) {
97914
+ const sourceTemplates = sources.get(sourceKey) || [];
97915
+ const sourceUrl = sourceTemplates[0]?.sourceUrl;
97916
+ const sourceLabel = sourceKey === "local" ? "Local" : `Import: ${sourceKey}`;
97917
+ if (sourceUrl) {
97918
+ console.log(source_default.magenta.bold(`[${sourceLabel}]`) + source_default.gray(` ${sourceUrl}`));
97919
+ } else {
97920
+ console.log(source_default.magenta.bold(`[${sourceLabel}]`));
97921
+ }
97922
+ const maxNameLen = Math.max(...sourceTemplates.map((t) => t.name.length), 4);
97923
+ for (const t of sourceTemplates) {
97924
+ const name = source_default.cyan(t.name.padEnd(maxNameLen + 2));
97925
+ const desc = t.description || source_default.gray("No description");
97926
+ console.log(` ${name}${desc}`);
97927
+ }
97928
+ console.log();
97705
97929
  }
97706
- console.log();
97707
97930
  }
97708
97931
  } catch (error48) {
97709
97932
  console.error(source_default.red("Error:"), error48 instanceof Error ? error48.message : String(error48));
@@ -97831,7 +98054,7 @@ export function {{camelCase name}}() {
97831
98054
  await writeFile17(join38(templateDir, "example.ts.hbs"), exampleTemplate, "utf-8");
97832
98055
  console.log();
97833
98056
  console.log(source_default.green(`\u2713 Created template: ${name}`));
97834
- console.log(source_default.gray(` Location: ${TEMPLATES_DIR3}/${name}/`));
98057
+ console.log(source_default.gray(` Location: ${TEMPLATES_DIR4}/${name}/`));
97835
98058
  console.log();
97836
98059
  console.log(source_default.cyan("Files created:"));
97837
98060
  console.log(source_default.gray(" - _template.yaml (config)"));
@@ -98636,7 +98859,7 @@ async function notifyCliUpdate(options2) {
98636
98859
  // package.json
98637
98860
  var package_default = {
98638
98861
  name: "knowns",
98639
- version: "0.10.1",
98862
+ version: "0.10.3",
98640
98863
  description: "AI-native task and documentation management for dev teams",
98641
98864
  module: "index.ts",
98642
98865
  type: "module",