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.
- package/dist/commands/analyze.d.ts +1 -1
- package/dist/commands/analyze.js +15 -15
- package/dist/commands/atlassian-mcp.d.ts +42 -0
- package/dist/commands/atlassian-mcp.js +98 -0
- package/dist/commands/ci.d.ts +3 -3
- package/dist/commands/ci.js +185 -147
- package/dist/commands/crash-recovery.d.ts +34 -0
- package/dist/commands/crash-recovery.js +123 -0
- package/dist/commands/doctor.d.ts +2 -2
- package/dist/commands/doctor.js +113 -61
- package/dist/commands/harness-audit.d.ts +35 -0
- package/dist/commands/harness-audit.js +277 -0
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +384 -141
- package/dist/commands/llmstxt.d.ts +1 -1
- package/dist/commands/llmstxt.js +36 -34
- package/dist/commands/parallel-batch.d.ts +42 -0
- package/dist/commands/parallel-batch.js +90 -0
- package/dist/commands/plugin.d.ts +10 -1
- package/dist/commands/plugin.js +92 -47
- package/dist/commands/secret-scanner.d.ts +30 -0
- package/dist/commands/secret-scanner.js +272 -0
- package/dist/commands/security-analysis.d.ts +74 -0
- package/dist/commands/security-analysis.js +487 -0
- package/dist/commands/security.d.ts +11 -5
- package/dist/commands/security.js +216 -76
- package/dist/commands/skill-scanner.d.ts +63 -0
- package/dist/commands/skill-scanner.js +383 -0
- package/dist/commands/skills.d.ts +62 -5
- package/dist/commands/skills.js +439 -54
- package/dist/commands/supply-chain.d.ts +23 -0
- package/dist/commands/supply-chain.js +126 -0
- package/dist/commands/tdd-pipeline.d.ts +17 -0
- package/dist/commands/tdd-pipeline.js +144 -0
- package/dist/commands/tdd.d.ts +1 -1
- package/dist/commands/tdd.js +21 -18
- package/dist/commands/team-presets.d.ts +53 -0
- package/dist/commands/team-presets.js +201 -0
- package/dist/commands/workflow.d.ts +23 -0
- package/dist/commands/workflow.js +114 -0
- package/dist/constants.d.ts +15 -1
- package/dist/constants.js +161 -122
- package/dist/index.js +308 -98
- package/dist/lib/agent-skills.d.ts +36 -1
- package/dist/lib/agent-skills.js +168 -19
- package/dist/lib/auto-skill-install.d.ts +37 -0
- package/dist/lib/auto-skill-install.js +92 -0
- package/dist/lib/auto-wire.d.ts +20 -0
- package/dist/lib/auto-wire.js +240 -0
- package/dist/lib/claudemd.d.ts +13 -1
- package/dist/lib/claudemd.js +174 -24
- package/dist/lib/codex-export.d.ts +1 -1
- package/dist/lib/codex-export.js +29 -31
- package/dist/lib/common.d.ts +1 -1
- package/dist/lib/common.js +52 -44
- package/dist/lib/context.d.ts +17 -2
- package/dist/lib/context.js +142 -13
- package/dist/lib/docker.d.ts +1 -1
- package/dist/lib/docker.js +141 -112
- package/dist/lib/frontmatter.d.ts +1 -1
- package/dist/lib/frontmatter.js +29 -15
- package/dist/lib/plugin.d.ts +9 -3
- package/dist/lib/plugin.js +128 -69
- package/dist/lib/skill-publish.d.ts +40 -0
- package/dist/lib/skill-publish.js +146 -0
- package/dist/lib/stack-detector.d.ts +38 -0
- package/dist/lib/stack-detector.js +207 -0
- package/dist/lib/template.d.ts +16 -1
- package/dist/lib/template.js +46 -17
- package/dist/lib/workflow/discovery.d.ts +19 -0
- package/dist/lib/workflow/discovery.js +68 -0
- package/dist/lib/workflow/index.d.ts +5 -0
- package/dist/lib/workflow/index.js +5 -0
- package/dist/lib/workflow/parser.d.ts +16 -0
- package/dist/lib/workflow/parser.js +198 -0
- package/dist/lib/workflow/renderer.d.ts +9 -0
- package/dist/lib/workflow/renderer.js +152 -0
- package/dist/lib/workflow/validator.d.ts +10 -0
- package/dist/lib/workflow/validator.js +189 -0
- package/dist/tasks/index.d.ts +4 -0
- package/dist/tasks/index.js +4 -0
- package/dist/tasks/scaffold-tasks.d.ts +3 -0
- package/dist/tasks/scaffold-tasks.js +14 -0
- package/dist/tasks/task-id.d.ts +30 -0
- package/dist/tasks/task-id.js +55 -0
- package/dist/tasks/task-tracker.d.ts +15 -0
- package/dist/tasks/task-tracker.js +81 -0
- package/dist/types/index.d.ts +134 -6
- package/dist/types/index.js +11 -1
- package/dist/ui/AnalyzeUI.d.ts +1 -1
- package/dist/ui/AnalyzeUI.js +38 -39
- package/dist/ui/App.d.ts +5 -3
- package/dist/ui/App.js +86 -46
- package/dist/ui/AutoSkills.d.ts +9 -0
- package/dist/ui/AutoSkills.js +124 -0
- package/dist/ui/CI.d.ts +2 -2
- package/dist/ui/CI.js +24 -26
- package/dist/ui/CIContext.d.ts +1 -1
- package/dist/ui/CIContext.js +3 -2
- package/dist/ui/CISelector.d.ts +2 -2
- package/dist/ui/CISelector.js +23 -15
- package/dist/ui/Doctor.d.ts +1 -1
- package/dist/ui/Doctor.js +35 -29
- package/dist/ui/Header.d.ts +1 -1
- package/dist/ui/Header.js +14 -14
- package/dist/ui/HookProfileSelector.d.ts +9 -0
- package/dist/ui/HookProfileSelector.js +54 -0
- package/dist/ui/LlmsTxt.d.ts +1 -1
- package/dist/ui/LlmsTxt.js +31 -22
- package/dist/ui/MemorySelector.d.ts +2 -2
- package/dist/ui/MemorySelector.js +28 -16
- package/dist/ui/NameInput.d.ts +1 -1
- package/dist/ui/NameInput.js +21 -21
- package/dist/ui/OptionSelector.d.ts +6 -2
- package/dist/ui/OptionSelector.js +83 -32
- package/dist/ui/Plugin.d.ts +4 -3
- package/dist/ui/Plugin.js +78 -35
- package/dist/ui/Progress.d.ts +3 -3
- package/dist/ui/Progress.js +23 -22
- package/dist/ui/Skills.d.ts +2 -2
- package/dist/ui/Skills.js +61 -32
- package/dist/ui/StackSelector.d.ts +2 -2
- package/dist/ui/StackSelector.js +26 -16
- package/dist/ui/Summary.d.ts +3 -3
- package/dist/ui/Summary.js +60 -50
- package/dist/ui/Welcome.d.ts +1 -1
- package/dist/ui/Welcome.js +15 -16
- package/dist/ui/theme.d.ts +1 -1
- package/dist/ui/theme.js +6 -6
- package/package.json +9 -6
- package/templates/common/atlassian/mcp-atlassian-snippet.json +16 -0
- package/templates/common/repoforge/mcp-repoforge-snippet.json +11 -0
- package/templates/common/repoforge/repoforge.yaml +34 -0
- package/templates/github/deploy-docker-zero-downtime.yml +140 -0
- package/templates/github/repoforge-graph.yml +45 -0
- package/templates/gitlab/deploy-docker-zero-downtime.yml +57 -0
- package/templates/local-ai/.env.example +17 -0
- package/templates/local-ai/docker-compose.yml +95 -0
- package/templates/security-hooks/claude-settings-security.json +30 -0
- package/templates/security-hooks/commit-msg-signing +29 -0
- package/templates/security-hooks/pre-commit-permissions +74 -0
- package/templates/security-hooks/pre-commit-secrets +74 -0
- package/templates/security-hooks/pre-push-branch-protection +62 -0
- package/templates/security-hooks/pre-push-deps +83 -0
- package/templates/security-hooks/pre-push-signing +67 -0
- package/templates/woodpecker/deploy-docker-zero-downtime.yml +50 -0
- package/templates/workflows/ci-pipeline.dot +15 -0
- package/templates/workflows/feature-flow.dot +21 -0
- package/templates/workflows/release.dot +16 -0
- package/dist/__integration__/helpers.d.ts +0 -20
- package/dist/__integration__/helpers.d.ts.map +0 -1
- package/dist/__integration__/helpers.js +0 -31
- package/dist/__integration__/helpers.js.map +0 -1
- package/dist/commands/analyze.d.ts.map +0 -1
- package/dist/commands/analyze.js.map +0 -1
- package/dist/commands/ci.d.ts.map +0 -1
- package/dist/commands/ci.js.map +0 -1
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/llmstxt.d.ts.map +0 -1
- package/dist/commands/llmstxt.js.map +0 -1
- package/dist/commands/plugin.d.ts.map +0 -1
- package/dist/commands/plugin.js.map +0 -1
- package/dist/commands/security.d.ts.map +0 -1
- package/dist/commands/security.js.map +0 -1
- package/dist/commands/skills.d.ts.map +0 -1
- package/dist/commands/skills.js.map +0 -1
- package/dist/commands/tdd.d.ts.map +0 -1
- package/dist/commands/tdd.js.map +0 -1
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/agent-skills.d.ts.map +0 -1
- package/dist/lib/agent-skills.js.map +0 -1
- package/dist/lib/claudemd.d.ts.map +0 -1
- package/dist/lib/claudemd.js.map +0 -1
- package/dist/lib/codex-export.d.ts.map +0 -1
- package/dist/lib/codex-export.js.map +0 -1
- package/dist/lib/common.d.ts.map +0 -1
- package/dist/lib/common.js.map +0 -1
- package/dist/lib/context.d.ts.map +0 -1
- package/dist/lib/context.js.map +0 -1
- package/dist/lib/docker.d.ts.map +0 -1
- package/dist/lib/docker.js.map +0 -1
- package/dist/lib/frontmatter.d.ts.map +0 -1
- package/dist/lib/frontmatter.js.map +0 -1
- package/dist/lib/plugin.d.ts.map +0 -1
- package/dist/lib/plugin.js.map +0 -1
- package/dist/lib/template.d.ts.map +0 -1
- package/dist/lib/template.js.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js.map +0 -1
- package/dist/ui/AnalyzeUI.d.ts.map +0 -1
- package/dist/ui/AnalyzeUI.js.map +0 -1
- package/dist/ui/App.d.ts.map +0 -1
- package/dist/ui/App.js.map +0 -1
- package/dist/ui/CI.d.ts.map +0 -1
- package/dist/ui/CI.js.map +0 -1
- package/dist/ui/CIContext.d.ts.map +0 -1
- package/dist/ui/CIContext.js.map +0 -1
- package/dist/ui/CISelector.d.ts.map +0 -1
- package/dist/ui/CISelector.js.map +0 -1
- package/dist/ui/Doctor.d.ts.map +0 -1
- package/dist/ui/Doctor.js.map +0 -1
- package/dist/ui/Header.d.ts.map +0 -1
- package/dist/ui/Header.js.map +0 -1
- package/dist/ui/LlmsTxt.d.ts.map +0 -1
- package/dist/ui/LlmsTxt.js.map +0 -1
- package/dist/ui/MemorySelector.d.ts.map +0 -1
- package/dist/ui/MemorySelector.js.map +0 -1
- package/dist/ui/NameInput.d.ts.map +0 -1
- package/dist/ui/NameInput.js.map +0 -1
- package/dist/ui/OptionSelector.d.ts.map +0 -1
- package/dist/ui/OptionSelector.js.map +0 -1
- package/dist/ui/Plugin.d.ts.map +0 -1
- package/dist/ui/Plugin.js.map +0 -1
- package/dist/ui/Progress.d.ts.map +0 -1
- package/dist/ui/Progress.js.map +0 -1
- package/dist/ui/Skills.d.ts.map +0 -1
- package/dist/ui/Skills.js.map +0 -1
- package/dist/ui/StackSelector.d.ts.map +0 -1
- package/dist/ui/StackSelector.js.map +0 -1
- package/dist/ui/Summary.d.ts.map +0 -1
- package/dist/ui/Summary.js.map +0 -1
- package/dist/ui/Welcome.d.ts.map +0 -1
- package/dist/ui/Welcome.js.map +0 -1
- package/dist/ui/theme.d.ts.map +0 -1
- 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
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
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(
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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:
|
|
95
|
-
stack: { type:
|
|
96
|
-
ci: { type:
|
|
97
|
-
memory: { type:
|
|
98
|
-
projectName: { type:
|
|
99
|
-
ghagga: { type:
|
|
100
|
-
mock: { type:
|
|
101
|
-
|
|
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:
|
|
104
|
-
shell: { type:
|
|
105
|
-
detect: { type:
|
|
106
|
-
docker: { type:
|
|
107
|
-
ciGhagga: { type:
|
|
108
|
-
security: { type:
|
|
109
|
-
timeout: { type:
|
|
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:
|
|
112
|
-
budget: { type:
|
|
113
|
-
skillsDir: { type:
|
|
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] ??
|
|
117
|
-
const VALID_STACKS = [
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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,
|
|
160
|
+
Object.defineProperty(fakeStdin, "isTTY", { value: false });
|
|
126
161
|
const inkStdin = isTTY ? process.stdin : fakeStdin;
|
|
127
162
|
switch (subcommand) {
|
|
128
|
-
case
|
|
129
|
-
if (cli.input[1] ===
|
|
130
|
-
const { installTddHooks } = await import(
|
|
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(
|
|
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(
|
|
143
|
-
console.error(
|
|
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
|
|
202
|
+
case "ci": {
|
|
149
203
|
// Sub-command: javi-forge ci init → install git hooks
|
|
150
|
-
if (cli.input[1] ===
|
|
151
|
-
const { installCIHooks } = await import(
|
|
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(
|
|
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
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
303
|
+
case "plugin": {
|
|
187
304
|
const pluginAction = cli.input[1];
|
|
188
|
-
const VALID_PLUGIN_ACTIONS = [
|
|
189
|
-
|
|
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
|
|
324
|
+
case "skills": {
|
|
196
325
|
const skillsAction = cli.input[1];
|
|
197
|
-
const VALID_SKILLS_ACTIONS = [
|
|
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(
|
|
200
|
-
console.error(
|
|
201
|
-
console.error(
|
|
202
|
-
console.error(
|
|
203
|
-
console.error(
|
|
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 ===
|
|
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 ||
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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 ?
|
|
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(
|
|
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 ?
|
|
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
|
|
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 = [
|
|
441
|
+
const VALID_SECURITY_ACTIONS = ["baseline", "check", "update", "allowlist"];
|
|
261
442
|
if (!securityAction || !VALID_SECURITY_ACTIONS.includes(securityAction)) {
|
|
262
|
-
console.error(
|
|
263
|
-
console.error(
|
|
264
|
-
console.error(
|
|
265
|
-
console.error(
|
|
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(
|
|
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
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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 (
|
|
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
|
|
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 {
|
|
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
|