javi-forge 1.6.0 → 1.7.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 (322) hide show
  1. package/README.md +45 -1
  2. package/ci-local/README.md +56 -11
  3. package/ci-local/ci-local.ps1 +445 -0
  4. package/ci-local/ci-local.sh +52 -9
  5. package/ci-local/docker/python.Dockerfile +7 -0
  6. package/ci-local/hooks/commit-msg +120 -44
  7. package/ci-local/hooks/commit-msg.test.sh +286 -0
  8. package/ci-local/hooks/pre-commit +9 -1
  9. package/ci-local/hooks/pre-push +13 -2
  10. package/ci-local/install.ps1 +367 -0
  11. package/ci-local/install.sh +151 -5
  12. package/ci-local/uninstall.ps1 +85 -0
  13. package/ci-local/uninstall.sh +95 -0
  14. package/dist/cli/dispatch/ci.d.ts +12 -0
  15. package/dist/cli/dispatch/ci.js +38 -0
  16. package/dist/cli/dispatch/security.d.ts +11 -0
  17. package/dist/cli/dispatch/security.js +68 -0
  18. package/dist/cli/dispatch/simple-renderers.d.ts +16 -0
  19. package/dist/cli/dispatch/simple-renderers.js +65 -0
  20. package/dist/cli/dispatch/skill-publish.d.ts +15 -0
  21. package/dist/cli/dispatch/skill-publish.js +44 -0
  22. package/dist/cli/dispatch/skills-cmd.d.ts +13 -0
  23. package/dist/cli/dispatch/skills-cmd.js +93 -0
  24. package/dist/cli/dispatch/tdd.d.ts +11 -0
  25. package/dist/cli/dispatch/tdd.js +45 -0
  26. package/dist/cli/dispatch/types.d.ts +29 -0
  27. package/dist/cli/dispatch/types.js +2 -0
  28. package/dist/cli/dispatch/workflow.d.ts +11 -0
  29. package/dist/cli/dispatch/workflow.js +67 -0
  30. package/dist/cli/help.d.ts +127 -0
  31. package/dist/cli/help.js +138 -0
  32. package/dist/cli/runtime.d.ts +16 -0
  33. package/dist/cli/runtime.js +38 -0
  34. package/dist/cli/validators.d.ts +17 -0
  35. package/dist/cli/validators.js +35 -0
  36. package/dist/commands/analyze.d.ts +1 -1
  37. package/dist/commands/analyze.js +14 -16
  38. package/dist/commands/ci.d.ts +50 -3
  39. package/dist/commands/ci.js +537 -182
  40. package/dist/commands/doctor.d.ts +2 -2
  41. package/dist/commands/doctor.js +112 -62
  42. package/dist/commands/init/report.d.ts +13 -0
  43. package/dist/commands/init/report.js +13 -0
  44. package/dist/commands/init/steps/agent-skills.d.ts +13 -0
  45. package/dist/commands/init/steps/agent-skills.js +45 -0
  46. package/dist/commands/init/steps/ai-sync.d.ts +15 -0
  47. package/dist/commands/init/steps/ai-sync.js +62 -0
  48. package/dist/commands/init/steps/ci.d.ts +24 -0
  49. package/dist/commands/init/steps/ci.js +74 -0
  50. package/dist/commands/init/steps/claude-md.d.ts +14 -0
  51. package/dist/commands/init/steps/claude-md.js +54 -0
  52. package/dist/commands/init/steps/code-graph.d.ts +16 -0
  53. package/dist/commands/init/steps/code-graph.js +68 -0
  54. package/dist/commands/init/steps/context-dir.d.ts +13 -0
  55. package/dist/commands/init/steps/context-dir.js +47 -0
  56. package/dist/commands/init/steps/docker-deploy.d.ts +16 -0
  57. package/dist/commands/init/steps/docker-deploy.js +60 -0
  58. package/dist/commands/init/steps/ghagga.d.ts +15 -0
  59. package/dist/commands/init/steps/ghagga.js +58 -0
  60. package/dist/commands/init/steps/git.d.ts +25 -0
  61. package/dist/commands/init/steps/git.js +81 -0
  62. package/dist/commands/init/steps/gitignore.d.ts +13 -0
  63. package/dist/commands/init/steps/gitignore.js +39 -0
  64. package/dist/commands/init/steps/local-ai.d.ts +14 -0
  65. package/dist/commands/init/steps/local-ai.js +53 -0
  66. package/dist/commands/init/steps/manifest.d.ts +13 -0
  67. package/dist/commands/init/steps/manifest.js +58 -0
  68. package/dist/commands/init/steps/memory.d.ts +15 -0
  69. package/dist/commands/init/steps/memory.js +60 -0
  70. package/dist/commands/init/steps/mock.d.ts +13 -0
  71. package/dist/commands/init/steps/mock.js +64 -0
  72. package/dist/commands/init/steps/sdd.d.ts +12 -0
  73. package/dist/commands/init/steps/sdd.js +40 -0
  74. package/dist/commands/init/steps/security.d.ts +28 -0
  75. package/dist/commands/init/steps/security.js +103 -0
  76. package/dist/commands/init/types.d.ts +30 -0
  77. package/dist/commands/init/types.js +2 -0
  78. package/dist/commands/init.d.ts +5 -4
  79. package/dist/commands/init.js +42 -387
  80. package/dist/commands/llmstxt.d.ts +1 -1
  81. package/dist/commands/llmstxt.js +36 -34
  82. package/dist/commands/plugin.d.ts +10 -1
  83. package/dist/commands/plugin.js +92 -47
  84. package/dist/commands/security.d.ts +11 -5
  85. package/dist/commands/security.js +236 -77
  86. package/dist/commands/skills/analysis.d.ts +19 -0
  87. package/dist/commands/skills/analysis.js +211 -0
  88. package/dist/commands/skills/benchmark.d.ts +6 -0
  89. package/dist/commands/skills/benchmark.js +82 -0
  90. package/dist/commands/skills/constants.d.ts +10 -0
  91. package/dist/commands/skills/constants.js +27 -0
  92. package/dist/commands/skills/directives.d.ts +21 -0
  93. package/dist/commands/skills/directives.js +101 -0
  94. package/dist/commands/skills/parsing.d.ts +16 -0
  95. package/dist/commands/skills/parsing.js +108 -0
  96. package/dist/commands/skills/rules.d.ts +5 -0
  97. package/dist/commands/skills/rules.js +32 -0
  98. package/dist/commands/skills/scoring.d.ts +47 -0
  99. package/dist/commands/skills/scoring.js +306 -0
  100. package/dist/commands/skills.d.ts +8 -69
  101. package/dist/commands/skills.js +9 -490
  102. package/dist/commands/tdd-pipeline.d.ts +17 -0
  103. package/dist/commands/tdd-pipeline.js +144 -0
  104. package/dist/commands/tdd.d.ts +1 -1
  105. package/dist/commands/tdd.js +21 -18
  106. package/dist/commands/workflow.d.ts +23 -0
  107. package/dist/commands/workflow.js +116 -0
  108. package/dist/constants.d.ts +15 -1
  109. package/dist/constants.js +161 -122
  110. package/dist/index.js +43 -280
  111. package/dist/lib/agent-skills.d.ts +36 -1
  112. package/dist/lib/agent-skills.js +168 -19
  113. package/dist/lib/atlassian-mcp.d.ts +42 -0
  114. package/dist/lib/atlassian-mcp.js +98 -0
  115. package/dist/lib/auto-skill-install.d.ts +37 -0
  116. package/dist/lib/auto-skill-install.js +91 -0
  117. package/dist/lib/auto-wire.d.ts +20 -0
  118. package/dist/lib/auto-wire.js +240 -0
  119. package/dist/lib/ci-config.d.ts +65 -0
  120. package/dist/lib/ci-config.js +297 -0
  121. package/dist/lib/claudemd.d.ts +13 -1
  122. package/dist/lib/claudemd.js +174 -24
  123. package/dist/lib/codex-export.d.ts +1 -1
  124. package/dist/lib/codex-export.js +26 -32
  125. package/dist/lib/common.d.ts +1 -1
  126. package/dist/lib/common.js +52 -44
  127. package/dist/lib/context.d.ts +17 -2
  128. package/dist/lib/context.js +142 -13
  129. package/dist/lib/crash-recovery.d.ts +34 -0
  130. package/dist/lib/crash-recovery.js +123 -0
  131. package/dist/lib/docker.d.ts +23 -2
  132. package/dist/lib/docker.js +168 -131
  133. package/dist/lib/exec.d.ts +10 -0
  134. package/dist/lib/exec.js +11 -0
  135. package/dist/lib/frontmatter.d.ts +1 -1
  136. package/dist/lib/frontmatter.js +29 -15
  137. package/dist/lib/harness-audit.d.ts +35 -0
  138. package/dist/lib/harness-audit.js +277 -0
  139. package/dist/lib/parallel-batch.d.ts +42 -0
  140. package/dist/lib/parallel-batch.js +88 -0
  141. package/dist/lib/plugin.d.ts +9 -3
  142. package/dist/lib/plugin.js +127 -70
  143. package/dist/lib/secret-scanner.d.ts +30 -0
  144. package/dist/lib/secret-scanner.js +274 -0
  145. package/dist/lib/security-analysis.d.ts +74 -0
  146. package/dist/lib/security-analysis.js +489 -0
  147. package/dist/lib/skill-publish.d.ts +40 -0
  148. package/dist/lib/skill-publish.js +164 -0
  149. package/dist/lib/skill-scanner.d.ts +63 -0
  150. package/dist/lib/skill-scanner.js +383 -0
  151. package/dist/lib/stack-detector.d.ts +38 -0
  152. package/dist/lib/stack-detector.js +207 -0
  153. package/dist/lib/supply-chain.d.ts +23 -0
  154. package/dist/lib/supply-chain.js +126 -0
  155. package/dist/lib/team-presets.d.ts +53 -0
  156. package/dist/lib/team-presets.js +201 -0
  157. package/dist/lib/template.d.ts +16 -1
  158. package/dist/lib/template.js +46 -17
  159. package/dist/lib/workflow/discovery.d.ts +27 -0
  160. package/dist/lib/workflow/discovery.js +85 -0
  161. package/dist/lib/workflow/index.d.ts +5 -0
  162. package/dist/lib/workflow/index.js +5 -0
  163. package/dist/lib/workflow/parser.d.ts +16 -0
  164. package/dist/lib/workflow/parser.js +198 -0
  165. package/dist/lib/workflow/renderer.d.ts +9 -0
  166. package/dist/lib/workflow/renderer.js +152 -0
  167. package/dist/lib/workflow/validator.d.ts +10 -0
  168. package/dist/lib/workflow/validator.js +189 -0
  169. package/dist/tasks/index.d.ts +4 -0
  170. package/dist/tasks/index.js +4 -0
  171. package/dist/tasks/scaffold-tasks.d.ts +3 -0
  172. package/dist/tasks/scaffold-tasks.js +14 -0
  173. package/dist/tasks/task-id.d.ts +30 -0
  174. package/dist/tasks/task-id.js +59 -0
  175. package/dist/tasks/task-tracker.d.ts +15 -0
  176. package/dist/tasks/task-tracker.js +81 -0
  177. package/dist/types/index.d.ts +134 -6
  178. package/dist/types/index.js +11 -1
  179. package/dist/ui/AnalyzeUI.d.ts +1 -1
  180. package/dist/ui/AnalyzeUI.js +38 -39
  181. package/dist/ui/App.d.ts +5 -3
  182. package/dist/ui/App.js +86 -46
  183. package/dist/ui/AutoSkills.d.ts +9 -0
  184. package/dist/ui/AutoSkills.js +124 -0
  185. package/dist/ui/CI.d.ts +2 -2
  186. package/dist/ui/CI.js +24 -26
  187. package/dist/ui/CIContext.d.ts +1 -1
  188. package/dist/ui/CIContext.js +2 -2
  189. package/dist/ui/CISelector.d.ts +2 -2
  190. package/dist/ui/CISelector.js +23 -15
  191. package/dist/ui/Doctor.d.ts +1 -1
  192. package/dist/ui/Doctor.js +35 -29
  193. package/dist/ui/Header.d.ts +1 -1
  194. package/dist/ui/Header.js +14 -14
  195. package/dist/ui/HookProfileSelector.d.ts +9 -0
  196. package/dist/ui/HookProfileSelector.js +54 -0
  197. package/dist/ui/LlmsTxt.d.ts +1 -1
  198. package/dist/ui/LlmsTxt.js +31 -22
  199. package/dist/ui/MemorySelector.d.ts +2 -2
  200. package/dist/ui/MemorySelector.js +28 -16
  201. package/dist/ui/NameInput.d.ts +1 -1
  202. package/dist/ui/NameInput.js +21 -21
  203. package/dist/ui/OptionSelector.d.ts +6 -2
  204. package/dist/ui/OptionSelector.js +83 -32
  205. package/dist/ui/Plugin.d.ts +4 -3
  206. package/dist/ui/Plugin.js +78 -35
  207. package/dist/ui/Progress.d.ts +3 -3
  208. package/dist/ui/Progress.js +23 -22
  209. package/dist/ui/Skills.d.ts +2 -2
  210. package/dist/ui/Skills.js +61 -32
  211. package/dist/ui/StackSelector.d.ts +2 -2
  212. package/dist/ui/StackSelector.js +27 -17
  213. package/dist/ui/Summary.d.ts +3 -3
  214. package/dist/ui/Summary.js +60 -50
  215. package/dist/ui/Welcome.d.ts +1 -1
  216. package/dist/ui/Welcome.js +15 -16
  217. package/dist/ui/theme.d.ts +1 -1
  218. package/dist/ui/theme.js +6 -6
  219. package/lib/common.psm1 +167 -0
  220. package/lib/common.sh +30 -0
  221. package/package.json +46 -24
  222. package/templates/common/atlassian/mcp-atlassian-snippet.json +16 -0
  223. package/templates/common/repoforge/mcp-repoforge-snippet.json +11 -0
  224. package/templates/common/repoforge/repoforge.yaml +34 -0
  225. package/templates/github/deploy-docker-zero-downtime.yml +140 -0
  226. package/templates/github/repoforge-graph.yml +45 -0
  227. package/templates/gitlab/deploy-docker-zero-downtime.yml +57 -0
  228. package/templates/local-ai/.env.example +17 -0
  229. package/templates/local-ai/docker-compose.yml +95 -0
  230. package/templates/security-hooks/claude-settings-security.json +30 -0
  231. package/templates/security-hooks/commit-msg-signing +29 -0
  232. package/templates/security-hooks/pre-commit-permissions +74 -0
  233. package/templates/security-hooks/pre-commit-secrets +74 -0
  234. package/templates/security-hooks/pre-push-branch-protection +62 -0
  235. package/templates/security-hooks/pre-push-deps +83 -0
  236. package/templates/security-hooks/pre-push-signing +67 -0
  237. package/templates/woodpecker/deploy-docker-zero-downtime.yml +50 -0
  238. package/templates/workflows/ci-pipeline.dot +15 -0
  239. package/templates/workflows/feature-flow.dot +21 -0
  240. package/templates/workflows/release.dot +16 -0
  241. package/dist/__integration__/helpers.d.ts +0 -20
  242. package/dist/__integration__/helpers.d.ts.map +0 -1
  243. package/dist/__integration__/helpers.js +0 -31
  244. package/dist/__integration__/helpers.js.map +0 -1
  245. package/dist/commands/analyze.d.ts.map +0 -1
  246. package/dist/commands/analyze.js.map +0 -1
  247. package/dist/commands/ci.d.ts.map +0 -1
  248. package/dist/commands/ci.js.map +0 -1
  249. package/dist/commands/doctor.d.ts.map +0 -1
  250. package/dist/commands/doctor.js.map +0 -1
  251. package/dist/commands/init.d.ts.map +0 -1
  252. package/dist/commands/init.js.map +0 -1
  253. package/dist/commands/llmstxt.d.ts.map +0 -1
  254. package/dist/commands/llmstxt.js.map +0 -1
  255. package/dist/commands/plugin.d.ts.map +0 -1
  256. package/dist/commands/plugin.js.map +0 -1
  257. package/dist/commands/security.d.ts.map +0 -1
  258. package/dist/commands/security.js.map +0 -1
  259. package/dist/commands/skills.d.ts.map +0 -1
  260. package/dist/commands/skills.js.map +0 -1
  261. package/dist/commands/tdd.d.ts.map +0 -1
  262. package/dist/commands/tdd.js.map +0 -1
  263. package/dist/constants.d.ts.map +0 -1
  264. package/dist/constants.js.map +0 -1
  265. package/dist/index.d.ts.map +0 -1
  266. package/dist/index.js.map +0 -1
  267. package/dist/lib/agent-skills.d.ts.map +0 -1
  268. package/dist/lib/agent-skills.js.map +0 -1
  269. package/dist/lib/claudemd.d.ts.map +0 -1
  270. package/dist/lib/claudemd.js.map +0 -1
  271. package/dist/lib/codex-export.d.ts.map +0 -1
  272. package/dist/lib/codex-export.js.map +0 -1
  273. package/dist/lib/common.d.ts.map +0 -1
  274. package/dist/lib/common.js.map +0 -1
  275. package/dist/lib/context.d.ts.map +0 -1
  276. package/dist/lib/context.js.map +0 -1
  277. package/dist/lib/docker.d.ts.map +0 -1
  278. package/dist/lib/docker.js.map +0 -1
  279. package/dist/lib/frontmatter.d.ts.map +0 -1
  280. package/dist/lib/frontmatter.js.map +0 -1
  281. package/dist/lib/plugin.d.ts.map +0 -1
  282. package/dist/lib/plugin.js.map +0 -1
  283. package/dist/lib/template.d.ts.map +0 -1
  284. package/dist/lib/template.js.map +0 -1
  285. package/dist/types/index.d.ts.map +0 -1
  286. package/dist/types/index.js.map +0 -1
  287. package/dist/ui/AnalyzeUI.d.ts.map +0 -1
  288. package/dist/ui/AnalyzeUI.js.map +0 -1
  289. package/dist/ui/App.d.ts.map +0 -1
  290. package/dist/ui/App.js.map +0 -1
  291. package/dist/ui/CI.d.ts.map +0 -1
  292. package/dist/ui/CI.js.map +0 -1
  293. package/dist/ui/CIContext.d.ts.map +0 -1
  294. package/dist/ui/CIContext.js.map +0 -1
  295. package/dist/ui/CISelector.d.ts.map +0 -1
  296. package/dist/ui/CISelector.js.map +0 -1
  297. package/dist/ui/Doctor.d.ts.map +0 -1
  298. package/dist/ui/Doctor.js.map +0 -1
  299. package/dist/ui/Header.d.ts.map +0 -1
  300. package/dist/ui/Header.js.map +0 -1
  301. package/dist/ui/LlmsTxt.d.ts.map +0 -1
  302. package/dist/ui/LlmsTxt.js.map +0 -1
  303. package/dist/ui/MemorySelector.d.ts.map +0 -1
  304. package/dist/ui/MemorySelector.js.map +0 -1
  305. package/dist/ui/NameInput.d.ts.map +0 -1
  306. package/dist/ui/NameInput.js.map +0 -1
  307. package/dist/ui/OptionSelector.d.ts.map +0 -1
  308. package/dist/ui/OptionSelector.js.map +0 -1
  309. package/dist/ui/Plugin.d.ts.map +0 -1
  310. package/dist/ui/Plugin.js.map +0 -1
  311. package/dist/ui/Progress.d.ts.map +0 -1
  312. package/dist/ui/Progress.js.map +0 -1
  313. package/dist/ui/Skills.d.ts.map +0 -1
  314. package/dist/ui/Skills.js.map +0 -1
  315. package/dist/ui/StackSelector.d.ts.map +0 -1
  316. package/dist/ui/StackSelector.js.map +0 -1
  317. package/dist/ui/Summary.d.ts.map +0 -1
  318. package/dist/ui/Summary.js.map +0 -1
  319. package/dist/ui/Welcome.d.ts.map +0 -1
  320. package/dist/ui/Welcome.js.map +0 -1
  321. package/dist/ui/theme.d.ts.map +0 -1
  322. package/dist/ui/theme.js.map +0 -1
@@ -1,20 +1,20 @@
1
- import YAML from 'yaml';
1
+ import YAML from "yaml";
2
2
  /**
3
3
  * Extract YAML frontmatter from a markdown string.
4
4
  * Frontmatter is delimited by --- at the start of the file.
5
5
  */
6
6
  export function parseFrontmatter(raw) {
7
7
  const trimmed = raw.trimStart();
8
- if (!trimmed.startsWith('---'))
8
+ if (!trimmed.startsWith("---"))
9
9
  return null;
10
- const endIdx = trimmed.indexOf('---', 3);
10
+ const endIdx = trimmed.indexOf("---", 3);
11
11
  if (endIdx === -1)
12
12
  return null;
13
13
  const yamlBlock = trimmed.slice(3, endIdx).trim();
14
14
  const content = trimmed.slice(endIdx + 3).trim();
15
15
  try {
16
16
  const data = YAML.parse(yamlBlock);
17
- if (typeof data !== 'object' || data === null)
17
+ if (typeof data !== "object" || data === null)
18
18
  return null;
19
19
  return { data, content };
20
20
  }
@@ -29,30 +29,44 @@ const KEBAB_CASE_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
29
29
  export function validateFrontmatter(frontmatter, type) {
30
30
  const errors = [];
31
31
  // name: required, kebab-case, 2-60 chars
32
- const name = frontmatter['name'];
33
- if (typeof name !== 'string' || !name) {
34
- errors.push({ field: 'name', message: 'name is required and must be a string' });
32
+ const name = frontmatter.name;
33
+ if (typeof name !== "string" || !name) {
34
+ errors.push({
35
+ field: "name",
36
+ message: "name is required and must be a string",
37
+ });
35
38
  }
36
39
  else {
37
40
  if (name.length < 2 || name.length > 60) {
38
- errors.push({ field: 'name', message: 'name must be 2-60 characters' });
41
+ errors.push({ field: "name", message: "name must be 2-60 characters" });
39
42
  }
40
43
  if (!KEBAB_CASE_RE.test(name)) {
41
- errors.push({ field: 'name', message: 'name must be kebab-case (e.g. my-skill-name)' });
44
+ errors.push({
45
+ field: "name",
46
+ message: "name must be kebab-case (e.g. my-skill-name)",
47
+ });
42
48
  }
43
49
  }
44
50
  // description: required, non-empty, min 10 chars
45
- const desc = frontmatter['description'];
46
- if (typeof desc !== 'string' || !desc) {
47
- errors.push({ field: 'description', message: 'description is required and must be a string' });
51
+ const desc = frontmatter.description;
52
+ if (typeof desc !== "string" || !desc) {
53
+ errors.push({
54
+ field: "description",
55
+ message: "description is required and must be a string",
56
+ });
48
57
  }
49
58
  else if (desc.length < 10) {
50
- errors.push({ field: 'description', message: 'description must be at least 10 characters' });
59
+ errors.push({
60
+ field: "description",
61
+ message: "description must be at least 10 characters",
62
+ });
51
63
  }
52
64
  // skill-specific: description should include "Trigger:" hint
53
- if (type === 'skill' && typeof desc === 'string' && !desc.includes('Trigger:')) {
65
+ if (type === "skill" &&
66
+ typeof desc === "string" &&
67
+ !desc.includes("Trigger:")) {
54
68
  errors.push({
55
- field: 'description',
69
+ field: "description",
56
70
  message: 'skill description should include a "Trigger:" hint for auto-invoke',
57
71
  });
58
72
  }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Harness audit — scores how well-configured the AI agent development
3
+ * environment is (hooks, skills, memory, configs). Detects which AI
4
+ * agent harness is installed and generates appropriate config.
5
+ */
6
+ export type Harness = "claude" | "cursor" | "codex" | "copilot" | "windsurf" | "none";
7
+ export interface HarnessDetection {
8
+ harness: Harness;
9
+ configDir: string | null;
10
+ version: string | null;
11
+ }
12
+ export interface AuditCategory {
13
+ name: string;
14
+ score: number;
15
+ maxScore: number;
16
+ checks: AuditCheck[];
17
+ }
18
+ export interface AuditCheck {
19
+ id: string;
20
+ label: string;
21
+ passed: boolean;
22
+ points: number;
23
+ detail?: string;
24
+ }
25
+ export interface HarnessAuditResult {
26
+ harness: Harness;
27
+ totalScore: number;
28
+ maxScore: number;
29
+ grade: string;
30
+ categories: AuditCategory[];
31
+ }
32
+ export declare function detectHarness(projectDir: string): HarnessDetection;
33
+ export declare function detectAllHarnesses(projectDir: string): HarnessDetection[];
34
+ export declare function runHarnessAudit(projectDir: string): HarnessAuditResult;
35
+ //# sourceMappingURL=harness-audit.d.ts.map
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Harness audit — scores how well-configured the AI agent development
3
+ * environment is (hooks, skills, memory, configs). Detects which AI
4
+ * agent harness is installed and generates appropriate config.
5
+ */
6
+ import path from "node:path";
7
+ import fs from "fs-extra";
8
+ // ── Harness Detection ──
9
+ const HARNESS_SIGNATURES = [
10
+ {
11
+ harness: "claude",
12
+ markers: [".claude", "CLAUDE.md"],
13
+ configDir: ".claude",
14
+ },
15
+ {
16
+ harness: "cursor",
17
+ markers: [".cursor", ".cursorrules"],
18
+ configDir: ".cursor",
19
+ },
20
+ { harness: "codex", markers: [".codex", "AGENTS.md"], configDir: ".codex" },
21
+ {
22
+ harness: "copilot",
23
+ markers: [".github/copilot-instructions.md"],
24
+ configDir: ".github",
25
+ },
26
+ { harness: "windsurf", markers: [".windsurfrules"], configDir: "." },
27
+ ];
28
+ export function detectHarness(projectDir) {
29
+ for (const sig of HARNESS_SIGNATURES) {
30
+ for (const marker of sig.markers) {
31
+ const fullPath = path.join(projectDir, marker);
32
+ if (fs.existsSync(fullPath)) {
33
+ return {
34
+ harness: sig.harness,
35
+ configDir: path.join(projectDir, sig.configDir),
36
+ version: null,
37
+ };
38
+ }
39
+ }
40
+ }
41
+ // Check home directory for global installs
42
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
43
+ if (home && fs.existsSync(path.join(home, ".claude"))) {
44
+ return {
45
+ harness: "claude",
46
+ configDir: path.join(home, ".claude"),
47
+ version: null,
48
+ };
49
+ }
50
+ return { harness: "none", configDir: null, version: null };
51
+ }
52
+ export function detectAllHarnesses(projectDir) {
53
+ const found = [];
54
+ for (const sig of HARNESS_SIGNATURES) {
55
+ for (const marker of sig.markers) {
56
+ if (fs.existsSync(path.join(projectDir, marker))) {
57
+ found.push({
58
+ harness: sig.harness,
59
+ configDir: path.join(projectDir, sig.configDir),
60
+ version: null,
61
+ });
62
+ break; // one detection per harness
63
+ }
64
+ }
65
+ }
66
+ return found;
67
+ }
68
+ // ── Audit Checks ──
69
+ function checkFileExists(dir, relativePath) {
70
+ return fs.existsSync(path.join(dir, relativePath));
71
+ }
72
+ function checkDirHasFiles(dir, relativePath) {
73
+ const full = path.join(dir, relativePath);
74
+ if (!fs.existsSync(full))
75
+ return false;
76
+ try {
77
+ const entries = fs.readdirSync(full);
78
+ return entries.length > 0;
79
+ }
80
+ catch {
81
+ return false;
82
+ }
83
+ }
84
+ function auditClaude(projectDir, configDir) {
85
+ const categories = [];
86
+ // Config category
87
+ const configChecks = [
88
+ {
89
+ id: "claude-md",
90
+ label: "CLAUDE.md exists",
91
+ passed: checkFileExists(projectDir, "CLAUDE.md") ||
92
+ checkFileExists(configDir, "CLAUDE.md"),
93
+ points: 15,
94
+ },
95
+ {
96
+ id: "settings",
97
+ label: "settings.json configured",
98
+ passed: checkFileExists(configDir, "settings.json") ||
99
+ checkFileExists(configDir, "settings.local.json"),
100
+ points: 10,
101
+ },
102
+ {
103
+ id: "project-config",
104
+ label: "Project-level config exists",
105
+ passed: checkDirHasFiles(configDir, "projects"),
106
+ points: 5,
107
+ },
108
+ ];
109
+ // Skills category
110
+ const skillChecks = [
111
+ {
112
+ id: "skills-dir",
113
+ label: "Skills directory exists",
114
+ passed: checkDirHasFiles(configDir, "skills"),
115
+ points: 15,
116
+ },
117
+ {
118
+ id: "skills-count",
119
+ label: "At least 5 skills installed",
120
+ passed: countSubdirs(path.join(configDir, "skills")) >= 5,
121
+ points: 10,
122
+ },
123
+ {
124
+ id: "shared-conventions",
125
+ label: "Shared conventions configured",
126
+ passed: checkDirHasFiles(configDir, "skills/_shared"),
127
+ points: 5,
128
+ },
129
+ ];
130
+ // Hooks category
131
+ const hookChecks = [
132
+ {
133
+ id: "hooks-configured",
134
+ label: "Hooks configured in settings",
135
+ passed: hasHooksInSettings(configDir),
136
+ points: 15,
137
+ },
138
+ {
139
+ id: "pre-commit-hook",
140
+ label: "Pre-commit or CI hook exists",
141
+ passed: checkFileExists(projectDir, ".husky/pre-commit") ||
142
+ checkFileExists(projectDir, ".git/hooks/pre-commit"),
143
+ points: 5,
144
+ },
145
+ ];
146
+ // Memory category
147
+ const memoryChecks = [
148
+ {
149
+ id: "memory-dir",
150
+ label: "Memory/projects directory exists",
151
+ passed: checkDirHasFiles(configDir, "projects"),
152
+ points: 10,
153
+ },
154
+ {
155
+ id: "memory-md",
156
+ label: "MEMORY.md exists in projects",
157
+ passed: hasMemoryMd(configDir),
158
+ points: 10,
159
+ },
160
+ ];
161
+ categories.push(buildCategory("Configuration", configChecks));
162
+ categories.push(buildCategory("Skills", skillChecks));
163
+ categories.push(buildCategory("Hooks", hookChecks));
164
+ categories.push(buildCategory("Memory", memoryChecks));
165
+ return categories;
166
+ }
167
+ function auditGeneric(projectDir) {
168
+ const checks = [
169
+ {
170
+ id: "has-config",
171
+ label: "AI agent config file exists",
172
+ passed: HARNESS_SIGNATURES.some((sig) => sig.markers.some((m) => checkFileExists(projectDir, m))),
173
+ points: 30,
174
+ },
175
+ {
176
+ id: "has-gitignore",
177
+ label: ".gitignore excludes agent artifacts",
178
+ passed: gitignoreHasAgent(projectDir),
179
+ points: 10,
180
+ },
181
+ ];
182
+ return [buildCategory("Basic Setup", checks)];
183
+ }
184
+ // ── Helpers ──
185
+ function countSubdirs(dir) {
186
+ if (!fs.existsSync(dir))
187
+ return 0;
188
+ try {
189
+ return fs
190
+ .readdirSync(dir, { withFileTypes: true })
191
+ .filter((d) => d.isDirectory()).length;
192
+ }
193
+ catch {
194
+ return 0;
195
+ }
196
+ }
197
+ function hasHooksInSettings(configDir) {
198
+ const settingsPath = path.join(configDir, "settings.json");
199
+ if (!fs.existsSync(settingsPath))
200
+ return false;
201
+ try {
202
+ const content = fs.readFileSync(settingsPath, "utf-8");
203
+ return content.includes("hooks") || content.includes("hook");
204
+ }
205
+ catch {
206
+ return false;
207
+ }
208
+ }
209
+ function hasMemoryMd(configDir) {
210
+ const projectsDir = path.join(configDir, "projects");
211
+ if (!fs.existsSync(projectsDir))
212
+ return false;
213
+ try {
214
+ const dirs = fs.readdirSync(projectsDir, { withFileTypes: true });
215
+ return dirs.some((d) => {
216
+ if (!d.isDirectory())
217
+ return false;
218
+ const memDir = path.join(projectsDir, d.name, "memory");
219
+ return (fs.existsSync(memDir) && fs.existsSync(path.join(memDir, "MEMORY.md")));
220
+ });
221
+ }
222
+ catch {
223
+ return false;
224
+ }
225
+ }
226
+ function gitignoreHasAgent(projectDir) {
227
+ const giPath = path.join(projectDir, ".gitignore");
228
+ if (!fs.existsSync(giPath))
229
+ return false;
230
+ try {
231
+ const content = fs.readFileSync(giPath, "utf-8");
232
+ return (content.includes(".claude") ||
233
+ content.includes(".cursor") ||
234
+ content.includes(".codex"));
235
+ }
236
+ catch {
237
+ return false;
238
+ }
239
+ }
240
+ function buildCategory(name, checks) {
241
+ const score = checks
242
+ .filter((c) => c.passed)
243
+ .reduce((sum, c) => sum + c.points, 0);
244
+ const maxScore = checks.reduce((sum, c) => sum + c.points, 0);
245
+ return { name, score, maxScore, checks };
246
+ }
247
+ function computeGrade(score, max) {
248
+ if (max === 0)
249
+ return "F";
250
+ const pct = (score / max) * 100;
251
+ if (pct >= 90)
252
+ return "A";
253
+ if (pct >= 75)
254
+ return "B";
255
+ if (pct >= 60)
256
+ return "C";
257
+ if (pct >= 40)
258
+ return "D";
259
+ return "F";
260
+ }
261
+ // ── Main ──
262
+ export function runHarnessAudit(projectDir) {
263
+ const detection = detectHarness(projectDir);
264
+ const categories = detection.harness === "claude" && detection.configDir
265
+ ? auditClaude(projectDir, detection.configDir)
266
+ : auditGeneric(projectDir);
267
+ const totalScore = categories.reduce((s, c) => s + c.score, 0);
268
+ const maxScore = categories.reduce((s, c) => s + c.maxScore, 0);
269
+ return {
270
+ harness: detection.harness,
271
+ totalScore,
272
+ maxScore,
273
+ grade: computeGrade(totalScore, maxScore),
274
+ categories,
275
+ };
276
+ }
277
+ //# sourceMappingURL=harness-audit.js.map
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Parallel batch sub-agents — spawn test/lint/build runners per module
3
+ * in parallel during quality scoring. Collects results and aggregates.
4
+ */
5
+ export type JobStatus = "pending" | "running" | "done" | "error";
6
+ export interface BatchJob {
7
+ id: string;
8
+ name: string;
9
+ command: string;
10
+ module: string;
11
+ status: JobStatus;
12
+ startedAt: number | null;
13
+ completedAt: number | null;
14
+ durationMs: number;
15
+ exitCode: number | null;
16
+ stdout: string;
17
+ stderr: string;
18
+ }
19
+ export interface BatchResult {
20
+ jobs: BatchJob[];
21
+ totalDurationMs: number;
22
+ passedCount: number;
23
+ failedCount: number;
24
+ parallelism: number;
25
+ }
26
+ export interface BatchConfig {
27
+ maxParallel: number;
28
+ timeoutMs: number;
29
+ }
30
+ export declare const DEFAULT_BATCH_CONFIG: BatchConfig;
31
+ export declare function createJob(name: string, command: string, module: string): BatchJob;
32
+ export type JobExecutor = (job: BatchJob) => Promise<BatchJob>;
33
+ /**
34
+ * Default executor — runs command via child_process.
35
+ */
36
+ export declare function createShellExecutor(timeoutMs?: number): JobExecutor;
37
+ /**
38
+ * Run jobs in parallel with configurable concurrency.
39
+ */
40
+ export declare function runBatch(jobs: BatchJob[], executor: JobExecutor, config?: BatchConfig): Promise<BatchResult>;
41
+ export declare function formatBatchResult(result: BatchResult): string;
42
+ //# sourceMappingURL=parallel-batch.d.ts.map
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Parallel batch sub-agents — spawn test/lint/build runners per module
3
+ * in parallel during quality scoring. Collects results and aggregates.
4
+ */
5
+ import { execFileAsync } from "./exec.js";
6
+ export const DEFAULT_BATCH_CONFIG = {
7
+ maxParallel: 4,
8
+ timeoutMs: 60_000,
9
+ };
10
+ // ── Job creation ──
11
+ let _jobCounter = 0;
12
+ export function createJob(name, command, module) {
13
+ _jobCounter++;
14
+ return {
15
+ id: `job-${Date.now()}-${_jobCounter}`,
16
+ name,
17
+ command,
18
+ module,
19
+ status: "pending",
20
+ startedAt: null,
21
+ completedAt: null,
22
+ durationMs: 0,
23
+ exitCode: null,
24
+ stdout: "",
25
+ stderr: "",
26
+ };
27
+ }
28
+ /**
29
+ * Default executor — runs command via child_process.
30
+ */
31
+ export function createShellExecutor(timeoutMs = 60_000) {
32
+ return async (job) => {
33
+ job.status = "running";
34
+ job.startedAt = Date.now();
35
+ try {
36
+ const { stdout, stderr } = await execFileAsync("sh", ["-c", job.command], { timeout: timeoutMs, maxBuffer: 5 * 1024 * 1024 });
37
+ job.stdout = stdout;
38
+ job.stderr = stderr;
39
+ job.exitCode = 0;
40
+ job.status = "done";
41
+ }
42
+ catch (err) {
43
+ const e = err;
44
+ job.stdout = e.stdout ?? "";
45
+ job.stderr = e.stderr ?? "";
46
+ job.exitCode = e.killed ? -1 : (e.code ?? 1);
47
+ job.status = "error";
48
+ }
49
+ job.completedAt = Date.now();
50
+ job.durationMs = job.completedAt - job.startedAt;
51
+ return job;
52
+ };
53
+ }
54
+ /**
55
+ * Run jobs in parallel with configurable concurrency.
56
+ */
57
+ export async function runBatch(jobs, executor, config = DEFAULT_BATCH_CONFIG) {
58
+ const start = Date.now();
59
+ const results = [];
60
+ const queue = [...jobs];
61
+ // Process in waves of maxParallel
62
+ while (queue.length > 0) {
63
+ const wave = queue.splice(0, config.maxParallel);
64
+ const waveResults = await Promise.all(wave.map((j) => executor(j)));
65
+ results.push(...waveResults);
66
+ }
67
+ return {
68
+ jobs: results,
69
+ totalDurationMs: Date.now() - start,
70
+ passedCount: results.filter((j) => j.status === "done").length,
71
+ failedCount: results.filter((j) => j.status === "error").length,
72
+ parallelism: config.maxParallel,
73
+ };
74
+ }
75
+ // ── Formatting ──
76
+ export function formatBatchResult(result) {
77
+ const status = result.failedCount === 0 ? "✅ ALL PASSED" : "❌ FAILURES";
78
+ const lines = [];
79
+ lines.push(`## Batch Result: ${status}`);
80
+ lines.push(`**Jobs**: ${result.jobs.length} | **Passed**: ${result.passedCount} | **Failed**: ${result.failedCount} | **Time**: ${result.totalDurationMs}ms | **Parallelism**: ${result.parallelism}`);
81
+ lines.push("");
82
+ for (const job of result.jobs) {
83
+ const icon = job.status === "done" ? "✓" : "✗";
84
+ lines.push(` ${icon} ${job.name} (${job.module}) — ${job.durationMs}ms [exit ${job.exitCode}]`);
85
+ }
86
+ return lines.join("\n");
87
+ }
88
+ //# sourceMappingURL=parallel-batch.js.map
@@ -1,4 +1,4 @@
1
- import type { PluginValidationResult, InstalledPlugin, PluginRegistryEntry, PluginSyncResult } from '../types/index.js';
1
+ import type { InstalledPlugin, PluginRegistryEntry, PluginSyncResult, PluginValidationResult } from "../types/index.js";
2
2
  /**
3
3
  * Validate a plugin directory structure and manifest.
4
4
  */
@@ -37,8 +37,14 @@ export declare function searchRegistry(query?: string): Promise<PluginRegistryEn
37
37
  */
38
38
  export declare function detectProjectPlugins(projectDir: string): Promise<string[]>;
39
39
  /**
40
- * Sync detected plugins into the project manifest.
41
- * Returns a report of added, removed, and unchanged plugins.
40
+ * Detect installed plugins with full metadata (including manifest).
41
+ * Used by auto-wiring to read plugin capabilities.
42
+ */
43
+ export declare function detectProjectPluginsFull(projectDir: string): Promise<InstalledPlugin[]>;
44
+ /**
45
+ * Sync detected plugins into the project manifest and auto-wire
46
+ * their capabilities into CLAUDE.md and .claude/settings.json.
47
+ * Returns a report of added, removed, unchanged, wired, and unwired plugins.
42
48
  */
43
49
  export declare function syncPlugins(projectDir: string, options?: {
44
50
  dryRun?: boolean;