cortex-tms 3.1.0 → 3.2.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.
Files changed (77) hide show
  1. package/README.md +150 -53
  2. package/dist/cli.js +12 -4
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/auto-tier.d.ts.map +1 -1
  5. package/dist/commands/auto-tier.js +132 -58
  6. package/dist/commands/auto-tier.js.map +1 -1
  7. package/dist/commands/init.d.ts.map +1 -1
  8. package/dist/commands/init.js +23 -27
  9. package/dist/commands/init.js.map +1 -1
  10. package/dist/commands/migrate.d.ts.map +1 -1
  11. package/dist/commands/migrate.js +26 -7
  12. package/dist/commands/migrate.js.map +1 -1
  13. package/dist/commands/prompt.d.ts.map +1 -1
  14. package/dist/commands/prompt.js +2 -0
  15. package/dist/commands/prompt.js.map +1 -1
  16. package/dist/commands/review.d.ts.map +1 -1
  17. package/dist/commands/review.js +25 -25
  18. package/dist/commands/review.js.map +1 -1
  19. package/dist/commands/status.d.ts.map +1 -1
  20. package/dist/commands/status.js +4 -2
  21. package/dist/commands/status.js.map +1 -1
  22. package/dist/commands/tutorial.js +54 -3
  23. package/dist/commands/tutorial.js.map +1 -1
  24. package/dist/commands/validate.d.ts.map +1 -1
  25. package/dist/commands/validate.js +10 -3
  26. package/dist/commands/validate.js.map +1 -1
  27. package/dist/utils/errors.d.ts +20 -0
  28. package/dist/utils/errors.d.ts.map +1 -0
  29. package/dist/utils/errors.js +54 -0
  30. package/dist/utils/errors.js.map +1 -0
  31. package/dist/utils/git-history.d.ts.map +1 -1
  32. package/dist/utils/git-history.js +7 -3
  33. package/dist/utils/git-history.js.map +1 -1
  34. package/dist/utils/llm-client.d.ts.map +1 -1
  35. package/dist/utils/llm-client.js +5 -2
  36. package/dist/utils/llm-client.js.map +1 -1
  37. package/dist/utils/sanitize.d.ts +4 -0
  38. package/dist/utils/sanitize.d.ts.map +1 -0
  39. package/dist/utils/sanitize.js +44 -0
  40. package/dist/utils/sanitize.js.map +1 -0
  41. package/dist/utils/templates.d.ts.map +1 -1
  42. package/dist/utils/templates.js +11 -1
  43. package/dist/utils/templates.js.map +1 -1
  44. package/dist/utils/validation.d.ts +168 -0
  45. package/dist/utils/validation.d.ts.map +1 -0
  46. package/dist/utils/validation.js +186 -0
  47. package/dist/utils/validation.js.map +1 -0
  48. package/package.json +5 -2
  49. package/templates/CLAUDE.md +1 -1
  50. package/templates/FUTURE-ENHANCEMENTS.md +1 -1
  51. package/templates/NEXT-TASKS.md +1 -1
  52. package/templates/PROMPTS.md +1 -1
  53. package/templates/README.md +1 -1
  54. package/templates/docs/archive/v1.0-CHANGELOG.md +1 -1
  55. package/templates/docs/core/ARCHITECTURE.md +1 -1
  56. package/templates/docs/core/DECISIONS.md +1 -1
  57. package/templates/docs/core/DOMAIN-LOGIC.md +1 -1
  58. package/templates/docs/core/GLOSSARY.md +1 -1
  59. package/templates/docs/core/PATTERNS.md +1 -1
  60. package/templates/docs/core/SCHEMA.md +1 -1
  61. package/templates/docs/core/TROUBLESHOOTING.md +1 -1
  62. package/dist/__tests__/init.test.d.ts +0 -2
  63. package/dist/__tests__/init.test.d.ts.map +0 -1
  64. package/dist/__tests__/init.test.js +0 -173
  65. package/dist/__tests__/init.test.js.map +0 -1
  66. package/dist/__tests__/release.test.d.ts +0 -2
  67. package/dist/__tests__/release.test.d.ts.map +0 -1
  68. package/dist/__tests__/release.test.js +0 -484
  69. package/dist/__tests__/release.test.js.map +0 -1
  70. package/dist/__tests__/utils/temp-dir.d.ts +0 -6
  71. package/dist/__tests__/utils/temp-dir.d.ts.map +0 -1
  72. package/dist/__tests__/utils/temp-dir.js +0 -34
  73. package/dist/__tests__/utils/temp-dir.js.map +0 -1
  74. package/dist/__tests__/validate.test.d.ts +0 -2
  75. package/dist/__tests__/validate.test.d.ts.map +0 -1
  76. package/dist/__tests__/validate.test.js +0 -209
  77. package/dist/__tests__/validate.test.js.map +0 -1
package/README.md CHANGED
@@ -1,14 +1,24 @@
1
- # Cortex TMS 🧠
1
+ <p align="center">
2
+ <img src="website/public/logo.svg" alt="Cortex TMS Logo" width="200"/>
3
+ </p>
2
4
 
3
- **AI Governance Platform - Stop Wasting Tokens. Stop Burning GPU Cycles on Old Docs.**
5
+ <h1 align="center">Cortex TMS</h1>
6
+
7
+ <p align="center">
8
+ <strong>AI Governance Platform - Stop Wasting Tokens. Stop Burning GPU Cycles on Old Docs.</strong>
9
+ </p>
10
+
11
+ ---
4
12
 
5
13
  Cortex TMS is an **AI Governance Platform** built on three pillars:
6
14
 
7
- 1. **šŸ’° Cost Efficiency** - Reduce AI API costs by **40-60%** through intelligent context management
8
- 2. **āœ… Quality** - Prevent hallucinations from outdated docs with semantic validation
9
- 3. **🌱 Sustainability** - Cut compute requirements by **60-70%** with Green Governance (up to 94% with archives)
15
+ 1. **šŸ’° Cost Efficiency** - Reduce input tokens by **60-70%** through intelligent context management (works with ANY model)
16
+ 2. **āœ… Quality** - Reduce hallucinations from outdated docs with semantic validation and focused context
17
+ 3. **🌱 Sustainability** - Cut compute requirements by **60-70%** with Green Governance—less energy, greener development
10
18
 
11
- Stop feeding Claude/Copilot/Cursor thousands of outdated lines. **60-70% typical context reduction** (up to 94% with archives) means **10x lower costs**, **zero hallucinations**, and **less compute waste** from reading archived docs.
19
+ Stop feeding your AI coding tool thousands of outdated lines. **60-70% input token reduction** (measured across 47 sessions on Cortex TMS itself) means **lower costs for paid models**, **less compute for free models**, and **fewer hallucinations** from irrelevant context.
20
+
21
+ **Works with any AI coding tool** - Claude Code, Copilot, Cursor, Warp, Augment, you name it. The architecture is model-agnostic. Input token reduction is universal.
12
22
 
13
23
  [![npm version](https://img.shields.io/npm/v/cortex-tms.svg?style=flat-square)](https://www.npmjs.com/package/cortex-tms)
14
24
  [![npm downloads](https://img.shields.io/npm/dm/cortex-tms.svg?style=flat-square)](https://www.npmjs.com/package/cortex-tms)
@@ -22,23 +32,25 @@ Stop feeding Claude/Copilot/Cursor thousands of outdated lines. **60-70% typical
22
32
 
23
33
  ## šŸš€ Instant Activation
24
34
 
25
- Get started in under 60 seconds:
35
+ Get started in under 60 seconds (no installation required):
26
36
 
27
37
  ```bash
28
38
  # 1. Initialize your project
29
- npx cortex-tms init
39
+ npx cortex-tms@latest init
30
40
 
31
41
  # 2. Open the Project Cockpit
32
- npx cortex-tms status
42
+ npx cortex-tms@latest status
33
43
 
34
44
  # 3. Activate your AI Agent
35
- npx cortex-tms prompt init-session
45
+ npx cortex-tms@latest prompt init-session
36
46
  # (Copies project-aware prompt to clipboard!)
37
47
 
38
48
  # 4. Check version health
39
- npx cortex-tms migrate
49
+ npx cortex-tms@latest migrate
40
50
  ```
41
51
 
52
+ **Note**: Using `npx` requires no installation. For frequent use, install globally: `npm install -g cortex-tms@latest`
53
+
42
54
  Choose your scope (Nano/Standard/Enterprise) and start building with AI-optimized documentation and intelligent CLI tooling.
43
55
 
44
56
  šŸ“– **New here?** The Essential 7 prompts in `PROMPTS.md` will guide you through the entire development lifecycle.
@@ -51,9 +63,9 @@ Choose your scope (Nano/Standard/Enterprise) and start building with AI-optimize
51
63
 
52
64
  ---
53
65
 
54
- ## šŸ’° The Value: Measurable Cost Savings
66
+ ## šŸ’° The Value: Measurable Efficiency Gains
55
67
 
56
- **Real Numbers from Cortex TMS itself**:
68
+ **Real Numbers from Cortex TMS itself** (TypeScript monorepo, measured across 47 development sessions):
57
69
 
58
70
  ```bash
59
71
  cortex status --tokens -m claude-sonnet-4-5
@@ -61,11 +73,10 @@ cortex status --tokens -m claude-sonnet-4-5
61
73
 
62
74
  | Metric | Value | Impact |
63
75
  | :---------------------- | :------------------- | :---------------------------------------------- |
64
- | **Context Reduction** | 60-70% typical (94% max) | Read 3,647 tokens instead of 66,834 (with archives) |
65
- | **Cost per Session** | $0.01 | vs $0.20 without tiering (Claude Sonnet 4.5) |
66
- | **Cost Comparison** | 10x cheaper | Claude Sonnet vs GPT-4 ($0.01 vs $0.11/session) |
67
- | **Carbon Footprint** | 60-70% lower | Less compute = greener development |
68
- | **Quality Improvement** | 80% fewer violations | Guardian catches pattern drift |
76
+ | **Input Token Reduction** | 60-70% typical | Read 3,647 tokens instead of 66,834 (measured on our project) |
77
+ | **Cost Savings (Paid Models)** | ~60-70% lower costs | Example: Claude Sonnet $0.20 → $0.06/session |
78
+ | **Compute Savings (Free Models)** | ~60-70% less processing | Less GPU cycles = lower electricity + greener development |
79
+ | **Quality Improvement** | Fewer hallucinations | AI reads focused context, not thousands of irrelevant lines |
69
80
 
70
81
  **How?** The HOT/WARM/COLD tier system ensures AI agents only read what matters:
71
82
 
@@ -73,7 +84,33 @@ cortex status --tokens -m claude-sonnet-4-5
73
84
  - **WARM**: Architectural truth (on-demand) - 20,109 tokens
74
85
  - **COLD**: Historical archive (ignored) - 43,078 tokens
75
86
 
76
- **Result**: Your AI assistant stays focused, costs less, and makes fewer mistakes.
87
+ **Result**: Your AI assistant stays focused, costs less (paid models) or uses less compute (free models), and makes fewer mistakes.
88
+
89
+ **Tested Models**: Claude Sonnet/Opus, GPT-4. Architecture is model-agnostic—should work with any AI tool. Input token reduction benefit is universal.
90
+
91
+ ---
92
+
93
+ ## šŸ“Š Measurement & Validation
94
+
95
+ **How We Measured These Numbers**:
96
+
97
+ The 60-70% input token reduction is based on 47 development sessions working on Cortex TMS itself (TypeScript monorepo, ~66K total tokens). We tracked:
98
+ - HOT tier tokens: ~3,647 (what AI actually reads)
99
+ - Full repository: ~66,834 (without TMS)
100
+ - Reduction: ~94.5% when comparing HOT tier vs full repo with archives
101
+
102
+ **Transparency**:
103
+ - Sample: 47 sessions over 24 days (Jan 2026)
104
+ - Project type: TypeScript monorepo (Cortex TMS dogfooding itself)
105
+ - Tools tested: Claude Code, GitHub Copilot (in VS Code)
106
+ - Models tested: Claude Sonnet/Opus, GPT-4, and other Copilot models
107
+ - Your results may vary based on project size, structure, usage patterns, and model choice
108
+ - Read our measurement methodology: [Measuring Context Optimization](website/src/content/blog/measuring-context-optimization.mdx)
109
+
110
+ **Community Feedback Welcome**:
111
+ If you use other models (local LLMs, etc.) and your experience differs, please share! We're building a public benchmark suite to validate findings across diverse projects and models. See [FUTURE-ENHANCEMENTS.md](FUTURE-ENHANCEMENTS.md) for roadmap.
112
+
113
+ **Honest Approach**: These are our real measurements from dogfooding with the models we actually use. Not marketing fluff, not fake data. We invite the community to validate, challenge, and improve these findings.
77
114
 
78
115
  ---
79
116
 
@@ -89,6 +126,25 @@ Traditional repos drown AI agents in thousands of lines of historical tasks and
89
126
 
90
127
  ---
91
128
 
129
+ ## šŸ†• What's New in v3.2 (Upcoming)
130
+
131
+ **Security & Production Readiness** - Making Cortex TMS enterprise-grade:
132
+
133
+ - šŸ›”ļø **Centralized Error Handling** — No more process crashes. All commands use consistent `CLIError` patterns with proper cleanup
134
+ - āœ… **Zod-Based Input Validation** — Runtime type safety for all CLI commands with clear, actionable error messages
135
+ - 🧪 **Comprehensive E2E Tests** — 61 E2E tests covering full CLI workflows (init, validate, migrate, review, auto-tier)
136
+ - šŸ”’ **Path Traversal Protection** — Template operations secured against `../../etc/passwd` attacks with `validateSafePath()`
137
+ - šŸ” **API Key Sanitization** — Guardian automatically redacts Anthropic/OpenAI keys in all error messages and logs
138
+ - šŸ“Š **Automated Security Scanning** — CI pipeline runs `pnpm audit` on every PR to catch dependency vulnerabilities
139
+
140
+ **Test Coverage**: 316 tests (97% pass rate) — up from 269 tests (+17%)
141
+
142
+ **For Developers**: See [Security Testing Guide](docs/guides/SECURITY-TESTING.md) for how to verify security patterns.
143
+
144
+ **Full Details**: [CHANGELOG.md](CHANGELOG.md#320---unreleased)
145
+
146
+ ---
147
+
92
148
  ## šŸ› ļø CLI Commands
93
149
 
94
150
  Cortex TMS provides 8 production-ready commands:
@@ -146,10 +202,10 @@ cortex-tms status --tokens -m gpt-4 # Cost comparison across models
146
202
  **Token Analysis Features**:
147
203
 
148
204
  - HOT/WARM/COLD tier breakdown with token counts
149
- - Context reduction percentage (e.g., 94.5% reduction)
150
- - Cost estimates per session/day/month
205
+ - Context reduction percentage (typically 60-70%)
206
+ - Cost estimates per session/day/month (for paid models)
151
207
  - Model comparison (Claude Sonnet 4.5, Opus 4.5, GPT-4, etc.)
152
- - Sustainability impact tracking
208
+ - Sustainability impact tracking (compute savings for all models)
153
209
 
154
210
  ### `cortex-tms auto-tier`
155
211
 
@@ -166,10 +222,12 @@ cortex-tms auto-tier --force # Overwrite existing tags
166
222
 
167
223
  **How It Works**:
168
224
 
169
- - Analyzes git commit history to determine file modification recency
170
- - Assigns HOT/WARM/COLD tiers based on days since last change
225
+ - Analyzes git commit history and file paths to calculate priority scores
226
+ - **Scoring system**: Canonical files (100 pts) > docs/ (40 pts) + recency (15 pts)
227
+ - **Strict cap**: Maximum 10 HOT files (prevents context bloat)
228
+ - **Smart defaults**: `docs/archive/` → COLD, `docs/guides/` → WARM, canonical files always HOT
171
229
  - Adds `<!-- @cortex-tms-tier HOT -->` tags to markdown files
172
- - Default thresholds: HOT ≤ 7 days, WARM ≤ 30 days, COLD > 30 days
230
+ - Respects explicit tier tags unless `--force` is used
173
231
 
174
232
  **Why Auto-Tier?**
175
233
 
@@ -372,21 +430,21 @@ jobs:
372
430
 
373
431
  ---
374
432
 
375
- ## šŸš€ What's New in v2.6.1
433
+ ## šŸš€ What's New in v2.6.1 (Current Published Release)
376
434
 
377
435
  ### Token Counter - Prove Your Savings (GREEN GOVERNANCE)
378
436
 
379
437
  - **Real-Time Token Analysis**: `cortex status --tokens` shows HOT/WARM/COLD breakdown
380
438
  - **Multi-Model Cost Comparison**: Claude Sonnet 4.5, Opus 4.5, GPT-4, and more
381
439
  - **Sustainability Metrics**: Track your sustainability impact from less compute
382
- - **94.5% Context Reduction**: Cortex TMS reads 3,647 tokens instead of 66,834
383
- - **10x Cost Savings**: $0.01/session (Claude Sonnet) vs $0.11/session (GPT-4)
440
+ - **60-70% Input Token Reduction**: Measured on Cortex TMS itself (3,647 vs 66,834 tokens)
441
+ - **Universal Savings**: Lower costs for paid models, less compute for free models
384
442
 
385
443
  ### Guardian Semantic Validation (QUALITY ENFORCEMENT)
386
444
 
387
445
  - **Pattern Enforcement**: `cortex review <file>` validates against PATTERNS.md
388
446
  - **Domain Logic Checker**: Audits code against immutable project rules
389
- - **Zero False Negatives**: Never misses actual violations (65.5% baseline accuracy)
447
+ - **High Accuracy**: 80%+ accuracy target with Safe Mode (from 65.5% baseline)
390
448
  - **LLM-Powered Detection**: Uses Claude/GPT to catch semantic violations, not just syntax
391
449
 
392
450
  ### Integration Test Suite (PRODUCTION QUALITY)
@@ -574,27 +632,33 @@ We welcome contributions! Please read **[CONTRIBUTING.md](CONTRIBUTING.md)** for
574
632
 
575
633
  ## šŸŽÆ Why Cortex TMS? Three Pillars, Measurable Results
576
634
 
577
- ### šŸ’° Cost Efficiency (Pillar 1)
635
+ **Based on 47 development sessions on Cortex TMS itself (TypeScript monorepo) using Claude Code and GitHub Copilot with various models. Your results may vary.**
578
636
 
579
- **Before TMS**: Wasting **$0.19/session** reading 66,834 tokens of old docs
580
- **After TMS**: Paying **$0.01/session** with 94.5% context reduction
581
- **Impact**: **10x cost reduction** - Claude Sonnet 4.5 vs GPT-4 ($0.01 vs $0.11/session)
637
+ ### šŸ’° Cost Efficiency (Pillar 1) - Input Token Reduction
582
638
 
583
- **How**: HOT/WARM/COLD tiers ensure AI only reads what matters (3,647 vs 66,834 tokens)
639
+ **Before TMS**: AI reads entire repository (66,834 tokens in our case)
640
+ **After TMS**: AI reads focused context (3,647 tokens—60-70% reduction)
641
+ **Impact**:
642
+ - **Paid models** (tested: Claude, GPT-4): ~60-70% lower API costs
643
+ - **Free/local models** (untested, but architecturally supported): Should see ~60-70% less compute/electricity
644
+ - **Universal benefit**: Input token reduction works with any AI tool
584
645
 
585
- ### āœ… Quality (Pillar 2)
646
+ **How**: HOT/WARM/COLD tiers ensure AI only reads what matters (3,647 vs 66,834 tokens measured on our project with Claude/GPT)
586
647
 
587
- **Before TMS**: **40% pattern violations** from AI reading outdated examples
588
- **After TMS**: **80% fewer violations** with Guardian semantic validation
648
+ ### āœ… Quality (Pillar 2) - Focused Context Means Fewer Hallucinations
649
+
650
+ **Before TMS**: AI reads thousands of outdated lines, leading to pattern violations
651
+ **After TMS**: AI reads focused, current context—fewer mistakes from irrelevant information
589
652
  **Impact**: Guardian enforces `PATTERNS.md` and `DOMAIN-LOGIC.md` automatically
590
653
 
591
- **How**: LLM-powered review catches semantic drift that grep/regex can't find (**zero false negatives**)
654
+ **How**: LLM-powered semantic review catches drift that grep/regex can't find
592
655
 
593
- ### 🌱 Sustainability (Pillar 3)
656
+ ### 🌱 Sustainability (Pillar 3) - Greener Development Through Efficiency
594
657
 
595
- **Before TMS**: Burning unnecessary GPU cycles on 94.5% noise (archived changelogs, stale tasks)
596
- **After TMS**: **94.5% lower compute requirements** through intelligent tiering
597
- **Impact**: Less compute = greener development + happier planet
658
+ **Before TMS**: Burning GPU cycles on archived changelogs and stale tasks
659
+ **After TMS**: 60-70% lower compute requirements through intelligent tiering
660
+ **Impact**: Less compute = lower electricity costs + greener development
661
+ - Especially important for free/local models where YOU pay the electricity bill
598
662
 
599
663
  **How**: Stop reading COLD files unless explicitly needed
600
664
 
@@ -602,16 +666,49 @@ We welcome contributions! Please read **[CONTRIBUTING.md](CONTRIBUTING.md)** for
602
666
 
603
667
  - **Instant AI Activation**: Essential 7 prompts in `PROMPTS.md` (no manual prompt writing)
604
668
  - **Signal over Noise**: HOT/WARM/COLD system keeps AI focused
605
- - **Production-Ready**: 111 passing tests, stable 2.6.1 release
669
+ - **Production-Ready**: 316 tests (97% pass rate), enterprise-grade security (v3.2)
670
+ - **Tested With**: Claude Code, GitHub Copilot (in VS Code). Architecture supports any AI tool (Cursor, etc.).
606
671
 
607
672
  ---
608
673
 
609
- ## Contact
674
+ ## šŸ”’ Security
675
+
676
+ Cortex TMS implements enterprise-grade security practices:
677
+
678
+ - **API Key Protection**: Guardian automatically sanitizes API keys in all output (errors, logs, console)
679
+ - **Input Validation**: All CLI commands use Zod schemas for runtime type safety
680
+ - **Path Security**: Template operations protected against directory traversal attacks
681
+ - **Automated Scanning**: CI pipeline includes `pnpm audit` to catch dependency vulnerabilities
682
+
683
+ **Documentation**:
684
+ - [Security Overview](docs/core/SECURITY.md) — Threat model, mitigations, and best practices
685
+ - [Security Testing Guide](docs/guides/SECURITY-TESTING.md) — How to verify security patterns
686
+ - [Security Patterns](docs/core/PATTERNS.md) — Implementation patterns (Error Handling, Input Validation)
687
+
688
+ **Reporting Vulnerabilities**: Use [GitHub Security Advisories](https://github.com/cortex-tms/cortex-tms/security/advisories/new) for responsible disclosure.
689
+
690
+ ---
691
+
692
+ ## šŸ’¬ Community & Support
693
+
694
+ We have an active and growing community! ⭐ **146 stars** and counting.
695
+
696
+ ### Get Help & Connect
697
+ - **[GitHub Discussions](https://github.com/cortex-tms/cortex-tms/discussions)** - Ask questions, share ideas, showcase projects
698
+ - [Q&A](https://github.com/cortex-tms/cortex-tms/discussions/categories/q-a) - Get help from the community
699
+ - [Ideas](https://github.com/cortex-tms/cortex-tms/discussions/categories/ideas) - Suggest features (vote with šŸ‘)
700
+ - [Show and Tell](https://github.com/cortex-tms/cortex-tms/discussions/categories/show-and-tell) - Share what you've built
701
+ - [Announcements](https://github.com/cortex-tms/cortex-tms/discussions/categories/announcements) - Release notes and updates
702
+
703
+ ### Report Issues
704
+ - **[Bug Reports](https://github.com/cortex-tms/cortex-tms/issues/new)** - Found a bug? Let us know!
705
+ - **[Security Issues](https://github.com/cortex-tms/cortex-tms/security/advisories/new)** - Responsible disclosure for security vulnerabilities
706
+
707
+ ### Contributing
708
+ - **[Contributing Guide](CONTRIBUTING.md)** - How to contribute code, docs, or ideas
709
+ - **[Community Guide](docs/COMMUNITY.md)** - Community guidelines and best practices
610
710
 
611
- - **Bug Reports**: [GitHub Issues](https://github.com/cortex-tms/cortex-tms/issues/new) - Report bugs or technical issues
612
- - **Feature Requests**: [GitHub Issues](https://github.com/cortex-tms/cortex-tms/issues/new) - Suggest new features or improvements
613
- - **Questions & Support**: [GitHub Issues](https://github.com/cortex-tms/cortex-tms/issues/new) - Get help and ask questions
614
- - **Security Issues**: [GitHub Security Advisories](https://github.com/cortex-tms/cortex-tms/security/advisories/new) - Responsible disclosure
711
+ **Star us on GitHub** ⭐ if you find Cortex TMS useful!
615
712
 
616
713
  ---
617
714
 
@@ -623,9 +720,9 @@ MIT
623
720
 
624
721
  ## Status
625
722
 
626
- **Version**: 3.1.0 (Stable / Production Ready)
627
- **Last Updated**: 2026-01-23
628
- **Current Sprint**: v2.8 - "Marketing Pivot & Community Launch"
629
- **Completed Sprints**: v2.1, v2.2, v2.3, v2.4, v2.5, v2.6, v2.7 (see `docs/archive/`)
723
+ **Version**: 3.2.0 (Upcoming - Phase 1 Complete)
724
+ **Last Updated**: 2026-01-31
725
+ **Current Sprint**: v3.2 - "Security Hardening + Production Readiness"
726
+ **Recent Sprints**: v3.1 (Git-Based Auto-Tiering), v3.0 (AI-Powered Onboarding) — see [docs/archive/](docs/archive/)
630
727
 
631
- <!-- @cortex-tms-version 3.1.0 -->
728
+ <!-- @cortex-tms-version 3.2.0 -->
package/dist/cli.js CHANGED
@@ -4,6 +4,8 @@ import { readFileSync } from 'fs';
4
4
  import { fileURLToPath } from 'url';
5
5
  import { dirname, join } from 'path';
6
6
  import chalk from 'chalk';
7
+ import { CLIError, ValidationError, formatError } from './utils/errors.js';
8
+ import { sanitizeApiKey } from './utils/sanitize.js';
7
9
  const __filename = fileURLToPath(import.meta.url);
8
10
  const __dirname = dirname(__filename);
9
11
  const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
@@ -33,21 +35,27 @@ program.addCommand(tutorialCommand);
33
35
  program.addCommand(reviewCommand);
34
36
  program.addCommand(autoTierCommand);
35
37
  program.on('command:*', () => {
36
- console.error(chalk.red('\nāŒ Invalid command:'), chalk.bold(program.args.join(' ')));
37
- console.log(chalk.gray('\nRun'), chalk.cyan('cortex-tms --help'), chalk.gray('to see available commands.'));
38
- process.exit(1);
38
+ throw new ValidationError('Invalid command', {
39
+ command: program.args.join(' '),
40
+ hint: 'Run "cortex-tms --help" to see available commands',
41
+ });
39
42
  });
40
43
  program.exitOverride();
41
44
  try {
42
45
  await program.parseAsync(process.argv);
43
46
  }
44
47
  catch (error) {
48
+ if (error instanceof CLIError) {
49
+ console.error(chalk.red('\nāŒ Error:'), formatError(error));
50
+ process.exit(error.exitCode);
51
+ }
45
52
  if (error instanceof Error) {
46
53
  if ('code' in error && typeof error.code === 'string') {
47
54
  process.exit(1);
48
55
  }
49
56
  if (!error.message.includes('(outputHelp)')) {
50
- console.error(chalk.red('\nāŒ Error:'), error.message);
57
+ const sanitizedMessage = sanitizeApiKey(error.message);
58
+ console.error(chalk.red('\nāŒ Error:'), sanitizedMessage);
51
59
  }
52
60
  }
53
61
  process.exit(1);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AASA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAGtC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAC1D,CAAC;AAEF,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAG9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CACV,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC;IACzB,IAAI;IACJ,KAAK,CAAC,IAAI,CAAC,kDAAkD,CAAC;IAC9D,KAAK,CAAC,IAAI,CAAC,0DAA0D,CAAC,CACzE;KACA,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,4BAA4B,CAAC;KAC3E,UAAU,CAAC,YAAY,EAAE,0BAA0B,CAAC,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AAGpC,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE;IAC3B,MAAM,IAAI,eAAe,CAAC,iBAAiB,EAAE;QAC3C,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QAC/B,IAAI,EAAE,mDAAmD;KAC1D,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAGH,OAAO,CAAC,YAAY,EAAE,CAAC;AAGvB,IAAI,CAAC;IACH,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IAEf,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3D,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAGD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,IAAI,MAAM,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAEtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAGD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAC5C,MAAM,gBAAgB,GAAG,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACvD,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAGD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAClC,OAAO,CAAC,UAAU,EAAE,CAAC;AACvB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"auto-tier.d.ts","sourceRoot":"","sources":["../../src/commands/auto-tier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6BpC,wBAAgB,qBAAqB,IAAI,OAAO,CAc/C;AA0LD,eAAO,MAAM,eAAe,SAA0B,CAAC"}
1
+ {"version":3,"file":"auto-tier.d.ts","sourceRoot":"","sources":["../../src/commands/auto-tier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmHpC,wBAAgB,qBAAqB,IAAI,OAAO,CAe/C;AA4OD,eAAO,MAAM,eAAe,SAA0B,CAAC"}
@@ -5,14 +5,66 @@ import { glob } from 'glob';
5
5
  import { readFile, writeFile } from 'fs/promises';
6
6
  import { isGitRepo, analyzeFileHistory } from '../utils/git-history.js';
7
7
  import { readTierTag, writeTierTag } from '../utils/tier-tags.js';
8
- const MANDATORY_HOT = ['NEXT-TASKS.md', 'CLAUDE.md', '.github/copilot-instructions.md'];
8
+ import { GitError } from '../utils/errors.js';
9
+ import { autoTierOptionsSchema, validateOptions } from '../utils/validation.js';
10
+ const MANDATORY_HOT = [
11
+ 'NEXT-TASKS.md',
12
+ 'CLAUDE.md',
13
+ '.github/copilot-instructions.md',
14
+ 'docs/core/PATTERNS.md',
15
+ 'docs/core/GLOSSARY.md',
16
+ ];
17
+ function isCanonicalHot(filePath) {
18
+ return MANDATORY_HOT.includes(filePath);
19
+ }
20
+ function calculateFileScore(filePath, daysSinceChange, hotDays) {
21
+ let score = 0;
22
+ if (isCanonicalHot(filePath)) {
23
+ score += 100;
24
+ }
25
+ if (filePath.startsWith('docs/')) {
26
+ score += 40;
27
+ if (filePath.startsWith('docs/core/')) {
28
+ score += 10;
29
+ }
30
+ if (filePath.startsWith('docs/archive/')) {
31
+ score -= 60;
32
+ }
33
+ }
34
+ if (daysSinceChange <= hotDays) {
35
+ score += 15;
36
+ }
37
+ else if (daysSinceChange <= hotDays * 2) {
38
+ score += 5;
39
+ }
40
+ return score;
41
+ }
42
+ function getDirectoryBasedTier(filePath) {
43
+ if (filePath.startsWith('docs/archive/')) {
44
+ return { tier: 'COLD', directory: 'docs/archive/' };
45
+ }
46
+ if (filePath.startsWith('examples/')) {
47
+ return { tier: 'COLD', directory: 'examples/' };
48
+ }
49
+ if (filePath.startsWith('templates/')) {
50
+ return { tier: 'WARM', directory: 'templates/' };
51
+ }
52
+ if (filePath.startsWith('docs/guides/')) {
53
+ return { tier: 'WARM', directory: 'docs/guides/' };
54
+ }
55
+ if (filePath.startsWith('docs/tasks/')) {
56
+ return { tier: 'WARM', directory: 'docs/tasks/' };
57
+ }
58
+ return null;
59
+ }
9
60
  export function createAutoTierCommand() {
10
61
  const cmd = new Command('auto-tier');
11
62
  cmd
12
63
  .description('Analyze and apply tier tags based on git history (use --dry-run to preview)')
13
- .option('--hot <days>', 'Files modified within N days → HOT', '7')
14
- .option('--warm <days>', 'Files modified within N days → WARM', '30')
64
+ .option('--hot <days>', 'Files modified ≤N days ago get recency bonus', '7')
65
+ .option('--warm <days>', 'Files modified ≤N days ago → WARM (aging beyond this stays WARM until --cold)', '30')
15
66
  .option('--cold <days>', 'Files older than N days → COLD', '90')
67
+ .option('--max-hot <count>', 'Maximum number of HOT files (capped)', '10')
16
68
  .option('-d, --dry-run', 'Preview changes without applying')
17
69
  .option('-f, --force', 'Overwrite existing tier tags')
18
70
  .option('-v, --verbose', 'Show detailed output')
@@ -21,36 +73,14 @@ export function createAutoTierCommand() {
21
73
  }
22
74
  async function runAutoTier(options) {
23
75
  const cwd = process.cwd();
24
- const hotDays = parseInt(String(options.hot), 10);
25
- const warmDays = parseInt(String(options.warm), 10);
26
- const coldDays = parseInt(String(options.cold), 10);
27
- if (isNaN(hotDays) || hotDays < 0) {
28
- console.log(chalk.red('āŒ Error: --hot must be a positive number'));
29
- process.exit(1);
30
- }
31
- if (isNaN(warmDays) || warmDays < 0) {
32
- console.log(chalk.red('āŒ Error: --warm must be a positive number'));
33
- process.exit(1);
34
- }
35
- if (isNaN(coldDays) || coldDays < 0) {
36
- console.log(chalk.red('āŒ Error: --cold must be a positive number'));
37
- process.exit(1);
38
- }
39
- if (hotDays > warmDays) {
40
- console.log(chalk.red('āŒ Error: --hot threshold must be ≤ --warm threshold'));
41
- console.log(chalk.gray(` Got: hot=${hotDays}, warm=${warmDays}`));
42
- process.exit(1);
43
- }
44
- if (warmDays > coldDays) {
45
- console.log(chalk.red('āŒ Error: --warm threshold must be ≤ --cold threshold'));
46
- console.log(chalk.gray(` Got: warm=${warmDays}, cold=${coldDays}`));
47
- process.exit(1);
48
- }
76
+ const validated = validateOptions(autoTierOptionsSchema, options, 'auto-tier');
77
+ const hotDays = validated.hot;
78
+ const warmDays = validated.warm;
79
+ const coldDays = validated.cold;
80
+ const maxHotFiles = validated.maxHot ?? 10;
49
81
  console.log(chalk.bold.cyan('\nšŸ”„ Git-Based Auto-Tiering\n'));
50
82
  if (!isGitRepo(cwd)) {
51
- console.log(chalk.red('āŒ Error: Not a git repository'));
52
- console.log(chalk.gray(' Run this command in a git-initialized project.'));
53
- process.exit(1);
83
+ throw new GitError('Not a git repository. Run this command in a git-initialized project.');
54
84
  }
55
85
  if (options.dryRun) {
56
86
  console.log(chalk.yellow('šŸ” DRY RUN MODE: No files will be modified.\n'));
@@ -58,50 +88,74 @@ async function runAutoTier(options) {
58
88
  const spinner = ora('Analyzing git history...').start();
59
89
  const files = await glob('**/*.md', {
60
90
  cwd,
61
- ignore: ['node_modules/**', '.git/**', 'dist/**'],
91
+ dot: true,
92
+ ignore: ['**/node_modules/**', '.git/**', '**/dist/**'],
62
93
  });
63
94
  const gitInfo = analyzeFileHistory(cwd, files);
64
95
  spinner.text = 'Calculating tier suggestions...';
65
- const suggestions = [];
96
+ const scoredFiles = [];
66
97
  for (const info of gitInfo) {
98
+ if (!info.isTracked) {
99
+ continue;
100
+ }
67
101
  const content = await readFile(info.path, 'utf-8');
68
102
  const currentTier = readTierTag(content);
103
+ if (currentTier && !options.force && !isCanonicalHot(info.path)) {
104
+ continue;
105
+ }
106
+ const score = calculateFileScore(info.path, info.daysSinceChange, hotDays);
107
+ scoredFiles.push({
108
+ info,
109
+ content,
110
+ currentTier,
111
+ score,
112
+ });
113
+ }
114
+ scoredFiles.sort((a, b) => {
115
+ const scoreDiff = b.score - a.score;
116
+ if (scoreDiff !== 0)
117
+ return scoreDiff;
118
+ return a.info.path.localeCompare(b.info.path);
119
+ });
120
+ const suggestions = [];
121
+ let hotCount = 0;
122
+ for (const scored of scoredFiles) {
123
+ const { info, currentTier } = scored;
69
124
  let suggestedTier;
70
125
  let reason;
71
- if (MANDATORY_HOT.some(f => info.path.endsWith(f))) {
72
- suggestedTier = 'HOT';
73
- reason = 'Mandatory HOT file';
74
- }
75
- else if (info.isNewFile) {
76
- suggestedTier = 'HOT';
77
- reason = 'New/untracked file (active work)';
78
- }
79
- else if (info.daysSinceChange <= hotDays) {
126
+ if (hotCount < maxHotFiles && (isCanonicalHot(info.path) || scored.score >= 40)) {
80
127
  suggestedTier = 'HOT';
81
- reason = `Modified ${Math.round(info.daysSinceChange)} days ago`;
82
- }
83
- else if (info.daysSinceChange <= warmDays) {
84
- suggestedTier = 'WARM';
85
- reason = `Modified ${Math.round(info.daysSinceChange)} days ago`;
86
- }
87
- else if (info.daysSinceChange <= coldDays) {
88
- suggestedTier = 'WARM';
89
- reason = `Modified ${Math.round(info.daysSinceChange)} days ago (aging)`;
128
+ reason = isCanonicalHot(info.path)
129
+ ? 'Canonical HOT file'
130
+ : `High-value doc (score: ${scored.score})`;
131
+ hotCount++;
90
132
  }
91
133
  else {
92
- suggestedTier = 'COLD';
93
- reason = `No changes in ${Math.round(info.daysSinceChange)} days`;
134
+ const dirResult = getDirectoryBasedTier(info.path);
135
+ if (dirResult) {
136
+ suggestedTier = dirResult.tier;
137
+ reason = `Directory convention: ${dirResult.directory}`;
138
+ }
139
+ else if (info.daysSinceChange <= warmDays) {
140
+ suggestedTier = 'WARM';
141
+ reason = `Modified ${Math.round(info.daysSinceChange)} days ago`;
142
+ }
143
+ else if (info.daysSinceChange <= coldDays) {
144
+ suggestedTier = 'WARM';
145
+ reason = `Modified ${Math.round(info.daysSinceChange)} days ago (aging)`;
146
+ }
147
+ else {
148
+ suggestedTier = 'COLD';
149
+ reason = `No changes in ${Math.round(info.daysSinceChange)} days`;
150
+ }
94
151
  }
95
152
  let action;
96
153
  if (!currentTier) {
97
154
  action = 'CREATE';
98
155
  }
99
- else if (currentTier !== suggestedTier && options.force) {
156
+ else if (currentTier !== suggestedTier) {
100
157
  action = 'UPDATE';
101
158
  }
102
- else if (currentTier === suggestedTier) {
103
- action = 'SKIP';
104
- }
105
159
  else {
106
160
  action = 'SKIP';
107
161
  }
@@ -114,6 +168,25 @@ async function runAutoTier(options) {
114
168
  action,
115
169
  });
116
170
  }
171
+ for (const info of gitInfo) {
172
+ if (!info.isTracked)
173
+ continue;
174
+ const content = await readFile(info.path, 'utf-8');
175
+ const currentTier = readTierTag(content);
176
+ if (currentTier && !options.force) {
177
+ const alreadyAdded = suggestions.some(s => s.path === info.path);
178
+ if (!alreadyAdded) {
179
+ suggestions.push({
180
+ path: info.path,
181
+ currentTier,
182
+ suggestedTier: currentTier,
183
+ reason: 'Explicit tier tag (use --force to override)',
184
+ daysSinceChange: info.daysSinceChange,
185
+ action: 'SKIP',
186
+ });
187
+ }
188
+ }
189
+ }
117
190
  spinner.succeed(`Analyzed ${files.length} files`);
118
191
  printSuggestions(suggestions, options.verbose || false);
119
192
  if (!options.dryRun) {
@@ -121,8 +194,9 @@ async function runAutoTier(options) {
121
194
  }
122
195
  }
123
196
  function printSuggestions(suggestions, verbose) {
197
+ const toChange = suggestions.filter(s => s.action !== 'SKIP');
124
198
  const byTier = { HOT: [], WARM: [], COLD: [] };
125
- suggestions.forEach(s => byTier[s.suggestedTier].push(s));
199
+ toChange.forEach(s => byTier[s.suggestedTier].push(s));
126
200
  console.log(chalk.bold('\nšŸ“Š Tier Suggestions:\n'));
127
201
  console.log(chalk.red.bold(`šŸ”„ HOT (${byTier.HOT.length} files)`));
128
202
  byTier.HOT.slice(0, 10).forEach(s => {