@bhimudev/gnanai 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/README.md +270 -0
  2. package/dist/bin/cli.d.ts +3 -0
  3. package/dist/bin/cli.d.ts.map +1 -0
  4. package/dist/bin/cli.js +188 -0
  5. package/dist/bin/cli.js.map +1 -0
  6. package/dist/commands/cleanup.d.ts +21 -0
  7. package/dist/commands/cleanup.d.ts.map +1 -0
  8. package/dist/commands/cleanup.js +380 -0
  9. package/dist/commands/cleanup.js.map +1 -0
  10. package/dist/commands/dispatch.d.ts +13 -0
  11. package/dist/commands/dispatch.d.ts.map +1 -0
  12. package/dist/commands/dispatch.js +85 -0
  13. package/dist/commands/dispatch.js.map +1 -0
  14. package/dist/commands/doctor.d.ts +2 -0
  15. package/dist/commands/doctor.d.ts.map +1 -0
  16. package/dist/commands/doctor.js +155 -0
  17. package/dist/commands/doctor.js.map +1 -0
  18. package/dist/commands/generate.d.ts +3 -0
  19. package/dist/commands/generate.d.ts.map +1 -0
  20. package/dist/commands/generate.js +167 -0
  21. package/dist/commands/generate.js.map +1 -0
  22. package/dist/commands/init.d.ts +10 -0
  23. package/dist/commands/init.d.ts.map +1 -0
  24. package/dist/commands/init.js +711 -0
  25. package/dist/commands/init.js.map +1 -0
  26. package/dist/commands/knowledge-sync.d.ts +69 -0
  27. package/dist/commands/knowledge-sync.d.ts.map +1 -0
  28. package/dist/commands/knowledge-sync.js +661 -0
  29. package/dist/commands/knowledge-sync.js.map +1 -0
  30. package/dist/commands/knowledge.d.ts +35 -0
  31. package/dist/commands/knowledge.d.ts.map +1 -0
  32. package/dist/commands/knowledge.js +254 -0
  33. package/dist/commands/knowledge.js.map +1 -0
  34. package/dist/commands/rollback.d.ts +13 -0
  35. package/dist/commands/rollback.d.ts.map +1 -0
  36. package/dist/commands/rollback.js +186 -0
  37. package/dist/commands/rollback.js.map +1 -0
  38. package/dist/commands/setup-config.d.ts +6 -0
  39. package/dist/commands/setup-config.d.ts.map +1 -0
  40. package/dist/commands/setup-config.js +663 -0
  41. package/dist/commands/setup-config.js.map +1 -0
  42. package/dist/commands/setup-project.d.ts +6 -0
  43. package/dist/commands/setup-project.d.ts.map +1 -0
  44. package/dist/commands/setup-project.js +361 -0
  45. package/dist/commands/setup-project.js.map +1 -0
  46. package/dist/commands/setup.d.ts +3 -0
  47. package/dist/commands/setup.d.ts.map +1 -0
  48. package/dist/commands/setup.js +293 -0
  49. package/dist/commands/setup.js.map +1 -0
  50. package/dist/commands/status.d.ts +51 -0
  51. package/dist/commands/status.d.ts.map +1 -0
  52. package/dist/commands/status.js +182 -0
  53. package/dist/commands/status.js.map +1 -0
  54. package/dist/commands/uninstall.d.ts +3 -0
  55. package/dist/commands/uninstall.d.ts.map +1 -0
  56. package/dist/commands/uninstall.js +173 -0
  57. package/dist/commands/uninstall.js.map +1 -0
  58. package/dist/commands/update.d.ts +10 -0
  59. package/dist/commands/update.d.ts.map +1 -0
  60. package/dist/commands/update.js +435 -0
  61. package/dist/commands/update.js.map +1 -0
  62. package/dist/commands/worktree.d.ts +30 -0
  63. package/dist/commands/worktree.d.ts.map +1 -0
  64. package/dist/commands/worktree.js +262 -0
  65. package/dist/commands/worktree.js.map +1 -0
  66. package/dist/generator/claude-cli.d.ts +24 -0
  67. package/dist/generator/claude-cli.d.ts.map +1 -0
  68. package/dist/generator/claude-cli.js +239 -0
  69. package/dist/generator/claude-cli.js.map +1 -0
  70. package/dist/generator/prompt-builder.d.ts +7 -0
  71. package/dist/generator/prompt-builder.d.ts.map +1 -0
  72. package/dist/generator/prompt-builder.js +144 -0
  73. package/dist/generator/prompt-builder.js.map +1 -0
  74. package/dist/index.d.ts +36 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +45 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/mcp/embeddings.d.ts +53 -0
  79. package/dist/mcp/embeddings.d.ts.map +1 -0
  80. package/dist/mcp/embeddings.js +68 -0
  81. package/dist/mcp/embeddings.js.map +1 -0
  82. package/dist/mcp/hybrid-search.d.ts +25 -0
  83. package/dist/mcp/hybrid-search.d.ts.map +1 -0
  84. package/dist/mcp/hybrid-search.js +72 -0
  85. package/dist/mcp/hybrid-search.js.map +1 -0
  86. package/dist/mcp/knowledge-server.d.ts +4 -0
  87. package/dist/mcp/knowledge-server.d.ts.map +1 -0
  88. package/dist/mcp/knowledge-server.js +294 -0
  89. package/dist/mcp/knowledge-server.js.map +1 -0
  90. package/dist/mcp/knowledge-utils.d.ts +65 -0
  91. package/dist/mcp/knowledge-utils.d.ts.map +1 -0
  92. package/dist/mcp/knowledge-utils.js +207 -0
  93. package/dist/mcp/knowledge-utils.js.map +1 -0
  94. package/dist/mcp/search-factory.d.ts +9 -0
  95. package/dist/mcp/search-factory.d.ts.map +1 -0
  96. package/dist/mcp/search-factory.js +23 -0
  97. package/dist/mcp/search-factory.js.map +1 -0
  98. package/dist/mcp/search-index.d.ts +45 -0
  99. package/dist/mcp/search-index.d.ts.map +1 -0
  100. package/dist/mcp/search-index.js +2 -0
  101. package/dist/mcp/search-index.js.map +1 -0
  102. package/dist/mcp/search-minisearch.d.ts +46 -0
  103. package/dist/mcp/search-minisearch.d.ts.map +1 -0
  104. package/dist/mcp/search-minisearch.js +99 -0
  105. package/dist/mcp/search-minisearch.js.map +1 -0
  106. package/dist/mcp/search-sqlite.d.ts +30 -0
  107. package/dist/mcp/search-sqlite.d.ts.map +1 -0
  108. package/dist/mcp/search-sqlite.js +188 -0
  109. package/dist/mcp/search-sqlite.js.map +1 -0
  110. package/dist/mcp/vector-store.d.ts +52 -0
  111. package/dist/mcp/vector-store.d.ts.map +1 -0
  112. package/dist/mcp/vector-store.js +183 -0
  113. package/dist/mcp/vector-store.js.map +1 -0
  114. package/dist/scaffold/copy-core-agents.d.ts +2 -0
  115. package/dist/scaffold/copy-core-agents.d.ts.map +1 -0
  116. package/dist/scaffold/copy-core-agents.js +90 -0
  117. package/dist/scaffold/copy-core-agents.js.map +1 -0
  118. package/dist/scaffold/create-claude-settings.d.ts +40 -0
  119. package/dist/scaffold/create-claude-settings.d.ts.map +1 -0
  120. package/dist/scaffold/create-claude-settings.js +422 -0
  121. package/dist/scaffold/create-claude-settings.js.map +1 -0
  122. package/dist/scaffold/create-config.d.ts +14 -0
  123. package/dist/scaffold/create-config.d.ts.map +1 -0
  124. package/dist/scaffold/create-config.js +199 -0
  125. package/dist/scaffold/create-config.js.map +1 -0
  126. package/dist/scaffold/create-project-description.d.ts +12 -0
  127. package/dist/scaffold/create-project-description.d.ts.map +1 -0
  128. package/dist/scaffold/create-project-description.js +104 -0
  129. package/dist/scaffold/create-project-description.js.map +1 -0
  130. package/dist/scaffold/create-structure.d.ts +2 -0
  131. package/dist/scaffold/create-structure.d.ts.map +1 -0
  132. package/dist/scaffold/create-structure.js +146 -0
  133. package/dist/scaffold/create-structure.js.map +1 -0
  134. package/dist/types/dependency-analysis.d.ts +11 -0
  135. package/dist/types/dependency-analysis.d.ts.map +1 -0
  136. package/dist/types/dependency-analysis.js +2 -0
  137. package/dist/types/dependency-analysis.js.map +1 -0
  138. package/dist/types/index.d.ts +526 -0
  139. package/dist/types/index.d.ts.map +1 -0
  140. package/dist/types/index.js +3 -0
  141. package/dist/types/index.js.map +1 -0
  142. package/dist/types/task.d.ts +25 -0
  143. package/dist/types/task.d.ts.map +1 -0
  144. package/dist/types/task.js +3 -0
  145. package/dist/types/task.js.map +1 -0
  146. package/dist/utils/analyze-files.d.ts +7 -0
  147. package/dist/utils/analyze-files.d.ts.map +1 -0
  148. package/dist/utils/analyze-files.js +27 -0
  149. package/dist/utils/analyze-files.js.map +1 -0
  150. package/dist/utils/backup.d.ts +102 -0
  151. package/dist/utils/backup.d.ts.map +1 -0
  152. package/dist/utils/backup.js +352 -0
  153. package/dist/utils/backup.js.map +1 -0
  154. package/dist/utils/ci-provider.d.ts +23 -0
  155. package/dist/utils/ci-provider.d.ts.map +1 -0
  156. package/dist/utils/ci-provider.js +525 -0
  157. package/dist/utils/ci-provider.js.map +1 -0
  158. package/dist/utils/ci-status.d.ts +57 -0
  159. package/dist/utils/ci-status.d.ts.map +1 -0
  160. package/dist/utils/ci-status.js +349 -0
  161. package/dist/utils/ci-status.js.map +1 -0
  162. package/dist/utils/dependency-analysis.d.ts +34 -0
  163. package/dist/utils/dependency-analysis.d.ts.map +1 -0
  164. package/dist/utils/dependency-analysis.js +298 -0
  165. package/dist/utils/dependency-analysis.js.map +1 -0
  166. package/dist/utils/detect-git.d.ts +57 -0
  167. package/dist/utils/detect-git.d.ts.map +1 -0
  168. package/dist/utils/detect-git.js +439 -0
  169. package/dist/utils/detect-git.js.map +1 -0
  170. package/dist/utils/detect-mcp.d.ts +32 -0
  171. package/dist/utils/detect-mcp.d.ts.map +1 -0
  172. package/dist/utils/detect-mcp.js +178 -0
  173. package/dist/utils/detect-mcp.js.map +1 -0
  174. package/dist/utils/detect-project.d.ts +3 -0
  175. package/dist/utils/detect-project.d.ts.map +1 -0
  176. package/dist/utils/detect-project.js +155 -0
  177. package/dist/utils/detect-project.js.map +1 -0
  178. package/dist/utils/file-comparison.d.ts +89 -0
  179. package/dist/utils/file-comparison.d.ts.map +1 -0
  180. package/dist/utils/file-comparison.js +301 -0
  181. package/dist/utils/file-comparison.js.map +1 -0
  182. package/dist/utils/file-merger.d.ts +74 -0
  183. package/dist/utils/file-merger.d.ts.map +1 -0
  184. package/dist/utils/file-merger.js +350 -0
  185. package/dist/utils/file-merger.js.map +1 -0
  186. package/dist/utils/logger.d.ts +26 -0
  187. package/dist/utils/logger.d.ts.map +1 -0
  188. package/dist/utils/logger.js +72 -0
  189. package/dist/utils/logger.js.map +1 -0
  190. package/dist/utils/managed-process.d.ts +109 -0
  191. package/dist/utils/managed-process.d.ts.map +1 -0
  192. package/dist/utils/managed-process.js +481 -0
  193. package/dist/utils/managed-process.js.map +1 -0
  194. package/dist/utils/merge-claude-settings.d.ts +65 -0
  195. package/dist/utils/merge-claude-settings.d.ts.map +1 -0
  196. package/dist/utils/merge-claude-settings.js +133 -0
  197. package/dist/utils/merge-claude-settings.js.map +1 -0
  198. package/dist/utils/migration.d.ts +74 -0
  199. package/dist/utils/migration.d.ts.map +1 -0
  200. package/dist/utils/migration.js +345 -0
  201. package/dist/utils/migration.js.map +1 -0
  202. package/dist/utils/process-health.d.ts +51 -0
  203. package/dist/utils/process-health.d.ts.map +1 -0
  204. package/dist/utils/process-health.js +123 -0
  205. package/dist/utils/process-health.js.map +1 -0
  206. package/dist/utils/process-registry.d.ts +20 -0
  207. package/dist/utils/process-registry.d.ts.map +1 -0
  208. package/dist/utils/process-registry.js +151 -0
  209. package/dist/utils/process-registry.js.map +1 -0
  210. package/dist/utils/process-tree.d.ts +51 -0
  211. package/dist/utils/process-tree.d.ts.map +1 -0
  212. package/dist/utils/process-tree.js +499 -0
  213. package/dist/utils/process-tree.js.map +1 -0
  214. package/dist/utils/repair-mcp-config.d.ts +15 -0
  215. package/dist/utils/repair-mcp-config.d.ts.map +1 -0
  216. package/dist/utils/repair-mcp-config.js +129 -0
  217. package/dist/utils/repair-mcp-config.js.map +1 -0
  218. package/dist/utils/task-lifecycle.d.ts +60 -0
  219. package/dist/utils/task-lifecycle.d.ts.map +1 -0
  220. package/dist/utils/task-lifecycle.js +310 -0
  221. package/dist/utils/task-lifecycle.js.map +1 -0
  222. package/dist/utils/update-agent-mcp.d.ts +7 -0
  223. package/dist/utils/update-agent-mcp.d.ts.map +1 -0
  224. package/dist/utils/update-agent-mcp.js +115 -0
  225. package/dist/utils/update-agent-mcp.js.map +1 -0
  226. package/dist/utils/update-agent-templates.d.ts +6 -0
  227. package/dist/utils/update-agent-templates.d.ts.map +1 -0
  228. package/dist/utils/update-agent-templates.js +56 -0
  229. package/dist/utils/update-agent-templates.js.map +1 -0
  230. package/dist/utils/update-config-ci.d.ts +7 -0
  231. package/dist/utils/update-config-ci.d.ts.map +1 -0
  232. package/dist/utils/update-config-ci.js +72 -0
  233. package/dist/utils/update-config-ci.js.map +1 -0
  234. package/dist/utils/update-config-git.d.ts +18 -0
  235. package/dist/utils/update-config-git.d.ts.map +1 -0
  236. package/dist/utils/update-config-git.js +146 -0
  237. package/dist/utils/update-config-git.js.map +1 -0
  238. package/dist/utils/update-config-mcp.d.ts +7 -0
  239. package/dist/utils/update-config-mcp.d.ts.map +1 -0
  240. package/dist/utils/update-config-mcp.js +98 -0
  241. package/dist/utils/update-config-mcp.js.map +1 -0
  242. package/dist/utils/validate-config.d.ts +3 -0
  243. package/dist/utils/validate-config.d.ts.map +1 -0
  244. package/dist/utils/validate-config.js +109 -0
  245. package/dist/utils/validate-config.js.map +1 -0
  246. package/dist/utils/version-tracker.d.ts +130 -0
  247. package/dist/utils/version-tracker.d.ts.map +1 -0
  248. package/dist/utils/version-tracker.js +298 -0
  249. package/dist/utils/version-tracker.js.map +1 -0
  250. package/dist/utils/worktree.d.ts +68 -0
  251. package/dist/utils/worktree.d.ts.map +1 -0
  252. package/dist/utils/worktree.js +446 -0
  253. package/dist/utils/worktree.js.map +1 -0
  254. package/package.json +77 -0
  255. package/templates/ARCHAI_README.md +329 -0
  256. package/templates/CLAUDE.md +67 -0
  257. package/templates/PROMPTS.md +506 -0
  258. package/templates/core-agents/boss-agent.md +671 -0
  259. package/templates/core-agents/cleanup-agent.md +145 -0
  260. package/templates/core-agents/code-reviewer.md +175 -0
  261. package/templates/core-agents/critical-reviewer.md +117 -0
  262. package/templates/core-agents/deep-analyst.md +216 -0
  263. package/templates/core-agents/finalization-agent.md +252 -0
  264. package/templates/core-agents/git-coordinator.md +240 -0
  265. package/templates/core-agents/implementation-agent.md +151 -0
  266. package/templates/core-agents/maestro-agent.md +413 -0
  267. package/templates/core-agents/maestro-headless-agent.md +422 -0
  268. package/templates/core-agents/plan-validator.md +198 -0
  269. package/templates/core-agents/quick-fix.md +56 -0
  270. package/templates/core-agents/routing-templates.md +338 -0
  271. package/templates/core-agents/task-orchestrator.md +143 -0
  272. package/templates/core-agents/task-prep.md +202 -0
  273. package/templates/core-agents/tdd-designer.md +143 -0
  274. package/templates/specialist-meta.md +275 -0
@@ -0,0 +1,439 @@
1
+ import fs from 'fs-extra';
2
+ import { execSync } from 'child_process';
3
+ import { logger } from './logger.js';
4
+ /**
5
+ * Required .gitignore entries for archai.
6
+ * These patterns must be present for agents to work correctly.
7
+ */
8
+ const REQUIRED_GITIGNORE_ENTRIES = [
9
+ '.agents/scratch/*',
10
+ '.agents/thoughts/*',
11
+ '.agents/plans/*',
12
+ '.claude/state/*',
13
+ ];
14
+ /**
15
+ * Check if the current directory is a Git repository.
16
+ */
17
+ export async function detectGitRepo() {
18
+ return fs.pathExists('.git');
19
+ }
20
+ /**
21
+ * Check if the current directory is inside a linked git worktree.
22
+ * Returns true if .git is a file (linked worktree), false if directory (main repo) or missing.
23
+ */
24
+ export async function isWorktree() {
25
+ try {
26
+ const stat = await fs.stat('.git');
27
+ return stat.isFile();
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ }
33
+ /**
34
+ * Run a git command and return trimmed stdout, or null on failure.
35
+ * Never makes network calls.
36
+ */
37
+ function gitCommand(cmd, cwd) {
38
+ try {
39
+ const result = execSync(cmd, {
40
+ encoding: 'utf-8',
41
+ stdio: ['pipe', 'pipe', 'pipe'],
42
+ timeout: 5000,
43
+ ...(cwd ? { cwd } : {}),
44
+ });
45
+ return result.trim() || null;
46
+ }
47
+ catch {
48
+ return null;
49
+ }
50
+ }
51
+ /**
52
+ * Discover Git defaults by running local git commands.
53
+ * No network calls are made.
54
+ */
55
+ export async function discoverGitDefaults() {
56
+ // Current branch
57
+ const currentBranch = gitCommand('git branch --show-current') || 'unknown';
58
+ // Remote info
59
+ const remoteOutput = gitCommand('git remote -v');
60
+ let remote = null;
61
+ let remoteUrl = null;
62
+ if (remoteOutput) {
63
+ // Parse first fetch line: "origin\thttps://github.com/user/repo.git (fetch)"
64
+ const fetchLine = remoteOutput.split('\n').find(line => line.includes('(fetch)'));
65
+ if (fetchLine) {
66
+ const parts = fetchLine.split(/\s+/);
67
+ remote = parts[0] || null;
68
+ remoteUrl = parts[1] || null;
69
+ }
70
+ }
71
+ // Default branch discovery — try multiple methods
72
+ let defaultBranch = null;
73
+ // Method 1: git config init.defaultBranch
74
+ defaultBranch = gitCommand('git config init.defaultBranch');
75
+ // Method 2: remote HEAD reference
76
+ if (!defaultBranch && remote) {
77
+ const symref = gitCommand(`git symbolic-ref refs/remotes/${remote}/HEAD 2>/dev/null`);
78
+ if (symref) {
79
+ // refs/remotes/origin/HEAD -> refs/remotes/origin/main
80
+ const match = symref.match(/refs\/remotes\/[^/]+\/(.+)/);
81
+ if (match) {
82
+ defaultBranch = match[1];
83
+ }
84
+ }
85
+ }
86
+ // Method 3: check if main or master branch exists locally
87
+ if (!defaultBranch) {
88
+ const branches = gitCommand('git branch --list main master');
89
+ if (branches) {
90
+ const branchList = branches.split('\n').map(b => b.replace(/^\*?\s*/, '').trim()).filter(Boolean);
91
+ if (branchList.includes('main')) {
92
+ defaultBranch = 'main';
93
+ }
94
+ else if (branchList.includes('master')) {
95
+ defaultBranch = 'master';
96
+ }
97
+ }
98
+ }
99
+ // Final fallback
100
+ if (!defaultBranch) {
101
+ defaultBranch = 'main';
102
+ }
103
+ // Read branch convention from archai.config.md Git Conventions section if available.
104
+ // During archai setup, this value is overridden by detectGitPatterns() result.
105
+ // At runtime (agent operations), this is the primary source of the convention.
106
+ let branchConvention = 'agent/{task-id}-{description}';
107
+ try {
108
+ if (await fs.pathExists('archai.config.md')) {
109
+ const configContent = await fs.readFile('archai.config.md', 'utf-8');
110
+ // Extract the Git Conventions section first
111
+ const conventionsSection = configContent.match(/## Git Conventions\n[\s\S]*?(?=\n---\n|\n## |$)/);
112
+ if (conventionsSection) {
113
+ // Look for Branch Convention field WITHIN the Git Conventions section only
114
+ const conventionMatch = conventionsSection[0].match(/\*\*Branch Convention:\*\*\s*(.+)/);
115
+ if (conventionMatch && conventionMatch[1].trim() &&
116
+ !conventionMatch[1].includes('auto-configure')) {
117
+ branchConvention = conventionMatch[1].trim();
118
+ }
119
+ }
120
+ }
121
+ }
122
+ catch {
123
+ // Fallback to default silently
124
+ }
125
+ return {
126
+ defaultBranch,
127
+ remote,
128
+ remoteUrl,
129
+ currentBranch,
130
+ branchConvention,
131
+ };
132
+ }
133
+ /**
134
+ * Validate that .gitignore contains all required archai entries.
135
+ */
136
+ export async function validateGitignore() {
137
+ const gitignorePath = '.gitignore';
138
+ const missing = [];
139
+ if (!await fs.pathExists(gitignorePath)) {
140
+ return { valid: false, missing: [...REQUIRED_GITIGNORE_ENTRIES] };
141
+ }
142
+ const content = await fs.readFile(gitignorePath, 'utf-8');
143
+ for (const entry of REQUIRED_GITIGNORE_ENTRIES) {
144
+ if (!content.includes(entry)) {
145
+ missing.push(entry);
146
+ }
147
+ }
148
+ return { valid: missing.length === 0, missing };
149
+ }
150
+ /**
151
+ * Fix .gitignore by appending missing archai entries.
152
+ */
153
+ export async function fixGitignore(missing) {
154
+ if (missing.length === 0)
155
+ return;
156
+ const gitignorePath = '.gitignore';
157
+ let content = '';
158
+ if (await fs.pathExists(gitignorePath)) {
159
+ content = await fs.readFile(gitignorePath, 'utf-8');
160
+ // Ensure trailing newline before appending
161
+ if (content.length > 0 && !content.endsWith('\n')) {
162
+ content += '\n';
163
+ }
164
+ }
165
+ const additions = '\n# archai - Agent working files (auto-added by archai setup)\n' +
166
+ missing.map(entry => entry).join('\n') + '\n';
167
+ await fs.writeFile(gitignorePath, content + additions);
168
+ logger.debug('Fixed .gitignore', { added: missing });
169
+ }
170
+ // ---------------------------------------------------------------------------
171
+ // Known branch prefixes for classification
172
+ // ---------------------------------------------------------------------------
173
+ const KNOWN_PREFIXES = [
174
+ 'feature/', 'feat/', 'fix/', 'bugfix/', 'hotfix/',
175
+ 'release/', 'chore/', 'docs/', 'ci/', 'test/',
176
+ 'refactor/', 'agent/', 'archai/',
177
+ 'perf/', 'style/', 'build/', 'wip/', 'deps/',
178
+ 'improvement/', 'experiment/',
179
+ ];
180
+ // ---------------------------------------------------------------------------
181
+ // Pure helper functions (exported for testability)
182
+ // ---------------------------------------------------------------------------
183
+ /**
184
+ * Parse git for-each-ref output into cleaned branch names.
185
+ * Strips remote prefixes, deduplicates, and filters HEAD pointers.
186
+ */
187
+ export function parseBranchNames(rawOutput) {
188
+ if (!rawOutput || !rawOutput.trim())
189
+ return [];
190
+ const rawEntries = [];
191
+ const detectedRemotes = new Set();
192
+ for (const line of rawOutput.split('\n')) {
193
+ const name = line.trim();
194
+ if (!name)
195
+ continue;
196
+ // Detect remote names from HEAD pointer entries (e.g., origin/HEAD)
197
+ if (name.endsWith('/HEAD')) {
198
+ const remoteName = name.substring(0, name.length - '/HEAD'.length);
199
+ if (remoteName)
200
+ detectedRemotes.add(remoteName);
201
+ continue;
202
+ }
203
+ if (name === 'HEAD')
204
+ continue;
205
+ rawEntries.push(name);
206
+ }
207
+ const rawSet = new Set(rawEntries);
208
+ const cleaned = [];
209
+ const cleanedSet = new Set();
210
+ for (const name of rawEntries) {
211
+ const slashIdx = name.indexOf('/');
212
+ let cleanName = name;
213
+ if (slashIdx > 0) {
214
+ const firstSegment = name.substring(0, slashIdx);
215
+ const rest = name.substring(slashIdx + 1);
216
+ if (rest) {
217
+ const strippedExists = rawSet.has(rest);
218
+ const firstIsKnown = KNOWN_PREFIXES.includes(firstSegment + '/');
219
+ const restPrefix = rest.includes('/') ? rest.split('/')[0] + '/' : '';
220
+ const restHasKnownPrefix = restPrefix !== '' && KNOWN_PREFIXES.includes(restPrefix);
221
+ let peerStrippedExists = false;
222
+ if (!firstIsKnown) {
223
+ for (const other of rawSet) {
224
+ if (other !== name && other.startsWith(firstSegment + '/')) {
225
+ const otherRest = other.substring(firstSegment.length + 1);
226
+ if (rawSet.has(otherRest)) {
227
+ peerStrippedExists = true;
228
+ break;
229
+ }
230
+ }
231
+ }
232
+ }
233
+ const isDetectedRemote = detectedRemotes.has(firstSegment);
234
+ const isRemote = !firstIsKnown && (strippedExists || restHasKnownPrefix || peerStrippedExists || isDetectedRemote);
235
+ if (isRemote) {
236
+ cleanName = rest;
237
+ }
238
+ }
239
+ }
240
+ if (cleanName && !cleanedSet.has(cleanName)) {
241
+ cleanedSet.add(cleanName);
242
+ cleaned.push(cleanName);
243
+ }
244
+ }
245
+ return cleaned;
246
+ }
247
+ /**
248
+ * Classify branch names by their prefix (first path segment before /).
249
+ * Returns a map of prefix/ -> count for all branches containing a slash.
250
+ */
251
+ export function classifyBranchPrefixes(branches) {
252
+ const counts = new Map();
253
+ for (const branch of branches) {
254
+ const slashIdx = branch.indexOf('/');
255
+ if (slashIdx <= 0)
256
+ continue;
257
+ const prefix = branch.substring(0, slashIdx + 1);
258
+ counts.set(prefix, (counts.get(prefix) || 0) + 1);
259
+ }
260
+ return counts;
261
+ }
262
+ /**
263
+ * Parse git log output (format: %H %P\n%s) to detect merge commits and PR platforms.
264
+ */
265
+ export function parseMergeCommits(rawLogOutput) {
266
+ if (!rawLogOutput || !rawLogOutput.trim()) {
267
+ return { mergeCount: 0, totalCount: 0, prPlatform: null, usesPRs: false };
268
+ }
269
+ const lines = rawLogOutput.split('\n');
270
+ let totalCount = 0;
271
+ let mergeCount = 0;
272
+ let githubPRs = 0;
273
+ let gitlabMRs = 0;
274
+ let bitbucketPRs = 0;
275
+ let azurePRs = 0;
276
+ // Process pairs of lines: hash line + subject line
277
+ for (let i = 0; i < lines.length; i += 2) {
278
+ const hashLine = lines[i]?.trim();
279
+ const subject = lines[i + 1]?.trim();
280
+ if (!hashLine)
281
+ continue;
282
+ totalCount++;
283
+ // Check if merge commit: hash line has 3+ space-separated tokens (commit hash + 2+ parent hashes)
284
+ const parts = hashLine.split(/\s+/);
285
+ const isMerge = parts.length >= 3;
286
+ if (isMerge) {
287
+ mergeCount++;
288
+ }
289
+ // Check PR/MR platform from subject line
290
+ if (subject) {
291
+ if (/Merge pull request #\d+/.test(subject))
292
+ githubPRs++;
293
+ else if (/See merge request.*!\d+/.test(subject))
294
+ gitlabMRs++;
295
+ else if (/Merged in .* \(pull request #\d+\)/.test(subject))
296
+ bitbucketPRs++;
297
+ else if (/Merged PR \d+:/.test(subject))
298
+ azurePRs++;
299
+ }
300
+ }
301
+ // Determine dominant PR platform
302
+ let prPlatform = null;
303
+ const prCounts = [
304
+ { platform: 'github', count: githubPRs },
305
+ { platform: 'gitlab', count: gitlabMRs },
306
+ { platform: 'bitbucket', count: bitbucketPRs },
307
+ { platform: 'azure', count: azurePRs },
308
+ ];
309
+ const maxPR = prCounts.reduce((max, curr) => curr.count > max.count ? curr : max, prCounts[0]);
310
+ if (maxPR.count > 0) {
311
+ prPlatform = maxPR.platform;
312
+ }
313
+ const usesPRs = prPlatform !== null;
314
+ return { mergeCount, totalCount, prPlatform, usesPRs };
315
+ }
316
+ /**
317
+ * Determine the dominant merge strategy based on merge commit ratio.
318
+ */
319
+ export function determineMergeStrategy(mergeCount, totalCount) {
320
+ if (totalCount < 5)
321
+ return 'unknown';
322
+ const mergeRatio = mergeCount / totalCount;
323
+ if (mergeRatio > 0.7)
324
+ return 'merge';
325
+ if (totalCount >= 20 && mergeRatio < 0.1)
326
+ return 'rebase';
327
+ if (mergeRatio >= 0.1 && mergeRatio <= 0.7)
328
+ return 'mixed';
329
+ // Default: covers 5 <= totalCount < 20 with mergeRatio < 0.1
330
+ return 'unknown';
331
+ }
332
+ /**
333
+ * Build the agent branch naming convention based on detected patterns.
334
+ */
335
+ export function buildAgentConvention(topPrefix, isUsernamePattern, isJiraPattern) {
336
+ if (isUsernamePattern) {
337
+ return 'archai/{task-id}-{description}';
338
+ }
339
+ if (isJiraPattern) {
340
+ return 'agent/{task-id}-{description}';
341
+ }
342
+ if (topPrefix && topPrefix !== 'agent/' && topPrefix !== 'archai/') {
343
+ return `${topPrefix}agent-{task-id}-{description}`;
344
+ }
345
+ if (topPrefix === 'archai/') {
346
+ return 'archai/{task-id}-{description}';
347
+ }
348
+ return 'agent/{task-id}-{description}';
349
+ }
350
+ /**
351
+ * Detect git branching and merge patterns from repository history.
352
+ * Analyzes branch names (up to 100) and merge commits (up to 200).
353
+ * Never throws -- returns sensible defaults on any error.
354
+ */
355
+ export async function detectGitPatterns(projectRoot) {
356
+ const defaults = {
357
+ branchPrefix: '',
358
+ agentBranchConvention: 'agent/{task-id}-{description}',
359
+ targetBranch: 'main',
360
+ mergeStrategy: 'unknown',
361
+ usesPullRequests: false,
362
+ prPlatform: null,
363
+ detectedPrefixes: [],
364
+ branchesAnalyzed: 0,
365
+ mergeCommitsAnalyzed: 0,
366
+ };
367
+ try {
368
+ // Step 1: Get branch names (up to 100)
369
+ const branchOutput = gitCommand('git for-each-ref --count=100 --sort=-committerdate refs/heads refs/remotes --format=%(refname:short)', projectRoot);
370
+ const branches = branchOutput ? parseBranchNames(branchOutput) : [];
371
+ // Step 2: Classify branch prefixes
372
+ const prefixCounts = classifyBranchPrefixes(branches);
373
+ // Find top prefix by count
374
+ let topPrefix = '';
375
+ let topCount = 0;
376
+ for (const [prefix, count] of prefixCounts) {
377
+ if (count > topCount) {
378
+ topPrefix = prefix;
379
+ topCount = count;
380
+ }
381
+ }
382
+ // Determine if top prefix is username pattern or JIRA pattern
383
+ let isUsernamePattern = false;
384
+ let isJiraPattern = false;
385
+ if (topPrefix && !KNOWN_PREFIXES.includes(topPrefix)) {
386
+ if (/^[a-z]+\/$/.test(topPrefix)) {
387
+ isUsernamePattern = true;
388
+ }
389
+ }
390
+ if (!topPrefix) {
391
+ const jiraBranches = branches.filter(b => /^[A-Z]+-\d+/.test(b));
392
+ if (jiraBranches.length >= 2) {
393
+ isJiraPattern = true;
394
+ }
395
+ }
396
+ // Step 3: Build agent convention
397
+ const agentBranchConvention = buildAgentConvention(topPrefix, isUsernamePattern, isJiraPattern);
398
+ // Step 4: Discover target branch
399
+ let targetBranch = 'main';
400
+ const defaultBranchConfig = gitCommand('git config init.defaultBranch', projectRoot);
401
+ if (defaultBranchConfig) {
402
+ targetBranch = defaultBranchConfig;
403
+ }
404
+ else {
405
+ const branchList = gitCommand('git branch --list main master', projectRoot);
406
+ if (branchList) {
407
+ const branchNames = branchList.split('\n').map(b => b.replace(/^\*?\s*/, '').trim()).filter(Boolean);
408
+ if (branchNames.includes('main'))
409
+ targetBranch = 'main';
410
+ else if (branchNames.includes('master'))
411
+ targetBranch = 'master';
412
+ }
413
+ }
414
+ // Step 5: Analyze merge commits (up to 200)
415
+ const logOutput = gitCommand('git log --first-parent -200 --format=%H %P%n%s', projectRoot);
416
+ const defaultMerge = { mergeCount: 0, totalCount: 0, prPlatform: null, usesPRs: false };
417
+ const mergeResult = logOutput ? parseMergeCommits(logOutput) : defaultMerge;
418
+ const mergeStrategy = determineMergeStrategy(mergeResult.mergeCount, mergeResult.totalCount);
419
+ // Step 6: Build detected prefixes list (sorted by count descending)
420
+ const detectedPrefixes = [...prefixCounts.entries()]
421
+ .sort((a, b) => b[1] - a[1])
422
+ .map(([prefix]) => prefix);
423
+ return {
424
+ branchPrefix: topPrefix,
425
+ agentBranchConvention,
426
+ targetBranch,
427
+ mergeStrategy,
428
+ usesPullRequests: mergeResult.usesPRs,
429
+ prPlatform: mergeResult.prPlatform,
430
+ detectedPrefixes,
431
+ branchesAnalyzed: branches.length,
432
+ mergeCommitsAnalyzed: mergeResult.totalCount,
433
+ };
434
+ }
435
+ catch {
436
+ return defaults;
437
+ }
438
+ }
439
+ //# sourceMappingURL=detect-git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-git.js","sourceRoot":"","sources":["../../src/utils/detect-git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { McpServer, McpIntrospectionResult } from '../types/index.js';
2
+ /**
3
+ * Check if Claude CLI is available by running `claude --version`.
4
+ */
5
+ export declare function checkClaudeCli(): boolean;
6
+ /**
7
+ * Discover installed MCP servers by running `claude mcp list`.
8
+ * Parses the plain-text output line by line.
9
+ *
10
+ * Expected format:
11
+ * ```
12
+ * Checking MCP server health...
13
+ * claude.ai Figma: https://mcp.figma.com/mcp - ✓ Connected
14
+ * monday: mcp-server-monday-api -t <token> - ✓ Connected
15
+ * ```
16
+ */
17
+ export declare function discoverMcpServers(): McpServer[];
18
+ /**
19
+ * Identify which servers are task management MCPs based on name pattern matching.
20
+ * Only returns connected servers.
21
+ */
22
+ export declare function identifyTaskManagers(servers: McpServer[]): McpServer[];
23
+ /**
24
+ * Get the provider display name for a task manager server.
25
+ */
26
+ export declare function getProviderName(serverName: string): string;
27
+ /**
28
+ * Introspect a task manager MCP via `claude -p` to discover boards and concept mapping.
29
+ * Returns null if introspection fails or response cannot be parsed.
30
+ */
31
+ export declare function introspectTaskManager(serverName: string): McpIntrospectionResult | null;
32
+ //# sourceMappingURL=detect-mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-mcp.d.ts","sourceRoot":"","sources":["../../src/utils/detect-mcp.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAoC3E;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAGxC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,IAAI,SAAS,EAAE,CA2ChD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAMtE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAQ1D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI,CAkEvF"}
@@ -0,0 +1,178 @@
1
+ import { execSync } from 'child_process';
2
+ import { logger } from './logger.js';
3
+ /**
4
+ * Known task manager name patterns (case-insensitive match against server name).
5
+ */
6
+ const TASK_MANAGER_PATTERNS = {
7
+ monday: 'monday.com',
8
+ linear: 'linear',
9
+ jira: 'jira',
10
+ asana: 'asana',
11
+ clickup: 'clickup',
12
+ notion: 'notion',
13
+ };
14
+ /**
15
+ * Run a claude CLI command with CLAUDECODE unset.
16
+ * Returns stdout on success, null on failure.
17
+ */
18
+ function runClaudeCommand(args, timeoutMs = 30000) {
19
+ try {
20
+ const result = execSync(`CLAUDECODE= claude ${args}`, {
21
+ encoding: 'utf-8',
22
+ stdio: ['pipe', 'pipe', 'pipe'],
23
+ timeout: timeoutMs,
24
+ env: { ...process.env, CLAUDECODE: '' },
25
+ });
26
+ return result.trim() || null;
27
+ }
28
+ catch (error) {
29
+ logger.debug('Claude CLI command failed', {
30
+ args,
31
+ error: error instanceof Error ? error.message : 'Unknown error',
32
+ });
33
+ return null;
34
+ }
35
+ }
36
+ /**
37
+ * Check if Claude CLI is available by running `claude --version`.
38
+ */
39
+ export function checkClaudeCli() {
40
+ const result = runClaudeCommand('--version', 10000);
41
+ return result !== null;
42
+ }
43
+ /**
44
+ * Discover installed MCP servers by running `claude mcp list`.
45
+ * Parses the plain-text output line by line.
46
+ *
47
+ * Expected format:
48
+ * ```
49
+ * Checking MCP server health...
50
+ * claude.ai Figma: https://mcp.figma.com/mcp - ✓ Connected
51
+ * monday: mcp-server-monday-api -t <token> - ✓ Connected
52
+ * ```
53
+ */
54
+ export function discoverMcpServers() {
55
+ const output = runClaudeCommand('mcp list', 15000);
56
+ if (!output) {
57
+ return [];
58
+ }
59
+ const servers = [];
60
+ const lines = output.split('\n');
61
+ for (const line of lines) {
62
+ const trimmed = line.trim();
63
+ // Skip empty lines and header lines (like "Checking MCP server health...")
64
+ if (!trimmed || !trimmed.includes(' - ')) {
65
+ continue;
66
+ }
67
+ // Parse: "name: connectionInfo - status"
68
+ // The last " - " separates the status from the rest
69
+ const lastDashIndex = trimmed.lastIndexOf(' - ');
70
+ if (lastDashIndex === -1)
71
+ continue;
72
+ const statusPart = trimmed.slice(lastDashIndex + 3).trim();
73
+ const nameAndConnection = trimmed.slice(0, lastDashIndex).trim();
74
+ // Split name from connection info at the first ":"
75
+ const colonIndex = nameAndConnection.indexOf(':');
76
+ if (colonIndex === -1)
77
+ continue;
78
+ const name = nameAndConnection.slice(0, colonIndex).trim();
79
+ const connectionInfo = nameAndConnection.slice(colonIndex + 1).trim();
80
+ const isConnected = statusPart.toLowerCase().includes('connected');
81
+ servers.push({
82
+ name,
83
+ connectionInfo,
84
+ status: isConnected ? 'connected' : 'disconnected',
85
+ });
86
+ }
87
+ return servers;
88
+ }
89
+ /**
90
+ * Identify which servers are task management MCPs based on name pattern matching.
91
+ * Only returns connected servers.
92
+ */
93
+ export function identifyTaskManagers(servers) {
94
+ return servers.filter(server => {
95
+ if (server.status !== 'connected')
96
+ return false;
97
+ const lowerName = server.name.toLowerCase();
98
+ return Object.keys(TASK_MANAGER_PATTERNS).some(pattern => lowerName.includes(pattern));
99
+ });
100
+ }
101
+ /**
102
+ * Get the provider display name for a task manager server.
103
+ */
104
+ export function getProviderName(serverName) {
105
+ const lowerName = serverName.toLowerCase();
106
+ for (const [pattern, provider] of Object.entries(TASK_MANAGER_PATTERNS)) {
107
+ if (lowerName.includes(pattern)) {
108
+ return provider;
109
+ }
110
+ }
111
+ return serverName;
112
+ }
113
+ /**
114
+ * Introspect a task manager MCP via `claude -p` to discover boards and concept mapping.
115
+ * Returns null if introspection fails or response cannot be parsed.
116
+ */
117
+ export function introspectTaskManager(serverName) {
118
+ const prompt = [
119
+ `You have access to ${serverName} MCP tools.`,
120
+ 'Complete these steps in order:',
121
+ '1. List available workspaces/boards/projects (use the appropriate MCP tool)',
122
+ '2. For each, note the ID and name',
123
+ '3. Map the task manager concepts to these Archai concepts:',
124
+ ' - Epic (large feature/initiative)',
125
+ ' - Task (unit of work)',
126
+ ' - Subtask (part of a task)',
127
+ ' - Status (workflow states)',
128
+ '4. Output ONLY a JSON block (no other text before or after) with this exact structure:',
129
+ ' {"provider":"...","boards":[{"id":"...","name":"..."}],"mapping":{"epic":"...","task":"...","subtask":"...","statuses":["..."]}}',
130
+ ].join('\n');
131
+ // Escape the prompt for shell usage
132
+ const escapedPrompt = prompt.replace(/"/g, '\\"');
133
+ const output = runClaudeCommand(`-p "${escapedPrompt}" --output-format text`, 120000);
134
+ if (!output) {
135
+ logger.debug('Introspection returned no output');
136
+ return null;
137
+ }
138
+ // Extract JSON from the response
139
+ const jsonMatch = output.match(/\{[\s\S]*\}/);
140
+ if (!jsonMatch) {
141
+ logger.debug('No JSON found in introspection response', output.slice(0, 500));
142
+ return null;
143
+ }
144
+ try {
145
+ const parsed = JSON.parse(jsonMatch[0]);
146
+ // Validate required fields
147
+ if (!parsed.provider || !parsed.boards || !parsed.mapping) {
148
+ logger.debug('Introspection JSON missing required fields');
149
+ return null;
150
+ }
151
+ if (!parsed.mapping.epic || !parsed.mapping.task || !parsed.mapping.subtask || !Array.isArray(parsed.mapping.statuses)) {
152
+ logger.debug('Introspection mapping missing required fields');
153
+ return null;
154
+ }
155
+ return {
156
+ provider: String(parsed.provider),
157
+ boards: Array.isArray(parsed.boards)
158
+ ? parsed.boards.map((b) => ({
159
+ id: String(b.id || ''),
160
+ name: String(b.name || ''),
161
+ }))
162
+ : [],
163
+ mapping: {
164
+ epic: String(parsed.mapping.epic),
165
+ task: String(parsed.mapping.task),
166
+ subtask: String(parsed.mapping.subtask),
167
+ statuses: parsed.mapping.statuses.map(String),
168
+ },
169
+ };
170
+ }
171
+ catch (error) {
172
+ logger.debug('Failed to parse introspection JSON', {
173
+ error: error instanceof Error ? error.message : 'Unknown error',
174
+ });
175
+ return null;
176
+ }
177
+ }
178
+ //# sourceMappingURL=detect-mcp.js.map