agentsys 5.0.3 → 5.1.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 (264) hide show
  1. package/.claude-plugin/marketplace.json +21 -14
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/AGENTS.md +2 -1
  4. package/CHANGELOG.md +18 -0
  5. package/README.md +7 -6
  6. package/adapters/codex/skills/agnix/SKILL.md +0 -1
  7. package/adapters/codex/skills/audit-project/SKILL.md +0 -1
  8. package/adapters/codex/skills/audit-project-agents/SKILL.md +0 -1
  9. package/adapters/codex/skills/audit-project-github/SKILL.md +0 -1
  10. package/adapters/codex/skills/consult/SKILL.md +132 -57
  11. package/adapters/codex/skills/debate/SKILL.md +214 -0
  12. package/adapters/codex/skills/delivery-approval/SKILL.md +0 -1
  13. package/adapters/codex/skills/deslop/SKILL.md +0 -1
  14. package/adapters/codex/skills/drift-detect/SKILL.md +0 -1
  15. package/adapters/codex/skills/enhance/SKILL.md +0 -1
  16. package/adapters/codex/skills/learn/SKILL.md +0 -1
  17. package/adapters/codex/skills/next-task/SKILL.md +0 -1
  18. package/adapters/codex/skills/perf/SKILL.md +0 -1
  19. package/adapters/codex/skills/repo-map/SKILL.md +0 -1
  20. package/adapters/codex/skills/ship/SKILL.md +0 -1
  21. package/adapters/codex/skills/ship-ci-review-loop/SKILL.md +0 -1
  22. package/adapters/codex/skills/ship-deployment/SKILL.md +0 -1
  23. package/adapters/codex/skills/ship-error-handling/SKILL.md +0 -1
  24. package/adapters/codex/skills/sync-docs/SKILL.md +0 -1
  25. package/adapters/opencode/agents/agent-enhancer.md +0 -1
  26. package/adapters/opencode/agents/agnix-agent.md +0 -1
  27. package/adapters/opencode/agents/ci-fixer.md +0 -1
  28. package/adapters/opencode/agents/ci-monitor.md +0 -1
  29. package/adapters/opencode/agents/claudemd-enhancer.md +0 -1
  30. package/adapters/opencode/agents/consult-agent.md +122 -30
  31. package/adapters/opencode/agents/cross-file-enhancer.md +0 -1
  32. package/adapters/opencode/agents/debate-orchestrator.md +169 -0
  33. package/adapters/opencode/agents/delivery-validator.md +0 -1
  34. package/adapters/opencode/agents/deslop-agent.md +0 -1
  35. package/adapters/opencode/agents/docs-enhancer.md +0 -1
  36. package/adapters/opencode/agents/exploration-agent.md +0 -1
  37. package/adapters/opencode/agents/hooks-enhancer.md +0 -1
  38. package/adapters/opencode/agents/implementation-agent.md +0 -1
  39. package/adapters/opencode/agents/learn-agent.md +0 -1
  40. package/adapters/opencode/agents/map-validator.md +0 -1
  41. package/adapters/opencode/agents/perf-analyzer.md +0 -1
  42. package/adapters/opencode/agents/perf-code-paths.md +0 -1
  43. package/adapters/opencode/agents/perf-investigation-logger.md +0 -1
  44. package/adapters/opencode/agents/perf-orchestrator.md +0 -1
  45. package/adapters/opencode/agents/perf-theory-gatherer.md +0 -1
  46. package/adapters/opencode/agents/perf-theory-tester.md +0 -1
  47. package/adapters/opencode/agents/plan-synthesizer.md +0 -1
  48. package/adapters/opencode/agents/planning-agent.md +0 -1
  49. package/adapters/opencode/agents/plugin-enhancer.md +0 -1
  50. package/adapters/opencode/agents/prompt-enhancer.md +0 -1
  51. package/adapters/opencode/agents/simple-fixer.md +0 -1
  52. package/adapters/opencode/agents/skills-enhancer.md +0 -1
  53. package/adapters/opencode/agents/sync-docs-agent.md +0 -1
  54. package/adapters/opencode/agents/task-discoverer.md +0 -1
  55. package/adapters/opencode/agents/test-coverage-checker.md +0 -1
  56. package/adapters/opencode/agents/worktree-manager.md +0 -1
  57. package/adapters/opencode/commands/agnix.md +0 -1
  58. package/adapters/opencode/commands/audit-project-agents.md +0 -1
  59. package/adapters/opencode/commands/audit-project-github.md +0 -1
  60. package/adapters/opencode/commands/audit-project.md +0 -1
  61. package/adapters/opencode/commands/consult.md +133 -57
  62. package/adapters/opencode/commands/debate.md +224 -0
  63. package/adapters/opencode/commands/delivery-approval.md +0 -1
  64. package/adapters/opencode/commands/deslop.md +0 -1
  65. package/adapters/opencode/commands/drift-detect.md +0 -1
  66. package/adapters/opencode/commands/enhance.md +0 -1
  67. package/adapters/opencode/commands/learn.md +0 -1
  68. package/adapters/opencode/commands/next-task.md +0 -1
  69. package/adapters/opencode/commands/perf.md +0 -1
  70. package/adapters/opencode/commands/repo-map.md +0 -1
  71. package/adapters/opencode/commands/ship-ci-review-loop.md +0 -1
  72. package/adapters/opencode/commands/ship-deployment.md +0 -1
  73. package/adapters/opencode/commands/ship-error-handling.md +0 -1
  74. package/adapters/opencode/commands/ship.md +0 -1
  75. package/adapters/opencode/commands/sync-docs.md +0 -1
  76. package/adapters/opencode/skills/agnix/SKILL.md +1 -2
  77. package/adapters/opencode/skills/consult/SKILL.md +33 -23
  78. package/adapters/opencode/skills/debate/SKILL.md +245 -0
  79. package/adapters/opencode/skills/deslop/SKILL.md +1 -2
  80. package/adapters/opencode/skills/discover-tasks/SKILL.md +1 -2
  81. package/adapters/opencode/skills/drift-analysis/SKILL.md +1 -2
  82. package/adapters/opencode/skills/enhance-agent-prompts/SKILL.md +1 -2
  83. package/adapters/opencode/skills/enhance-claude-memory/SKILL.md +1 -2
  84. package/adapters/opencode/skills/enhance-cross-file/SKILL.md +1 -2
  85. package/adapters/opencode/skills/enhance-docs/SKILL.md +1 -2
  86. package/adapters/opencode/skills/enhance-hooks/SKILL.md +1 -2
  87. package/adapters/opencode/skills/enhance-orchestrator/SKILL.md +1 -2
  88. package/adapters/opencode/skills/enhance-plugins/SKILL.md +1 -2
  89. package/adapters/opencode/skills/enhance-prompts/SKILL.md +1 -2
  90. package/adapters/opencode/skills/enhance-skills/SKILL.md +1 -2
  91. package/adapters/opencode/skills/learn/SKILL.md +1 -2
  92. package/adapters/opencode/skills/orchestrate-review/SKILL.md +0 -1
  93. package/adapters/opencode/skills/perf-analyzer/SKILL.md +1 -2
  94. package/adapters/opencode/skills/perf-baseline-manager/SKILL.md +1 -2
  95. package/adapters/opencode/skills/perf-benchmarker/SKILL.md +1 -2
  96. package/adapters/opencode/skills/perf-code-paths/SKILL.md +1 -2
  97. package/adapters/opencode/skills/perf-investigation-logger/SKILL.md +1 -2
  98. package/adapters/opencode/skills/perf-profiler/SKILL.md +1 -2
  99. package/adapters/opencode/skills/perf-theory-gatherer/SKILL.md +1 -2
  100. package/adapters/opencode/skills/perf-theory-tester/SKILL.md +1 -2
  101. package/adapters/opencode/skills/repo-mapping/SKILL.md +1 -2
  102. package/adapters/opencode/skills/sync-docs/SKILL.md +1 -2
  103. package/adapters/opencode/skills/validate-delivery/SKILL.md +1 -2
  104. package/lib/adapter-transforms.js +24 -4
  105. package/package.json +1 -1
  106. package/plugins/agnix/.claude-plugin/plugin.json +1 -1
  107. package/plugins/agnix/skills/agnix/SKILL.md +1 -1
  108. package/plugins/audit-project/.claude-plugin/plugin.json +1 -1
  109. package/plugins/audit-project/lib/adapter-transforms.js +24 -4
  110. package/plugins/consult/.claude-plugin/plugin.json +1 -1
  111. package/plugins/consult/agents/consult-agent.md +122 -29
  112. package/plugins/consult/commands/consult.md +135 -58
  113. package/plugins/consult/skills/consult/SKILL.md +31 -20
  114. package/plugins/debate/.claude-plugin/plugin.json +21 -0
  115. package/plugins/debate/agents/debate-orchestrator.md +175 -0
  116. package/plugins/debate/commands/debate.md +221 -0
  117. package/plugins/debate/lib/adapter-transforms.js +298 -0
  118. package/plugins/debate/lib/collectors/codebase.js +392 -0
  119. package/plugins/debate/lib/collectors/docs-patterns.js +713 -0
  120. package/plugins/debate/lib/collectors/documentation.js +219 -0
  121. package/plugins/debate/lib/collectors/github.js +330 -0
  122. package/plugins/debate/lib/collectors/index.js +126 -0
  123. package/plugins/debate/lib/config/index.js +14 -0
  124. package/plugins/debate/lib/cross-platform/index.js +539 -0
  125. package/plugins/debate/lib/discovery/index.js +352 -0
  126. package/plugins/debate/lib/drift-detect/collectors.js +37 -0
  127. package/plugins/debate/lib/enhance/agent-analyzer.js +421 -0
  128. package/plugins/debate/lib/enhance/agent-patterns.js +571 -0
  129. package/plugins/debate/lib/enhance/auto-suppression.js +622 -0
  130. package/plugins/debate/lib/enhance/benchmark.js +417 -0
  131. package/plugins/debate/lib/enhance/cross-file-analyzer.js +930 -0
  132. package/plugins/debate/lib/enhance/cross-file-patterns.js +370 -0
  133. package/plugins/debate/lib/enhance/docs-analyzer.js +325 -0
  134. package/plugins/debate/lib/enhance/docs-patterns.js +671 -0
  135. package/plugins/debate/lib/enhance/fixer.js +721 -0
  136. package/plugins/debate/lib/enhance/hook-analyzer.js +135 -0
  137. package/plugins/debate/lib/enhance/hook-patterns.js +40 -0
  138. package/plugins/debate/lib/enhance/index.js +127 -0
  139. package/plugins/debate/lib/enhance/plugin-analyzer.js +402 -0
  140. package/plugins/debate/lib/enhance/plugin-patterns.js +326 -0
  141. package/plugins/debate/lib/enhance/projectmemory-analyzer.js +551 -0
  142. package/plugins/debate/lib/enhance/projectmemory-patterns.js +617 -0
  143. package/plugins/debate/lib/enhance/prompt-analyzer.js +457 -0
  144. package/plugins/debate/lib/enhance/prompt-patterns.js +1484 -0
  145. package/plugins/debate/lib/enhance/reporter.js +1348 -0
  146. package/plugins/debate/lib/enhance/security-patterns.js +284 -0
  147. package/plugins/debate/lib/enhance/skill-analyzer.js +182 -0
  148. package/plugins/debate/lib/enhance/skill-patterns.js +147 -0
  149. package/plugins/debate/lib/enhance/suppression.js +352 -0
  150. package/plugins/debate/lib/enhance/tool-patterns.js +373 -0
  151. package/plugins/debate/lib/index.js +270 -0
  152. package/plugins/debate/lib/patterns/cli-enhancers.js +611 -0
  153. package/plugins/debate/lib/patterns/pipeline.js +948 -0
  154. package/plugins/debate/lib/patterns/review-patterns.js +558 -0
  155. package/plugins/debate/lib/patterns/slop-analyzers.js +2305 -0
  156. package/plugins/debate/lib/patterns/slop-patterns.js +1187 -0
  157. package/plugins/debate/lib/perf/analyzer/index.js +22 -0
  158. package/plugins/debate/lib/perf/argument-parser.js +105 -0
  159. package/plugins/debate/lib/perf/baseline-comparator.js +50 -0
  160. package/plugins/debate/lib/perf/baseline-store.js +127 -0
  161. package/plugins/debate/lib/perf/benchmark-runner.js +404 -0
  162. package/plugins/debate/lib/perf/breaking-point-finder.js +52 -0
  163. package/plugins/debate/lib/perf/breaking-point-runner.js +60 -0
  164. package/plugins/debate/lib/perf/checkpoint.js +123 -0
  165. package/plugins/debate/lib/perf/code-paths.js +86 -0
  166. package/plugins/debate/lib/perf/consolidation.js +37 -0
  167. package/plugins/debate/lib/perf/constraint-runner.js +71 -0
  168. package/plugins/debate/lib/perf/experiment-runner.js +32 -0
  169. package/plugins/debate/lib/perf/index.js +41 -0
  170. package/plugins/debate/lib/perf/investigation-state.js +874 -0
  171. package/plugins/debate/lib/perf/optimization-runner.js +79 -0
  172. package/plugins/debate/lib/perf/profilers/go.js +22 -0
  173. package/plugins/debate/lib/perf/profilers/index.js +46 -0
  174. package/plugins/debate/lib/perf/profilers/java.js +23 -0
  175. package/plugins/debate/lib/perf/profilers/node.js +27 -0
  176. package/plugins/debate/lib/perf/profilers/python.js +23 -0
  177. package/plugins/debate/lib/perf/profilers/rust.js +23 -0
  178. package/plugins/debate/lib/perf/profiling-runner.js +75 -0
  179. package/plugins/debate/lib/perf/schemas.js +140 -0
  180. package/plugins/debate/lib/platform/detect-platform.js +413 -0
  181. package/plugins/debate/lib/platform/detection-configs.js +93 -0
  182. package/plugins/debate/lib/platform/state-dir.js +132 -0
  183. package/plugins/debate/lib/platform/verify-tools.js +182 -0
  184. package/plugins/debate/lib/repo-map/cache.js +152 -0
  185. package/plugins/debate/lib/repo-map/concurrency.js +29 -0
  186. package/plugins/debate/lib/repo-map/index.js +222 -0
  187. package/plugins/debate/lib/repo-map/installer.js +212 -0
  188. package/plugins/debate/lib/repo-map/queries/go.js +27 -0
  189. package/plugins/debate/lib/repo-map/queries/index.js +100 -0
  190. package/plugins/debate/lib/repo-map/queries/java.js +38 -0
  191. package/plugins/debate/lib/repo-map/queries/javascript.js +55 -0
  192. package/plugins/debate/lib/repo-map/queries/python.js +24 -0
  193. package/plugins/debate/lib/repo-map/queries/rust.js +73 -0
  194. package/plugins/debate/lib/repo-map/queries/typescript.js +38 -0
  195. package/plugins/debate/lib/repo-map/runner.js +1364 -0
  196. package/plugins/debate/lib/repo-map/updater.js +562 -0
  197. package/plugins/debate/lib/repo-map/usage-analyzer.js +407 -0
  198. package/plugins/debate/lib/schemas/plugin-manifest.schema.json +57 -0
  199. package/plugins/debate/lib/schemas/validator.js +247 -0
  200. package/plugins/debate/lib/sources/custom-handler.js +199 -0
  201. package/plugins/debate/lib/sources/policy-questions.js +246 -0
  202. package/plugins/debate/lib/sources/source-cache.js +165 -0
  203. package/plugins/debate/lib/state/workflow-state.js +576 -0
  204. package/plugins/debate/lib/types/agent-frontmatter.d.ts +134 -0
  205. package/plugins/debate/lib/types/command-frontmatter.d.ts +107 -0
  206. package/plugins/debate/lib/types/hook-frontmatter.d.ts +115 -0
  207. package/plugins/debate/lib/types/index.d.ts +84 -0
  208. package/plugins/debate/lib/types/plugin-manifest.d.ts +102 -0
  209. package/plugins/debate/lib/types/skill-frontmatter.d.ts +89 -0
  210. package/plugins/debate/lib/utils/atomic-write.js +94 -0
  211. package/plugins/debate/lib/utils/cache-manager.js +159 -0
  212. package/plugins/debate/lib/utils/command-parser.js +0 -0
  213. package/plugins/debate/lib/utils/context-optimizer.js +300 -0
  214. package/plugins/debate/lib/utils/deprecation.js +37 -0
  215. package/plugins/debate/lib/utils/shell-escape.js +88 -0
  216. package/plugins/debate/lib/utils/state-helpers.js +61 -0
  217. package/plugins/debate/skills/debate/SKILL.md +264 -0
  218. package/plugins/deslop/.claude-plugin/plugin.json +1 -1
  219. package/plugins/deslop/lib/adapter-transforms.js +24 -4
  220. package/plugins/deslop/skills/deslop/SKILL.md +1 -1
  221. package/plugins/drift-detect/.claude-plugin/plugin.json +1 -1
  222. package/plugins/drift-detect/lib/adapter-transforms.js +24 -4
  223. package/plugins/drift-detect/skills/drift-analysis/SKILL.md +1 -1
  224. package/plugins/enhance/.claude-plugin/plugin.json +1 -1
  225. package/plugins/enhance/lib/adapter-transforms.js +24 -4
  226. package/plugins/enhance/skills/enhance-agent-prompts/SKILL.md +1 -1
  227. package/plugins/enhance/skills/enhance-claude-memory/SKILL.md +1 -1
  228. package/plugins/enhance/skills/enhance-cross-file/SKILL.md +1 -1
  229. package/plugins/enhance/skills/enhance-docs/SKILL.md +1 -1
  230. package/plugins/enhance/skills/enhance-hooks/SKILL.md +1 -1
  231. package/plugins/enhance/skills/enhance-orchestrator/SKILL.md +1 -1
  232. package/plugins/enhance/skills/enhance-plugins/SKILL.md +1 -1
  233. package/plugins/enhance/skills/enhance-prompts/SKILL.md +1 -1
  234. package/plugins/enhance/skills/enhance-skills/SKILL.md +1 -1
  235. package/plugins/learn/.claude-plugin/plugin.json +1 -1
  236. package/plugins/learn/agents/learn-agent.md +1 -1
  237. package/plugins/learn/lib/adapter-transforms.js +24 -4
  238. package/plugins/learn/skills/learn/SKILL.md +1 -1
  239. package/plugins/next-task/.claude-plugin/plugin.json +1 -1
  240. package/plugins/next-task/agents/exploration-agent.md +1 -1
  241. package/plugins/next-task/lib/adapter-transforms.js +24 -4
  242. package/plugins/next-task/skills/discover-tasks/SKILL.md +1 -1
  243. package/plugins/next-task/skills/validate-delivery/SKILL.md +1 -1
  244. package/plugins/perf/.claude-plugin/plugin.json +1 -1
  245. package/plugins/perf/lib/adapter-transforms.js +24 -4
  246. package/plugins/perf/skills/perf-analyzer/SKILL.md +1 -1
  247. package/plugins/perf/skills/perf-baseline-manager/SKILL.md +1 -1
  248. package/plugins/perf/skills/perf-benchmarker/SKILL.md +1 -1
  249. package/plugins/perf/skills/perf-code-paths/SKILL.md +1 -1
  250. package/plugins/perf/skills/perf-investigation-logger/SKILL.md +1 -1
  251. package/plugins/perf/skills/perf-profiler/SKILL.md +1 -1
  252. package/plugins/perf/skills/perf-theory-gatherer/SKILL.md +1 -1
  253. package/plugins/perf/skills/perf-theory-tester/SKILL.md +1 -1
  254. package/plugins/repo-map/.claude-plugin/plugin.json +1 -1
  255. package/plugins/repo-map/lib/adapter-transforms.js +24 -4
  256. package/plugins/ship/.claude-plugin/plugin.json +1 -1
  257. package/plugins/ship/lib/adapter-transforms.js +24 -4
  258. package/plugins/sync-docs/.claude-plugin/plugin.json +1 -1
  259. package/plugins/sync-docs/lib/adapter-transforms.js +24 -4
  260. package/plugins/sync-docs/skills/sync-docs/SKILL.md +1 -1
  261. package/scripts/gen-adapters.js +6 -7
  262. package/scripts/generate-docs.js +4 -2
  263. package/scripts/plugins.txt +1 -0
  264. package/site/content.json +6 -6
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Cache Manager
3
+ * Centralized caching abstraction with TTL and size limits
4
+ *
5
+ * @module lib/utils/cache-manager
6
+ * @author Avi Fenesh
7
+ * @license MIT
8
+ */
9
+
10
+ /**
11
+ * Cache manager with TTL and size limits
12
+ */
13
+ class CacheManager {
14
+ /**
15
+ * Create a new cache manager
16
+ * @param {Object} options - Cache configuration
17
+ * @param {number} options.maxSize - Maximum number of entries (default: 100)
18
+ * @param {number} options.ttl - Time-to-live in milliseconds (default: 60000)
19
+ * @param {number} options.maxValueSize - Maximum size per value in bytes (default: null - unlimited)
20
+ */
21
+ constructor(options = {}) {
22
+ this.maxSize = options.maxSize || 100;
23
+ this.ttl = options.ttl || 60000; // 1 minute default
24
+ this.maxValueSize = options.maxValueSize || null;
25
+
26
+ // Use Map for insertion-order guarantee (FIFO eviction)
27
+ this._cache = new Map();
28
+ this._timestamps = new Map();
29
+ }
30
+
31
+ /**
32
+ * Get a value from cache
33
+ * @param {string} key - Cache key
34
+ * @returns {*} Cached value or undefined if not found/expired
35
+ */
36
+ get(key) {
37
+ if (!this._cache.has(key)) {
38
+ return undefined;
39
+ }
40
+
41
+ // Check if expired
42
+ const timestamp = this._timestamps.get(key);
43
+ if (Date.now() - timestamp > this.ttl) {
44
+ this.delete(key);
45
+ return undefined;
46
+ }
47
+
48
+ return this._cache.get(key);
49
+ }
50
+
51
+ /**
52
+ * Set a value in cache
53
+ * @param {string} key - Cache key
54
+ * @param {*} value - Value to cache
55
+ * @returns {boolean} True if cached, false if value too large
56
+ */
57
+ set(key, value) {
58
+ // Check value size if limit set
59
+ if (this.maxValueSize !== null && typeof value === 'string') {
60
+ if (value.length > this.maxValueSize) {
61
+ return false; // Value too large, don't cache
62
+ }
63
+ }
64
+
65
+ // Update or add entry
66
+ this._cache.set(key, value);
67
+ this._timestamps.set(key, Date.now());
68
+
69
+ // Enforce size limit with FIFO eviction
70
+ this._enforceMaxSize();
71
+
72
+ return true;
73
+ }
74
+
75
+ /**
76
+ * Check if key exists and is not expired
77
+ * @param {string} key - Cache key
78
+ * @returns {boolean} True if key exists and is valid
79
+ */
80
+ has(key) {
81
+ return this.get(key) !== undefined;
82
+ }
83
+
84
+ /**
85
+ * Delete a key from cache
86
+ * @param {string} key - Cache key
87
+ * @returns {boolean} True if key existed
88
+ */
89
+ delete(key) {
90
+ this._timestamps.delete(key);
91
+ return this._cache.delete(key);
92
+ }
93
+
94
+ /**
95
+ * Clear all cache entries
96
+ */
97
+ clear() {
98
+ this._cache.clear();
99
+ this._timestamps.clear();
100
+ }
101
+
102
+ /**
103
+ * Get current cache size
104
+ * @returns {number} Number of entries
105
+ */
106
+ get size() {
107
+ return this._cache.size;
108
+ }
109
+
110
+ /**
111
+ * Get cache statistics
112
+ * @returns {Object} Stats object with size, ttl, maxSize
113
+ */
114
+ getStats() {
115
+ return {
116
+ size: this._cache.size,
117
+ maxSize: this.maxSize,
118
+ ttl: this.ttl,
119
+ maxValueSize: this.maxValueSize
120
+ };
121
+ }
122
+
123
+ /**
124
+ * Enforce maximum cache size using FIFO eviction
125
+ * @private
126
+ */
127
+ _enforceMaxSize() {
128
+ // Only evict if cache exceeds limit
129
+ if (this._cache.size <= this.maxSize) {
130
+ return;
131
+ }
132
+
133
+ // Map maintains insertion order - first key is oldest
134
+ while (this._cache.size > this.maxSize) {
135
+ const firstKey = this._cache.keys().next().value;
136
+ this.delete(firstKey);
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Remove expired entries (useful for long-running processes)
142
+ * @returns {number} Number of entries removed
143
+ */
144
+ prune() {
145
+ let removed = 0;
146
+ const now = Date.now();
147
+
148
+ for (const [key, timestamp] of this._timestamps.entries()) {
149
+ if (now - timestamp > this.ttl) {
150
+ this.delete(key);
151
+ removed++;
152
+ }
153
+ }
154
+
155
+ return removed;
156
+ }
157
+ }
158
+
159
+ module.exports = { CacheManager };
@@ -0,0 +1,300 @@
1
+ /**
2
+ * Context Optimizer Utilities
3
+ * Provides optimized git commands to minimize token usage while gathering context
4
+ *
5
+ * Target: Keep command execution under 50k tokens
6
+ *
7
+ * @author Avi Fenesh
8
+ * @license MIT
9
+ */
10
+
11
+ const {
12
+ escapeShell,
13
+ escapeSingleQuotes,
14
+ sanitizeExtension
15
+ } = require('./shell-escape');
16
+
17
+ /**
18
+ * Validate git branch name to prevent command injection
19
+ * @param {string} branch - Branch name to validate
20
+ * @returns {string} Validated branch name
21
+ * @throws {Error} If branch name contains invalid characters
22
+ */
23
+ function validateBranchName(branch) {
24
+ if (typeof branch !== 'string' || branch.length === 0) {
25
+ throw new Error('Branch name must be a non-empty string');
26
+ }
27
+ if (branch.length > 255) {
28
+ throw new Error('Branch name too long (max 255 characters)');
29
+ }
30
+ // Allow alphanumeric, underscore, hyphen, forward slash, and dot
31
+ if (!/^[a-zA-Z0-9/_.-]+$/.test(branch)) {
32
+ throw new Error('Branch name contains invalid characters');
33
+ }
34
+ // Prevent git option injection
35
+ if (branch.startsWith('-')) {
36
+ throw new Error('Branch name cannot start with hyphen');
37
+ }
38
+ return branch;
39
+ }
40
+
41
+ /**
42
+ * Validate git reference to prevent command injection
43
+ * @param {string} ref - Git reference to validate
44
+ * @returns {string} Validated reference
45
+ * @throws {Error} If reference contains invalid characters
46
+ */
47
+ function validateGitRef(ref) {
48
+ if (typeof ref !== 'string' || ref.length === 0) {
49
+ throw new Error('Git reference must be a non-empty string');
50
+ }
51
+ if (ref.length > 255) {
52
+ throw new Error('Git reference too long (max 255 characters)');
53
+ }
54
+ // Allow alphanumeric, tilde, caret, dot, hyphen, underscore, forward slash
55
+ if (!/^[a-zA-Z0-9~^._/-]+$/.test(ref)) {
56
+ throw new Error('Git reference contains invalid characters');
57
+ }
58
+ // Prevent git option injection
59
+ if (ref.startsWith('-')) {
60
+ throw new Error('Git reference cannot start with hyphen');
61
+ }
62
+ return ref;
63
+ }
64
+
65
+ /**
66
+ * Validate numeric limit parameter
67
+ * @param {number} limit - Limit value to validate
68
+ * @param {number} max - Maximum allowed value (default: 1000)
69
+ * @returns {number} Validated limit
70
+ * @throws {Error} If limit is invalid
71
+ */
72
+ function validateLimit(limit, max = 1000) {
73
+ // Strict type check - must be number or numeric string
74
+ if (typeof limit === 'string') {
75
+ // Only allow pure numeric strings
76
+ if (!/^\d+$/.test(limit)) {
77
+ throw new Error('Limit must be a positive integer');
78
+ }
79
+ }
80
+ const num = typeof limit === 'number' ? limit : parseInt(limit, 10);
81
+ if (!Number.isInteger(num) || num < 1) {
82
+ throw new Error('Limit must be a positive integer');
83
+ }
84
+ if (num > max) {
85
+ throw new Error(`Limit cannot exceed ${max}`);
86
+ }
87
+ return num;
88
+ }
89
+
90
+ /**
91
+ * Git command optimization utilities for context efficiency
92
+ */
93
+ const contextOptimizer = {
94
+ /**
95
+ * Get recent commits with minimal formatting
96
+ * @param {number} limit - Number of commits to retrieve (default: 10)
97
+ * @returns {string} Git command
98
+ */
99
+ recentCommits: (limit = 10) => {
100
+ const safeLimit = validateLimit(limit);
101
+ return `git log --oneline --no-decorate -${safeLimit} --format="%h %s"`;
102
+ },
103
+
104
+ /**
105
+ * Get compact git status (untracked files excluded)
106
+ * @returns {string} Git command
107
+ */
108
+ compactStatus: () =>
109
+ 'git status -uno --porcelain',
110
+
111
+ /**
112
+ * Get file changes between refs
113
+ * @param {string} ref - Reference to compare from (default: 'HEAD~5')
114
+ * @returns {string} Git command
115
+ */
116
+ fileChanges: (ref = 'HEAD~5') => {
117
+ const safeRef = validateGitRef(ref);
118
+ return `git diff ${safeRef}..HEAD --name-status`;
119
+ },
120
+
121
+ /**
122
+ * Get current branch name
123
+ * @returns {string} Git command
124
+ */
125
+ currentBranch: () =>
126
+ 'git branch --show-current',
127
+
128
+ /**
129
+ * Get remote information (limited to 2 lines)
130
+ * @returns {string} Git command
131
+ */
132
+ remoteInfo: () =>
133
+ 'git remote -v | head -2',
134
+
135
+ /**
136
+ * Check if there are stashed changes
137
+ * @returns {string} Git command
138
+ */
139
+ hasStashes: () =>
140
+ 'git stash list --oneline | wc -l',
141
+
142
+ /**
143
+ * Get worktree list in porcelain format
144
+ * @returns {string} Git command
145
+ */
146
+ worktreeList: () =>
147
+ 'git worktree list --porcelain',
148
+
149
+ /**
150
+ * Get the age of a specific line (for TODO checking)
151
+ * @param {string} file - File path
152
+ * @param {number} line - Line number
153
+ * @returns {string} Git command
154
+ */
155
+ lineAge: (file, line) => {
156
+ // Validate line is a positive integer with reasonable bounds
157
+ const lineNum = parseInt(line, 10);
158
+ const MAX_LINE_NUMBER = 10000000; // 10 million lines - reasonable upper bound
159
+ if (!Number.isInteger(lineNum) || lineNum < 1) {
160
+ throw new Error('Line must be a positive integer');
161
+ }
162
+ if (lineNum > MAX_LINE_NUMBER) {
163
+ throw new Error(`Line number cannot exceed ${MAX_LINE_NUMBER}`);
164
+ }
165
+ // Escape file path for safe shell usage
166
+ const safeFile = escapeShell(file);
167
+ return `git blame -L ${lineNum},${lineNum} "${safeFile}" --porcelain | grep '^committer-time' | cut -d' ' -f2`;
168
+ },
169
+
170
+ /**
171
+ * Find source files by extension
172
+ * @param {string} extension - File extension (e.g., 'ts', 'py', 'rs')
173
+ * @returns {string} Git command
174
+ */
175
+ findSourceFiles: (extension = 'ts') => {
176
+ const safeExt = sanitizeExtension(extension);
177
+ return `git ls-files | grep '\\.${safeExt}$'`;
178
+ },
179
+
180
+ /**
181
+ * Get diff stat summary
182
+ * @param {string} ref - Reference to compare from (default: 'HEAD~5')
183
+ * @returns {string} Git command
184
+ */
185
+ diffStat: (ref = 'HEAD~5') => {
186
+ const safeRef = validateGitRef(ref);
187
+ return `git diff ${safeRef}..HEAD --stat | head -20`;
188
+ },
189
+
190
+ /**
191
+ * Get contributors list (limited to top 10)
192
+ * @returns {string} Git command
193
+ */
194
+ contributors: () =>
195
+ 'git shortlog -sn --no-merges | head -10',
196
+
197
+ /**
198
+ * Get last commit message
199
+ * @returns {string} Git command
200
+ */
201
+ lastCommitMessage: () =>
202
+ 'git log -1 --format=%s',
203
+
204
+ /**
205
+ * Get files changed in last commit
206
+ * @returns {string} Git command
207
+ */
208
+ lastCommitFiles: () =>
209
+ 'git diff-tree --no-commit-id --name-only -r HEAD',
210
+
211
+ /**
212
+ * Get branch list (local only, limited)
213
+ * @param {number} limit - Number of branches (default: 10)
214
+ * @returns {string} Git command
215
+ */
216
+ branches: (limit = 10) => {
217
+ const safeLimit = validateLimit(limit);
218
+ return `git branch --format='%(refname:short)' | head -${safeLimit}`;
219
+ },
220
+
221
+ /**
222
+ * Get tags list (limited)
223
+ * @param {number} limit - Number of tags (default: 10)
224
+ * @returns {string} Git command
225
+ */
226
+ tags: (limit = 10) => {
227
+ const safeLimit = validateLimit(limit);
228
+ return `git tag --sort=-creatordate | head -${safeLimit}`;
229
+ },
230
+
231
+ /**
232
+ * Get count of commits on current branch since branching from main
233
+ * @param {string} mainBranch - Main branch name (default: 'main')
234
+ * @returns {string} Git command
235
+ */
236
+ commitsSinceBranch: (mainBranch = 'main') => {
237
+ const safeBranch = validateBranchName(mainBranch);
238
+ return `git rev-list --count ${safeBranch}..HEAD`;
239
+ },
240
+
241
+ /**
242
+ * Check if working directory is clean
243
+ * @returns {string} Git command
244
+ */
245
+ isClean: () =>
246
+ 'git status --porcelain | wc -l',
247
+
248
+ /**
249
+ * Get merge base with main branch
250
+ * @param {string} mainBranch - Main branch name (default: 'main')
251
+ * @returns {string} Git command
252
+ */
253
+ mergeBase: (mainBranch = 'main') => {
254
+ const safeBranch = validateBranchName(mainBranch);
255
+ return `git merge-base ${safeBranch} HEAD`;
256
+ },
257
+
258
+ /**
259
+ * Get files modified in current branch (since branching)
260
+ * @param {string} mainBranch - Main branch name (default: 'main')
261
+ * @returns {string} Git command
262
+ */
263
+ branchChangedFiles: (mainBranch = 'main') => {
264
+ const safeBranch = validateBranchName(mainBranch);
265
+ return `git diff ${safeBranch}...HEAD --name-only`;
266
+ },
267
+
268
+ /**
269
+ * Get commit count by author
270
+ * @param {string} author - Author name or email
271
+ * @returns {string} Git command
272
+ */
273
+ authorCommitCount: (author) => {
274
+ const safeAuthor = escapeShell(author);
275
+ return `git log --author="${safeAuthor}" --oneline | wc -l`;
276
+ },
277
+
278
+ /**
279
+ * Check if file exists in repository
280
+ * @param {string} file - File path
281
+ * @returns {string} Git command
282
+ */
283
+ fileExists: (file) => {
284
+ const safeFile = escapeSingleQuotes(file);
285
+ return `git ls-files | grep -q '${safeFile}' && echo 'true' || echo 'false'`;
286
+ }
287
+ };
288
+
289
+ // Export main API
290
+ module.exports = contextOptimizer;
291
+
292
+ // Export internal functions for testing
293
+ module.exports._internal = {
294
+ escapeShell,
295
+ escapeSingleQuotes,
296
+ sanitizeExtension,
297
+ validateBranchName,
298
+ validateGitRef,
299
+ validateLimit
300
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Deprecation Warning Utility
3
+ * Centralized utility for handling deprecation warnings across the codebase
4
+ *
5
+ * @author Avi Fenesh
6
+ * @license MIT
7
+ */
8
+
9
+ // Track which functions have already shown deprecation warnings (once per function)
10
+ const _deprecationWarned = new Set();
11
+
12
+ /**
13
+ * Show deprecation warning for sync functions (once per function name)
14
+ * @param {string} funcName - Name of the deprecated sync function
15
+ * @param {string} asyncAlt - Name of the async alternative
16
+ */
17
+ function warnDeprecation(funcName, asyncAlt) {
18
+ if (_deprecationWarned.has(funcName)) return;
19
+ _deprecationWarned.add(funcName);
20
+ console.warn(
21
+ `DEPRECATED: ${funcName}() is synchronous and blocks the event loop. ` +
22
+ `Use ${asyncAlt}() instead. Will be removed in v3.0.0.`
23
+ );
24
+ }
25
+
26
+ /**
27
+ * Reset deprecation warnings (for testing only)
28
+ * @private
29
+ */
30
+ function _resetDeprecationWarnings() {
31
+ _deprecationWarned.clear();
32
+ }
33
+
34
+ module.exports = {
35
+ warnDeprecation,
36
+ _resetDeprecationWarnings
37
+ };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Shell Escaping Utilities
3
+ * Centralized string escaping functions for safe shell command construction
4
+ *
5
+ * @module lib/utils/shell-escape
6
+ * @author Avi Fenesh
7
+ * @license MIT
8
+ */
9
+
10
+ /**
11
+ * Escape shell special characters for safe command interpolation
12
+ * Handles all dangerous shell metacharacters including command injection vectors
13
+ * Optimized: uses single regex test instead of multiple .includes() calls
14
+ * @param {string} str - String to escape
15
+ * @returns {string} Escaped string safe for shell use
16
+ * @throws {Error} If string contains null bytes or newlines
17
+ */
18
+ function escapeShell(str) {
19
+ if (typeof str !== 'string') return '';
20
+
21
+ // Reject null bytes and newlines which could be used for injection
22
+ // Optimized: single regex test instead of 3 separate .includes() scans
23
+ // Use \x00 instead of \0 for better portability across JS engines
24
+ if (/[\x00\n\r]/.test(str)) {
25
+ throw new Error('Input contains invalid characters (null bytes or newlines)');
26
+ }
27
+
28
+ // Escape all shell metacharacters: " $ ` \ ! ; | & > < ( ) { } [ ] * ? ~ # ' space tab
29
+ return str.replace(/["\$`\\!;|&><(){}[\]*?~#'\s]/g, '\\$&');
30
+ }
31
+
32
+ /**
33
+ * Escape single quotes for shell (replace ' with '\''
34
+ * Use this for strings that will be wrapped in single quotes
35
+ * @param {string} str - String to escape
36
+ * @returns {string} Escaped string safe for single-quoted shell use
37
+ */
38
+ function escapeSingleQuotes(str) {
39
+ if (typeof str !== 'string') return '';
40
+ return str.replace(/'/g, "'\\''");
41
+ }
42
+
43
+ /**
44
+ * Validate and sanitize file extension
45
+ * Removes all non-alphanumeric characters
46
+ * @param {string} ext - Extension to validate
47
+ * @returns {string} Safe extension (alphanumeric only), defaults to 'ts' if empty
48
+ */
49
+ function sanitizeExtension(ext) {
50
+ if (typeof ext !== 'string') return 'ts';
51
+ const safe = ext.replace(/[^a-zA-Z0-9]/g, '');
52
+ return safe || 'ts';
53
+ }
54
+
55
+ /**
56
+ * Escape a string for use in a double-quoted shell context
57
+ * More permissive than escapeShell but still safe
58
+ * @param {string} str - String to escape
59
+ * @returns {string} Escaped string safe for double-quoted shell use
60
+ */
61
+ function escapeDoubleQuotes(str) {
62
+ if (typeof str !== 'string') return '';
63
+
64
+ // In double quotes, we need to escape: $ ` " \ and newlines
65
+ return str.replace(/[$`"\\\n]/g, '\\$&');
66
+ }
67
+
68
+ /**
69
+ * Quote a string for safe shell use
70
+ * Wraps in single quotes and escapes any embedded single quotes
71
+ * This is often safer than escapeShell for complex strings
72
+ * @param {string} str - String to quote
73
+ * @returns {string} Safely quoted string
74
+ */
75
+ function quoteShell(str) {
76
+ if (typeof str !== 'string') return "''";
77
+
78
+ // Wrap in single quotes and escape any embedded single quotes
79
+ return "'" + str.replace(/'/g, "'\\''") + "'";
80
+ }
81
+
82
+ module.exports = {
83
+ escapeShell,
84
+ escapeSingleQuotes,
85
+ sanitizeExtension,
86
+ escapeDoubleQuotes,
87
+ quoteShell
88
+ };
@@ -0,0 +1,61 @@
1
+ 'use strict';
2
+
3
+ const { isDeepStrictEqual } = require('util');
4
+
5
+ const RETRY_SLEEP_STATE = typeof SharedArrayBuffer === 'function' && typeof Atomics === 'object' && typeof Atomics.wait === 'function'
6
+ ? new Int32Array(new SharedArrayBuffer(4))
7
+ : null;
8
+
9
+ function isPlainObject(value) {
10
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
11
+ }
12
+
13
+ function hasUpdatedSubset(target, subset) {
14
+ if (!isPlainObject(subset)) {
15
+ return isDeepStrictEqual(target, subset);
16
+ }
17
+ if (!isPlainObject(target)) {
18
+ return false;
19
+ }
20
+
21
+ for (const [key, value] of Object.entries(subset)) {
22
+ if (!hasUpdatedSubset(target[key], value)) {
23
+ return false;
24
+ }
25
+ }
26
+ return true;
27
+ }
28
+
29
+ function updatesApplied(state, updates) {
30
+ if (!state) return false;
31
+
32
+ for (const [key, value] of Object.entries(updates || {})) {
33
+ if (key === '_version') continue;
34
+ if (!hasUpdatedSubset(state[key], value)) {
35
+ return false;
36
+ }
37
+ }
38
+
39
+ return true;
40
+ }
41
+
42
+ function sleepForRetry(ms) {
43
+ if (!Number.isFinite(ms) || ms <= 0) {
44
+ return;
45
+ }
46
+
47
+ const delayMs = Math.floor(ms);
48
+ if (RETRY_SLEEP_STATE) {
49
+ try {
50
+ Atomics.wait(RETRY_SLEEP_STATE, 0, 0, delayMs);
51
+ } catch {
52
+ // Ignore environments where Atomics.wait exists but cannot be used.
53
+ }
54
+ }
55
+ }
56
+
57
+ module.exports = {
58
+ isPlainObject,
59
+ updatesApplied,
60
+ sleepForRetry
61
+ };