javi-forge 1.6.0 → 1.6.1

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 (231) hide show
  1. package/dist/commands/analyze.d.ts +1 -1
  2. package/dist/commands/analyze.js +15 -15
  3. package/dist/commands/atlassian-mcp.d.ts +42 -0
  4. package/dist/commands/atlassian-mcp.js +98 -0
  5. package/dist/commands/ci.d.ts +3 -3
  6. package/dist/commands/ci.js +185 -147
  7. package/dist/commands/crash-recovery.d.ts +34 -0
  8. package/dist/commands/crash-recovery.js +123 -0
  9. package/dist/commands/doctor.d.ts +2 -2
  10. package/dist/commands/doctor.js +113 -61
  11. package/dist/commands/harness-audit.d.ts +35 -0
  12. package/dist/commands/harness-audit.js +277 -0
  13. package/dist/commands/init.d.ts +1 -1
  14. package/dist/commands/init.js +384 -141
  15. package/dist/commands/llmstxt.d.ts +1 -1
  16. package/dist/commands/llmstxt.js +36 -34
  17. package/dist/commands/parallel-batch.d.ts +42 -0
  18. package/dist/commands/parallel-batch.js +90 -0
  19. package/dist/commands/plugin.d.ts +10 -1
  20. package/dist/commands/plugin.js +92 -47
  21. package/dist/commands/secret-scanner.d.ts +30 -0
  22. package/dist/commands/secret-scanner.js +272 -0
  23. package/dist/commands/security-analysis.d.ts +74 -0
  24. package/dist/commands/security-analysis.js +487 -0
  25. package/dist/commands/security.d.ts +11 -5
  26. package/dist/commands/security.js +216 -76
  27. package/dist/commands/skill-scanner.d.ts +63 -0
  28. package/dist/commands/skill-scanner.js +383 -0
  29. package/dist/commands/skills.d.ts +62 -5
  30. package/dist/commands/skills.js +439 -54
  31. package/dist/commands/supply-chain.d.ts +23 -0
  32. package/dist/commands/supply-chain.js +126 -0
  33. package/dist/commands/tdd-pipeline.d.ts +17 -0
  34. package/dist/commands/tdd-pipeline.js +144 -0
  35. package/dist/commands/tdd.d.ts +1 -1
  36. package/dist/commands/tdd.js +21 -18
  37. package/dist/commands/team-presets.d.ts +53 -0
  38. package/dist/commands/team-presets.js +201 -0
  39. package/dist/commands/workflow.d.ts +23 -0
  40. package/dist/commands/workflow.js +114 -0
  41. package/dist/constants.d.ts +15 -1
  42. package/dist/constants.js +161 -122
  43. package/dist/index.js +308 -98
  44. package/dist/lib/agent-skills.d.ts +36 -1
  45. package/dist/lib/agent-skills.js +168 -19
  46. package/dist/lib/auto-skill-install.d.ts +37 -0
  47. package/dist/lib/auto-skill-install.js +92 -0
  48. package/dist/lib/auto-wire.d.ts +20 -0
  49. package/dist/lib/auto-wire.js +240 -0
  50. package/dist/lib/claudemd.d.ts +13 -1
  51. package/dist/lib/claudemd.js +174 -24
  52. package/dist/lib/codex-export.d.ts +1 -1
  53. package/dist/lib/codex-export.js +29 -31
  54. package/dist/lib/common.d.ts +1 -1
  55. package/dist/lib/common.js +52 -44
  56. package/dist/lib/context.d.ts +17 -2
  57. package/dist/lib/context.js +142 -13
  58. package/dist/lib/docker.d.ts +1 -1
  59. package/dist/lib/docker.js +141 -112
  60. package/dist/lib/frontmatter.d.ts +1 -1
  61. package/dist/lib/frontmatter.js +29 -15
  62. package/dist/lib/plugin.d.ts +9 -3
  63. package/dist/lib/plugin.js +128 -69
  64. package/dist/lib/skill-publish.d.ts +40 -0
  65. package/dist/lib/skill-publish.js +146 -0
  66. package/dist/lib/stack-detector.d.ts +38 -0
  67. package/dist/lib/stack-detector.js +207 -0
  68. package/dist/lib/template.d.ts +16 -1
  69. package/dist/lib/template.js +46 -17
  70. package/dist/lib/workflow/discovery.d.ts +19 -0
  71. package/dist/lib/workflow/discovery.js +68 -0
  72. package/dist/lib/workflow/index.d.ts +5 -0
  73. package/dist/lib/workflow/index.js +5 -0
  74. package/dist/lib/workflow/parser.d.ts +16 -0
  75. package/dist/lib/workflow/parser.js +198 -0
  76. package/dist/lib/workflow/renderer.d.ts +9 -0
  77. package/dist/lib/workflow/renderer.js +152 -0
  78. package/dist/lib/workflow/validator.d.ts +10 -0
  79. package/dist/lib/workflow/validator.js +189 -0
  80. package/dist/tasks/index.d.ts +4 -0
  81. package/dist/tasks/index.js +4 -0
  82. package/dist/tasks/scaffold-tasks.d.ts +3 -0
  83. package/dist/tasks/scaffold-tasks.js +14 -0
  84. package/dist/tasks/task-id.d.ts +30 -0
  85. package/dist/tasks/task-id.js +55 -0
  86. package/dist/tasks/task-tracker.d.ts +15 -0
  87. package/dist/tasks/task-tracker.js +81 -0
  88. package/dist/types/index.d.ts +134 -6
  89. package/dist/types/index.js +11 -1
  90. package/dist/ui/AnalyzeUI.d.ts +1 -1
  91. package/dist/ui/AnalyzeUI.js +38 -39
  92. package/dist/ui/App.d.ts +5 -3
  93. package/dist/ui/App.js +86 -46
  94. package/dist/ui/AutoSkills.d.ts +9 -0
  95. package/dist/ui/AutoSkills.js +124 -0
  96. package/dist/ui/CI.d.ts +2 -2
  97. package/dist/ui/CI.js +24 -26
  98. package/dist/ui/CIContext.d.ts +1 -1
  99. package/dist/ui/CIContext.js +3 -2
  100. package/dist/ui/CISelector.d.ts +2 -2
  101. package/dist/ui/CISelector.js +23 -15
  102. package/dist/ui/Doctor.d.ts +1 -1
  103. package/dist/ui/Doctor.js +35 -29
  104. package/dist/ui/Header.d.ts +1 -1
  105. package/dist/ui/Header.js +14 -14
  106. package/dist/ui/HookProfileSelector.d.ts +9 -0
  107. package/dist/ui/HookProfileSelector.js +54 -0
  108. package/dist/ui/LlmsTxt.d.ts +1 -1
  109. package/dist/ui/LlmsTxt.js +31 -22
  110. package/dist/ui/MemorySelector.d.ts +2 -2
  111. package/dist/ui/MemorySelector.js +28 -16
  112. package/dist/ui/NameInput.d.ts +1 -1
  113. package/dist/ui/NameInput.js +21 -21
  114. package/dist/ui/OptionSelector.d.ts +6 -2
  115. package/dist/ui/OptionSelector.js +83 -32
  116. package/dist/ui/Plugin.d.ts +4 -3
  117. package/dist/ui/Plugin.js +78 -35
  118. package/dist/ui/Progress.d.ts +3 -3
  119. package/dist/ui/Progress.js +23 -22
  120. package/dist/ui/Skills.d.ts +2 -2
  121. package/dist/ui/Skills.js +61 -32
  122. package/dist/ui/StackSelector.d.ts +2 -2
  123. package/dist/ui/StackSelector.js +26 -16
  124. package/dist/ui/Summary.d.ts +3 -3
  125. package/dist/ui/Summary.js +60 -50
  126. package/dist/ui/Welcome.d.ts +1 -1
  127. package/dist/ui/Welcome.js +15 -16
  128. package/dist/ui/theme.d.ts +1 -1
  129. package/dist/ui/theme.js +6 -6
  130. package/package.json +9 -6
  131. package/templates/common/atlassian/mcp-atlassian-snippet.json +16 -0
  132. package/templates/common/repoforge/mcp-repoforge-snippet.json +11 -0
  133. package/templates/common/repoforge/repoforge.yaml +34 -0
  134. package/templates/github/deploy-docker-zero-downtime.yml +140 -0
  135. package/templates/github/repoforge-graph.yml +45 -0
  136. package/templates/gitlab/deploy-docker-zero-downtime.yml +57 -0
  137. package/templates/local-ai/.env.example +17 -0
  138. package/templates/local-ai/docker-compose.yml +95 -0
  139. package/templates/security-hooks/claude-settings-security.json +30 -0
  140. package/templates/security-hooks/commit-msg-signing +29 -0
  141. package/templates/security-hooks/pre-commit-permissions +74 -0
  142. package/templates/security-hooks/pre-commit-secrets +74 -0
  143. package/templates/security-hooks/pre-push-branch-protection +62 -0
  144. package/templates/security-hooks/pre-push-deps +83 -0
  145. package/templates/security-hooks/pre-push-signing +67 -0
  146. package/templates/woodpecker/deploy-docker-zero-downtime.yml +50 -0
  147. package/templates/workflows/ci-pipeline.dot +15 -0
  148. package/templates/workflows/feature-flow.dot +21 -0
  149. package/templates/workflows/release.dot +16 -0
  150. package/dist/__integration__/helpers.d.ts +0 -20
  151. package/dist/__integration__/helpers.d.ts.map +0 -1
  152. package/dist/__integration__/helpers.js +0 -31
  153. package/dist/__integration__/helpers.js.map +0 -1
  154. package/dist/commands/analyze.d.ts.map +0 -1
  155. package/dist/commands/analyze.js.map +0 -1
  156. package/dist/commands/ci.d.ts.map +0 -1
  157. package/dist/commands/ci.js.map +0 -1
  158. package/dist/commands/doctor.d.ts.map +0 -1
  159. package/dist/commands/doctor.js.map +0 -1
  160. package/dist/commands/init.d.ts.map +0 -1
  161. package/dist/commands/init.js.map +0 -1
  162. package/dist/commands/llmstxt.d.ts.map +0 -1
  163. package/dist/commands/llmstxt.js.map +0 -1
  164. package/dist/commands/plugin.d.ts.map +0 -1
  165. package/dist/commands/plugin.js.map +0 -1
  166. package/dist/commands/security.d.ts.map +0 -1
  167. package/dist/commands/security.js.map +0 -1
  168. package/dist/commands/skills.d.ts.map +0 -1
  169. package/dist/commands/skills.js.map +0 -1
  170. package/dist/commands/tdd.d.ts.map +0 -1
  171. package/dist/commands/tdd.js.map +0 -1
  172. package/dist/constants.d.ts.map +0 -1
  173. package/dist/constants.js.map +0 -1
  174. package/dist/index.d.ts.map +0 -1
  175. package/dist/index.js.map +0 -1
  176. package/dist/lib/agent-skills.d.ts.map +0 -1
  177. package/dist/lib/agent-skills.js.map +0 -1
  178. package/dist/lib/claudemd.d.ts.map +0 -1
  179. package/dist/lib/claudemd.js.map +0 -1
  180. package/dist/lib/codex-export.d.ts.map +0 -1
  181. package/dist/lib/codex-export.js.map +0 -1
  182. package/dist/lib/common.d.ts.map +0 -1
  183. package/dist/lib/common.js.map +0 -1
  184. package/dist/lib/context.d.ts.map +0 -1
  185. package/dist/lib/context.js.map +0 -1
  186. package/dist/lib/docker.d.ts.map +0 -1
  187. package/dist/lib/docker.js.map +0 -1
  188. package/dist/lib/frontmatter.d.ts.map +0 -1
  189. package/dist/lib/frontmatter.js.map +0 -1
  190. package/dist/lib/plugin.d.ts.map +0 -1
  191. package/dist/lib/plugin.js.map +0 -1
  192. package/dist/lib/template.d.ts.map +0 -1
  193. package/dist/lib/template.js.map +0 -1
  194. package/dist/types/index.d.ts.map +0 -1
  195. package/dist/types/index.js.map +0 -1
  196. package/dist/ui/AnalyzeUI.d.ts.map +0 -1
  197. package/dist/ui/AnalyzeUI.js.map +0 -1
  198. package/dist/ui/App.d.ts.map +0 -1
  199. package/dist/ui/App.js.map +0 -1
  200. package/dist/ui/CI.d.ts.map +0 -1
  201. package/dist/ui/CI.js.map +0 -1
  202. package/dist/ui/CIContext.d.ts.map +0 -1
  203. package/dist/ui/CIContext.js.map +0 -1
  204. package/dist/ui/CISelector.d.ts.map +0 -1
  205. package/dist/ui/CISelector.js.map +0 -1
  206. package/dist/ui/Doctor.d.ts.map +0 -1
  207. package/dist/ui/Doctor.js.map +0 -1
  208. package/dist/ui/Header.d.ts.map +0 -1
  209. package/dist/ui/Header.js.map +0 -1
  210. package/dist/ui/LlmsTxt.d.ts.map +0 -1
  211. package/dist/ui/LlmsTxt.js.map +0 -1
  212. package/dist/ui/MemorySelector.d.ts.map +0 -1
  213. package/dist/ui/MemorySelector.js.map +0 -1
  214. package/dist/ui/NameInput.d.ts.map +0 -1
  215. package/dist/ui/NameInput.js.map +0 -1
  216. package/dist/ui/OptionSelector.d.ts.map +0 -1
  217. package/dist/ui/OptionSelector.js.map +0 -1
  218. package/dist/ui/Plugin.d.ts.map +0 -1
  219. package/dist/ui/Plugin.js.map +0 -1
  220. package/dist/ui/Progress.d.ts.map +0 -1
  221. package/dist/ui/Progress.js.map +0 -1
  222. package/dist/ui/Skills.d.ts.map +0 -1
  223. package/dist/ui/Skills.js.map +0 -1
  224. package/dist/ui/StackSelector.d.ts.map +0 -1
  225. package/dist/ui/StackSelector.js.map +0 -1
  226. package/dist/ui/Summary.d.ts.map +0 -1
  227. package/dist/ui/Summary.js.map +0 -1
  228. package/dist/ui/Welcome.d.ts.map +0 -1
  229. package/dist/ui/Welcome.js.map +0 -1
  230. package/dist/ui/theme.d.ts.map +0 -1
  231. package/dist/ui/theme.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,22 +1,23 @@
1
1
  #!/usr/bin/env node
2
- import path from 'path';
3
- import React from 'react';
4
- import { render } from 'ink';
5
- import { PassThrough } from 'node:stream';
6
- import meow from 'meow';
7
- import updateNotifier from 'update-notifier';
8
- import { createRequire } from 'module';
9
- import App from './ui/App.js';
10
- import Doctor from './ui/Doctor.js';
11
- import AnalyzeUI from './ui/AnalyzeUI.js';
12
- import Plugin from './ui/Plugin.js';
13
- import Skills from './ui/Skills.js';
14
- import LlmsTxt from './ui/LlmsTxt.js';
15
- import CI from './ui/CI.js';
16
- import { CIProvider as CIContextProvider } from './ui/CIContext.js';
2
+ import { PassThrough } from "node:stream";
3
+ import { render } from "ink";
4
+ import meow from "meow";
5
+ import { createRequire } from "module";
6
+ import path from "path";
7
+ import React from "react";
8
+ import updateNotifier from "update-notifier";
9
+ import AnalyzeUI from "./ui/AnalyzeUI.js";
10
+ import App from "./ui/App.js";
11
+ import AutoSkills from "./ui/AutoSkills.js";
12
+ import CI from "./ui/CI.js";
13
+ import { CIProvider as CIContextProvider } from "./ui/CIContext.js";
14
+ import Doctor from "./ui/Doctor.js";
15
+ import LlmsTxt from "./ui/LlmsTxt.js";
16
+ import Plugin from "./ui/Plugin.js";
17
+ import Skills from "./ui/Skills.js";
17
18
  // Check for updates in background (non-blocking, cached 24h)
18
19
  const _require = createRequire(import.meta.url);
19
- const pkg = _require('../package.json');
20
+ const pkg = _require("../package.json");
20
21
  updateNotifier({ pkg, updateCheckInterval: 1000 * 60 * 60 * 24 }).notify();
21
22
  const cli = meow(`
22
23
  Usage
@@ -26,8 +27,12 @@ const cli = meow(`
26
27
  init Bootstrap a new project (default)
27
28
  ci Run CI simulation (lint + compile + test + security + ghagga)
28
29
  tdd init Install TDD-enforcing pre-commit hook (auto-detects stack)
30
+ tdd pipeline Install TDD pipeline pre-push hook (--mode strict|warn)
29
31
  analyze Run repoforge skills analysis
30
32
  doctor Show health report
33
+ workflow show Render a workflow graph as ASCII (--template <name> or file path)
34
+ workflow validate Validate project state against a workflow graph
35
+ workflow list List available workflows and built-in templates
31
36
  plugin add Install a plugin from GitHub (org/repo)
32
37
  plugin remove Remove an installed plugin
33
38
  plugin list List installed plugins
@@ -35,14 +40,21 @@ const cli = meow(`
35
40
  plugin validate Validate a local plugin directory
36
41
  plugin sync Auto-detect and wire installed plugins
37
42
  plugin export Export plugin to Agent Skills spec format (skills.json)
43
+ plugin export --codex: Export plugin to Codex-compatible TOML subagent files
44
+ plugin export-skills Generate aggregated skills.json from all installed plugins
45
+ plugin export-skills global Generate global skills.json from all globally installed plugins
38
46
  plugin import Import an Agent Skills spec package as a javi-forge plugin
39
47
  skills doctor Show skills health report (add --deep for conflict detection)
40
48
  skills budget Show token cost of loaded skills (add -b N for custom budget)
41
49
  skills score Score a skill on quality dimensions (completeness, clarity, testability, token-efficiency)
42
50
  skills benchmark Benchmark a skill with structural quality checks
43
- security baseline Create security baseline from current audit findings
44
- security check Check for regressions against baseline (exits non-zero if found)
45
- security update Re-snapshot baseline (acknowledge current vulns)
51
+ skills auto Auto-detect project stack and suggest/install matching AI skills
52
+ skills auto-install Alias for skills auto
53
+ skill publish Package a skill directory for marketplace distribution (generates plugin.json)
54
+ security baseline Create security baseline from current audit findings
55
+ security check Check for regressions against baseline (exits non-zero if found)
56
+ security update Re-snapshot baseline (acknowledge current vulns)
57
+ security allowlist Add all current findings to the allowlist (suppress in future checks)
46
58
  llms-txt Generate AI-friendly llms.txt for current project
47
59
 
48
60
  Options
@@ -53,10 +65,13 @@ const cli = meow(`
53
65
  --project-name Project name (skips name prompt)
54
66
  --ghagga Enable GHAGGA review system
55
67
  --mock Enable mock-first mode (no real API keys needed)
68
+ --local-ai Include local AI dev stack (Ollama + Docker Compose)
56
69
  --batch Non-interactive mode (auto-proceed, no keyboard input)
57
70
  --deep Enable deep analysis (conflict + duplicate detection)
58
71
  --budget, -b Token budget limit for skills (default: 8000)
59
72
  --skills-dir Custom skills directory path
73
+ --author Author name for skill publish
74
+ --repo Repository URL for skill publish
60
75
  --version Show version
61
76
  --help Show this help
62
77
 
@@ -91,68 +106,107 @@ const cli = meow(`
91
106
  `, {
92
107
  importMeta: import.meta,
93
108
  flags: {
94
- dryRun: { type: 'boolean', default: false },
95
- stack: { type: 'string', default: '' },
96
- ci: { type: 'string', default: '' },
97
- memory: { type: 'string', default: '' },
98
- projectName: { type: 'string', default: '' },
99
- ghagga: { type: 'boolean', default: false },
100
- mock: { type: 'boolean', default: false },
101
- batch: { type: 'boolean', default: false },
109
+ dryRun: { type: "boolean", default: false },
110
+ stack: { type: "string", default: "" },
111
+ ci: { type: "string", default: "" },
112
+ memory: { type: "string", default: "" },
113
+ projectName: { type: "string", default: "" },
114
+ ghagga: { type: "boolean", default: false },
115
+ mock: { type: "boolean", default: false },
116
+ localAi: { type: "boolean", default: false },
117
+ batch: { type: "boolean", default: false },
102
118
  // CI flags
103
- quick: { type: 'boolean', default: false },
104
- shell: { type: 'boolean', default: false },
105
- detect: { type: 'boolean', default: false },
106
- docker: { type: 'boolean', default: true },
107
- ciGhagga: { type: 'boolean', default: true },
108
- security: { type: 'boolean', default: true },
109
- timeout: { type: 'number', default: 600 },
119
+ quick: { type: "boolean", default: false },
120
+ shell: { type: "boolean", default: false },
121
+ detect: { type: "boolean", default: false },
122
+ docker: { type: "boolean", default: true },
123
+ ciGhagga: { type: "boolean", default: true },
124
+ security: { type: "boolean", default: true },
125
+ timeout: { type: "number", default: 600 },
126
+ // Security check flags
127
+ minSeverity: { type: "string", default: "low" },
128
+ staleDays: { type: "number", default: 30 },
129
+ json: { type: "boolean", default: false },
130
+ // Plugin flags
131
+ codex: { type: "boolean", default: false },
110
132
  // Skills flags
111
- deep: { type: 'boolean', default: false },
112
- budget: { type: 'number', shortFlag: 'b', default: 8000 },
113
- skillsDir: { type: 'string', default: '' },
114
- }
133
+ deep: { type: "boolean", default: false },
134
+ budget: { type: "number", shortFlag: "b", default: 8000 },
135
+ skillsDir: { type: "string", default: "" },
136
+ // Skill publish flags
137
+ author: { type: "string", default: "" },
138
+ repo: { type: "string", default: "" },
139
+ // Workflow flags
140
+ template: { type: "string", default: "" },
141
+ },
115
142
  });
116
- const subcommand = cli.input[0] ?? 'init';
117
- const VALID_STACKS = ['node', 'python', 'go', 'rust', 'java-gradle', 'java-maven', 'elixir'];
118
- const VALID_CI = ['github', 'gitlab', 'woodpecker'];
119
- const VALID_MEMORY = ['engram', 'obsidian-brain', 'memory-simple', 'none'];
120
- const isCI = cli.flags.batch || process.env['CI'] === '1' || process.env['CI'] === 'true';
143
+ const subcommand = cli.input[0] ?? "init";
144
+ const VALID_STACKS = [
145
+ "node",
146
+ "python",
147
+ "go",
148
+ "rust",
149
+ "java-gradle",
150
+ "java-maven",
151
+ "elixir",
152
+ ];
153
+ const VALID_CI = ["github", "gitlab", "woodpecker"];
154
+ const VALID_MEMORY = ["engram", "obsidian-brain", "memory-simple", "none"];
155
+ const isCI = cli.flags.batch || process.env["CI"] === "1" || process.env["CI"] === "true";
121
156
  // When stdin doesn't support raw mode (pipes, subprocesses, CI), provide a fake
122
157
  // stdin stream so Ink doesn't crash trying to enable raw mode on a non-TTY pipe.
123
158
  const isTTY = process.stdin.isTTY === true;
124
159
  const fakeStdin = new PassThrough();
125
- Object.defineProperty(fakeStdin, 'isTTY', { value: false });
160
+ Object.defineProperty(fakeStdin, "isTTY", { value: false });
126
161
  const inkStdin = isTTY ? process.stdin : fakeStdin;
127
162
  switch (subcommand) {
128
- case 'tdd': {
129
- if (cli.input[1] === 'init') {
130
- const { installTddHooks } = await import('./commands/tdd.js');
163
+ case "tdd": {
164
+ if (cli.input[1] === "init") {
165
+ const { installTddHooks } = await import("./commands/tdd.js");
131
166
  const { installed, errors } = await installTddHooks(process.cwd());
132
167
  if (installed.length > 0) {
133
- console.log(`\u2713 Installed TDD hooks: ${installed.join(', ')}`);
134
- console.log(' Pre-commit hook enforces tests must pass before commit');
168
+ console.log(`\u2713 Installed TDD hooks: ${installed.join(", ")}`);
169
+ console.log(" Pre-commit hook enforces tests must pass before commit");
135
170
  }
136
171
  for (const err of errors) {
137
172
  console.error(`\u2717 ${err}`);
138
173
  }
139
174
  process.exit(errors.length > 0 ? 1 : 0);
140
175
  }
176
+ else if (cli.input[1] === "pipeline") {
177
+ const { installTddPipelineHook } = await import("./commands/tdd-pipeline.js");
178
+ const mode = cli.flags.mode === "warn"
179
+ ? "warn"
180
+ : "strict";
181
+ const result = await installTddPipelineHook(process.cwd(), mode);
182
+ if (result.installed.length > 0) {
183
+ console.log(`\u2713 Installed TDD pipeline hook: ${result.installed.join(", ")} [${result.mode}]`);
184
+ console.log(` Pre-push hook enforces TDD pipeline (${result.mode} mode)`);
185
+ }
186
+ for (const skip of result.skipped) {
187
+ console.log(`\u26A0 ${skip}`);
188
+ }
189
+ for (const err of result.errors) {
190
+ console.error(`\u2717 ${err}`);
191
+ }
192
+ process.exit(result.errors.length > 0 ? 1 : 0);
193
+ }
141
194
  else {
142
- console.error('Usage: javi-forge tdd init');
143
- console.error(' init Install TDD-enforcing pre-commit hook');
195
+ console.error("Usage: javi-forge tdd <command>");
196
+ console.error(" init Install TDD-enforcing pre-commit hook");
197
+ console.error(" pipeline Install TDD pipeline pre-push hook (--mode strict|warn)");
144
198
  process.exit(1);
145
199
  }
146
200
  break;
147
201
  }
148
- case 'ci': {
202
+ case "ci": {
149
203
  // Sub-command: javi-forge ci init → install git hooks
150
- if (cli.input[1] === 'init') {
151
- const { installCIHooks } = await import('./commands/ci.js');
204
+ if (cli.input[1] === "init") {
205
+ const { installCIHooks } = await import("./commands/ci.js");
152
206
  const { installed, errors } = await installCIHooks(process.cwd());
153
207
  if (installed.length > 0) {
154
- console.log(`✓ Installed git hooks: ${installed.join(', ')}`);
155
- console.log(' Hooks call javi-forge ci (with npx fallback)');
208
+ console.log(`✓ Installed git hooks: ${installed.join(", ")}`);
209
+ console.log(" Hooks call javi-forge ci (with npx fallback)");
156
210
  }
157
211
  for (const err of errors) {
158
212
  console.error(`✗ ${err}`);
@@ -160,62 +214,153 @@ switch (subcommand) {
160
214
  process.exit(errors.length > 0 ? 1 : 0);
161
215
  break;
162
216
  }
163
- const ciMode = cli.flags.detect ? 'detect'
164
- : cli.flags.shell ? 'shell'
165
- : cli.flags.quick ? 'quick'
166
- : 'full';
217
+ const ciMode = cli.flags.detect
218
+ ? "detect"
219
+ : cli.flags.shell
220
+ ? "shell"
221
+ : cli.flags.quick
222
+ ? "quick"
223
+ : "full";
167
224
  render(React.createElement(CIContextProvider, { isCI: true },
168
225
  React.createElement(CI, { projectDir: process.cwd(), mode: ciMode, noDocker: !cli.flags.docker, noGhagga: !cli.flags.ciGhagga, noSecurity: !cli.flags.security, timeout: cli.flags.timeout })), { stdin: inkStdin });
169
226
  break;
170
227
  }
171
- case 'doctor': {
228
+ case "doctor": {
172
229
  render(React.createElement(CIContextProvider, { isCI: isCI },
173
230
  React.createElement(Doctor, null)), { stdin: inkStdin });
174
231
  break;
175
232
  }
176
- case 'analyze': {
233
+ case "analyze": {
177
234
  render(React.createElement(CIContextProvider, { isCI: isCI },
178
235
  React.createElement(AnalyzeUI, { dryRun: cli.flags.dryRun })), { stdin: inkStdin });
179
236
  break;
180
237
  }
181
- case 'llms-txt': {
238
+ case "workflow": {
239
+ const workflowAction = cli.input[1];
240
+ const VALID_WORKFLOW_ACTIONS = ["show", "validate", "list"];
241
+ if (!workflowAction || !VALID_WORKFLOW_ACTIONS.includes(workflowAction)) {
242
+ console.error("Usage: javi-forge workflow <show|validate|list>");
243
+ console.error(" show Render a workflow graph as ASCII");
244
+ console.error(" validate Validate project state against a workflow graph");
245
+ console.error(" list List available workflows and built-in templates");
246
+ console.error("");
247
+ console.error(" Options:");
248
+ console.error(" --template <name> Use a built-in template (ci-pipeline, release, feature-flow)");
249
+ console.error(" <file> Path to a .dot or .mermaid file");
250
+ process.exit(1);
251
+ break;
252
+ }
253
+ const { runWorkflowShow, runWorkflowValidate, runWorkflowList } = await import("./commands/workflow.js");
254
+ const workflowTarget = cli.input[2];
255
+ const workflowTemplate = cli.flags.template || undefined;
256
+ const onStep = (step) => {
257
+ const icon = step.status === "done"
258
+ ? "\u2713"
259
+ : step.status === "error"
260
+ ? "\u2717"
261
+ : "\u25CB";
262
+ console.log(`${icon} ${step.label}`);
263
+ if (step.detail)
264
+ console.log(` ${step.detail}`);
265
+ };
266
+ try {
267
+ if (workflowAction === "show") {
268
+ const output = await runWorkflowShow(process.cwd(), onStep, {
269
+ target: workflowTarget,
270
+ template: workflowTemplate,
271
+ });
272
+ if (output)
273
+ console.log("\n" + output);
274
+ else
275
+ process.exit(1);
276
+ }
277
+ else if (workflowAction === "validate") {
278
+ const output = await runWorkflowValidate(process.cwd(), onStep, {
279
+ target: workflowTarget,
280
+ template: workflowTemplate,
281
+ });
282
+ if (output)
283
+ console.log("\n" + output);
284
+ else
285
+ process.exit(1);
286
+ }
287
+ else {
288
+ const output = await runWorkflowList(process.cwd(), onStep);
289
+ console.log("\n" + output);
290
+ }
291
+ }
292
+ catch (e) {
293
+ console.error(`\u2717 ${e instanceof Error ? e.message : String(e)}`);
294
+ process.exit(1);
295
+ }
296
+ break;
297
+ }
298
+ case "llms-txt": {
182
299
  render(React.createElement(CIContextProvider, { isCI: isCI },
183
300
  React.createElement(LlmsTxt, { projectDir: process.cwd(), dryRun: cli.flags.dryRun })), { stdin: inkStdin });
184
301
  break;
185
302
  }
186
- case 'plugin': {
303
+ case "plugin": {
187
304
  const pluginAction = cli.input[1];
188
- const VALID_PLUGIN_ACTIONS = ['add', 'remove', 'list', 'search', 'validate', 'sync', 'export', 'import'];
189
- const action = pluginAction && VALID_PLUGIN_ACTIONS.includes(pluginAction) ? pluginAction : 'list';
305
+ const VALID_PLUGIN_ACTIONS = [
306
+ "add",
307
+ "remove",
308
+ "list",
309
+ "search",
310
+ "validate",
311
+ "sync",
312
+ "export",
313
+ "import",
314
+ "export-skills",
315
+ ];
316
+ const action = pluginAction && VALID_PLUGIN_ACTIONS.includes(pluginAction)
317
+ ? pluginAction
318
+ : "list";
190
319
  const target = cli.input[2];
191
320
  render(React.createElement(CIContextProvider, { isCI: isCI },
192
- React.createElement(Plugin, { action: action, target: target, dryRun: cli.flags.dryRun })), { stdin: inkStdin });
321
+ React.createElement(Plugin, { action: action, target: target, dryRun: cli.flags.dryRun, codex: cli.flags.codex })), { stdin: inkStdin });
193
322
  break;
194
323
  }
195
- case 'skills': {
324
+ case "skills": {
196
325
  const skillsAction = cli.input[1];
197
- const VALID_SKILLS_ACTIONS = ['doctor', 'budget', 'score', 'benchmark'];
326
+ const VALID_SKILLS_ACTIONS = [
327
+ "doctor",
328
+ "budget",
329
+ "score",
330
+ "benchmark",
331
+ "auto",
332
+ "auto-install",
333
+ ];
198
334
  if (!skillsAction || !VALID_SKILLS_ACTIONS.includes(skillsAction)) {
199
- console.error('Usage: javi-forge skills <doctor|budget|score|benchmark>');
200
- console.error(' doctor Show skills health report (add --deep for conflict detection)');
201
- console.error(' budget Show token cost of loaded skills (add -b N for custom budget)');
202
- console.error(' score Score a skill on quality dimensions (0-100)');
203
- console.error(' benchmark Benchmark a skill with structural quality checks');
335
+ console.error("Usage: javi-forge skills <doctor|budget|score|benchmark|auto>");
336
+ console.error(" doctor Show skills health report (add --deep for conflict detection)");
337
+ console.error(" budget Show token cost of loaded skills (add -b N for custom budget)");
338
+ console.error(" score Score a skill on quality dimensions (0-100)");
339
+ console.error(" benchmark Benchmark a skill with structural quality checks");
340
+ console.error(" auto Auto-detect project stack and suggest/install matching AI skills");
341
+ console.error(" auto-install Alias for auto");
204
342
  process.exit(1);
205
343
  break;
206
344
  }
345
+ // Auto / auto-install: render interactive Ink UI
346
+ if (skillsAction === "auto" || skillsAction === "auto-install") {
347
+ render(React.createElement(CIContextProvider, { isCI: isCI },
348
+ React.createElement(AutoSkills, { projectDir: process.cwd(), skillsDir: cli.flags.skillsDir || undefined, dryRun: cli.flags.dryRun })), { stdin: inkStdin });
349
+ break;
350
+ }
207
351
  // Score and benchmark are non-interactive CLI commands
208
- if (skillsAction === 'score' || skillsAction === 'benchmark') {
352
+ if (skillsAction === "score" || skillsAction === "benchmark") {
209
353
  const targetSkill = cli.input[2];
210
354
  if (!targetSkill) {
211
355
  console.error(`Usage: javi-forge skills ${skillsAction} <skill-name>`);
212
356
  process.exit(1);
213
357
  break;
214
358
  }
215
- const skillsDir = cli.flags.skillsDir || path.join(process.env['HOME'] ?? '~', '.claude', 'skills');
216
- const skillPath = path.join(skillsDir, targetSkill, 'SKILL.md');
217
- if (skillsAction === 'score') {
218
- const { scoreSkill } = await import('./commands/skills.js');
359
+ const skillsDir = cli.flags.skillsDir ||
360
+ path.join(process.env["HOME"] ?? "~", ".claude", "skills");
361
+ const skillPath = path.join(skillsDir, targetSkill, "SKILL.md");
362
+ if (skillsAction === "score") {
363
+ const { scoreSkill } = await import("./commands/skills.js");
219
364
  const result = await scoreSkill(skillPath, cli.flags.budget);
220
365
  if (!result) {
221
366
  console.error(`\u2717 Skill not found: ${skillPath}`);
@@ -227,13 +372,17 @@ switch (subcommand) {
227
372
  console.log(` Clarity: ${result.clarity}/100`);
228
373
  console.log(` Testability: ${result.testability}/100`);
229
374
  console.log(` Token Efficiency: ${result.tokenEfficiency}/100`);
375
+ console.log(` Safety: ${result.safety}/100`);
376
+ console.log(` Agent Readiness: ${result.agentReadiness}/100`);
377
+ console.log(` ─────────────────────────`);
230
378
  console.log(` Overall: ${result.overall}/100`);
379
+ console.log(` Grade: ${result.grade}`);
231
380
  console.log(` Threshold: ${result.threshold}`);
232
- console.log(` Status: ${result.passing ? '\u2713 PASSING' : '\u2717 FAILING'}`);
381
+ console.log(` Status: ${result.passing ? "\u2713 PASSING" : "\u2717 FAILING"}`);
233
382
  process.exit(result.passing ? 0 : 1);
234
383
  }
235
384
  else {
236
- const { benchmarkSkill } = await import('./commands/skills.js');
385
+ const { benchmarkSkill } = await import("./commands/skills.js");
237
386
  const result = await benchmarkSkill(skillPath);
238
387
  if (!result) {
239
388
  console.error(`\u2717 Skill not found: ${skillPath}`);
@@ -242,8 +391,8 @@ switch (subcommand) {
242
391
  }
243
392
  console.log(`\nBenchmark: ${result.skillName}`);
244
393
  for (const check of result.checks) {
245
- const icon = check.passed ? '\u2713' : '\u2717';
246
- console.log(` ${icon} ${check.name}${check.detail ? ` — ${check.detail}` : ''}`);
394
+ const icon = check.passed ? "\u2713" : "\u2717";
395
+ console.log(` ${icon} ${check.name}${check.detail ? ` — ${check.detail}` : ""}`);
247
396
  }
248
397
  console.log(`\n Pass rate: ${result.passRate}%`);
249
398
  process.exit(result.passRate >= 50 ? 0 : 1);
@@ -255,30 +404,91 @@ switch (subcommand) {
255
404
  React.createElement(Skills, { mode: skillsMode, budget: cli.flags.budget, deep: cli.flags.deep, skillsDir: cli.flags.skillsDir || undefined })), { stdin: inkStdin });
256
405
  break;
257
406
  }
258
- case 'security': {
407
+ case "skill": {
408
+ const skillAction = cli.input[1];
409
+ if (skillAction !== "publish") {
410
+ console.error("Usage: javi-forge skill <publish>");
411
+ console.error(" publish Package a skill directory for marketplace distribution");
412
+ process.exit(1);
413
+ break;
414
+ }
415
+ const targetDir = cli.input[2] ?? process.cwd();
416
+ const { publishSkill } = await import("./lib/skill-publish.js");
417
+ const result = await publishSkill({
418
+ skillDir: path.resolve(targetDir),
419
+ author: cli.flags.author || undefined,
420
+ repository: cli.flags.repo || undefined,
421
+ dryRun: cli.flags.dryRun,
422
+ });
423
+ if (result.success) {
424
+ console.log(`\u2713 Published: ${result.manifest?.name}@${result.manifest?.version}`);
425
+ console.log(` plugin.json: ${result.pluginJsonPath}`);
426
+ if (result.manifest?.tags?.length) {
427
+ console.log(` tags: ${result.manifest.tags.join(", ")}`);
428
+ }
429
+ if (cli.flags.dryRun) {
430
+ console.log(" (dry-run: no files written)");
431
+ }
432
+ }
433
+ else {
434
+ console.error(`\u2717 ${result.error}`);
435
+ process.exit(1);
436
+ }
437
+ break;
438
+ }
439
+ case "security": {
259
440
  const securityAction = cli.input[1];
260
- const VALID_SECURITY_ACTIONS = ['baseline', 'check', 'update'];
441
+ const VALID_SECURITY_ACTIONS = ["baseline", "check", "update", "allowlist"];
261
442
  if (!securityAction || !VALID_SECURITY_ACTIONS.includes(securityAction)) {
262
- console.error('Usage: javi-forge security <baseline|check|update>');
263
- console.error(' baseline Create security baseline from current audit findings');
264
- console.error(' check Check for regressions against baseline');
265
- console.error(' update Re-snapshot baseline (acknowledge current vulns)');
443
+ console.error("Usage: javi-forge security <baseline|check|update|allowlist>");
444
+ console.error(" baseline Create security baseline from current audit findings");
445
+ console.error(" check Check for regressions against baseline (exits non-zero if found)");
446
+ console.error(" update Re-snapshot baseline (acknowledge current vulns)");
447
+ console.error(" allowlist Add all current findings to the allowlist (suppress in future checks)");
448
+ console.error("");
449
+ console.error(" Options (check mode):");
450
+ console.error(" --min-severity <level> Only fail on regressions >= level (critical|high|moderate|low|info)");
451
+ console.error(" --stale-days <N> Warn if baseline older than N days (default: 30)");
452
+ console.error(" --json Output result as JSON (for CI integration)");
266
453
  process.exit(1);
267
454
  break;
268
455
  }
269
- const { runSecurity } = await import('./commands/security.js');
456
+ const { runSecurity } = await import("./commands/security.js");
270
457
  const mode = securityAction;
458
+ const rawMinSev = cli.flags["minSeverity"];
459
+ const validSeverities = [
460
+ "critical",
461
+ "high",
462
+ "moderate",
463
+ "low",
464
+ "info",
465
+ ];
466
+ const checkOptions = {
467
+ minSeverity: (rawMinSev && validSeverities.includes(rawMinSev)
468
+ ? rawMinSev
469
+ : "low"),
470
+ staleDays: cli.flags["staleDays"],
471
+ };
472
+ const jsonOutput = !!cli.flags["json"];
271
473
  try {
272
474
  const result = await runSecurity(mode, process.cwd(), (step) => {
273
- const icon = step.status === 'done' ? '\u2713'
274
- : step.status === 'error' ? '\u2717'
275
- : step.status === 'skipped' ? '-'
276
- : '\u25CB';
475
+ if (jsonOutput)
476
+ return; // suppress step output in JSON mode
477
+ const icon = step.status === "done"
478
+ ? "\u2713"
479
+ : step.status === "error"
480
+ ? "\u2717"
481
+ : step.status === "skipped"
482
+ ? "-"
483
+ : "\u25CB";
277
484
  console.log(`${icon} ${step.label}`);
278
485
  if (step.detail)
279
486
  console.log(` ${step.detail}`);
280
- });
281
- if (mode === 'check' && result && result.regressions.length > 0) {
487
+ }, checkOptions);
488
+ if (jsonOutput && result) {
489
+ console.log(JSON.stringify(result, null, 2));
490
+ }
491
+ if (mode === "check" && result && result.filteredRegressions.length > 0) {
282
492
  process.exit(1);
283
493
  }
284
494
  }
@@ -287,7 +497,7 @@ switch (subcommand) {
287
497
  }
288
498
  break;
289
499
  }
290
- case 'init':
500
+ case "init":
291
501
  default: {
292
502
  const presetStack = VALID_STACKS.includes(cli.flags.stack)
293
503
  ? cli.flags.stack
@@ -300,7 +510,7 @@ switch (subcommand) {
300
510
  : undefined;
301
511
  const presetName = cli.flags.projectName || undefined;
302
512
  render(React.createElement(CIContextProvider, { isCI: isCI },
303
- React.createElement(App, { dryRun: cli.flags.dryRun, presetStack: presetStack, presetCI: presetCI, presetMemory: presetMemory, presetName: presetName, presetGhagga: cli.flags.ghagga, presetMock: cli.flags.mock ?? false })), { stdin: inkStdin });
513
+ React.createElement(App, { dryRun: cli.flags.dryRun, presetStack: presetStack, presetCI: presetCI, presetMemory: presetMemory, presetName: presetName, presetGhagga: cli.flags.ghagga, presetMock: cli.flags.mock ?? false, presetLocalAi: cli.flags.localAi ?? false })), { stdin: inkStdin });
304
514
  break;
305
515
  }
306
516
  }
@@ -1,4 +1,4 @@
1
- import type { PluginManifest, AgentSkillsManifest } from '../types/index.js';
1
+ import type { AgentSkillsManifest, AggregatedSkillsManifest, InstalledPlugin, PluginManifest } from "../types/index.js";
2
2
  /**
3
3
  * Convert a javi-forge PluginManifest to an Agent Skills spec manifest.
4
4
  */
@@ -35,4 +35,39 @@ export declare function importAgentSkillsPackage(sourceDir: string, options?: {
35
35
  name?: string;
36
36
  error?: string;
37
37
  }>;
38
+ /**
39
+ * Aggregate multiple installed plugins into a single Agent Skills spec manifest.
40
+ * This enables the entire registry (or a project's installed plugins) to be
41
+ * discoverable via `npx skills add` by any of the 40+ compatible AI agents.
42
+ *
43
+ * Pure function — no I/O.
44
+ */
45
+ export declare function aggregatePluginsToSkillsJson(plugins: InstalledPlugin[], registryName?: string, registryVersion?: string): AggregatedSkillsManifest;
46
+ /**
47
+ * Generate a project-level skills.json from all installed plugins in a project.
48
+ * Writes the aggregated manifest to the project's .javi-forge/ directory.
49
+ */
50
+ export declare function generateProjectSkillsJson(projectDir: string, options?: {
51
+ dryRun?: boolean;
52
+ registryName?: string;
53
+ }): Promise<{
54
+ success: boolean;
55
+ path?: string;
56
+ skillCount: number;
57
+ pluginCount: number;
58
+ error?: string;
59
+ }>;
60
+ /**
61
+ * Generate a skills.json from all globally installed plugins.
62
+ * Writes to the global plugins directory.
63
+ */
64
+ export declare function generateGlobalSkillsJson(options?: {
65
+ dryRun?: boolean;
66
+ }): Promise<{
67
+ success: boolean;
68
+ path?: string;
69
+ skillCount: number;
70
+ pluginCount: number;
71
+ error?: string;
72
+ }>;
38
73
  //# sourceMappingURL=agent-skills.d.ts.map