@devran-ai/kit 4.1.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/.agent/CheatSheet.md +350 -0
- package/.agent/README.md +76 -0
- package/.agent/agents/README.md +155 -0
- package/.agent/agents/architect.md +185 -0
- package/.agent/agents/backend-specialist.md +276 -0
- package/.agent/agents/build-error-resolver.md +207 -0
- package/.agent/agents/code-reviewer.md +162 -0
- package/.agent/agents/database-architect.md +138 -0
- package/.agent/agents/devops-engineer.md +144 -0
- package/.agent/agents/doc-updater.md +229 -0
- package/.agent/agents/e2e-runner.md +145 -0
- package/.agent/agents/explorer-agent.md +143 -0
- package/.agent/agents/frontend-specialist.md +144 -0
- package/.agent/agents/go-reviewer.md +128 -0
- package/.agent/agents/knowledge-agent.md +197 -0
- package/.agent/agents/mobile-developer.md +150 -0
- package/.agent/agents/performance-optimizer.md +175 -0
- package/.agent/agents/planner.md +133 -0
- package/.agent/agents/pr-reviewer.md +148 -0
- package/.agent/agents/python-reviewer.md +123 -0
- package/.agent/agents/refactor-cleaner.md +201 -0
- package/.agent/agents/reliability-engineer.md +156 -0
- package/.agent/agents/security-reviewer.md +141 -0
- package/.agent/agents/sprint-orchestrator.md +124 -0
- package/.agent/agents/tdd-guide.md +179 -0
- package/.agent/agents/typescript-reviewer.md +110 -0
- package/.agent/checklists/README.md +102 -0
- package/.agent/checklists/pre-commit.md +93 -0
- package/.agent/checklists/session-end.md +99 -0
- package/.agent/checklists/session-start.md +102 -0
- package/.agent/checklists/task-complete.md +81 -0
- package/.agent/commands/README.md +130 -0
- package/.agent/commands/adr.md +29 -0
- package/.agent/commands/ask.md +28 -0
- package/.agent/commands/build.md +30 -0
- package/.agent/commands/changelog.md +40 -0
- package/.agent/commands/checkpoint.md +28 -0
- package/.agent/commands/code-review.md +65 -0
- package/.agent/commands/compact.md +28 -0
- package/.agent/commands/cook.md +30 -0
- package/.agent/commands/db.md +30 -0
- package/.agent/commands/debug.md +31 -0
- package/.agent/commands/deploy.md +37 -0
- package/.agent/commands/design.md +29 -0
- package/.agent/commands/doc.md +30 -0
- package/.agent/commands/eval.md +30 -0
- package/.agent/commands/fix.md +32 -0
- package/.agent/commands/git.md +32 -0
- package/.agent/commands/help.md +273 -0
- package/.agent/commands/implement.md +30 -0
- package/.agent/commands/integrate.md +32 -0
- package/.agent/commands/learn.md +29 -0
- package/.agent/commands/perf.md +31 -0
- package/.agent/commands/plan.md +56 -0
- package/.agent/commands/pr-describe.md +65 -0
- package/.agent/commands/pr-fix.md +45 -0
- package/.agent/commands/pr-merge.md +45 -0
- package/.agent/commands/pr-review.md +50 -0
- package/.agent/commands/pr-split.md +54 -0
- package/.agent/commands/pr-status.md +56 -0
- package/.agent/commands/pr.md +58 -0
- package/.agent/commands/refactor.md +32 -0
- package/.agent/commands/research.md +28 -0
- package/.agent/commands/scout.md +30 -0
- package/.agent/commands/security-scan.md +33 -0
- package/.agent/commands/setup.md +31 -0
- package/.agent/commands/status.md +59 -0
- package/.agent/commands/tdd.md +73 -0
- package/.agent/commands/verify.md +58 -0
- package/.agent/contexts/brainstorm.md +26 -0
- package/.agent/contexts/debug.md +28 -0
- package/.agent/contexts/implement.md +29 -0
- package/.agent/contexts/plan-quality-log.md +30 -0
- package/.agent/contexts/review.md +27 -0
- package/.agent/contexts/ship.md +28 -0
- package/.agent/decisions/001-trust-grade-governance.md +46 -0
- package/.agent/decisions/002-cross-ide-generation.md +15 -0
- package/.agent/engine/identity.json +4 -0
- package/.agent/engine/loading-rules.json +193 -0
- package/.agent/engine/marketplace-index.json +29 -0
- package/.agent/engine/mcp-servers/filesystem.json +9 -0
- package/.agent/engine/mcp-servers/github.json +11 -0
- package/.agent/engine/mcp-servers/postgres.json +11 -0
- package/.agent/engine/mcp-servers/supabase.json +11 -0
- package/.agent/engine/mcp-servers/vercel.json +11 -0
- package/.agent/engine/reliability-config.json +14 -0
- package/.agent/engine/sdlc-map.json +50 -0
- package/.agent/engine/workflow-state.json +167 -0
- package/.agent/hooks/README.md +101 -0
- package/.agent/hooks/hooks.json +104 -0
- package/.agent/hooks/templates/session-end.md +110 -0
- package/.agent/hooks/templates/session-start.md +95 -0
- package/.agent/manifest.json +466 -0
- package/.agent/rules/agent-upgrade-policy.md +56 -0
- package/.agent/rules/architecture.md +111 -0
- package/.agent/rules/coding-style.md +75 -0
- package/.agent/rules/documentation.md +74 -0
- package/.agent/rules/git-workflow.md +140 -0
- package/.agent/rules/quality-gate.md +117 -0
- package/.agent/rules/security.md +67 -0
- package/.agent/rules/sprint-tracking.md +103 -0
- package/.agent/rules/testing.md +80 -0
- package/.agent/rules/workflow-standards.md +30 -0
- package/.agent/rules.md +293 -0
- package/.agent/session-context.md +69 -0
- package/.agent/session-state.json +27 -0
- package/.agent/skills/README.md +135 -0
- package/.agent/skills/api-patterns/SKILL.md +117 -0
- package/.agent/skills/app-builder/SKILL.md +202 -0
- package/.agent/skills/architecture/SKILL.md +101 -0
- package/.agent/skills/behavioral-modes/SKILL.md +295 -0
- package/.agent/skills/brainstorming/SKILL.md +156 -0
- package/.agent/skills/clean-code/SKILL.md +142 -0
- package/.agent/skills/context-budget/SKILL.md +78 -0
- package/.agent/skills/continuous-learning/SKILL.md +145 -0
- package/.agent/skills/database-design/SKILL.md +303 -0
- package/.agent/skills/debugging-strategies/SKILL.md +158 -0
- package/.agent/skills/deployment-procedures/SKILL.md +191 -0
- package/.agent/skills/docker-patterns/SKILL.md +161 -0
- package/.agent/skills/eval-harness/SKILL.md +89 -0
- package/.agent/skills/frontend-patterns/SKILL.md +141 -0
- package/.agent/skills/git-workflow/SKILL.md +159 -0
- package/.agent/skills/i18n-localization/SKILL.md +191 -0
- package/.agent/skills/intelligent-routing/SKILL.md +180 -0
- package/.agent/skills/mcp-integration/SKILL.md +240 -0
- package/.agent/skills/mobile-design/SKILL.md +191 -0
- package/.agent/skills/nodejs-patterns/SKILL.md +164 -0
- package/.agent/skills/parallel-agents/SKILL.md +200 -0
- package/.agent/skills/performance-profiling/SKILL.md +134 -0
- package/.agent/skills/plan-validation/SKILL.md +192 -0
- package/.agent/skills/plan-writing/SKILL.md +183 -0
- package/.agent/skills/plan-writing/domain-enhancers.md +184 -0
- package/.agent/skills/plan-writing/plan-retrospective.md +116 -0
- package/.agent/skills/plan-writing/plan-schema.md +119 -0
- package/.agent/skills/pr-toolkit/SKILL.md +174 -0
- package/.agent/skills/production-readiness/SKILL.md +126 -0
- package/.agent/skills/security-practices/SKILL.md +109 -0
- package/.agent/skills/shell-conventions/SKILL.md +92 -0
- package/.agent/skills/strategic-compact/SKILL.md +62 -0
- package/.agent/skills/testing-patterns/SKILL.md +141 -0
- package/.agent/skills/typescript-expert/SKILL.md +160 -0
- package/.agent/skills/ui-ux-pro-max/SKILL.md +137 -0
- package/.agent/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/.agent/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/.agent/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/.agent/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/.agent/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/.agent/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.agent/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/.agent/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.agent/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.agent/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/.agent/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.agent/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/.agent/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.agent/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.agent/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.agent/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/.agent/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.agent/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.agent/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.agent/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/.agent/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/.agent/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/.agent/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.agent/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/.agent/skills/ui-ux-pro-max/scripts/core.py +253 -0
- package/.agent/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/.agent/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/.agent/skills/verification-loop/SKILL.md +89 -0
- package/.agent/skills/webapp-testing/SKILL.md +175 -0
- package/.agent/templates/adr-template.md +32 -0
- package/.agent/templates/bug-report.md +37 -0
- package/.agent/templates/feature-request.md +32 -0
- package/.agent/workflows/README.md +101 -0
- package/.agent/workflows/brainstorm.md +86 -0
- package/.agent/workflows/create.md +85 -0
- package/.agent/workflows/debug.md +83 -0
- package/.agent/workflows/deploy.md +114 -0
- package/.agent/workflows/enhance.md +85 -0
- package/.agent/workflows/orchestrate.md +106 -0
- package/.agent/workflows/plan.md +105 -0
- package/.agent/workflows/pr-fix.md +163 -0
- package/.agent/workflows/pr-merge.md +117 -0
- package/.agent/workflows/pr-review.md +178 -0
- package/.agent/workflows/pr-split.md +118 -0
- package/.agent/workflows/pr.md +184 -0
- package/.agent/workflows/preflight.md +107 -0
- package/.agent/workflows/preview.md +95 -0
- package/.agent/workflows/quality-gate.md +103 -0
- package/.agent/workflows/retrospective.md +100 -0
- package/.agent/workflows/review.md +104 -0
- package/.agent/workflows/status.md +89 -0
- package/.agent/workflows/test.md +98 -0
- package/.agent/workflows/ui-ux-pro-max.md +93 -0
- package/.agent/workflows/upgrade.md +97 -0
- package/LICENSE +21 -0
- package/README.md +218 -0
- package/bin/kit.js +773 -0
- package/lib/agent-registry.js +228 -0
- package/lib/agent-reputation.js +343 -0
- package/lib/circuit-breaker.js +195 -0
- package/lib/cli-commands.js +322 -0
- package/lib/config-validator.js +274 -0
- package/lib/conflict-detector.js +252 -0
- package/lib/constants.js +47 -0
- package/lib/engineering-manager.js +336 -0
- package/lib/error-budget.js +370 -0
- package/lib/hook-system.js +256 -0
- package/lib/ide-generator.js +434 -0
- package/lib/identity.js +240 -0
- package/lib/io.js +146 -0
- package/lib/learning-engine.js +163 -0
- package/lib/loading-engine.js +421 -0
- package/lib/logger.js +118 -0
- package/lib/marketplace.js +321 -0
- package/lib/plugin-system.js +604 -0
- package/lib/plugin-verifier.js +197 -0
- package/lib/rate-limiter.js +113 -0
- package/lib/security-scanner.js +312 -0
- package/lib/self-healing.js +468 -0
- package/lib/session-manager.js +264 -0
- package/lib/skill-sandbox.js +244 -0
- package/lib/task-governance.js +522 -0
- package/lib/task-model.js +332 -0
- package/lib/updater.js +240 -0
- package/lib/verify.js +279 -0
- package/lib/workflow-engine.js +373 -0
- package/lib/workflow-events.js +166 -0
- package/lib/workflow-persistence.js +160 -0
- package/package.json +57 -0
package/bin/kit.js
ADDED
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Devran AI Kit CLI
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx @devran-ai/kit init
|
|
8
|
+
* kit init [options]
|
|
9
|
+
*
|
|
10
|
+
* @author Emre Dursun
|
|
11
|
+
* @license MIT
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
|
|
17
|
+
const VERSION = require('../package.json').version;
|
|
18
|
+
const AGENT_FOLDER = '.agent';
|
|
19
|
+
const { safeCopyDirSync, readJsonSafe } = require('../lib/io');
|
|
20
|
+
const { USER_DATA_FILES, USER_DATA_DIRS } = require('../lib/updater');
|
|
21
|
+
|
|
22
|
+
// ANSI colors
|
|
23
|
+
const colors = {
|
|
24
|
+
reset: '\x1b[0m',
|
|
25
|
+
bright: '\x1b[1m',
|
|
26
|
+
green: '\x1b[32m',
|
|
27
|
+
blue: '\x1b[34m',
|
|
28
|
+
yellow: '\x1b[33m',
|
|
29
|
+
red: '\x1b[31m',
|
|
30
|
+
cyan: '\x1b[36m',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function log(message, color = 'reset') {
|
|
34
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function logStep(step, message) {
|
|
38
|
+
console.log(`${colors.cyan}[${step}]${colors.reset} ${message}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function loadBannerCounts() {
|
|
42
|
+
try {
|
|
43
|
+
const manifestPath = path.join(__dirname, '..', AGENT_FOLDER, 'manifest.json');
|
|
44
|
+
const manifest = readJsonSafe(manifestPath, null);
|
|
45
|
+
if (manifest?.capabilities) {
|
|
46
|
+
return {
|
|
47
|
+
agents: manifest.capabilities.agents?.count || 19,
|
|
48
|
+
skills: manifest.capabilities.skills?.count || 32,
|
|
49
|
+
commands: manifest.capabilities.commands?.count || 31,
|
|
50
|
+
workflows: manifest.capabilities.workflows?.count || 14,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
} catch { /* fallback to defaults */ }
|
|
54
|
+
return { agents: 19, skills: 32, commands: 31, workflows: 14 };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function showBanner() {
|
|
58
|
+
const counts = loadBannerCounts();
|
|
59
|
+
console.log(`
|
|
60
|
+
${colors.bright}${colors.blue}Devran AI Kit${colors.reset} ${colors.green}v${VERSION}${colors.reset}
|
|
61
|
+
Trust-grade AI development framework
|
|
62
|
+
|
|
63
|
+
${counts.agents} Agents | ${counts.skills} Skills | ${counts.commands} Commands | ${counts.workflows} Workflows
|
|
64
|
+
`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function showHelp() {
|
|
68
|
+
showBanner();
|
|
69
|
+
console.log(`
|
|
70
|
+
${colors.bright}Usage:${colors.reset}
|
|
71
|
+
kit init [options] Install .agent folder to your project
|
|
72
|
+
kit update Update to latest version
|
|
73
|
+
kit status Check installation status (alias: dashboard)
|
|
74
|
+
kit verify Run manifest integrity checks
|
|
75
|
+
kit scan Run security scan
|
|
76
|
+
kit plugin list List installed plugins
|
|
77
|
+
kit plugin install <p> Install plugin from directory
|
|
78
|
+
kit plugin remove <n> Remove installed plugin
|
|
79
|
+
kit market search <q> Search marketplace plugins
|
|
80
|
+
kit market info <name> Get marketplace plugin details
|
|
81
|
+
kit market install <n> Install from marketplace
|
|
82
|
+
kit heal [--file <f>] Detect and diagnose CI failures
|
|
83
|
+
kit health Run aggregated health check
|
|
84
|
+
kit --help Show this help message
|
|
85
|
+
kit --version Show version
|
|
86
|
+
|
|
87
|
+
${colors.bright}Options:${colors.reset}
|
|
88
|
+
--force Overwrite existing .agent folder
|
|
89
|
+
--path <dir> Install to specific directory
|
|
90
|
+
--quiet Suppress output (for CI/CD)
|
|
91
|
+
--dry-run Preview actions without executing
|
|
92
|
+
--apply Apply self-healing patches (default: dry-run)
|
|
93
|
+
--file <path> CI log file for heal command
|
|
94
|
+
--ide <name> Generate config for single IDE (cursor|opencode|codex)
|
|
95
|
+
--skip-ide Skip IDE config generation
|
|
96
|
+
|
|
97
|
+
${colors.bright}Examples:${colors.reset}
|
|
98
|
+
npx @devran-ai/kit init
|
|
99
|
+
kit init --force
|
|
100
|
+
kit scan
|
|
101
|
+
kit plugin list
|
|
102
|
+
|
|
103
|
+
${colors.bright}IDE Reference:${colors.reset}
|
|
104
|
+
Type ${colors.cyan}/help${colors.reset} in your AI-powered IDE for the full reference:
|
|
105
|
+
commands, workflows, agents, skills, rules, and checklists.
|
|
106
|
+
`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Creates a timestamped backup of a directory.
|
|
111
|
+
* @param {string} dirPath - Directory to back up
|
|
112
|
+
* @returns {string} Path to the backup directory
|
|
113
|
+
*/
|
|
114
|
+
function backupDirectory(dirPath) {
|
|
115
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
116
|
+
const backupPath = `${dirPath}.backup-${timestamp}`;
|
|
117
|
+
safeCopyDirSync(dirPath, backupPath);
|
|
118
|
+
return backupPath;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Checks if there is an active session with in-progress work.
|
|
123
|
+
* @param {string} agentPath - Path to existing .agent directory
|
|
124
|
+
* @returns {boolean} True if session-state indicates active work
|
|
125
|
+
*/
|
|
126
|
+
function hasActiveSession(agentPath) {
|
|
127
|
+
const statePath = path.join(agentPath, 'session-state.json');
|
|
128
|
+
const state = readJsonSafe(statePath, null);
|
|
129
|
+
if (!state) return false;
|
|
130
|
+
return state.currentTask || state.inProgress || state.activeWorkflow;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function countItems(dir, type = 'dir') {
|
|
134
|
+
try {
|
|
135
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
136
|
+
if (type === 'dir') {
|
|
137
|
+
return entries.filter(e => e.isDirectory()).length;
|
|
138
|
+
}
|
|
139
|
+
return entries.filter(e => e.isFile() && e.name !== 'README.md' && e.name.endsWith('.md')).length;
|
|
140
|
+
} catch {
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Generates IDE-specific config files during init.
|
|
147
|
+
* Extracted from initCommand for readability (gemini-code-assist M-2).
|
|
148
|
+
*/
|
|
149
|
+
function generateIdeConfigsForInit(agentPath, targetDir, options) {
|
|
150
|
+
try {
|
|
151
|
+
const { generateAllIdeConfigs, writeIdeConfigs, generateCursorConfig, generateOpenCodeConfig, generateCodexConfig } = require('../lib/ide-generator');
|
|
152
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(agentPath, 'manifest.json'), 'utf-8'));
|
|
153
|
+
const rulesContent = fs.readFileSync(path.join(agentPath, 'rules.md'), 'utf-8');
|
|
154
|
+
|
|
155
|
+
const generatorMap = {
|
|
156
|
+
cursor: () => generateCursorConfig(manifest, rulesContent),
|
|
157
|
+
opencode: () => generateOpenCodeConfig(manifest),
|
|
158
|
+
codex: () => generateCodexConfig(manifest),
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
let configs;
|
|
162
|
+
if (options.ide && generatorMap[options.ide]) {
|
|
163
|
+
configs = [generatorMap[options.ide]()];
|
|
164
|
+
} else if (options.ide) {
|
|
165
|
+
const supported = Object.keys(generatorMap).join(', ');
|
|
166
|
+
log(` ⚠️ Unknown IDE: "${options.ide}". Supported: ${supported}`, 'yellow');
|
|
167
|
+
log(' Skipping IDE config generation.', 'yellow');
|
|
168
|
+
return;
|
|
169
|
+
} else {
|
|
170
|
+
configs = generateAllIdeConfigs(manifest, rulesContent);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const result = writeIdeConfigs(targetDir, configs, { force: options.force, skipExisting: !options.force });
|
|
174
|
+
for (const f of result.written) log(` ✓ ${f}`, 'green');
|
|
175
|
+
for (const f of result.skipped) log(` ⏭ ${f} (already exists)`, 'yellow');
|
|
176
|
+
} catch (err) {
|
|
177
|
+
log(` ⚠️ IDE config generation failed: ${err.message}`, 'yellow');
|
|
178
|
+
log(' .agent/ installed successfully — IDE configs can be generated later', 'yellow');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function initCommand(options) {
|
|
183
|
+
const targetDir = options.path || process.cwd();
|
|
184
|
+
const agentPath = path.join(targetDir, AGENT_FOLDER);
|
|
185
|
+
const sourcePath = path.join(__dirname, '..', AGENT_FOLDER);
|
|
186
|
+
|
|
187
|
+
// Verify source .agent folder exists
|
|
188
|
+
if (!fs.existsSync(sourcePath)) {
|
|
189
|
+
log(`\n❌ Source .agent folder not found at: ${sourcePath}`, 'red');
|
|
190
|
+
log(' The package may be corrupted. Try reinstalling:', 'yellow');
|
|
191
|
+
log(' npm install -g @devran-ai/kit\n', 'yellow');
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (!options.quiet) {
|
|
196
|
+
showBanner();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Check if already exists
|
|
200
|
+
if (fs.existsSync(agentPath) && !options.force) {
|
|
201
|
+
log(`\n⚠️ ${AGENT_FOLDER} folder already exists!`, 'yellow');
|
|
202
|
+
log(' Use --force to overwrite', 'yellow');
|
|
203
|
+
log(' Use kit update for non-destructive updates\n', 'yellow');
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// M-3: Active session warning for --force
|
|
208
|
+
if (options.force && fs.existsSync(agentPath) && hasActiveSession(agentPath)) {
|
|
209
|
+
log('\n⚠️ Active session detected! Force-overwrite will destroy in-progress work.', 'yellow');
|
|
210
|
+
log(' Consider using kit update instead.\n', 'yellow');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (options.dryRun) {
|
|
214
|
+
log('\n🔍 Dry run mode - no changes will be made\n', 'cyan');
|
|
215
|
+
log(` Would copy: ${sourcePath}`, 'cyan');
|
|
216
|
+
log(` To: ${agentPath}\n`, 'cyan');
|
|
217
|
+
// M-2: Show force damage preview
|
|
218
|
+
if (options.force && fs.existsSync(agentPath)) {
|
|
219
|
+
log(' ⚠️ --force would overwrite these user files (restored from backup):', 'yellow');
|
|
220
|
+
for (const f of USER_DATA_FILES) {
|
|
221
|
+
if (fs.existsSync(path.join(agentPath, f))) {
|
|
222
|
+
log(` • ${f}`, 'yellow');
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
for (const d of USER_DATA_DIRS) {
|
|
226
|
+
if (fs.existsSync(path.join(agentPath, d))) {
|
|
227
|
+
log(` • ${d}/ (directory)`, 'yellow');
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
log('', 'reset');
|
|
231
|
+
}
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// C-2: Auto-backup before force-overwrite
|
|
236
|
+
let backupPath = null;
|
|
237
|
+
if (options.force && fs.existsSync(agentPath)) {
|
|
238
|
+
logStep('1/5', 'Backing up existing .agent folder...');
|
|
239
|
+
try {
|
|
240
|
+
backupPath = backupDirectory(agentPath);
|
|
241
|
+
log(` ✓ Backup created: ${path.basename(backupPath)}`, 'green');
|
|
242
|
+
} catch (err) {
|
|
243
|
+
log(` ⚠️ Backup failed: ${err.message}`, 'yellow');
|
|
244
|
+
log(' Proceeding without backup...', 'yellow');
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Dynamic step counter — avoids hardcoded step strings
|
|
249
|
+
const isForceWithBackup = backupPath !== null;
|
|
250
|
+
const totalSteps = isForceWithBackup ? 6 : 4;
|
|
251
|
+
let currentStep = isForceWithBackup ? 2 : 1;
|
|
252
|
+
|
|
253
|
+
// C-3: Atomic copy via temp directory
|
|
254
|
+
logStep(`${currentStep}/${totalSteps}`, 'Copying .agent folder...');
|
|
255
|
+
|
|
256
|
+
const tempPath = `${agentPath}.tmp-${Date.now()}`;
|
|
257
|
+
try {
|
|
258
|
+
safeCopyDirSync(sourcePath, tempPath);
|
|
259
|
+
// Remove old directory if force-overwriting
|
|
260
|
+
if (fs.existsSync(agentPath)) {
|
|
261
|
+
fs.rmSync(agentPath, { recursive: true, force: true });
|
|
262
|
+
}
|
|
263
|
+
// Atomic rename: move temp to final
|
|
264
|
+
fs.renameSync(tempPath, agentPath);
|
|
265
|
+
log(' ✓ Copied successfully', 'green');
|
|
266
|
+
} catch (err) {
|
|
267
|
+
// Cleanup temp directory on failure
|
|
268
|
+
try {
|
|
269
|
+
if (fs.existsSync(tempPath)) {
|
|
270
|
+
fs.rmSync(tempPath, { recursive: true, force: true });
|
|
271
|
+
}
|
|
272
|
+
} catch {
|
|
273
|
+
// Cleanup failure is non-critical
|
|
274
|
+
}
|
|
275
|
+
log(` ✗ Failed to copy: ${err.message}`, 'red');
|
|
276
|
+
process.exit(1);
|
|
277
|
+
}
|
|
278
|
+
currentStep++;
|
|
279
|
+
|
|
280
|
+
// E3: Restore user data files from backup after force-overwrite
|
|
281
|
+
if (isForceWithBackup) {
|
|
282
|
+
logStep(`${currentStep}/${totalSteps}`, 'Restoring user session data from backup...');
|
|
283
|
+
let restoredCount = 0;
|
|
284
|
+
|
|
285
|
+
for (const file of USER_DATA_FILES) {
|
|
286
|
+
const backupFile = path.join(backupPath, file);
|
|
287
|
+
const targetFile = path.join(agentPath, file);
|
|
288
|
+
if (fs.existsSync(backupFile)) {
|
|
289
|
+
const targetDirPath = path.dirname(targetFile);
|
|
290
|
+
if (!fs.existsSync(targetDirPath)) {
|
|
291
|
+
fs.mkdirSync(targetDirPath, { recursive: true });
|
|
292
|
+
}
|
|
293
|
+
fs.copyFileSync(backupFile, targetFile);
|
|
294
|
+
log(` ✓ Restored ${file}`, 'green');
|
|
295
|
+
restoredCount++;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
for (const dir of USER_DATA_DIRS) {
|
|
300
|
+
const backupDir = path.join(backupPath, dir);
|
|
301
|
+
const targetDirPath = path.join(agentPath, dir);
|
|
302
|
+
if (fs.existsSync(backupDir)) {
|
|
303
|
+
safeCopyDirSync(backupDir, targetDirPath);
|
|
304
|
+
log(` ✓ Restored ${dir}/`, 'green');
|
|
305
|
+
restoredCount++;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (restoredCount === 0) {
|
|
310
|
+
log(' ○ No user data to restore', 'yellow');
|
|
311
|
+
}
|
|
312
|
+
currentStep++;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Verify installation
|
|
316
|
+
logStep(`${currentStep}/${totalSteps}`, 'Verifying installation...');
|
|
317
|
+
const skills = countItems(path.join(agentPath, 'skills'), 'dir');
|
|
318
|
+
const commands = countItems(path.join(agentPath, 'commands'), 'file');
|
|
319
|
+
const workflows = countItems(path.join(agentPath, 'workflows'), 'file');
|
|
320
|
+
log(` ✓ Skills: ${skills}, Commands: ${commands}, Workflows: ${workflows}`, 'green');
|
|
321
|
+
currentStep++;
|
|
322
|
+
|
|
323
|
+
// Generate IDE configurations (Cursor, OpenCode, Codex)
|
|
324
|
+
if (!options.skipIde) {
|
|
325
|
+
logStep(`${currentStep}/${totalSteps}`, 'Generating IDE configurations...');
|
|
326
|
+
generateIdeConfigsForInit(agentPath, targetDir, options);
|
|
327
|
+
}
|
|
328
|
+
currentStep++;
|
|
329
|
+
|
|
330
|
+
// Final message
|
|
331
|
+
logStep(`${currentStep}/${totalSteps}`, 'Setup complete!');
|
|
332
|
+
|
|
333
|
+
if (!options.quiet) {
|
|
334
|
+
console.log(`
|
|
335
|
+
${colors.green}Devran AI Kit installed successfully.${colors.reset}
|
|
336
|
+
|
|
337
|
+
${colors.bright}Next steps:${colors.reset}
|
|
338
|
+
1. Open your project in an AI-powered IDE
|
|
339
|
+
2. Run ${colors.cyan}/status${colors.reset} to verify
|
|
340
|
+
3. Use ${colors.cyan}/help${colors.reset} to see available commands
|
|
341
|
+
|
|
342
|
+
${colors.bright}Validate your installation:${colors.reset}
|
|
343
|
+
${colors.cyan}kit verify${colors.reset} Manifest integrity check
|
|
344
|
+
${colors.cyan}kit scan${colors.reset} Security scan
|
|
345
|
+
|
|
346
|
+
${colors.bright}Quick start:${colors.reset}
|
|
347
|
+
${colors.cyan}/plan${colors.reset} Create implementation plan
|
|
348
|
+
${colors.cyan}/implement${colors.reset} Execute the plan
|
|
349
|
+
${colors.cyan}/verify${colors.reset} Run quality gates
|
|
350
|
+
|
|
351
|
+
${colors.yellow}📚 Documentation: https://github.com/devran-ai/kit${colors.reset}
|
|
352
|
+
`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function statusCommand() {
|
|
357
|
+
showBanner();
|
|
358
|
+
|
|
359
|
+
const agentPath = path.join(process.cwd(), AGENT_FOLDER);
|
|
360
|
+
|
|
361
|
+
if (!fs.existsSync(agentPath)) {
|
|
362
|
+
log('❌ Not installed in current directory', 'red');
|
|
363
|
+
log(' Run: kit init\n', 'yellow');
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
log('Devran AI Kit is installed\n', 'green');
|
|
368
|
+
|
|
369
|
+
const skills = countItems(path.join(agentPath, 'skills'), 'dir');
|
|
370
|
+
const commands = countItems(path.join(agentPath, 'commands'), 'file');
|
|
371
|
+
const workflows = countItems(path.join(agentPath, 'workflows'), 'file');
|
|
372
|
+
|
|
373
|
+
log(' ═══ Capabilities ═══', 'cyan');
|
|
374
|
+
console.log(` 📦 Skills: ${skills}`);
|
|
375
|
+
console.log(` ⌨️ Commands: ${commands}`);
|
|
376
|
+
console.log(` 🔄 Workflows: ${workflows}`);
|
|
377
|
+
|
|
378
|
+
// Workflow phase + available transitions
|
|
379
|
+
try {
|
|
380
|
+
const workflowEngine = require('../lib/workflow-engine');
|
|
381
|
+
const phase = workflowEngine.getCurrentPhase(process.cwd());
|
|
382
|
+
const available = workflowEngine.getAvailableTransitions(process.cwd());
|
|
383
|
+
console.log(` 🔁 Phase: ${phase}`);
|
|
384
|
+
if (available.length > 0) {
|
|
385
|
+
const nextPhases = available.map((t) => t.to).join(', ');
|
|
386
|
+
console.log(` ➡️ Next: ${nextPhases}`);
|
|
387
|
+
}
|
|
388
|
+
} catch {
|
|
389
|
+
// Engine not available, skip silently
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Error budget
|
|
393
|
+
try {
|
|
394
|
+
const errorBudget = require('../lib/error-budget');
|
|
395
|
+
const report = errorBudget.getBudgetReport(process.cwd());
|
|
396
|
+
const statusIcon = report.status === 'HEALTHY' ? '🟢' : report.status === 'WARNING' ? '🟡' : '🔴';
|
|
397
|
+
console.log(` ${statusIcon} Budget: ${report.status}`);
|
|
398
|
+
if (report.violations.length > 0) {
|
|
399
|
+
log(` ⚠️ Violations: ${report.violations.join(', ')}`, 'yellow');
|
|
400
|
+
}
|
|
401
|
+
} catch {
|
|
402
|
+
// Budget not available, skip silently
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Task metrics
|
|
406
|
+
try {
|
|
407
|
+
const taskModel = require('../lib/task-model');
|
|
408
|
+
const metrics = taskModel.getTaskMetrics(process.cwd());
|
|
409
|
+
if (metrics.total > 0) {
|
|
410
|
+
console.log('');
|
|
411
|
+
log(' ═══ Tasks ═══', 'cyan');
|
|
412
|
+
console.log(` 📋 Open: ${metrics.counts.open || 0}`);
|
|
413
|
+
console.log(` 🔨 In Progress: ${metrics.counts['in-progress'] || 0}`);
|
|
414
|
+
console.log(` 👁️ In Review: ${metrics.counts.review || 0}`);
|
|
415
|
+
console.log(` ✅ Done: ${metrics.counts.done || 0}`);
|
|
416
|
+
console.log(` 🚫 Blocked: ${metrics.counts.blocked || 0}`);
|
|
417
|
+
if (metrics.completionRate > 0) {
|
|
418
|
+
console.log(` 📊 Completion: ${metrics.completionRate}%`);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
} catch {
|
|
422
|
+
// Task model not available, skip silently
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Hook readiness
|
|
426
|
+
try {
|
|
427
|
+
const hookSystem = require('../lib/hook-system');
|
|
428
|
+
const hookReport = hookSystem.getHookReport(process.cwd());
|
|
429
|
+
console.log('');
|
|
430
|
+
log(' ═══ Hooks ═══', 'cyan');
|
|
431
|
+
console.log(` 🪝 Events: ${hookReport.events.length}`);
|
|
432
|
+
console.log(` ✅ Ready: ${hookReport.readyCount}/${hookReport.events.length}`);
|
|
433
|
+
} catch {
|
|
434
|
+
// Hook system not available, skip silently
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Developer identity
|
|
438
|
+
try {
|
|
439
|
+
const identity = require('../lib/identity');
|
|
440
|
+
const current = identity.getCurrentIdentity(process.cwd());
|
|
441
|
+
if (current) {
|
|
442
|
+
console.log('');
|
|
443
|
+
log(' ═══ Identity ═══', 'cyan');
|
|
444
|
+
console.log(` 👤 Developer: ${current.name}`);
|
|
445
|
+
console.log(` 🔑 Role: ${current.role}`);
|
|
446
|
+
}
|
|
447
|
+
} catch {
|
|
448
|
+
// Identity not available, skip silently
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Plugins
|
|
452
|
+
try {
|
|
453
|
+
const pluginSystem = require('../lib/plugin-system');
|
|
454
|
+
const plugins = pluginSystem.listPlugins(process.cwd());
|
|
455
|
+
if (plugins.length > 0) {
|
|
456
|
+
console.log('');
|
|
457
|
+
log(' ═══ Plugins ═══', 'cyan');
|
|
458
|
+
console.log(` 🔌 Installed: ${plugins.length}`);
|
|
459
|
+
for (const plugin of plugins) {
|
|
460
|
+
console.log(` • ${plugin.name} v${plugin.version}`);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
} catch {
|
|
464
|
+
// Plugin system not available, skip silently
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Phase 4 dashboard sections (D-5, E-5)
|
|
468
|
+
try {
|
|
469
|
+
const cliCommands = require('../lib/cli-commands');
|
|
470
|
+
cliCommands.renderDashboardSections(process.cwd());
|
|
471
|
+
} catch {
|
|
472
|
+
// Phase 4 modules not available, skip silently
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
console.log('');
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function verifyCommand() {
|
|
479
|
+
showBanner();
|
|
480
|
+
logStep('1/1', 'Running manifest integrity checks...\n');
|
|
481
|
+
|
|
482
|
+
try {
|
|
483
|
+
const verify = require('../lib/verify');
|
|
484
|
+
const report = verify.runAllChecks(process.cwd());
|
|
485
|
+
|
|
486
|
+
for (const result of report.results) {
|
|
487
|
+
const icon = result.status === 'pass' ? '✓' : result.status === 'fail' ? '✗' : '⚠';
|
|
488
|
+
const color = result.status === 'pass' ? 'green' : result.status === 'fail' ? 'red' : 'yellow';
|
|
489
|
+
log(` ${icon} ${result.message}`, color);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
console.log('');
|
|
493
|
+
log(` Passed: ${report.passed} Failed: ${report.failed} Warnings: ${report.warnings}`, report.failed > 0 ? 'red' : 'green');
|
|
494
|
+
console.log('');
|
|
495
|
+
|
|
496
|
+
if (report.failed > 0) {
|
|
497
|
+
process.exit(1);
|
|
498
|
+
}
|
|
499
|
+
} catch (/** @type {any} */ error) {
|
|
500
|
+
log(` ✗ Verification failed: ${error.message}`, 'red');
|
|
501
|
+
process.exit(1);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function updateCommand(updateOptions) {
|
|
506
|
+
showBanner();
|
|
507
|
+
|
|
508
|
+
const agentPath = path.join(updateOptions.path || process.cwd(), '.agent');
|
|
509
|
+
if (!fs.existsSync(agentPath)) {
|
|
510
|
+
log('\n❌ No .agent/ folder found. Run: kit init\n', 'red');
|
|
511
|
+
process.exit(1);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const sourceRoot = path.join(__dirname, '..');
|
|
515
|
+
const targetRoot = updateOptions.path || process.cwd();
|
|
516
|
+
|
|
517
|
+
try {
|
|
518
|
+
const updater = require('../lib/updater');
|
|
519
|
+
const isDryRun = updateOptions.dryRun;
|
|
520
|
+
|
|
521
|
+
// M-1: Show version transition (use source kit version, not CLI version)
|
|
522
|
+
const sourcePackage = readJsonSafe(path.join(sourceRoot, 'package.json'), {});
|
|
523
|
+
const kitVersion = sourcePackage.version || VERSION;
|
|
524
|
+
const currentManifest = readJsonSafe(path.join(agentPath, 'manifest.json'), {});
|
|
525
|
+
const currentVersion = currentManifest.kitVersion || 'unknown';
|
|
526
|
+
if (currentVersion !== kitVersion) {
|
|
527
|
+
log(`\n 📦 Upgrading: v${currentVersion} → v${kitVersion}`, 'cyan');
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
if (isDryRun) {
|
|
531
|
+
log('\n🔍 Dry run mode — no changes will be made\n', 'cyan');
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
logStep('1/2', isDryRun ? 'Analyzing differences...' : 'Applying updates...');
|
|
535
|
+
|
|
536
|
+
const report = updater.applyUpdate(sourceRoot, targetRoot, isDryRun);
|
|
537
|
+
|
|
538
|
+
if (report.added.length > 0) {
|
|
539
|
+
log(`\n 📁 New files (${report.added.length}):`, 'green');
|
|
540
|
+
for (const file of report.added) {
|
|
541
|
+
log(` + ${file}`, 'green');
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (report.updated.length > 0) {
|
|
546
|
+
log(`\n 📝 Updated files (${report.updated.length}):`, 'cyan');
|
|
547
|
+
for (const file of report.updated) {
|
|
548
|
+
log(` ~ ${file}`, 'cyan');
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (report.skipped.length > 0) {
|
|
553
|
+
log(`\n 🔒 Preserved files (${report.skipped.length}):`, 'yellow');
|
|
554
|
+
for (const file of report.skipped) {
|
|
555
|
+
log(` ○ ${file}`, 'yellow');
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
logStep('2/2', 'Summary');
|
|
560
|
+
console.log(`\n Added: ${report.added.length} Updated: ${report.updated.length} Skipped: ${report.skipped.length} Unchanged: ${report.unchanged.length}\n`);
|
|
561
|
+
|
|
562
|
+
if (report.added.length === 0 && report.updated.length === 0) {
|
|
563
|
+
log(' ✅ Already up to date!\n', 'green');
|
|
564
|
+
} else if (!isDryRun) {
|
|
565
|
+
log(' ✅ Update complete!\n', 'green');
|
|
566
|
+
}
|
|
567
|
+
} catch (/** @type {any} */ error) {
|
|
568
|
+
log(` ✗ Update failed: ${error.message}`, 'red');
|
|
569
|
+
process.exit(1);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function scanCommand() {
|
|
574
|
+
showBanner();
|
|
575
|
+
logStep('1/1', 'Running enhanced security scan...\n');
|
|
576
|
+
|
|
577
|
+
try {
|
|
578
|
+
const scanner = require('../lib/security-scanner');
|
|
579
|
+
const report = scanner.getSecurityReport(process.cwd());
|
|
580
|
+
|
|
581
|
+
log(` 📂 Files scanned: ${report.filesScanned}`, 'cyan');
|
|
582
|
+
console.log('');
|
|
583
|
+
|
|
584
|
+
if (report.findings.length === 0) {
|
|
585
|
+
log(' ✅ No security findings — all clear!\n', 'green');
|
|
586
|
+
} else {
|
|
587
|
+
for (const finding of report.findings) {
|
|
588
|
+
const icon = finding.severity === 'critical' ? '🔴' : finding.severity === 'high' ? '🟠' : finding.severity === 'medium' ? '🟡' : '⚪';
|
|
589
|
+
log(` ${icon} [${finding.severity.toUpperCase()}] ${finding.detail}`, finding.severity === 'critical' ? 'red' : finding.severity === 'high' ? 'yellow' : 'reset');
|
|
590
|
+
console.log(` File: ${finding.file}${finding.line ? `:${finding.line}` : ''}`);
|
|
591
|
+
}
|
|
592
|
+
console.log('');
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
log(` 🔴 Critical: ${report.criticalCount} 🟠 High: ${report.highCount} 🟡 Medium: ${report.mediumCount} ⚪ Low: ${report.lowCount}`, report.clean ? 'green' : 'red');
|
|
596
|
+
console.log('');
|
|
597
|
+
|
|
598
|
+
if (!report.clean) {
|
|
599
|
+
process.exit(1);
|
|
600
|
+
}
|
|
601
|
+
} catch (/** @type {any} */ error) {
|
|
602
|
+
log(` ✗ Security scan failed: ${error.message}`, 'red');
|
|
603
|
+
process.exit(1);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
function pluginCommand(subCommand, pluginArg) {
|
|
608
|
+
showBanner();
|
|
609
|
+
|
|
610
|
+
try {
|
|
611
|
+
const pluginSystem = require('../lib/plugin-system');
|
|
612
|
+
|
|
613
|
+
switch (subCommand) {
|
|
614
|
+
case 'list': {
|
|
615
|
+
const plugins = pluginSystem.listPlugins(process.cwd());
|
|
616
|
+
if (plugins.length === 0) {
|
|
617
|
+
log(' No plugins installed\n', 'yellow');
|
|
618
|
+
} else {
|
|
619
|
+
log(` ═══ Installed Plugins (${plugins.length}) ═══\n`, 'cyan');
|
|
620
|
+
for (const plugin of plugins) {
|
|
621
|
+
console.log(` 🔌 ${plugin.name} v${plugin.version}`);
|
|
622
|
+
console.log(` Author: ${plugin.author}`);
|
|
623
|
+
console.log(` Installed: ${plugin.installedAt}`);
|
|
624
|
+
console.log('');
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
break;
|
|
628
|
+
}
|
|
629
|
+
case 'install': {
|
|
630
|
+
if (!pluginArg) {
|
|
631
|
+
log(' ✗ Usage: kit plugin install <path>\n', 'red');
|
|
632
|
+
process.exit(1);
|
|
633
|
+
}
|
|
634
|
+
const pluginPath = path.resolve(pluginArg);
|
|
635
|
+
logStep('1/1', `Installing plugin from ${pluginPath}...`);
|
|
636
|
+
const result = pluginSystem.installPlugin(pluginPath, process.cwd());
|
|
637
|
+
if (result.success) {
|
|
638
|
+
log('\n ✅ Plugin installed successfully!', 'green');
|
|
639
|
+
console.log(` Agents: ${result.installed.agents} Skills: ${result.installed.skills} Workflows: ${result.installed.workflows} Hooks: ${result.installed.hooks}\n`);
|
|
640
|
+
} else {
|
|
641
|
+
log('\n ✗ Plugin installation failed:', 'red');
|
|
642
|
+
for (const error of result.errors) {
|
|
643
|
+
log(` • ${error}`, 'red');
|
|
644
|
+
}
|
|
645
|
+
console.log('');
|
|
646
|
+
process.exit(1);
|
|
647
|
+
}
|
|
648
|
+
break;
|
|
649
|
+
}
|
|
650
|
+
case 'remove': {
|
|
651
|
+
if (!pluginArg) {
|
|
652
|
+
log(' ✗ Usage: kit plugin remove <name>\n', 'red');
|
|
653
|
+
process.exit(1);
|
|
654
|
+
}
|
|
655
|
+
logStep('1/1', `Removing plugin: ${pluginArg}...`);
|
|
656
|
+
const result = pluginSystem.removePlugin(pluginArg, process.cwd());
|
|
657
|
+
if (result.success) {
|
|
658
|
+
log('\n ✅ Plugin removed successfully!\n', 'green');
|
|
659
|
+
} else {
|
|
660
|
+
log(`\n ✗ ${result.error}\n`, 'red');
|
|
661
|
+
process.exit(1);
|
|
662
|
+
}
|
|
663
|
+
break;
|
|
664
|
+
}
|
|
665
|
+
default:
|
|
666
|
+
log(' Usage: kit plugin <list|install|remove>', 'yellow');
|
|
667
|
+
console.log('');
|
|
668
|
+
break;
|
|
669
|
+
}
|
|
670
|
+
} catch (/** @type {any} */ error) {
|
|
671
|
+
log(` ✗ Plugin command failed: ${error.message}`, 'red');
|
|
672
|
+
process.exit(1);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// Parse arguments
|
|
677
|
+
const args = process.argv.slice(2);
|
|
678
|
+
const command = args[0];
|
|
679
|
+
|
|
680
|
+
const options = {
|
|
681
|
+
force: args.includes('--force'),
|
|
682
|
+
quiet: args.includes('--quiet'),
|
|
683
|
+
dryRun: args.includes('--dry-run'),
|
|
684
|
+
apply: args.includes('--apply'),
|
|
685
|
+
skipIde: args.includes('--skip-ide'),
|
|
686
|
+
ide: null,
|
|
687
|
+
path: null,
|
|
688
|
+
file: null,
|
|
689
|
+
};
|
|
690
|
+
|
|
691
|
+
// Parse --ide option
|
|
692
|
+
const ideIndex = args.indexOf('--ide');
|
|
693
|
+
if (ideIndex !== -1 && args[ideIndex + 1]) {
|
|
694
|
+
options.ide = args[ideIndex + 1].toLowerCase();
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// Parse --path option with traversal protection (H-7: use path.resolve boundary check)
|
|
698
|
+
const pathIndex = args.indexOf('--path');
|
|
699
|
+
if (pathIndex !== -1 && args[pathIndex + 1]) {
|
|
700
|
+
const resolvedPath = path.resolve(args[pathIndex + 1]);
|
|
701
|
+
const cwd = process.cwd();
|
|
702
|
+
if (!resolvedPath.startsWith(cwd + path.sep) && resolvedPath !== cwd) {
|
|
703
|
+
log('Error: --path must resolve within current working directory', 'red');
|
|
704
|
+
process.exit(1);
|
|
705
|
+
}
|
|
706
|
+
options.path = resolvedPath;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// Parse --file option with traversal protection (H-7: use path.resolve boundary check)
|
|
710
|
+
const fileIndex = args.indexOf('--file');
|
|
711
|
+
if (fileIndex !== -1 && args[fileIndex + 1]) {
|
|
712
|
+
const resolvedFile = path.resolve(args[fileIndex + 1]);
|
|
713
|
+
const cwdForFile = process.cwd();
|
|
714
|
+
if (!resolvedFile.startsWith(cwdForFile + path.sep) && resolvedFile !== cwdForFile) {
|
|
715
|
+
log('Error: --file must resolve within current working directory', 'red');
|
|
716
|
+
process.exit(1);
|
|
717
|
+
}
|
|
718
|
+
options.file = resolvedFile;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// Execute command
|
|
722
|
+
switch (command) {
|
|
723
|
+
case 'init':
|
|
724
|
+
initCommand(options);
|
|
725
|
+
break;
|
|
726
|
+
case 'status':
|
|
727
|
+
case 'dashboard':
|
|
728
|
+
statusCommand();
|
|
729
|
+
break;
|
|
730
|
+
case 'update':
|
|
731
|
+
updateCommand(options);
|
|
732
|
+
break;
|
|
733
|
+
case 'verify':
|
|
734
|
+
verifyCommand();
|
|
735
|
+
break;
|
|
736
|
+
case 'scan':
|
|
737
|
+
scanCommand();
|
|
738
|
+
break;
|
|
739
|
+
case 'plugin':
|
|
740
|
+
pluginCommand(args[1], args[2]);
|
|
741
|
+
break;
|
|
742
|
+
case 'market': {
|
|
743
|
+
const cliCommands = require('../lib/cli-commands');
|
|
744
|
+
cliCommands.marketCommand(process.cwd(), args[1], args[2], options);
|
|
745
|
+
break;
|
|
746
|
+
}
|
|
747
|
+
case 'heal': {
|
|
748
|
+
const cliCmd = require('../lib/cli-commands');
|
|
749
|
+
cliCmd.healCommand(process.cwd(), { file: options.file, apply: options.apply });
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
752
|
+
case 'health': {
|
|
753
|
+
const cliHealth = require('../lib/cli-commands');
|
|
754
|
+
const result = cliHealth.healthCommand(process.cwd());
|
|
755
|
+
if (!result.healthy) {
|
|
756
|
+
process.exit(1);
|
|
757
|
+
}
|
|
758
|
+
break;
|
|
759
|
+
}
|
|
760
|
+
case '--version':
|
|
761
|
+
case '-v':
|
|
762
|
+
console.log(VERSION);
|
|
763
|
+
break;
|
|
764
|
+
case '--help':
|
|
765
|
+
case '-h':
|
|
766
|
+
case undefined:
|
|
767
|
+
showHelp();
|
|
768
|
+
break;
|
|
769
|
+
default:
|
|
770
|
+
log(`Unknown command: ${command}`, 'red');
|
|
771
|
+
log('Run kit --help for usage\n', 'yellow');
|
|
772
|
+
process.exit(1);
|
|
773
|
+
}
|