javi-forge 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -1
- package/ci-local/README.md +56 -11
- package/ci-local/ci-local.ps1 +445 -0
- package/ci-local/ci-local.sh +52 -9
- package/ci-local/docker/python.Dockerfile +7 -0
- package/ci-local/hooks/commit-msg +120 -44
- package/ci-local/hooks/commit-msg.test.sh +286 -0
- package/ci-local/hooks/pre-commit +9 -1
- package/ci-local/hooks/pre-push +13 -2
- package/ci-local/install.ps1 +367 -0
- package/ci-local/install.sh +151 -5
- package/ci-local/uninstall.ps1 +85 -0
- package/ci-local/uninstall.sh +95 -0
- package/dist/cli/dispatch/ci.d.ts +12 -0
- package/dist/cli/dispatch/ci.js +38 -0
- package/dist/cli/dispatch/security.d.ts +11 -0
- package/dist/cli/dispatch/security.js +68 -0
- package/dist/cli/dispatch/simple-renderers.d.ts +16 -0
- package/dist/cli/dispatch/simple-renderers.js +65 -0
- package/dist/cli/dispatch/skill-publish.d.ts +15 -0
- package/dist/cli/dispatch/skill-publish.js +44 -0
- package/dist/cli/dispatch/skills-cmd.d.ts +13 -0
- package/dist/cli/dispatch/skills-cmd.js +93 -0
- package/dist/cli/dispatch/tdd.d.ts +11 -0
- package/dist/cli/dispatch/tdd.js +45 -0
- package/dist/cli/dispatch/types.d.ts +29 -0
- package/dist/cli/dispatch/types.js +2 -0
- package/dist/cli/dispatch/workflow.d.ts +11 -0
- package/dist/cli/dispatch/workflow.js +67 -0
- package/dist/cli/help.d.ts +127 -0
- package/dist/cli/help.js +138 -0
- package/dist/cli/runtime.d.ts +16 -0
- package/dist/cli/runtime.js +38 -0
- package/dist/cli/validators.d.ts +17 -0
- package/dist/cli/validators.js +35 -0
- package/dist/commands/analyze.d.ts +1 -1
- package/dist/commands/analyze.js +14 -16
- package/dist/commands/ci.d.ts +50 -3
- package/dist/commands/ci.js +537 -182
- package/dist/commands/doctor.d.ts +2 -2
- package/dist/commands/doctor.js +112 -62
- package/dist/commands/init/report.d.ts +13 -0
- package/dist/commands/init/report.js +13 -0
- package/dist/commands/init/steps/agent-skills.d.ts +13 -0
- package/dist/commands/init/steps/agent-skills.js +45 -0
- package/dist/commands/init/steps/ai-sync.d.ts +15 -0
- package/dist/commands/init/steps/ai-sync.js +62 -0
- package/dist/commands/init/steps/ci.d.ts +24 -0
- package/dist/commands/init/steps/ci.js +74 -0
- package/dist/commands/init/steps/claude-md.d.ts +14 -0
- package/dist/commands/init/steps/claude-md.js +54 -0
- package/dist/commands/init/steps/code-graph.d.ts +16 -0
- package/dist/commands/init/steps/code-graph.js +68 -0
- package/dist/commands/init/steps/context-dir.d.ts +13 -0
- package/dist/commands/init/steps/context-dir.js +47 -0
- package/dist/commands/init/steps/docker-deploy.d.ts +16 -0
- package/dist/commands/init/steps/docker-deploy.js +60 -0
- package/dist/commands/init/steps/ghagga.d.ts +15 -0
- package/dist/commands/init/steps/ghagga.js +58 -0
- package/dist/commands/init/steps/git.d.ts +25 -0
- package/dist/commands/init/steps/git.js +81 -0
- package/dist/commands/init/steps/gitignore.d.ts +13 -0
- package/dist/commands/init/steps/gitignore.js +39 -0
- package/dist/commands/init/steps/local-ai.d.ts +14 -0
- package/dist/commands/init/steps/local-ai.js +53 -0
- package/dist/commands/init/steps/manifest.d.ts +13 -0
- package/dist/commands/init/steps/manifest.js +58 -0
- package/dist/commands/init/steps/memory.d.ts +15 -0
- package/dist/commands/init/steps/memory.js +60 -0
- package/dist/commands/init/steps/mock.d.ts +13 -0
- package/dist/commands/init/steps/mock.js +64 -0
- package/dist/commands/init/steps/sdd.d.ts +12 -0
- package/dist/commands/init/steps/sdd.js +40 -0
- package/dist/commands/init/steps/security.d.ts +28 -0
- package/dist/commands/init/steps/security.js +103 -0
- package/dist/commands/init/types.d.ts +30 -0
- package/dist/commands/init/types.js +2 -0
- package/dist/commands/init.d.ts +5 -4
- package/dist/commands/init.js +42 -387
- package/dist/commands/llmstxt.d.ts +1 -1
- package/dist/commands/llmstxt.js +36 -34
- package/dist/commands/plugin.d.ts +10 -1
- package/dist/commands/plugin.js +92 -47
- package/dist/commands/security.d.ts +11 -5
- package/dist/commands/security.js +236 -77
- package/dist/commands/skills/analysis.d.ts +19 -0
- package/dist/commands/skills/analysis.js +211 -0
- package/dist/commands/skills/benchmark.d.ts +6 -0
- package/dist/commands/skills/benchmark.js +82 -0
- package/dist/commands/skills/constants.d.ts +10 -0
- package/dist/commands/skills/constants.js +27 -0
- package/dist/commands/skills/directives.d.ts +21 -0
- package/dist/commands/skills/directives.js +101 -0
- package/dist/commands/skills/parsing.d.ts +16 -0
- package/dist/commands/skills/parsing.js +108 -0
- package/dist/commands/skills/rules.d.ts +5 -0
- package/dist/commands/skills/rules.js +32 -0
- package/dist/commands/skills/scoring.d.ts +47 -0
- package/dist/commands/skills/scoring.js +306 -0
- package/dist/commands/skills.d.ts +8 -69
- package/dist/commands/skills.js +9 -490
- 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/workflow.d.ts +23 -0
- package/dist/commands/workflow.js +116 -0
- package/dist/constants.d.ts +15 -1
- package/dist/constants.js +161 -122
- package/dist/index.js +43 -280
- package/dist/lib/agent-skills.d.ts +36 -1
- package/dist/lib/agent-skills.js +168 -19
- package/dist/lib/atlassian-mcp.d.ts +42 -0
- package/dist/lib/atlassian-mcp.js +98 -0
- package/dist/lib/auto-skill-install.d.ts +37 -0
- package/dist/lib/auto-skill-install.js +91 -0
- package/dist/lib/auto-wire.d.ts +20 -0
- package/dist/lib/auto-wire.js +240 -0
- package/dist/lib/ci-config.d.ts +65 -0
- package/dist/lib/ci-config.js +297 -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 +26 -32
- 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/crash-recovery.d.ts +34 -0
- package/dist/lib/crash-recovery.js +123 -0
- package/dist/lib/docker.d.ts +23 -2
- package/dist/lib/docker.js +168 -131
- package/dist/lib/exec.d.ts +10 -0
- package/dist/lib/exec.js +11 -0
- package/dist/lib/frontmatter.d.ts +1 -1
- package/dist/lib/frontmatter.js +29 -15
- package/dist/lib/harness-audit.d.ts +35 -0
- package/dist/lib/harness-audit.js +277 -0
- package/dist/lib/parallel-batch.d.ts +42 -0
- package/dist/lib/parallel-batch.js +88 -0
- package/dist/lib/plugin.d.ts +9 -3
- package/dist/lib/plugin.js +127 -70
- package/dist/lib/secret-scanner.d.ts +30 -0
- package/dist/lib/secret-scanner.js +274 -0
- package/dist/lib/security-analysis.d.ts +74 -0
- package/dist/lib/security-analysis.js +489 -0
- package/dist/lib/skill-publish.d.ts +40 -0
- package/dist/lib/skill-publish.js +164 -0
- package/dist/lib/skill-scanner.d.ts +63 -0
- package/dist/lib/skill-scanner.js +383 -0
- package/dist/lib/stack-detector.d.ts +38 -0
- package/dist/lib/stack-detector.js +207 -0
- package/dist/lib/supply-chain.d.ts +23 -0
- package/dist/lib/supply-chain.js +126 -0
- package/dist/lib/team-presets.d.ts +53 -0
- package/dist/lib/team-presets.js +201 -0
- package/dist/lib/template.d.ts +16 -1
- package/dist/lib/template.js +46 -17
- package/dist/lib/workflow/discovery.d.ts +27 -0
- package/dist/lib/workflow/discovery.js +85 -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 +59 -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 +2 -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 +27 -17
- 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/lib/common.psm1 +167 -0
- package/lib/common.sh +30 -0
- package/package.json +46 -24
- 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,306 +1,69 @@
|
|
|
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 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 { createRequire } from "node:module";
|
|
3
|
+
import meow from "meow";
|
|
4
|
+
import { handleCi } from "./cli/dispatch/ci.js";
|
|
5
|
+
import { handleSecurity } from "./cli/dispatch/security.js";
|
|
6
|
+
import { handleAnalyze, handleDoctor, handleInitDefault, handleLlmsTxt, handlePlugin, } from "./cli/dispatch/simple-renderers.js";
|
|
7
|
+
import { handleSkillPublish } from "./cli/dispatch/skill-publish.js";
|
|
8
|
+
import { handleSkillsCmd } from "./cli/dispatch/skills-cmd.js";
|
|
9
|
+
import { handleTdd } from "./cli/dispatch/tdd.js";
|
|
10
|
+
import { handleWorkflow } from "./cli/dispatch/workflow.js";
|
|
11
|
+
import { FLAGS_SCHEMA, HELP_TEXT } from "./cli/help.js";
|
|
12
|
+
import { createInkStdin, detectCI, setupUpdateNotifier, } from "./cli/runtime.js";
|
|
17
13
|
// Check for updates in background (non-blocking, cached 24h)
|
|
18
14
|
const _require = createRequire(import.meta.url);
|
|
19
|
-
const pkg = _require(
|
|
20
|
-
|
|
21
|
-
const cli = meow(
|
|
22
|
-
Usage
|
|
23
|
-
$ javi-forge [command] [options]
|
|
24
|
-
|
|
25
|
-
Commands
|
|
26
|
-
init Bootstrap a new project (default)
|
|
27
|
-
ci Run CI simulation (lint + compile + test + security + ghagga)
|
|
28
|
-
tdd init Install TDD-enforcing pre-commit hook (auto-detects stack)
|
|
29
|
-
analyze Run repoforge skills analysis
|
|
30
|
-
doctor Show health report
|
|
31
|
-
plugin add Install a plugin from GitHub (org/repo)
|
|
32
|
-
plugin remove Remove an installed plugin
|
|
33
|
-
plugin list List installed plugins
|
|
34
|
-
plugin search Search the plugin registry
|
|
35
|
-
plugin validate Validate a local plugin directory
|
|
36
|
-
plugin sync Auto-detect and wire installed plugins
|
|
37
|
-
plugin export Export plugin to Agent Skills spec format (skills.json)
|
|
38
|
-
plugin import Import an Agent Skills spec package as a javi-forge plugin
|
|
39
|
-
skills doctor Show skills health report (add --deep for conflict detection)
|
|
40
|
-
skills budget Show token cost of loaded skills (add -b N for custom budget)
|
|
41
|
-
skills score Score a skill on quality dimensions (completeness, clarity, testability, token-efficiency)
|
|
42
|
-
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)
|
|
46
|
-
llms-txt Generate AI-friendly llms.txt for current project
|
|
47
|
-
|
|
48
|
-
Options
|
|
49
|
-
--dry-run Preview changes without writing files
|
|
50
|
-
--stack Project stack (node, python, go, rust, java-gradle, java-maven, elixir)
|
|
51
|
-
--ci CI provider (github, gitlab, woodpecker)
|
|
52
|
-
--memory Memory module (engram, obsidian-brain, memory-simple, none)
|
|
53
|
-
--project-name Project name (skips name prompt)
|
|
54
|
-
--ghagga Enable GHAGGA review system
|
|
55
|
-
--mock Enable mock-first mode (no real API keys needed)
|
|
56
|
-
--batch Non-interactive mode (auto-proceed, no keyboard input)
|
|
57
|
-
--deep Enable deep analysis (conflict + duplicate detection)
|
|
58
|
-
--budget, -b Token budget limit for skills (default: 8000)
|
|
59
|
-
--skills-dir Custom skills directory path
|
|
60
|
-
--version Show version
|
|
61
|
-
--help Show this help
|
|
62
|
-
|
|
63
|
-
CI options (javi-forge ci)
|
|
64
|
-
--quick Lint + compile only (fast, for pre-commit)
|
|
65
|
-
--shell Open interactive shell in CI container
|
|
66
|
-
--detect Show detected stack and exit
|
|
67
|
-
--no-docker Run commands natively (no Docker)
|
|
68
|
-
--no-ci-ghagga Skip GHAGGA review
|
|
69
|
-
--no-security Skip Semgrep security scan
|
|
70
|
-
--timeout N Per-step timeout in seconds (default: 600)
|
|
71
|
-
|
|
72
|
-
CI hooks (javi-forge ci init)
|
|
73
|
-
Install git hooks that call javi-forge ci.
|
|
74
|
-
No files copied — hooks reference the global CLI.
|
|
75
|
-
|
|
76
|
-
Examples
|
|
77
|
-
$ javi-forge
|
|
78
|
-
$ javi-forge init --dry-run
|
|
79
|
-
$ javi-forge init --stack node --ci github
|
|
80
|
-
$ javi-forge ci
|
|
81
|
-
$ javi-forge ci init
|
|
82
|
-
$ javi-forge tdd init
|
|
83
|
-
$ javi-forge ci --quick
|
|
84
|
-
$ javi-forge ci --no-ci-ghagga --no-security
|
|
85
|
-
$ javi-forge ci --no-docker
|
|
86
|
-
$ javi-forge ci --shell
|
|
87
|
-
$ javi-forge analyze
|
|
88
|
-
$ javi-forge doctor
|
|
89
|
-
$ javi-forge plugin add mapbox/agent-skills
|
|
90
|
-
$ javi-forge plugin list
|
|
91
|
-
`, {
|
|
15
|
+
const pkg = _require("../package.json");
|
|
16
|
+
setupUpdateNotifier(pkg);
|
|
17
|
+
const cli = meow(HELP_TEXT, {
|
|
92
18
|
importMeta: import.meta,
|
|
93
|
-
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 },
|
|
102
|
-
// 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 },
|
|
110
|
-
// Skills flags
|
|
111
|
-
deep: { type: 'boolean', default: false },
|
|
112
|
-
budget: { type: 'number', shortFlag: 'b', default: 8000 },
|
|
113
|
-
skillsDir: { type: 'string', default: '' },
|
|
114
|
-
}
|
|
19
|
+
flags: FLAGS_SCHEMA,
|
|
115
20
|
});
|
|
116
|
-
const subcommand = cli.input[0] ??
|
|
117
|
-
const
|
|
118
|
-
const
|
|
119
|
-
const VALID_MEMORY = ['engram', 'obsidian-brain', 'memory-simple', 'none'];
|
|
120
|
-
const isCI = cli.flags.batch || process.env['CI'] === '1' || process.env['CI'] === 'true';
|
|
121
|
-
// When stdin doesn't support raw mode (pipes, subprocesses, CI), provide a fake
|
|
122
|
-
// stdin stream so Ink doesn't crash trying to enable raw mode on a non-TTY pipe.
|
|
123
|
-
const isTTY = process.stdin.isTTY === true;
|
|
124
|
-
const fakeStdin = new PassThrough();
|
|
125
|
-
Object.defineProperty(fakeStdin, 'isTTY', { value: false });
|
|
126
|
-
const inkStdin = isTTY ? process.stdin : fakeStdin;
|
|
21
|
+
const subcommand = cli.input[0] ?? "init";
|
|
22
|
+
const isCI = detectCI(cli.flags);
|
|
23
|
+
const inkStdin = createInkStdin();
|
|
127
24
|
switch (subcommand) {
|
|
128
|
-
case
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
process.exit(errors.length > 0 ? 1 : 0);
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
console.error('Usage: javi-forge tdd init');
|
|
143
|
-
console.error(' init Install TDD-enforcing pre-commit hook');
|
|
144
|
-
process.exit(1);
|
|
145
|
-
}
|
|
25
|
+
case "tdd": {
|
|
26
|
+
await handleTdd(cli);
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
case "ci": {
|
|
30
|
+
await handleCi(cli, { inkStdin, isCI });
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
case "doctor": {
|
|
34
|
+
handleDoctor(cli, { inkStdin, isCI });
|
|
146
35
|
break;
|
|
147
36
|
}
|
|
148
|
-
case
|
|
149
|
-
|
|
150
|
-
if (cli.input[1] === 'init') {
|
|
151
|
-
const { installCIHooks } = await import('./commands/ci.js');
|
|
152
|
-
const { installed, errors } = await installCIHooks(process.cwd());
|
|
153
|
-
if (installed.length > 0) {
|
|
154
|
-
console.log(`✓ Installed git hooks: ${installed.join(', ')}`);
|
|
155
|
-
console.log(' Hooks call javi-forge ci (with npx fallback)');
|
|
156
|
-
}
|
|
157
|
-
for (const err of errors) {
|
|
158
|
-
console.error(`✗ ${err}`);
|
|
159
|
-
}
|
|
160
|
-
process.exit(errors.length > 0 ? 1 : 0);
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
const ciMode = cli.flags.detect ? 'detect'
|
|
164
|
-
: cli.flags.shell ? 'shell'
|
|
165
|
-
: cli.flags.quick ? 'quick'
|
|
166
|
-
: 'full';
|
|
167
|
-
render(React.createElement(CIContextProvider, { isCI: true },
|
|
168
|
-
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 });
|
|
37
|
+
case "analyze": {
|
|
38
|
+
handleAnalyze(cli, { inkStdin, isCI });
|
|
169
39
|
break;
|
|
170
40
|
}
|
|
171
|
-
case
|
|
172
|
-
|
|
173
|
-
React.createElement(Doctor, null)), { stdin: inkStdin });
|
|
41
|
+
case "workflow": {
|
|
42
|
+
await handleWorkflow(cli);
|
|
174
43
|
break;
|
|
175
44
|
}
|
|
176
|
-
case
|
|
177
|
-
|
|
178
|
-
React.createElement(AnalyzeUI, { dryRun: cli.flags.dryRun })), { stdin: inkStdin });
|
|
45
|
+
case "llms-txt": {
|
|
46
|
+
handleLlmsTxt(cli, { inkStdin, isCI });
|
|
179
47
|
break;
|
|
180
48
|
}
|
|
181
|
-
case
|
|
182
|
-
|
|
183
|
-
React.createElement(LlmsTxt, { projectDir: process.cwd(), dryRun: cli.flags.dryRun })), { stdin: inkStdin });
|
|
49
|
+
case "plugin": {
|
|
50
|
+
handlePlugin(cli, { inkStdin, isCI });
|
|
184
51
|
break;
|
|
185
52
|
}
|
|
186
|
-
case
|
|
187
|
-
|
|
188
|
-
const VALID_PLUGIN_ACTIONS = ['add', 'remove', 'list', 'search', 'validate', 'sync', 'export', 'import'];
|
|
189
|
-
const action = pluginAction && VALID_PLUGIN_ACTIONS.includes(pluginAction) ? pluginAction : 'list';
|
|
190
|
-
const target = cli.input[2];
|
|
191
|
-
render(React.createElement(CIContextProvider, { isCI: isCI },
|
|
192
|
-
React.createElement(Plugin, { action: action, target: target, dryRun: cli.flags.dryRun })), { stdin: inkStdin });
|
|
53
|
+
case "skills": {
|
|
54
|
+
await handleSkillsCmd(cli, { inkStdin, isCI });
|
|
193
55
|
break;
|
|
194
56
|
}
|
|
195
|
-
case
|
|
196
|
-
|
|
197
|
-
const VALID_SKILLS_ACTIONS = ['doctor', 'budget', 'score', 'benchmark'];
|
|
198
|
-
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');
|
|
204
|
-
process.exit(1);
|
|
205
|
-
break;
|
|
206
|
-
}
|
|
207
|
-
// Score and benchmark are non-interactive CLI commands
|
|
208
|
-
if (skillsAction === 'score' || skillsAction === 'benchmark') {
|
|
209
|
-
const targetSkill = cli.input[2];
|
|
210
|
-
if (!targetSkill) {
|
|
211
|
-
console.error(`Usage: javi-forge skills ${skillsAction} <skill-name>`);
|
|
212
|
-
process.exit(1);
|
|
213
|
-
break;
|
|
214
|
-
}
|
|
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');
|
|
219
|
-
const result = await scoreSkill(skillPath, cli.flags.budget);
|
|
220
|
-
if (!result) {
|
|
221
|
-
console.error(`\u2717 Skill not found: ${skillPath}`);
|
|
222
|
-
process.exit(1);
|
|
223
|
-
break;
|
|
224
|
-
}
|
|
225
|
-
console.log(`\nSkill: ${result.skillName}`);
|
|
226
|
-
console.log(` Completeness: ${result.completeness}/100`);
|
|
227
|
-
console.log(` Clarity: ${result.clarity}/100`);
|
|
228
|
-
console.log(` Testability: ${result.testability}/100`);
|
|
229
|
-
console.log(` Token Efficiency: ${result.tokenEfficiency}/100`);
|
|
230
|
-
console.log(` Overall: ${result.overall}/100`);
|
|
231
|
-
console.log(` Threshold: ${result.threshold}`);
|
|
232
|
-
console.log(` Status: ${result.passing ? '\u2713 PASSING' : '\u2717 FAILING'}`);
|
|
233
|
-
process.exit(result.passing ? 0 : 1);
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
const { benchmarkSkill } = await import('./commands/skills.js');
|
|
237
|
-
const result = await benchmarkSkill(skillPath);
|
|
238
|
-
if (!result) {
|
|
239
|
-
console.error(`\u2717 Skill not found: ${skillPath}`);
|
|
240
|
-
process.exit(1);
|
|
241
|
-
break;
|
|
242
|
-
}
|
|
243
|
-
console.log(`\nBenchmark: ${result.skillName}`);
|
|
244
|
-
for (const check of result.checks) {
|
|
245
|
-
const icon = check.passed ? '\u2713' : '\u2717';
|
|
246
|
-
console.log(` ${icon} ${check.name}${check.detail ? ` — ${check.detail}` : ''}`);
|
|
247
|
-
}
|
|
248
|
-
console.log(`\n Pass rate: ${result.passRate}%`);
|
|
249
|
-
process.exit(result.passRate >= 50 ? 0 : 1);
|
|
250
|
-
}
|
|
251
|
-
break;
|
|
252
|
-
}
|
|
253
|
-
const skillsMode = skillsAction;
|
|
254
|
-
render(React.createElement(CIContextProvider, { isCI: isCI },
|
|
255
|
-
React.createElement(Skills, { mode: skillsMode, budget: cli.flags.budget, deep: cli.flags.deep, skillsDir: cli.flags.skillsDir || undefined })), { stdin: inkStdin });
|
|
57
|
+
case "skill": {
|
|
58
|
+
await handleSkillPublish(cli);
|
|
256
59
|
break;
|
|
257
60
|
}
|
|
258
|
-
case
|
|
259
|
-
|
|
260
|
-
const VALID_SECURITY_ACTIONS = ['baseline', 'check', 'update'];
|
|
261
|
-
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)');
|
|
266
|
-
process.exit(1);
|
|
267
|
-
break;
|
|
268
|
-
}
|
|
269
|
-
const { runSecurity } = await import('./commands/security.js');
|
|
270
|
-
const mode = securityAction;
|
|
271
|
-
try {
|
|
272
|
-
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';
|
|
277
|
-
console.log(`${icon} ${step.label}`);
|
|
278
|
-
if (step.detail)
|
|
279
|
-
console.log(` ${step.detail}`);
|
|
280
|
-
});
|
|
281
|
-
if (mode === 'check' && result && result.regressions.length > 0) {
|
|
282
|
-
process.exit(1);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
catch {
|
|
286
|
-
process.exit(1);
|
|
287
|
-
}
|
|
61
|
+
case "security": {
|
|
62
|
+
await handleSecurity(cli);
|
|
288
63
|
break;
|
|
289
64
|
}
|
|
290
|
-
case 'init':
|
|
291
65
|
default: {
|
|
292
|
-
|
|
293
|
-
? cli.flags.stack
|
|
294
|
-
: undefined;
|
|
295
|
-
const presetCI = VALID_CI.includes(cli.flags.ci)
|
|
296
|
-
? cli.flags.ci
|
|
297
|
-
: undefined;
|
|
298
|
-
const presetMemory = VALID_MEMORY.includes(cli.flags.memory)
|
|
299
|
-
? cli.flags.memory
|
|
300
|
-
: undefined;
|
|
301
|
-
const presetName = cli.flags.projectName || undefined;
|
|
302
|
-
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 });
|
|
66
|
+
handleInitDefault(cli, { inkStdin, isCI });
|
|
304
67
|
break;
|
|
305
68
|
}
|
|
306
69
|
}
|
|
@@ -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
|
package/dist/lib/agent-skills.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { AGENT_SKILLS_MANIFEST_FILE, PLUGIN_MANIFEST_FILE, PLUGINS_DIR } from
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { AGENT_SKILLS_MANIFEST_FILE, PLUGIN_MANIFEST_FILE, PLUGINS_DIR, } from "../constants.js";
|
|
4
4
|
// ── Conversion ─────────────────────────────────────────────────────────────
|
|
5
5
|
/**
|
|
6
6
|
* Convert a javi-forge PluginManifest to an Agent Skills spec manifest.
|
|
7
7
|
*/
|
|
8
8
|
export function pluginToAgentSkills(manifest, source) {
|
|
9
|
-
const skills = (manifest.skills ?? []).map(s => ({
|
|
9
|
+
const skills = (manifest.skills ?? []).map((s) => ({
|
|
10
10
|
name: s,
|
|
11
11
|
description: `${s} skill from ${manifest.name}`,
|
|
12
12
|
path: `skills/${s}`,
|
|
@@ -27,8 +27,8 @@ export function agentSkillsToPlugin(agentManifest) {
|
|
|
27
27
|
name: agentManifest.name,
|
|
28
28
|
version: agentManifest.version,
|
|
29
29
|
description: agentManifest.description,
|
|
30
|
-
skills: agentManifest.skills.map(s => s.name),
|
|
31
|
-
tags: [
|
|
30
|
+
skills: agentManifest.skills.map((s) => s.name),
|
|
31
|
+
tags: ["agent-skills-import"],
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
// ── File I/O ───────────────────────────────────────────────────────────────
|
|
@@ -37,15 +37,15 @@ export function agentSkillsToPlugin(agentManifest) {
|
|
|
37
37
|
*/
|
|
38
38
|
export async function generateAgentSkillsManifest(pluginDir, source) {
|
|
39
39
|
const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST_FILE);
|
|
40
|
-
if (!await fs.pathExists(manifestPath)) {
|
|
41
|
-
return { success: false, error:
|
|
40
|
+
if (!(await fs.pathExists(manifestPath))) {
|
|
41
|
+
return { success: false, error: "plugin.json not found" };
|
|
42
42
|
}
|
|
43
43
|
let manifest;
|
|
44
44
|
try {
|
|
45
|
-
manifest = await fs.readJson(manifestPath);
|
|
45
|
+
manifest = (await fs.readJson(manifestPath));
|
|
46
46
|
}
|
|
47
47
|
catch {
|
|
48
|
-
return { success: false, error:
|
|
48
|
+
return { success: false, error: "invalid plugin.json" };
|
|
49
49
|
}
|
|
50
50
|
const agentManifest = pluginToAgentSkills(manifest, source);
|
|
51
51
|
const outPath = path.join(pluginDir, AGENT_SKILLS_MANIFEST_FILE);
|
|
@@ -58,7 +58,7 @@ export async function generateAgentSkillsManifest(pluginDir, source) {
|
|
|
58
58
|
*/
|
|
59
59
|
export async function exportPluginAsAgentSkills(name) {
|
|
60
60
|
const pluginDir = path.join(PLUGINS_DIR, name);
|
|
61
|
-
if (!await fs.pathExists(pluginDir)) {
|
|
61
|
+
if (!(await fs.pathExists(pluginDir))) {
|
|
62
62
|
return { success: false, error: `plugin "${name}" is not installed` };
|
|
63
63
|
}
|
|
64
64
|
return generateAgentSkillsManifest(pluginDir);
|
|
@@ -70,18 +70,23 @@ export async function exportPluginAsAgentSkills(name) {
|
|
|
70
70
|
export async function importAgentSkillsPackage(sourceDir, options = {}) {
|
|
71
71
|
const { dryRun = false } = options;
|
|
72
72
|
const skillsPath = path.join(sourceDir, AGENT_SKILLS_MANIFEST_FILE);
|
|
73
|
-
if (!await fs.pathExists(skillsPath)) {
|
|
74
|
-
return { success: false, error:
|
|
73
|
+
if (!(await fs.pathExists(skillsPath))) {
|
|
74
|
+
return { success: false, error: "skills.json not found" };
|
|
75
75
|
}
|
|
76
76
|
let agentManifest;
|
|
77
77
|
try {
|
|
78
|
-
agentManifest = await fs.readJson(skillsPath);
|
|
78
|
+
agentManifest = (await fs.readJson(skillsPath));
|
|
79
79
|
}
|
|
80
80
|
catch {
|
|
81
|
-
return { success: false, error:
|
|
81
|
+
return { success: false, error: "invalid skills.json" };
|
|
82
82
|
}
|
|
83
|
-
if (!agentManifest.name ||
|
|
84
|
-
|
|
83
|
+
if (!agentManifest.name ||
|
|
84
|
+
!agentManifest.version ||
|
|
85
|
+
!agentManifest.description) {
|
|
86
|
+
return {
|
|
87
|
+
success: false,
|
|
88
|
+
error: "skills.json missing required fields (name, version, description)",
|
|
89
|
+
};
|
|
85
90
|
}
|
|
86
91
|
const pluginName = agentManifest.name;
|
|
87
92
|
if (dryRun) {
|
|
@@ -96,7 +101,9 @@ export async function importAgentSkillsPackage(sourceDir, options = {}) {
|
|
|
96
101
|
await fs.copy(sourceDir, destDir);
|
|
97
102
|
// Generate plugin.json from skills.json
|
|
98
103
|
const pluginManifest = agentSkillsToPlugin(agentManifest);
|
|
99
|
-
await fs.writeJson(path.join(destDir, PLUGIN_MANIFEST_FILE), pluginManifest, {
|
|
104
|
+
await fs.writeJson(path.join(destDir, PLUGIN_MANIFEST_FILE), pluginManifest, {
|
|
105
|
+
spaces: 2,
|
|
106
|
+
});
|
|
100
107
|
// Write install metadata
|
|
101
108
|
const installedPlugin = {
|
|
102
109
|
name: pluginName,
|
|
@@ -105,7 +112,149 @@ export async function importAgentSkillsPackage(sourceDir, options = {}) {
|
|
|
105
112
|
source: `agent-skills:${sourceDir}`,
|
|
106
113
|
manifest: pluginManifest,
|
|
107
114
|
};
|
|
108
|
-
await fs.writeJson(path.join(destDir,
|
|
115
|
+
await fs.writeJson(path.join(destDir, ".installed.json"), installedPlugin, {
|
|
116
|
+
spaces: 2,
|
|
117
|
+
});
|
|
109
118
|
return { success: true, name: pluginName };
|
|
110
119
|
}
|
|
120
|
+
// ── Aggregation ──────────────────────────────────────────────────────────
|
|
121
|
+
/**
|
|
122
|
+
* Aggregate multiple installed plugins into a single Agent Skills spec manifest.
|
|
123
|
+
* This enables the entire registry (or a project's installed plugins) to be
|
|
124
|
+
* discoverable via `npx skills add` by any of the 40+ compatible AI agents.
|
|
125
|
+
*
|
|
126
|
+
* Pure function — no I/O.
|
|
127
|
+
*/
|
|
128
|
+
export function aggregatePluginsToSkillsJson(plugins, registryName = "javi-forge-registry", registryVersion = "1.0.0") {
|
|
129
|
+
const skills = [];
|
|
130
|
+
const sources = [];
|
|
131
|
+
for (const plugin of plugins) {
|
|
132
|
+
const { manifest } = plugin;
|
|
133
|
+
if (!manifest)
|
|
134
|
+
continue;
|
|
135
|
+
sources.push({
|
|
136
|
+
plugin: manifest.name,
|
|
137
|
+
version: manifest.version,
|
|
138
|
+
...(manifest.repository ? { repository: manifest.repository } : {}),
|
|
139
|
+
});
|
|
140
|
+
for (const skillName of manifest.skills ?? []) {
|
|
141
|
+
skills.push({
|
|
142
|
+
name: `${manifest.name}/${skillName}`,
|
|
143
|
+
description: `${skillName} skill from ${manifest.name} plugin`,
|
|
144
|
+
path: `plugins/${manifest.name}/skills/${skillName}`,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
name: registryName,
|
|
150
|
+
version: registryVersion,
|
|
151
|
+
description: `Aggregated skills from ${plugins.length} javi-forge plugin(s)`,
|
|
152
|
+
skills,
|
|
153
|
+
sources,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Generate a project-level skills.json from all installed plugins in a project.
|
|
158
|
+
* Writes the aggregated manifest to the project's .javi-forge/ directory.
|
|
159
|
+
*/
|
|
160
|
+
export async function generateProjectSkillsJson(projectDir, options = {}) {
|
|
161
|
+
const { dryRun = false, registryName } = options;
|
|
162
|
+
const pluginsDir = path.join(projectDir, ".javi-forge", "plugins");
|
|
163
|
+
if (!(await fs.pathExists(pluginsDir))) {
|
|
164
|
+
return {
|
|
165
|
+
success: false,
|
|
166
|
+
skillCount: 0,
|
|
167
|
+
pluginCount: 0,
|
|
168
|
+
error: "no plugins directory found",
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
const entries = await fs.readdir(pluginsDir);
|
|
172
|
+
const plugins = [];
|
|
173
|
+
for (const entry of entries) {
|
|
174
|
+
if (entry.startsWith("."))
|
|
175
|
+
continue;
|
|
176
|
+
const metaPath = path.join(pluginsDir, entry, ".installed.json");
|
|
177
|
+
if (await fs.pathExists(metaPath)) {
|
|
178
|
+
try {
|
|
179
|
+
const meta = (await fs.readJson(metaPath));
|
|
180
|
+
if (meta.name)
|
|
181
|
+
plugins.push(meta);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
/* skip corrupt entries */
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (plugins.length === 0) {
|
|
189
|
+
return {
|
|
190
|
+
success: false,
|
|
191
|
+
skillCount: 0,
|
|
192
|
+
pluginCount: 0,
|
|
193
|
+
error: "no installed plugins found",
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const projectName = registryName ?? path.basename(projectDir);
|
|
197
|
+
const aggregated = aggregatePluginsToSkillsJson(plugins, projectName);
|
|
198
|
+
const outPath = path.join(projectDir, AGENT_SKILLS_MANIFEST_FILE);
|
|
199
|
+
if (!dryRun) {
|
|
200
|
+
await fs.writeJson(outPath, aggregated, { spaces: 2 });
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
success: true,
|
|
204
|
+
path: outPath,
|
|
205
|
+
skillCount: aggregated.skills.length,
|
|
206
|
+
pluginCount: plugins.length,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Generate a skills.json from all globally installed plugins.
|
|
211
|
+
* Writes to the global plugins directory.
|
|
212
|
+
*/
|
|
213
|
+
export async function generateGlobalSkillsJson(options = {}) {
|
|
214
|
+
const { dryRun = false } = options;
|
|
215
|
+
if (!(await fs.pathExists(PLUGINS_DIR))) {
|
|
216
|
+
return {
|
|
217
|
+
success: false,
|
|
218
|
+
skillCount: 0,
|
|
219
|
+
pluginCount: 0,
|
|
220
|
+
error: "no plugins directory found",
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
const entries = await fs.readdir(PLUGINS_DIR);
|
|
224
|
+
const plugins = [];
|
|
225
|
+
for (const entry of entries) {
|
|
226
|
+
if (entry.startsWith("."))
|
|
227
|
+
continue;
|
|
228
|
+
const metaPath = path.join(PLUGINS_DIR, entry, ".installed.json");
|
|
229
|
+
if (await fs.pathExists(metaPath)) {
|
|
230
|
+
try {
|
|
231
|
+
const meta = (await fs.readJson(metaPath));
|
|
232
|
+
if (meta.name)
|
|
233
|
+
plugins.push(meta);
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
/* skip corrupt entries */
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (plugins.length === 0) {
|
|
241
|
+
return {
|
|
242
|
+
success: false,
|
|
243
|
+
skillCount: 0,
|
|
244
|
+
pluginCount: 0,
|
|
245
|
+
error: "no installed plugins found",
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const aggregated = aggregatePluginsToSkillsJson(plugins);
|
|
249
|
+
const outPath = path.join(PLUGINS_DIR, AGENT_SKILLS_MANIFEST_FILE);
|
|
250
|
+
if (!dryRun) {
|
|
251
|
+
await fs.writeJson(outPath, aggregated, { spaces: 2 });
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
success: true,
|
|
255
|
+
path: outPath,
|
|
256
|
+
skillCount: aggregated.skills.length,
|
|
257
|
+
pluginCount: plugins.length,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
111
260
|
//# sourceMappingURL=agent-skills.js.map
|