javi-forge 1.5.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 (217) hide show
  1. package/README.md +191 -3
  2. package/ci-local/hooks/pre-push +17 -13
  3. package/dist/commands/analyze.d.ts +1 -1
  4. package/dist/commands/analyze.js +15 -15
  5. package/dist/commands/atlassian-mcp.d.ts +42 -0
  6. package/dist/commands/atlassian-mcp.js +98 -0
  7. package/dist/commands/ci.d.ts +3 -3
  8. package/dist/commands/ci.js +185 -147
  9. package/dist/commands/crash-recovery.d.ts +34 -0
  10. package/dist/commands/crash-recovery.js +123 -0
  11. package/dist/commands/doctor.d.ts +2 -2
  12. package/dist/commands/doctor.js +113 -61
  13. package/dist/commands/harness-audit.d.ts +35 -0
  14. package/dist/commands/harness-audit.js +277 -0
  15. package/dist/commands/init.d.ts +1 -1
  16. package/dist/commands/init.js +415 -118
  17. package/dist/commands/llmstxt.d.ts +1 -1
  18. package/dist/commands/llmstxt.js +36 -34
  19. package/dist/commands/parallel-batch.d.ts +42 -0
  20. package/dist/commands/parallel-batch.js +90 -0
  21. package/dist/commands/plugin.d.ts +26 -1
  22. package/dist/commands/plugin.js +138 -24
  23. package/dist/commands/secret-scanner.d.ts +30 -0
  24. package/dist/commands/secret-scanner.js +272 -0
  25. package/dist/commands/security-analysis.d.ts +74 -0
  26. package/dist/commands/security-analysis.js +487 -0
  27. package/dist/commands/security.d.ts +31 -0
  28. package/dist/commands/security.js +445 -0
  29. package/dist/commands/skill-scanner.d.ts +63 -0
  30. package/dist/commands/skill-scanner.js +383 -0
  31. package/dist/commands/skills.d.ts +139 -0
  32. package/dist/commands/skills.js +895 -0
  33. package/dist/commands/supply-chain.d.ts +23 -0
  34. package/dist/commands/supply-chain.js +126 -0
  35. package/dist/commands/tdd-pipeline.d.ts +17 -0
  36. package/dist/commands/tdd-pipeline.js +144 -0
  37. package/dist/commands/tdd.d.ts +21 -0
  38. package/dist/commands/tdd.js +120 -0
  39. package/dist/commands/team-presets.d.ts +53 -0
  40. package/dist/commands/team-presets.js +201 -0
  41. package/dist/commands/workflow.d.ts +23 -0
  42. package/dist/commands/workflow.js +114 -0
  43. package/dist/constants.d.ts +21 -0
  44. package/dist/constants.js +208 -37
  45. package/dist/index.js +400 -54
  46. package/dist/lib/agent-skills.d.ts +73 -0
  47. package/dist/lib/agent-skills.js +260 -0
  48. package/dist/lib/auto-skill-install.d.ts +37 -0
  49. package/dist/lib/auto-skill-install.js +92 -0
  50. package/dist/lib/auto-wire.d.ts +20 -0
  51. package/dist/lib/auto-wire.js +240 -0
  52. package/dist/lib/claudemd.d.ts +20 -0
  53. package/dist/lib/claudemd.js +222 -0
  54. package/dist/lib/codex-export.d.ts +16 -0
  55. package/dist/lib/codex-export.js +109 -0
  56. package/dist/lib/common.d.ts +1 -1
  57. package/dist/lib/common.js +52 -44
  58. package/dist/lib/context.d.ts +27 -0
  59. package/dist/lib/context.js +204 -0
  60. package/dist/lib/docker.d.ts +1 -1
  61. package/dist/lib/docker.js +141 -112
  62. package/dist/lib/frontmatter.d.ts +1 -1
  63. package/dist/lib/frontmatter.js +29 -15
  64. package/dist/lib/plugin.d.ts +19 -1
  65. package/dist/lib/plugin.js +174 -47
  66. package/dist/lib/skill-publish.d.ts +40 -0
  67. package/dist/lib/skill-publish.js +146 -0
  68. package/dist/lib/stack-detector.d.ts +38 -0
  69. package/dist/lib/stack-detector.js +207 -0
  70. package/dist/lib/template.d.ts +16 -1
  71. package/dist/lib/template.js +46 -17
  72. package/dist/lib/workflow/discovery.d.ts +19 -0
  73. package/dist/lib/workflow/discovery.js +68 -0
  74. package/dist/lib/workflow/index.d.ts +5 -0
  75. package/dist/lib/workflow/index.js +5 -0
  76. package/dist/lib/workflow/parser.d.ts +16 -0
  77. package/dist/lib/workflow/parser.js +198 -0
  78. package/dist/lib/workflow/renderer.d.ts +9 -0
  79. package/dist/lib/workflow/renderer.js +152 -0
  80. package/dist/lib/workflow/validator.d.ts +10 -0
  81. package/dist/lib/workflow/validator.js +189 -0
  82. package/dist/tasks/index.d.ts +4 -0
  83. package/dist/tasks/index.js +4 -0
  84. package/dist/tasks/scaffold-tasks.d.ts +3 -0
  85. package/dist/tasks/scaffold-tasks.js +14 -0
  86. package/dist/tasks/task-id.d.ts +30 -0
  87. package/dist/tasks/task-id.js +55 -0
  88. package/dist/tasks/task-tracker.d.ts +15 -0
  89. package/dist/tasks/task-tracker.js +81 -0
  90. package/dist/types/index.d.ts +252 -5
  91. package/dist/types/index.js +11 -1
  92. package/dist/ui/AnalyzeUI.d.ts +1 -1
  93. package/dist/ui/AnalyzeUI.js +38 -39
  94. package/dist/ui/App.d.ts +5 -3
  95. package/dist/ui/App.js +92 -46
  96. package/dist/ui/AutoSkills.d.ts +9 -0
  97. package/dist/ui/AutoSkills.js +124 -0
  98. package/dist/ui/CI.d.ts +2 -2
  99. package/dist/ui/CI.js +24 -26
  100. package/dist/ui/CIContext.d.ts +1 -1
  101. package/dist/ui/CIContext.js +3 -2
  102. package/dist/ui/CISelector.d.ts +2 -2
  103. package/dist/ui/CISelector.js +23 -15
  104. package/dist/ui/Doctor.d.ts +1 -1
  105. package/dist/ui/Doctor.js +35 -29
  106. package/dist/ui/Header.d.ts +1 -1
  107. package/dist/ui/Header.js +14 -14
  108. package/dist/ui/HookProfileSelector.d.ts +9 -0
  109. package/dist/ui/HookProfileSelector.js +54 -0
  110. package/dist/ui/LlmsTxt.d.ts +1 -1
  111. package/dist/ui/LlmsTxt.js +31 -22
  112. package/dist/ui/MemorySelector.d.ts +2 -2
  113. package/dist/ui/MemorySelector.js +28 -16
  114. package/dist/ui/NameInput.d.ts +1 -1
  115. package/dist/ui/NameInput.js +21 -21
  116. package/dist/ui/OptionSelector.d.ts +8 -2
  117. package/dist/ui/OptionSelector.js +83 -26
  118. package/dist/ui/Plugin.d.ts +4 -3
  119. package/dist/ui/Plugin.js +89 -29
  120. package/dist/ui/Progress.d.ts +3 -3
  121. package/dist/ui/Progress.js +23 -22
  122. package/dist/ui/Skills.d.ts +11 -0
  123. package/dist/ui/Skills.js +148 -0
  124. package/dist/ui/StackSelector.d.ts +2 -2
  125. package/dist/ui/StackSelector.js +26 -16
  126. package/dist/ui/Summary.d.ts +3 -3
  127. package/dist/ui/Summary.js +60 -50
  128. package/dist/ui/Welcome.d.ts +1 -1
  129. package/dist/ui/Welcome.js +15 -16
  130. package/dist/ui/theme.d.ts +1 -1
  131. package/dist/ui/theme.js +6 -6
  132. package/package.json +9 -6
  133. package/templates/common/atlassian/mcp-atlassian-snippet.json +16 -0
  134. package/templates/common/repoforge/mcp-repoforge-snippet.json +11 -0
  135. package/templates/common/repoforge/repoforge.yaml +34 -0
  136. package/templates/github/deploy-docker-zero-downtime.yml +140 -0
  137. package/templates/github/repoforge-graph.yml +45 -0
  138. package/templates/gitlab/deploy-docker-zero-downtime.yml +57 -0
  139. package/templates/local-ai/.env.example +17 -0
  140. package/templates/local-ai/docker-compose.yml +95 -0
  141. package/templates/security-hooks/claude-settings-security.json +30 -0
  142. package/templates/security-hooks/commit-msg-signing +29 -0
  143. package/templates/security-hooks/pre-commit-permissions +74 -0
  144. package/templates/security-hooks/pre-commit-secrets +74 -0
  145. package/templates/security-hooks/pre-push-branch-protection +62 -0
  146. package/templates/security-hooks/pre-push-deps +83 -0
  147. package/templates/security-hooks/pre-push-signing +67 -0
  148. package/templates/woodpecker/deploy-docker-zero-downtime.yml +50 -0
  149. package/templates/workflows/ci-pipeline.dot +15 -0
  150. package/templates/workflows/feature-flow.dot +21 -0
  151. package/templates/workflows/release.dot +16 -0
  152. package/dist/__integration__/helpers.d.ts +0 -20
  153. package/dist/__integration__/helpers.d.ts.map +0 -1
  154. package/dist/__integration__/helpers.js +0 -31
  155. package/dist/__integration__/helpers.js.map +0 -1
  156. package/dist/commands/analyze.d.ts.map +0 -1
  157. package/dist/commands/analyze.js.map +0 -1
  158. package/dist/commands/ci.d.ts.map +0 -1
  159. package/dist/commands/ci.js.map +0 -1
  160. package/dist/commands/doctor.d.ts.map +0 -1
  161. package/dist/commands/doctor.js.map +0 -1
  162. package/dist/commands/init.d.ts.map +0 -1
  163. package/dist/commands/init.js.map +0 -1
  164. package/dist/commands/llmstxt.d.ts.map +0 -1
  165. package/dist/commands/llmstxt.js.map +0 -1
  166. package/dist/commands/plugin.d.ts.map +0 -1
  167. package/dist/commands/plugin.js.map +0 -1
  168. package/dist/constants.d.ts.map +0 -1
  169. package/dist/constants.js.map +0 -1
  170. package/dist/index.d.ts.map +0 -1
  171. package/dist/index.js.map +0 -1
  172. package/dist/lib/common.d.ts.map +0 -1
  173. package/dist/lib/common.js.map +0 -1
  174. package/dist/lib/docker.d.ts.map +0 -1
  175. package/dist/lib/docker.js.map +0 -1
  176. package/dist/lib/frontmatter.d.ts.map +0 -1
  177. package/dist/lib/frontmatter.js.map +0 -1
  178. package/dist/lib/plugin.d.ts.map +0 -1
  179. package/dist/lib/plugin.js.map +0 -1
  180. package/dist/lib/template.d.ts.map +0 -1
  181. package/dist/lib/template.js.map +0 -1
  182. package/dist/types/index.d.ts.map +0 -1
  183. package/dist/types/index.js.map +0 -1
  184. package/dist/ui/AnalyzeUI.d.ts.map +0 -1
  185. package/dist/ui/AnalyzeUI.js.map +0 -1
  186. package/dist/ui/App.d.ts.map +0 -1
  187. package/dist/ui/App.js.map +0 -1
  188. package/dist/ui/CI.d.ts.map +0 -1
  189. package/dist/ui/CI.js.map +0 -1
  190. package/dist/ui/CIContext.d.ts.map +0 -1
  191. package/dist/ui/CIContext.js.map +0 -1
  192. package/dist/ui/CISelector.d.ts.map +0 -1
  193. package/dist/ui/CISelector.js.map +0 -1
  194. package/dist/ui/Doctor.d.ts.map +0 -1
  195. package/dist/ui/Doctor.js.map +0 -1
  196. package/dist/ui/Header.d.ts.map +0 -1
  197. package/dist/ui/Header.js.map +0 -1
  198. package/dist/ui/LlmsTxt.d.ts.map +0 -1
  199. package/dist/ui/LlmsTxt.js.map +0 -1
  200. package/dist/ui/MemorySelector.d.ts.map +0 -1
  201. package/dist/ui/MemorySelector.js.map +0 -1
  202. package/dist/ui/NameInput.d.ts.map +0 -1
  203. package/dist/ui/NameInput.js.map +0 -1
  204. package/dist/ui/OptionSelector.d.ts.map +0 -1
  205. package/dist/ui/OptionSelector.js.map +0 -1
  206. package/dist/ui/Plugin.d.ts.map +0 -1
  207. package/dist/ui/Plugin.js.map +0 -1
  208. package/dist/ui/Progress.d.ts.map +0 -1
  209. package/dist/ui/Progress.js.map +0 -1
  210. package/dist/ui/StackSelector.d.ts.map +0 -1
  211. package/dist/ui/StackSelector.js.map +0 -1
  212. package/dist/ui/Summary.d.ts.map +0 -1
  213. package/dist/ui/Summary.js.map +0 -1
  214. package/dist/ui/Welcome.d.ts.map +0 -1
  215. package/dist/ui/Welcome.js.map +0 -1
  216. package/dist/ui/theme.d.ts.map +0 -1
  217. package/dist/ui/theme.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,20 +1,23 @@
1
1
  #!/usr/bin/env node
2
- import React from 'react';
3
- import { render } from 'ink';
4
- import { PassThrough } from 'node:stream';
5
- import meow from 'meow';
6
- import updateNotifier from 'update-notifier';
7
- import { createRequire } from 'module';
8
- import App from './ui/App.js';
9
- import Doctor from './ui/Doctor.js';
10
- import AnalyzeUI from './ui/AnalyzeUI.js';
11
- import Plugin from './ui/Plugin.js';
12
- import LlmsTxt from './ui/LlmsTxt.js';
13
- import CI from './ui/CI.js';
14
- 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";
15
18
  // Check for updates in background (non-blocking, cached 24h)
16
19
  const _require = createRequire(import.meta.url);
17
- const pkg = _require('../package.json');
20
+ const pkg = _require("../package.json");
18
21
  updateNotifier({ pkg, updateCheckInterval: 1000 * 60 * 60 * 24 }).notify();
19
22
  const cli = meow(`
20
23
  Usage
@@ -23,13 +26,35 @@ const cli = meow(`
23
26
  Commands
24
27
  init Bootstrap a new project (default)
25
28
  ci Run CI simulation (lint + compile + test + security + ghagga)
29
+ tdd init Install TDD-enforcing pre-commit hook (auto-detects stack)
30
+ tdd pipeline Install TDD pipeline pre-push hook (--mode strict|warn)
26
31
  analyze Run repoforge skills analysis
27
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
28
36
  plugin add Install a plugin from GitHub (org/repo)
29
37
  plugin remove Remove an installed plugin
30
38
  plugin list List installed plugins
31
39
  plugin search Search the plugin registry
32
40
  plugin validate Validate a local plugin directory
41
+ plugin sync Auto-detect and wire installed plugins
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
46
+ plugin import Import an Agent Skills spec package as a javi-forge plugin
47
+ skills doctor Show skills health report (add --deep for conflict detection)
48
+ skills budget Show token cost of loaded skills (add -b N for custom budget)
49
+ skills score Score a skill on quality dimensions (completeness, clarity, testability, token-efficiency)
50
+ skills benchmark Benchmark a skill with structural quality checks
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)
33
58
  llms-txt Generate AI-friendly llms.txt for current project
34
59
 
35
60
  Options
@@ -40,7 +65,13 @@ const cli = meow(`
40
65
  --project-name Project name (skips name prompt)
41
66
  --ghagga Enable GHAGGA review system
42
67
  --mock Enable mock-first mode (no real API keys needed)
68
+ --local-ai Include local AI dev stack (Ollama + Docker Compose)
43
69
  --batch Non-interactive mode (auto-proceed, no keyboard input)
70
+ --deep Enable deep analysis (conflict + duplicate detection)
71
+ --budget, -b Token budget limit for skills (default: 8000)
72
+ --skills-dir Custom skills directory path
73
+ --author Author name for skill publish
74
+ --repo Repository URL for skill publish
44
75
  --version Show version
45
76
  --help Show this help
46
77
 
@@ -63,6 +94,7 @@ const cli = meow(`
63
94
  $ javi-forge init --stack node --ci github
64
95
  $ javi-forge ci
65
96
  $ javi-forge ci init
97
+ $ javi-forge tdd init
66
98
  $ javi-forge ci --quick
67
99
  $ javi-forge ci --no-ci-ghagga --no-security
68
100
  $ javi-forge ci --no-docker
@@ -74,44 +106,107 @@ const cli = meow(`
74
106
  `, {
75
107
  importMeta: import.meta,
76
108
  flags: {
77
- dryRun: { type: 'boolean', default: false },
78
- stack: { type: 'string', default: '' },
79
- ci: { type: 'string', default: '' },
80
- memory: { type: 'string', default: '' },
81
- projectName: { type: 'string', default: '' },
82
- ghagga: { type: 'boolean', default: false },
83
- mock: { type: 'boolean', default: false },
84
- 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 },
85
118
  // CI flags
86
- quick: { type: 'boolean', default: false },
87
- shell: { type: 'boolean', default: false },
88
- detect: { type: 'boolean', default: false },
89
- docker: { type: 'boolean', default: true },
90
- ciGhagga: { type: 'boolean', default: true },
91
- security: { type: 'boolean', default: true },
92
- timeout: { type: 'number', default: 600 },
93
- }
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 },
132
+ // Skills flags
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
+ },
94
142
  });
95
- const subcommand = cli.input[0] ?? 'init';
96
- const VALID_STACKS = ['node', 'python', 'go', 'rust', 'java-gradle', 'java-maven', 'elixir'];
97
- const VALID_CI = ['github', 'gitlab', 'woodpecker'];
98
- const VALID_MEMORY = ['engram', 'obsidian-brain', 'memory-simple', 'none'];
99
- 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";
100
156
  // When stdin doesn't support raw mode (pipes, subprocesses, CI), provide a fake
101
157
  // stdin stream so Ink doesn't crash trying to enable raw mode on a non-TTY pipe.
102
158
  const isTTY = process.stdin.isTTY === true;
103
159
  const fakeStdin = new PassThrough();
104
- Object.defineProperty(fakeStdin, 'isTTY', { value: false });
160
+ Object.defineProperty(fakeStdin, "isTTY", { value: false });
105
161
  const inkStdin = isTTY ? process.stdin : fakeStdin;
106
162
  switch (subcommand) {
107
- case 'ci': {
163
+ case "tdd": {
164
+ if (cli.input[1] === "init") {
165
+ const { installTddHooks } = await import("./commands/tdd.js");
166
+ const { installed, errors } = await installTddHooks(process.cwd());
167
+ if (installed.length > 0) {
168
+ console.log(`\u2713 Installed TDD hooks: ${installed.join(", ")}`);
169
+ console.log(" Pre-commit hook enforces tests must pass before commit");
170
+ }
171
+ for (const err of errors) {
172
+ console.error(`\u2717 ${err}`);
173
+ }
174
+ process.exit(errors.length > 0 ? 1 : 0);
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
+ }
194
+ else {
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)");
198
+ process.exit(1);
199
+ }
200
+ break;
201
+ }
202
+ case "ci": {
108
203
  // Sub-command: javi-forge ci init → install git hooks
109
- if (cli.input[1] === 'init') {
110
- const { installCIHooks } = await import('./commands/ci.js');
204
+ if (cli.input[1] === "init") {
205
+ const { installCIHooks } = await import("./commands/ci.js");
111
206
  const { installed, errors } = await installCIHooks(process.cwd());
112
207
  if (installed.length > 0) {
113
- console.log(`✓ Installed git hooks: ${installed.join(', ')}`);
114
- 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)");
115
210
  }
116
211
  for (const err of errors) {
117
212
  console.error(`✗ ${err}`);
@@ -119,39 +214,290 @@ switch (subcommand) {
119
214
  process.exit(errors.length > 0 ? 1 : 0);
120
215
  break;
121
216
  }
122
- const ciMode = cli.flags.detect ? 'detect'
123
- : cli.flags.shell ? 'shell'
124
- : cli.flags.quick ? 'quick'
125
- : 'full';
217
+ const ciMode = cli.flags.detect
218
+ ? "detect"
219
+ : cli.flags.shell
220
+ ? "shell"
221
+ : cli.flags.quick
222
+ ? "quick"
223
+ : "full";
126
224
  render(React.createElement(CIContextProvider, { isCI: true },
127
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 });
128
226
  break;
129
227
  }
130
- case 'doctor': {
228
+ case "doctor": {
131
229
  render(React.createElement(CIContextProvider, { isCI: isCI },
132
230
  React.createElement(Doctor, null)), { stdin: inkStdin });
133
231
  break;
134
232
  }
135
- case 'analyze': {
233
+ case "analyze": {
136
234
  render(React.createElement(CIContextProvider, { isCI: isCI },
137
235
  React.createElement(AnalyzeUI, { dryRun: cli.flags.dryRun })), { stdin: inkStdin });
138
236
  break;
139
237
  }
140
- 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": {
141
299
  render(React.createElement(CIContextProvider, { isCI: isCI },
142
300
  React.createElement(LlmsTxt, { projectDir: process.cwd(), dryRun: cli.flags.dryRun })), { stdin: inkStdin });
143
301
  break;
144
302
  }
145
- case 'plugin': {
303
+ case "plugin": {
146
304
  const pluginAction = cli.input[1];
147
- const VALID_PLUGIN_ACTIONS = ['add', 'remove', 'list', 'search', 'validate'];
148
- 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";
149
319
  const target = cli.input[2];
150
320
  render(React.createElement(CIContextProvider, { isCI: isCI },
151
- 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 });
322
+ break;
323
+ }
324
+ case "skills": {
325
+ const skillsAction = cli.input[1];
326
+ const VALID_SKILLS_ACTIONS = [
327
+ "doctor",
328
+ "budget",
329
+ "score",
330
+ "benchmark",
331
+ "auto",
332
+ "auto-install",
333
+ ];
334
+ if (!skillsAction || !VALID_SKILLS_ACTIONS.includes(skillsAction)) {
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");
342
+ process.exit(1);
343
+ break;
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
+ }
351
+ // Score and benchmark are non-interactive CLI commands
352
+ if (skillsAction === "score" || skillsAction === "benchmark") {
353
+ const targetSkill = cli.input[2];
354
+ if (!targetSkill) {
355
+ console.error(`Usage: javi-forge skills ${skillsAction} <skill-name>`);
356
+ process.exit(1);
357
+ break;
358
+ }
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");
364
+ const result = await scoreSkill(skillPath, cli.flags.budget);
365
+ if (!result) {
366
+ console.error(`\u2717 Skill not found: ${skillPath}`);
367
+ process.exit(1);
368
+ break;
369
+ }
370
+ console.log(`\nSkill: ${result.skillName}`);
371
+ console.log(` Completeness: ${result.completeness}/100`);
372
+ console.log(` Clarity: ${result.clarity}/100`);
373
+ console.log(` Testability: ${result.testability}/100`);
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(` ─────────────────────────`);
378
+ console.log(` Overall: ${result.overall}/100`);
379
+ console.log(` Grade: ${result.grade}`);
380
+ console.log(` Threshold: ${result.threshold}`);
381
+ console.log(` Status: ${result.passing ? "\u2713 PASSING" : "\u2717 FAILING"}`);
382
+ process.exit(result.passing ? 0 : 1);
383
+ }
384
+ else {
385
+ const { benchmarkSkill } = await import("./commands/skills.js");
386
+ const result = await benchmarkSkill(skillPath);
387
+ if (!result) {
388
+ console.error(`\u2717 Skill not found: ${skillPath}`);
389
+ process.exit(1);
390
+ break;
391
+ }
392
+ console.log(`\nBenchmark: ${result.skillName}`);
393
+ for (const check of result.checks) {
394
+ const icon = check.passed ? "\u2713" : "\u2717";
395
+ console.log(` ${icon} ${check.name}${check.detail ? ` — ${check.detail}` : ""}`);
396
+ }
397
+ console.log(`\n Pass rate: ${result.passRate}%`);
398
+ process.exit(result.passRate >= 50 ? 0 : 1);
399
+ }
400
+ break;
401
+ }
402
+ const skillsMode = skillsAction;
403
+ render(React.createElement(CIContextProvider, { isCI: isCI },
404
+ React.createElement(Skills, { mode: skillsMode, budget: cli.flags.budget, deep: cli.flags.deep, skillsDir: cli.flags.skillsDir || undefined })), { stdin: inkStdin });
405
+ break;
406
+ }
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": {
440
+ const securityAction = cli.input[1];
441
+ const VALID_SECURITY_ACTIONS = ["baseline", "check", "update", "allowlist"];
442
+ if (!securityAction || !VALID_SECURITY_ACTIONS.includes(securityAction)) {
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)");
453
+ process.exit(1);
454
+ break;
455
+ }
456
+ const { runSecurity } = await import("./commands/security.js");
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"];
473
+ try {
474
+ const result = await runSecurity(mode, process.cwd(), (step) => {
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";
484
+ console.log(`${icon} ${step.label}`);
485
+ if (step.detail)
486
+ console.log(` ${step.detail}`);
487
+ }, checkOptions);
488
+ if (jsonOutput && result) {
489
+ console.log(JSON.stringify(result, null, 2));
490
+ }
491
+ if (mode === "check" && result && result.filteredRegressions.length > 0) {
492
+ process.exit(1);
493
+ }
494
+ }
495
+ catch {
496
+ process.exit(1);
497
+ }
152
498
  break;
153
499
  }
154
- case 'init':
500
+ case "init":
155
501
  default: {
156
502
  const presetStack = VALID_STACKS.includes(cli.flags.stack)
157
503
  ? cli.flags.stack
@@ -164,7 +510,7 @@ switch (subcommand) {
164
510
  : undefined;
165
511
  const presetName = cli.flags.projectName || undefined;
166
512
  render(React.createElement(CIContextProvider, { isCI: isCI },
167
- 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 });
168
514
  break;
169
515
  }
170
516
  }
@@ -0,0 +1,73 @@
1
+ import type { AgentSkillsManifest, AggregatedSkillsManifest, InstalledPlugin, PluginManifest } from "../types/index.js";
2
+ /**
3
+ * Convert a javi-forge PluginManifest to an Agent Skills spec manifest.
4
+ */
5
+ export declare function pluginToAgentSkills(manifest: PluginManifest, source?: string): AgentSkillsManifest;
6
+ /**
7
+ * Convert an Agent Skills spec manifest to a javi-forge PluginManifest.
8
+ */
9
+ export declare function agentSkillsToPlugin(agentManifest: AgentSkillsManifest): PluginManifest;
10
+ /**
11
+ * Generate a skills.json file in the given plugin directory from its plugin.json.
12
+ */
13
+ export declare function generateAgentSkillsManifest(pluginDir: string, source?: string): Promise<{
14
+ success: boolean;
15
+ path?: string;
16
+ error?: string;
17
+ }>;
18
+ /**
19
+ * Export an installed plugin to Agent Skills format.
20
+ * Looks up the plugin by name in the global plugins directory.
21
+ */
22
+ export declare function exportPluginAsAgentSkills(name: string): Promise<{
23
+ success: boolean;
24
+ path?: string;
25
+ error?: string;
26
+ }>;
27
+ /**
28
+ * Import an Agent Skills spec package from a directory.
29
+ * Reads skills.json, converts to plugin.json, copies to plugins dir.
30
+ */
31
+ export declare function importAgentSkillsPackage(sourceDir: string, options?: {
32
+ dryRun?: boolean;
33
+ }): Promise<{
34
+ success: boolean;
35
+ name?: string;
36
+ error?: string;
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
+ }>;
73
+ //# sourceMappingURL=agent-skills.d.ts.map