@lenne.tech/cli 0.0.125 → 1.0.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/bin/lt +145 -14
- package/build/commands/claude/install-commands.js +332 -0
- package/build/commands/claude/install-skills.js +626 -0
- package/build/commands/config/config.js +25 -0
- package/build/commands/config/help.js +167 -0
- package/build/commands/config/init.js +143 -0
- package/build/commands/config/show.js +68 -0
- package/build/commands/server/add-property.js +163 -46
- package/build/commands/server/create.js +66 -4
- package/build/commands/server/module.js +133 -20
- package/build/commands/server/object.js +23 -15
- package/build/extensions/config.js +157 -0
- package/build/extensions/server.js +194 -63
- package/build/interfaces/lt-config.interface.js +3 -0
- package/build/templates/claude-commands/code-cleanup.md +82 -0
- package/build/templates/claude-commands/mr-description-clipboard.md +48 -0
- package/build/templates/claude-commands/mr-description.md +33 -0
- package/build/templates/claude-commands/sec-review.md +62 -0
- package/build/templates/claude-commands/skill-optimize.md +140 -0
- package/build/templates/claude-commands/test-generate.md +45 -0
- package/build/templates/claude-skills/lt-cli/SKILL.md +190 -259
- package/build/templates/claude-skills/lt-cli/examples.md +433 -203
- package/build/templates/claude-skills/lt-cli/reference.md +400 -226
- package/build/templates/claude-skills/nest-server-generator/SKILL.md +1891 -0
- package/build/templates/claude-skills/nest-server-generator/configuration.md +279 -0
- package/build/templates/claude-skills/nest-server-generator/declare-keyword-warning.md +124 -0
- package/build/templates/claude-skills/nest-server-generator/description-management.md +217 -0
- package/build/templates/claude-skills/nest-server-generator/examples.md +886 -0
- package/build/templates/claude-skills/nest-server-generator/quality-review.md +855 -0
- package/build/templates/claude-skills/nest-server-generator/reference.md +471 -0
- package/build/templates/claude-skills/nest-server-generator/security-rules.md +358 -0
- package/build/templates/claude-skills/story-tdd/SKILL.md +1173 -0
- package/build/templates/claude-skills/story-tdd/code-quality.md +266 -0
- package/build/templates/claude-skills/story-tdd/database-indexes.md +173 -0
- package/build/templates/claude-skills/story-tdd/examples.md +1332 -0
- package/build/templates/claude-skills/story-tdd/reference.md +1180 -0
- package/build/templates/claude-skills/story-tdd/security-review.md +299 -0
- package/build/templates/nest-server-module/inputs/template-create.input.ts.ejs +1 -3
- package/build/templates/nest-server-module/inputs/template.input.ts.ejs +1 -1
- package/build/templates/nest-server-module/template.controller.ts.ejs +24 -13
- package/build/templates/nest-server-module/template.model.ts.ejs +2 -2
- package/build/templates/nest-server-module/template.module.ts.ejs +4 -0
- package/build/templates/nest-server-module/template.service.ts.ejs +6 -6
- package/build/templates/nest-server-object/template.object.ts.ejs +2 -2
- package/package.json +13 -11
- package/build/commands/claude/install-skill.js +0 -93
package/bin/lt
CHANGED
|
@@ -2,20 +2,151 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
/* tslint:disable */
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
require(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
5
|
+
|
|
6
|
+
// Handle case where current working directory no longer exists
|
|
7
|
+
try {
|
|
8
|
+
process.cwd();
|
|
9
|
+
} catch (err) {
|
|
10
|
+
// Current directory doesn't exist - offer interactive solutions
|
|
11
|
+
var fs = require('fs');
|
|
12
|
+
var path = require('path');
|
|
13
|
+
var os = require('os');
|
|
14
|
+
var readline = require('readline');
|
|
15
|
+
|
|
16
|
+
console.error('\nError: Current working directory no longer exists.');
|
|
17
|
+
console.error('The directory you were in has been deleted or is no longer accessible.\n');
|
|
18
|
+
|
|
19
|
+
// Try to find the next existing parent directory
|
|
20
|
+
var originalPath = process.env.PWD || process.env.OLDPWD || '';
|
|
21
|
+
var parentDir = null;
|
|
22
|
+
|
|
23
|
+
if (originalPath) {
|
|
24
|
+
var testPath = path.dirname(originalPath);
|
|
25
|
+
while (testPath && testPath !== '/' && testPath !== '.') {
|
|
26
|
+
try {
|
|
27
|
+
if (fs.existsSync(testPath) && fs.statSync(testPath).isDirectory()) {
|
|
28
|
+
parentDir = testPath;
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
} catch (e) {
|
|
32
|
+
// Continue searching
|
|
33
|
+
}
|
|
34
|
+
testPath = path.dirname(testPath);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Build options
|
|
39
|
+
var options = [];
|
|
40
|
+
if (parentDir) {
|
|
41
|
+
options.push({ key: '1', label: 'Change to nearest existing parent directory: ' + parentDir, action: parentDir });
|
|
42
|
+
}
|
|
43
|
+
options.push({ key: parentDir ? '2' : '1', label: 'Change to home directory: ' + os.homedir(), action: os.homedir() });
|
|
44
|
+
options.push({ key: parentDir ? '3' : '2', label: 'Enter a custom directory path', action: 'custom' });
|
|
45
|
+
options.push({ key: parentDir ? '4' : '3', label: 'Cancel and exit', action: 'exit' });
|
|
46
|
+
|
|
47
|
+
// Display options
|
|
48
|
+
console.log('Please choose an option:\n');
|
|
49
|
+
options.forEach(function(opt) {
|
|
50
|
+
console.log(' ' + opt.key + ') ' + opt.label);
|
|
51
|
+
});
|
|
52
|
+
console.log('');
|
|
53
|
+
|
|
54
|
+
// Read user input
|
|
55
|
+
var rl = readline.createInterface({
|
|
56
|
+
input: process.stdin,
|
|
57
|
+
output: process.stdout
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
rl.question('Enter your choice: ', function(answer) {
|
|
61
|
+
var choice = options.find(function(opt) { return opt.key === answer.trim(); });
|
|
62
|
+
|
|
63
|
+
if (!choice) {
|
|
64
|
+
console.error('\nInvalid choice. Exiting.\n');
|
|
65
|
+
rl.close();
|
|
66
|
+
process.exit(1);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (choice.action === 'exit') {
|
|
71
|
+
console.log('\nCancelled.\n');
|
|
72
|
+
rl.close();
|
|
73
|
+
process.exit(0);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (choice.action === 'custom') {
|
|
78
|
+
rl.question('Enter directory path (absolute or relative to ' + (parentDir || os.homedir()) + '): ', function(customPath) {
|
|
79
|
+
var targetPath = customPath.trim();
|
|
80
|
+
|
|
81
|
+
// If relative path, resolve it relative to parent or home
|
|
82
|
+
if (!path.isAbsolute(targetPath)) {
|
|
83
|
+
targetPath = path.resolve(parentDir || os.homedir(), targetPath);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
if (!fs.existsSync(targetPath)) {
|
|
88
|
+
console.error('\nError: Directory does not exist: ' + targetPath + '\n');
|
|
89
|
+
rl.close();
|
|
90
|
+
process.exit(1);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
process.chdir(targetPath);
|
|
95
|
+
console.log('\nChanged to: ' + targetPath + '\n');
|
|
96
|
+
rl.close();
|
|
97
|
+
continueExecution();
|
|
98
|
+
} catch (e) {
|
|
99
|
+
console.error('\nError: Cannot change to directory: ' + targetPath);
|
|
100
|
+
console.error(e.message + '\n');
|
|
101
|
+
rl.close();
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Change to selected directory
|
|
109
|
+
try {
|
|
110
|
+
process.chdir(choice.action);
|
|
111
|
+
console.log('\nChanged to: ' + choice.action + '\n');
|
|
112
|
+
rl.close();
|
|
113
|
+
continueExecution();
|
|
114
|
+
} catch (e) {
|
|
115
|
+
console.error('\nError: Cannot change to directory: ' + choice.action);
|
|
116
|
+
console.error(e.message + '\n');
|
|
117
|
+
rl.close();
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Function to continue CLI execution after directory change
|
|
123
|
+
function continueExecution() {
|
|
124
|
+
runCLI();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Don't continue execution here - wait for user choice
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Normal execution path
|
|
132
|
+
runCLI();
|
|
133
|
+
|
|
134
|
+
function runCLI() {
|
|
135
|
+
// check if we're running in dev mode
|
|
136
|
+
var devMode = require('fs').existsSync(`${__dirname}/../src`);
|
|
137
|
+
// or want to "force" running the compiled version with --compiled-build
|
|
138
|
+
var wantsCompiled = process.argv.indexOf('--compiled-build') >= 0;
|
|
139
|
+
|
|
140
|
+
if (wantsCompiled || !devMode) {
|
|
141
|
+
// this runs from the compiled javascript source
|
|
142
|
+
require(`${__dirname}/../build/cli`).run(process.argv);
|
|
143
|
+
} else {
|
|
144
|
+
// this runs from the typescript source (for dev only)
|
|
145
|
+
// hook into ts-node so we can run typescript on the fly
|
|
146
|
+
require('ts-node').register({ project: `${__dirname}/../tsconfig.json` });
|
|
147
|
+
// run the CLI with the current process arguments
|
|
148
|
+
require(`${__dirname}/../src/cli`).run(process.argv);
|
|
149
|
+
}
|
|
19
150
|
}
|
|
20
151
|
|
|
21
152
|
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const os_1 = require("os");
|
|
13
|
+
const path_1 = require("path");
|
|
14
|
+
/**
|
|
15
|
+
* Get command description from .md frontmatter
|
|
16
|
+
*/
|
|
17
|
+
function getCommandDescription(commandPath, filesystem) {
|
|
18
|
+
if (!filesystem.exists(commandPath)) {
|
|
19
|
+
return 'No description available';
|
|
20
|
+
}
|
|
21
|
+
const content = filesystem.read(commandPath);
|
|
22
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
23
|
+
if (!frontmatterMatch) {
|
|
24
|
+
return 'No description available';
|
|
25
|
+
}
|
|
26
|
+
const frontmatter = frontmatterMatch[1];
|
|
27
|
+
const descMatch = frontmatter.match(/description:\s*([^\n]+)/);
|
|
28
|
+
return descMatch ? descMatch[1].trim() : 'No description available';
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Compare semantic versions
|
|
32
|
+
* Returns true if sourceVersion >= targetVersion
|
|
33
|
+
*/
|
|
34
|
+
function isVersionNewer(sourceVersion, targetVersion) {
|
|
35
|
+
const parseSemver = (version) => {
|
|
36
|
+
return version.split('.').map(n => parseInt(n, 10) || 0);
|
|
37
|
+
};
|
|
38
|
+
const source = parseSemver(sourceVersion);
|
|
39
|
+
const target = parseSemver(targetVersion);
|
|
40
|
+
// Compare major, minor, patch
|
|
41
|
+
for (let i = 0; i < 3; i++) {
|
|
42
|
+
if (source[i] > target[i]) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
if (source[i] < target[i]) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Versions are equal
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Parse frontmatter from markdown file and extract version
|
|
54
|
+
*/
|
|
55
|
+
function parseVersion(content) {
|
|
56
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
57
|
+
if (!frontmatterMatch) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const frontmatter = frontmatterMatch[1];
|
|
61
|
+
const versionMatch = frontmatter.match(/version:\s*([^\n]+)/);
|
|
62
|
+
return versionMatch ? versionMatch[1].trim() : null;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Install Claude Commands to ~/.claude/commands/ or .claude/commands/
|
|
66
|
+
*/
|
|
67
|
+
const NewCommand = {
|
|
68
|
+
alias: ['commands', 'ic'],
|
|
69
|
+
description: 'Installs Claude Custom Commands to ~/.claude/commands/ or .claude/commands/ for Claude Code integration. Use --global for global installation, --project for project-specific installation.',
|
|
70
|
+
hidden: false,
|
|
71
|
+
name: 'install-commands',
|
|
72
|
+
run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
|
|
73
|
+
var _a;
|
|
74
|
+
// Retrieve the tools we need
|
|
75
|
+
const { filesystem, parameters, print: { error, info, spin, success }, prompt, } = toolbox;
|
|
76
|
+
try {
|
|
77
|
+
// Get the CLI installation directory
|
|
78
|
+
const cliRoot = (0, path_1.join)(__dirname, '..', '..');
|
|
79
|
+
const commandsTemplateDir = (0, path_1.join)(cliRoot, 'templates', 'claude-commands');
|
|
80
|
+
// Check if claude-commands directory exists
|
|
81
|
+
if (!filesystem.exists(commandsTemplateDir)) {
|
|
82
|
+
error('Claude commands directory not found in CLI installation.');
|
|
83
|
+
info(`Expected location: ${commandsTemplateDir}`);
|
|
84
|
+
info('Please reinstall the CLI or report this issue.');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Get all available commands (*.md files, excluding README.md)
|
|
88
|
+
const allFiles = filesystem.list(commandsTemplateDir) || [];
|
|
89
|
+
const availableCommands = allFiles.filter(file => file.endsWith('.md') && file !== 'README.md');
|
|
90
|
+
if (availableCommands.length === 0) {
|
|
91
|
+
error('No commands found in CLI installation.');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
// Determine installation scope
|
|
95
|
+
const cwd = filesystem.cwd();
|
|
96
|
+
let scope = 'global';
|
|
97
|
+
let commandsDir = (0, path_1.join)((0, os_1.homedir)(), '.claude', 'commands');
|
|
98
|
+
const skipInteractive = parameters.options.y || parameters.options.yes || parameters.options['no-interactive'];
|
|
99
|
+
// Check if user specified scope
|
|
100
|
+
if (parameters.options.global) {
|
|
101
|
+
scope = 'global';
|
|
102
|
+
commandsDir = (0, path_1.join)((0, os_1.homedir)(), '.claude', 'commands');
|
|
103
|
+
}
|
|
104
|
+
else if (parameters.options.project) {
|
|
105
|
+
scope = 'project';
|
|
106
|
+
commandsDir = (0, path_1.join)(cwd, '.claude', 'commands');
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// Detect if we're in a project
|
|
110
|
+
let packageJsonPath = null;
|
|
111
|
+
let searchDir = cwd;
|
|
112
|
+
// Search up to 3 levels for package.json
|
|
113
|
+
for (let i = 0; i < 3; i++) {
|
|
114
|
+
const testPath = (0, path_1.join)(searchDir, 'package.json');
|
|
115
|
+
if (filesystem.exists(testPath)) {
|
|
116
|
+
packageJsonPath = testPath;
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
const parent = (0, path_1.join)(searchDir, '..');
|
|
120
|
+
if (parent === searchDir)
|
|
121
|
+
break; // Reached root
|
|
122
|
+
searchDir = parent;
|
|
123
|
+
}
|
|
124
|
+
// If in a project, ask where to install
|
|
125
|
+
if (packageJsonPath && !skipInteractive) {
|
|
126
|
+
info('');
|
|
127
|
+
info(`Detected project at: ${searchDir}`);
|
|
128
|
+
const installToProject = yield prompt.confirm('Install commands to this project only? (No = install globally for all projects)', true);
|
|
129
|
+
scope = installToProject ? 'project' : 'global';
|
|
130
|
+
if (scope === 'project') {
|
|
131
|
+
commandsDir = (0, path_1.join)(searchDir, '.claude', 'commands');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else if (packageJsonPath && skipInteractive) {
|
|
135
|
+
// In non-interactive mode with project detected, default to global
|
|
136
|
+
scope = 'global';
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Create commands directory if it doesn't exist
|
|
140
|
+
if (!filesystem.exists(commandsDir)) {
|
|
141
|
+
filesystem.dir(commandsDir);
|
|
142
|
+
}
|
|
143
|
+
info('');
|
|
144
|
+
info('Available commands:');
|
|
145
|
+
info('');
|
|
146
|
+
// Show all available commands with descriptions
|
|
147
|
+
availableCommands.forEach(cmd => {
|
|
148
|
+
const cmdPath = (0, path_1.join)(commandsTemplateDir, cmd);
|
|
149
|
+
const desc = getCommandDescription(cmdPath, filesystem);
|
|
150
|
+
const cmdName = cmd.replace('.md', '');
|
|
151
|
+
info(` • /${cmdName}`);
|
|
152
|
+
info(` ${desc}`);
|
|
153
|
+
info('');
|
|
154
|
+
});
|
|
155
|
+
let commandsToInstall = [];
|
|
156
|
+
// Check if specific commands provided as parameters
|
|
157
|
+
if (parameters.first && parameters.first !== 'all') {
|
|
158
|
+
// Non-interactive mode: install specific command(s)
|
|
159
|
+
const requestedCommands = parameters.array || [parameters.first];
|
|
160
|
+
// Add .md extension if not present
|
|
161
|
+
const requestedWithExt = requestedCommands.map(c => c.endsWith('.md') ? c : `${c}.md`);
|
|
162
|
+
// Validate requested commands
|
|
163
|
+
const invalidCommands = requestedWithExt.filter(c => !availableCommands.includes(c));
|
|
164
|
+
if (invalidCommands.length > 0) {
|
|
165
|
+
error(`Invalid command(s): ${invalidCommands.map(c => c.replace('.md', '')).join(', ')}`);
|
|
166
|
+
info('');
|
|
167
|
+
info('Available commands:');
|
|
168
|
+
availableCommands.forEach(c => {
|
|
169
|
+
const cmdName = c.replace('.md', '');
|
|
170
|
+
info(` • ${cmdName}`);
|
|
171
|
+
});
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
commandsToInstall = requestedWithExt;
|
|
175
|
+
}
|
|
176
|
+
else if (parameters.first === 'all' || skipInteractive) {
|
|
177
|
+
// Install all commands without prompting
|
|
178
|
+
commandsToInstall = availableCommands;
|
|
179
|
+
if (skipInteractive) {
|
|
180
|
+
info('Installing all commands (non-interactive mode)...');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
// Interactive mode: ask if user wants all or select individually
|
|
185
|
+
const installAll = yield prompt.confirm('Install all commands?', true);
|
|
186
|
+
if (installAll) {
|
|
187
|
+
commandsToInstall = availableCommands;
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
// Ask for each command
|
|
191
|
+
info('');
|
|
192
|
+
info('Select which commands to install:');
|
|
193
|
+
info('');
|
|
194
|
+
for (const cmd of availableCommands) {
|
|
195
|
+
const cmdName = cmd.replace('.md', '');
|
|
196
|
+
const shouldInstall = yield prompt.confirm(`Install /${cmdName}?`, true);
|
|
197
|
+
if (shouldInstall) {
|
|
198
|
+
commandsToInstall.push(cmd);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (commandsToInstall.length === 0) {
|
|
202
|
+
info('No commands selected. Installation cancelled.');
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const installSpinner = spin(`Installing ${commandsToInstall.length} command(s) to ${scope === 'global' ? '~/.claude/commands/' : '.claude/commands/'}...`);
|
|
208
|
+
let copiedCount = 0;
|
|
209
|
+
let skippedCount = 0;
|
|
210
|
+
let updatedCount = 0;
|
|
211
|
+
const skippedFiles = [];
|
|
212
|
+
// Install each command
|
|
213
|
+
for (const cmd of commandsToInstall) {
|
|
214
|
+
const sourcePath = (0, path_1.join)(commandsTemplateDir, cmd);
|
|
215
|
+
const targetPath = (0, path_1.join)(commandsDir, cmd);
|
|
216
|
+
const sourceContent = filesystem.read(sourcePath);
|
|
217
|
+
// Check if target file exists
|
|
218
|
+
if (filesystem.exists(targetPath)) {
|
|
219
|
+
const targetContent = filesystem.read(targetPath);
|
|
220
|
+
// Parse versions from both files
|
|
221
|
+
const sourceVersion = parseVersion(sourceContent);
|
|
222
|
+
const targetVersion = parseVersion(targetContent);
|
|
223
|
+
// If both have versions, compare them
|
|
224
|
+
if (sourceVersion && targetVersion) {
|
|
225
|
+
if (isVersionNewer(sourceVersion, targetVersion)) {
|
|
226
|
+
// Source is newer or equal, update
|
|
227
|
+
filesystem.write(targetPath, sourceContent);
|
|
228
|
+
updatedCount++;
|
|
229
|
+
copiedCount++;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
// Target is newer, skip
|
|
233
|
+
skippedCount++;
|
|
234
|
+
const reason = `local version ${targetVersion} is newer than ${sourceVersion}`;
|
|
235
|
+
skippedFiles.push({ file: cmd, reason });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else if (sourceVersion && !targetVersion) {
|
|
239
|
+
// Source has version, target doesn't - update
|
|
240
|
+
filesystem.write(targetPath, sourceContent);
|
|
241
|
+
updatedCount++;
|
|
242
|
+
copiedCount++;
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
// No version info, always update (backward compatibility)
|
|
246
|
+
filesystem.write(targetPath, sourceContent);
|
|
247
|
+
updatedCount++;
|
|
248
|
+
copiedCount++;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
// Target doesn't exist, create new
|
|
253
|
+
filesystem.write(targetPath, sourceContent);
|
|
254
|
+
copiedCount++;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (copiedCount === 0 && skippedCount === 0) {
|
|
258
|
+
installSpinner.fail();
|
|
259
|
+
error('No command files were processed.');
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (copiedCount === 0 && skippedCount > 0) {
|
|
263
|
+
installSpinner.succeed('All selected commands are already up to date!');
|
|
264
|
+
info('');
|
|
265
|
+
info(`Skipped: ${skippedCount} file(s)`);
|
|
266
|
+
info(`Location: ${commandsDir}`);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
installSpinner.succeed(`Successfully installed ${commandsToInstall.length} command(s)!`);
|
|
270
|
+
info('');
|
|
271
|
+
if (updatedCount > 0 && skippedCount > 0) {
|
|
272
|
+
success(`Updated ${updatedCount} file(s), skipped ${skippedCount} file(s)`);
|
|
273
|
+
}
|
|
274
|
+
else if (updatedCount > 0) {
|
|
275
|
+
success(`Updated ${updatedCount} file(s)`);
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
success(`Created ${copiedCount} file(s)`);
|
|
279
|
+
}
|
|
280
|
+
info('');
|
|
281
|
+
info('Installed commands:');
|
|
282
|
+
commandsToInstall.forEach(cmd => {
|
|
283
|
+
const cmdPath = (0, path_1.join)(commandsTemplateDir, cmd);
|
|
284
|
+
const desc = getCommandDescription(cmdPath, filesystem);
|
|
285
|
+
const cmdName = cmd.replace('.md', '');
|
|
286
|
+
info(` • /${cmdName}`);
|
|
287
|
+
info(` ${desc.substring(0, 80)}${desc.length > 80 ? '...' : ''}`);
|
|
288
|
+
});
|
|
289
|
+
info('');
|
|
290
|
+
info('These commands are now available in Claude Code!');
|
|
291
|
+
// Show first installed command as example
|
|
292
|
+
const firstCmd = (_a = commandsToInstall[0]) === null || _a === void 0 ? void 0 : _a.replace('.md', '');
|
|
293
|
+
info(`Use them by typing the command name with a leading slash, e.g., /${firstCmd || 'command-name'}`);
|
|
294
|
+
info('');
|
|
295
|
+
info('Examples:');
|
|
296
|
+
// Show up to 5 commands as examples (or all if less than 5)
|
|
297
|
+
const exampleCount = Math.min(commandsToInstall.length, 5);
|
|
298
|
+
for (let i = 0; i < exampleCount; i++) {
|
|
299
|
+
const cmd = commandsToInstall[i];
|
|
300
|
+
const cmdPath = (0, path_1.join)(commandsTemplateDir, cmd);
|
|
301
|
+
const desc = getCommandDescription(cmdPath, filesystem);
|
|
302
|
+
const cmdName = cmd.replace('.md', '');
|
|
303
|
+
info(` • /${cmdName} - ${desc}`);
|
|
304
|
+
}
|
|
305
|
+
info('');
|
|
306
|
+
info(`Location: ${commandsDir}`);
|
|
307
|
+
info(`Scope: ${scope === 'global' ? 'Global (all projects)' : 'Project-specific'}`);
|
|
308
|
+
if (skippedCount > 0) {
|
|
309
|
+
info('');
|
|
310
|
+
info(`Note: ${skippedCount} file(s) were skipped because your local versions are newer:`);
|
|
311
|
+
skippedFiles.forEach(({ file, reason }) => {
|
|
312
|
+
info(` • ${file} (${reason})`);
|
|
313
|
+
});
|
|
314
|
+
info('');
|
|
315
|
+
info('To force update, manually delete the files and run this command again.');
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch (err) {
|
|
319
|
+
error(`Failed to install command(s): ${err.message}`);
|
|
320
|
+
info('');
|
|
321
|
+
info('Troubleshooting:');
|
|
322
|
+
info(' • Ensure .claude directory exists and is writable');
|
|
323
|
+
info(' • Check file permissions');
|
|
324
|
+
info(' • Try running with sudo if permission issues persist');
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
// For tests
|
|
328
|
+
return `claude install-commands`;
|
|
329
|
+
}),
|
|
330
|
+
};
|
|
331
|
+
exports.default = NewCommand;
|
|
332
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5zdGFsbC1jb21tYW5kcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb21tYW5kcy9jbGF1ZGUvaW5zdGFsbC1jb21tYW5kcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQUNBLDJCQUE2QjtBQUM3QiwrQkFBNEI7QUFJNUI7O0dBRUc7QUFDSCxTQUFTLHFCQUFxQixDQUFDLFdBQW1CLEVBQUUsVUFBZTtJQUNqRSxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO1FBQ3BDLE9BQU8sMEJBQTBCLENBQUM7SUFDcEMsQ0FBQztJQUVELE1BQU0sT0FBTyxHQUFHLFVBQVUsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDN0MsTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLHVCQUF1QixDQUFDLENBQUM7SUFDaEUsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFDdEIsT0FBTywwQkFBMEIsQ0FBQztJQUNwQyxDQUFDO0lBRUQsTUFBTSxXQUFXLEdBQUcsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDeEMsTUFBTSxTQUFTLEdBQUcsV0FBVyxDQUFDLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO0lBRS9ELE9BQU8sU0FBUyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLDBCQUEwQixDQUFDO0FBQ3RFLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFTLGNBQWMsQ0FBQyxhQUFxQixFQUFFLGFBQXFCO0lBQ2xFLE1BQU0sV0FBVyxHQUFHLENBQUMsT0FBZSxFQUFZLEVBQUU7UUFDaEQsT0FBTyxPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDM0QsQ0FBQyxDQUFDO0lBRUYsTUFBTSxNQUFNLEdBQUcsV0FBVyxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQzFDLE1BQU0sTUFBTSxHQUFHLFdBQVcsQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUUxQyw4QkFBOEI7SUFDOUIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQzNCLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQzFCLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUNELElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQzFCLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztJQUNILENBQUM7SUFFRCxxQkFBcUI7SUFDckIsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFTLFlBQVksQ0FBQyxPQUFlO0lBQ25DLE1BQU0sZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO0lBQ2hFLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3RCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELE1BQU0sV0FBVyxHQUFHLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hDLE1BQU0sWUFBWSxHQUFHLFdBQVcsQ0FBQyxLQUFLLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUU5RCxPQUFPLFlBQVksQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7QUFDdEQsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLEdBQW1CO0lBQ2pDLEtBQUssRUFBRSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUM7SUFDekIsV0FBVyxFQUFFLDZMQUE2TDtJQUMxTSxNQUFNLEVBQUUsS0FBSztJQUNiLElBQUksRUFBRSxrQkFBa0I7SUFDeEIsR0FBRyxFQUFFLENBQU8sT0FBK0IsRUFBRSxFQUFFOztRQUM3Qyw2QkFBNkI7UUFDN0IsTUFBTSxFQUNKLFVBQVUsRUFDVixVQUFVLEVBQ1YsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLEVBQ3JDLE1BQU0sR0FDUCxHQUFHLE9BQU8sQ0FBQztRQUVaLElBQUksQ0FBQztZQUNILHFDQUFxQztZQUNyQyxNQUFNLE9BQU8sR0FBRyxJQUFBLFdBQUksRUFBQyxTQUFTLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQzVDLE1BQU0sbUJBQW1CLEdBQUcsSUFBQSxXQUFJLEVBQUMsT0FBTyxFQUFFLFdBQVcsRUFBRSxpQkFBaUIsQ0FBQyxDQUFDO1lBRTFFLDRDQUE0QztZQUM1QyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLENBQUM7Z0JBQzVDLEtBQUssQ0FBQywwREFBMEQsQ0FBQyxDQUFDO2dCQUNsRSxJQUFJLENBQUMsc0JBQXNCLG1CQUFtQixFQUFFLENBQUMsQ0FBQztnQkFDbEQsSUFBSSxDQUFDLGdEQUFnRCxDQUFDLENBQUM7Z0JBQ3ZELE9BQU87WUFDVCxDQUFDO1lBRUQsK0RBQStEO1lBQy9ELE1BQU0sUUFBUSxHQUFHLFVBQVUsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDNUQsTUFBTSxpQkFBaUIsR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQy9DLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLElBQUksSUFBSSxLQUFLLFdBQVcsQ0FDN0MsQ0FBQztZQUVGLElBQUksaUJBQWlCLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUNuQyxLQUFLLENBQUMsd0NBQXdDLENBQUMsQ0FBQztnQkFDaEQsT0FBTztZQUNULENBQUM7WUFFRCwrQkFBK0I7WUFDL0IsTUFBTSxHQUFHLEdBQUcsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQzdCLElBQUksS0FBSyxHQUF5QixRQUFRLENBQUM7WUFDM0MsSUFBSSxXQUFXLEdBQUcsSUFBQSxXQUFJLEVBQUMsSUFBQSxZQUFPLEdBQUUsRUFBRSxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFDekQsTUFBTSxlQUFlLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksVUFBVSxDQUFDLE9BQU8sQ0FBQyxHQUFHLElBQUksVUFBVSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1lBRS9HLGdDQUFnQztZQUNoQyxJQUFJLFVBQVUsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQzlCLEtBQUssR0FBRyxRQUFRLENBQUM7Z0JBQ2pCLFdBQVcsR0FBRyxJQUFBLFdBQUksRUFBQyxJQUFBLFlBQU8sR0FBRSxFQUFFLFNBQVMsRUFBRSxVQUFVLENBQUMsQ0FBQztZQUN2RCxDQUFDO2lCQUFNLElBQUksVUFBVSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDdEMsS0FBSyxHQUFHLFNBQVMsQ0FBQztnQkFDbEIsV0FBVyxHQUFHLElBQUEsV0FBSSxFQUFDLEdBQUcsRUFBRSxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFDakQsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLCtCQUErQjtnQkFDL0IsSUFBSSxlQUFlLEdBQUcsSUFBSSxDQUFDO2dCQUMzQixJQUFJLFNBQVMsR0FBRyxHQUFHLENBQUM7Z0JBRXBCLHlDQUF5QztnQkFDekMsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO29CQUMzQixNQUFNLFFBQVEsR0FBRyxJQUFBLFdBQUksRUFBQyxTQUFTLEVBQUUsY0FBYyxDQUFDLENBQUM7b0JBQ2pELElBQUksVUFBVSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO3dCQUNoQyxlQUFlLEdBQUcsUUFBUSxDQUFDO3dCQUMzQixNQUFNO29CQUNSLENBQUM7b0JBQ0QsTUFBTSxNQUFNLEdBQUcsSUFBQSxXQUFJLEVBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFDO29CQUNyQyxJQUFJLE1BQU0sS0FBSyxTQUFTO3dCQUFFLE1BQU0sQ0FBQyxlQUFlO29CQUNoRCxTQUFTLEdBQUcsTUFBTSxDQUFDO2dCQUNyQixDQUFDO2dCQUVELHdDQUF3QztnQkFDeEMsSUFBSSxlQUFlLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztvQkFDeEMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO29CQUNULElBQUksQ0FBQyx3QkFBd0IsU0FBUyxFQUFFLENBQUMsQ0FBQztvQkFDMUMsTUFBTSxnQkFBZ0IsR0FBRyxNQUFNLE1BQU0sQ0FBQyxPQUFPLENBQzNDLGlGQUFpRixFQUNqRixJQUFJLENBQ0wsQ0FBQztvQkFFRixLQUFLLEdBQUcsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDO29CQUVoRCxJQUFJLEtBQUssS0FBSyxTQUFTLEVBQUUsQ0FBQzt3QkFDeEIsV0FBVyxHQUFHLElBQUEsV0FBSSxFQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUM7b0JBQ3ZELENBQUM7Z0JBQ0gsQ0FBQztxQkFBTSxJQUFJLGVBQWUsSUFBSSxlQUFlLEVBQUUsQ0FBQztvQkFDOUMsbUVBQW1FO29CQUNuRSxLQUFLLEdBQUcsUUFBUSxDQUFDO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQztZQUVELGdEQUFnRDtZQUNoRCxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO2dCQUNwQyxVQUFVLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQzlCLENBQUM7WUFFRCxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDVCxJQUFJLENBQUMscUJBQXFCLENBQUMsQ0FBQztZQUM1QixJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7WUFFVCxnREFBZ0Q7WUFDaEQsaUJBQWlCLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFO2dCQUM5QixNQUFNLE9BQU8sR0FBRyxJQUFBLFdBQUksRUFBQyxtQkFBbUIsRUFBRSxHQUFHLENBQUMsQ0FBQztnQkFDL0MsTUFBTSxJQUFJLEdBQUcscUJBQXFCLENBQUMsT0FBTyxFQUFFLFVBQVUsQ0FBQyxDQUFDO2dCQUN4RCxNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFDdkMsSUFBSSxDQUFDLFFBQVEsT0FBTyxFQUFFLENBQUMsQ0FBQztnQkFDeEIsSUFBSSxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDcEIsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ1gsQ0FBQyxDQUFDLENBQUM7WUFFSCxJQUFJLGlCQUFpQixHQUFhLEVBQUUsQ0FBQztZQUVyQyxvREFBb0Q7WUFDcEQsSUFBSSxVQUFVLENBQUMsS0FBSyxJQUFJLFVBQVUsQ0FBQyxLQUFLLEtBQUssS0FBSyxFQUFFLENBQUM7Z0JBQ25ELG9EQUFvRDtnQkFDcEQsTUFBTSxpQkFBaUIsR0FBRyxVQUFVLENBQUMsS0FBSyxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUVqRSxtQ0FBbUM7Z0JBQ25DLE1BQU0sZ0JBQWdCLEdBQUcsaUJBQWlCLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQ2pELENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FDbEMsQ0FBQztnQkFFRiw4QkFBOEI7Z0JBQzlCLE1BQU0sZUFBZSxHQUFHLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsaUJBQWlCLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ3JGLElBQUksZUFBZSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztvQkFDL0IsS0FBSyxDQUFDLHVCQUF1QixlQUFlLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO29CQUMxRixJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7b0JBQ1QsSUFBSSxDQUFDLHFCQUFxQixDQUFDLENBQUM7b0JBQzVCLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRTt3QkFDNUIsTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7d0JBQ3JDLElBQUksQ0FBQyxPQUFPLE9BQU8sRUFBRSxDQUFDLENBQUM7b0JBQ3pCLENBQUMsQ0FBQyxDQUFDO29CQUNILE9BQU87Z0JBQ1QsQ0FBQztnQkFFRCxpQkFBaUIsR0FBRyxnQkFBZ0IsQ0FBQztZQUN2QyxDQUFDO2lCQUFNLElBQUksVUFBVSxDQUFDLEtBQUssS0FBSyxLQUFLLElBQUksZUFBZSxFQUFFLENBQUM7Z0JBQ3pELHlDQUF5QztnQkFDekMsaUJBQWlCLEdBQUcsaUJBQWlCLENBQUM7Z0JBQ3RDLElBQUksZUFBZSxFQUFFLENBQUM7b0JBQ3BCLElBQUksQ0FBQyxtREFBbUQsQ0FBQyxDQUFDO2dCQUM1RCxDQUFDO1lBQ0gsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLGlFQUFpRTtnQkFDakUsTUFBTSxVQUFVLEdBQUcsTUFBTSxNQUFNLENBQUMsT0FBTyxDQUFDLHVCQUF1QixFQUFFLElBQUksQ0FBQyxDQUFDO2dCQUV2RSxJQUFJLFVBQVUsRUFBRSxDQUFDO29CQUNmLGlCQUFpQixHQUFHLGlCQUFpQixDQUFDO2dCQUN4QyxDQUFDO3FCQUFNLENBQUM7b0JBQ04sdUJBQXVCO29CQUN2QixJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7b0JBQ1QsSUFBSSxDQUFDLG1DQUFtQyxDQUFDLENBQUM7b0JBQzFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztvQkFFVCxLQUFLLE1BQU0sR0FBRyxJQUFJLGlCQUFpQixFQUFFLENBQUM7d0JBQ3BDLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO3dCQUN2QyxNQUFNLGFBQWEsR0FBRyxNQUFNLE1BQU0sQ0FBQyxPQUFPLENBQUMsWUFBWSxPQUFPLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQzt3QkFDekUsSUFBSSxhQUFhLEVBQUUsQ0FBQzs0QkFDbEIsaUJBQWlCLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO3dCQUM5QixDQUFDO29CQUNILENBQUM7b0JBRUQsSUFBSSxpQkFBaUIsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7d0JBQ25DLElBQUksQ0FBQywrQ0FBK0MsQ0FBQyxDQUFDO3dCQUN0RCxPQUFPO29CQUNULENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7WUFFRCxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsY0FBYyxpQkFBaUIsQ0FBQyxNQUFNLGtCQUFrQixLQUFLLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsbUJBQW1CLEtBQUssQ0FBQyxDQUFDO1lBRTNKLElBQUksV0FBVyxHQUFHLENBQUMsQ0FBQztZQUNwQixJQUFJLFlBQVksR0FBRyxDQUFDLENBQUM7WUFDckIsSUFBSSxZQUFZLEdBQUcsQ0FBQyxDQUFDO1lBQ3JCLE1BQU0sWUFBWSxHQUE0QyxFQUFFLENBQUM7WUFFakUsdUJBQXVCO1lBQ3ZCLEtBQUssTUFBTSxHQUFHLElBQUksaUJBQWlCLEVBQUUsQ0FBQztnQkFDcEMsTUFBTSxVQUFVLEdBQUcsSUFBQSxXQUFJLEVBQUMsbUJBQW1CLEVBQUUsR0FBRyxDQUFDLENBQUM7Z0JBQ2xELE1BQU0sVUFBVSxHQUFHLElBQUEsV0FBSSxFQUFDLFdBQVcsRUFBRSxHQUFHLENBQUMsQ0FBQztnQkFFMUMsTUFBTSxhQUFhLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFFbEQsOEJBQThCO2dCQUM5QixJQUFJLFVBQVUsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztvQkFDbEMsTUFBTSxhQUFhLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztvQkFFbEQsaUNBQWlDO29CQUNqQyxNQUFNLGFBQWEsR0FBRyxZQUFZLENBQUMsYUFBYSxDQUFDLENBQUM7b0JBQ2xELE1BQU0sYUFBYSxHQUFHLFlBQVksQ0FBQyxhQUFhLENBQUMsQ0FBQztvQkFFbEQsc0NBQXNDO29CQUN0QyxJQUFJLGFBQWEsSUFBSSxhQUFhLEVBQUUsQ0FBQzt3QkFDbkMsSUFBSSxjQUFjLENBQUMsYUFBYSxFQUFFLGFBQWEsQ0FBQyxFQUFFLENBQUM7NEJBQ2pELG1DQUFtQzs0QkFDbkMsVUFBVSxDQUFDLEtBQUssQ0FBQyxVQUFVLEVBQUUsYUFBYSxDQUFDLENBQUM7NEJBQzVDLFlBQVksRUFBRSxDQUFDOzRCQUNmLFdBQVcsRUFBRSxDQUFDO3dCQUNoQixDQUFDOzZCQUFNLENBQUM7NEJBQ04sd0JBQXdCOzRCQUN4QixZQUFZLEVBQUUsQ0FBQzs0QkFDZixNQUFNLE1BQU0sR0FBRyxpQkFBaUIsYUFBYSxrQkFBa0IsYUFBYSxFQUFFLENBQUM7NEJBQy9FLFlBQVksQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7d0JBQzNDLENBQUM7b0JBQ0gsQ0FBQzt5QkFBTSxJQUFJLGFBQWEsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO3dCQUMzQyw4Q0FBOEM7d0JBQzlDLFVBQVUsQ0FBQyxLQUFLLENBQUMsVUFBVSxFQUFFLGFBQWEsQ0FBQyxDQUFDO3dCQUM1QyxZQUFZLEVBQUUsQ0FBQzt3QkFDZixXQUFXLEVBQUUsQ0FBQztvQkFDaEIsQ0FBQzt5QkFBTSxDQUFDO3dCQUNOLDBEQUEwRDt3QkFDMUQsVUFBVSxDQUFDLEtBQUssQ0FBQyxVQUFVLEVBQUUsYUFBYSxDQUFDLENBQUM7d0JBQzVDLFlBQVksRUFBRSxDQUFDO3dCQUNmLFdBQVcsRUFBRSxDQUFDO29CQUNoQixDQUFDO2dCQUNILENBQUM7cUJBQU0sQ0FBQztvQkFDTixtQ0FBbUM7b0JBQ25DLFVBQVUsQ0FBQyxLQUFLLENBQUMsVUFBVSxFQUFFLGFBQWEsQ0FBQyxDQUFDO29CQUM1QyxXQUFXLEVBQUUsQ0FBQztnQkFDaEIsQ0FBQztZQUNILENBQUM7WUFFRCxJQUFJLFdBQVcsS0FBSyxDQUFDLElBQUksWUFBWSxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUM1QyxjQUFjLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQ3RCLEtBQUssQ0FBQyxrQ0FBa0MsQ0FBQyxDQUFDO2dCQUMxQyxPQUFPO1lBQ1QsQ0FBQztZQUVELElBQUksV0FBVyxLQUFLLENBQUMsSUFBSSxZQUFZLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQzFDLGNBQWMsQ0FBQyxPQUFPLENBQUMsK0NBQStDLENBQUMsQ0FBQztnQkFDeEUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUNULElBQUksQ0FBQyxZQUFZLFlBQVksVUFBVSxDQUFDLENBQUM7Z0JBQ3pDLElBQUksQ0FBQyxhQUFhLFdBQVcsRUFBRSxDQUFDLENBQUM7Z0JBQ2pDLE9BQU87WUFDVCxDQUFDO1lBRUQsY0FBYyxDQUFDLE9BQU8sQ0FBQywwQkFBMEIsaUJBQWlCLENBQUMsTUFBTSxjQUFjLENBQUMsQ0FBQztZQUN6RixJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7WUFFVCxJQUFJLFlBQVksR0FBRyxDQUFDLElBQUksWUFBWSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUN6QyxPQUFPLENBQUMsV0FBVyxZQUFZLHFCQUFxQixZQUFZLFVBQVUsQ0FBQyxDQUFDO1lBQzlFLENBQUM7aUJBQU0sSUFBSSxZQUFZLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQzVCLE9BQU8sQ0FBQyxXQUFXLFlBQVksVUFBVSxDQUFDLENBQUM7WUFDN0MsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLE9BQU8sQ0FBQyxXQUFXLFdBQVcsVUFBVSxDQUFDLENBQUM7WUFDNUMsQ0FBQztZQUVELElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUNULElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1lBQzVCLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRTtnQkFDOUIsTUFBTSxPQUFPLEdBQUcsSUFBQSxXQUFJLEVBQUMsbUJBQW1CLEVBQUUsR0FBRyxDQUFDLENBQUM7Z0JBQy9DLE1BQU0sSUFBSSxHQUFHLHFCQUFxQixDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUMsQ0FBQztnQkFDeEQsTUFBTSxPQUFPLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQ3ZDLElBQUksQ0FBQyxRQUFRLE9BQU8sRUFBRSxDQUFDLENBQUM7Z0JBQ3hCLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDdkUsQ0FBQyxDQUFDLENBQUM7WUFFSCxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDVCxJQUFJLENBQUMsa0RBQWtELENBQUMsQ0FBQztZQUV6RCwwQ0FBMEM7WUFDMUMsTUFBTSxRQUFRLEdBQUcsTUFBQSxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsMENBQUUsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztZQUMxRCxJQUFJLENBQUMsb0VBQW9FLFFBQVEsSUFBSSxjQUFjLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZHLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUNULElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUVsQiw0REFBNEQ7WUFDNUQsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDM0QsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFlBQVksRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUN0QyxNQUFNLEdBQUcsR0FBRyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDakMsTUFBTSxPQUFPLEdBQUcsSUFBQSxXQUFJLEVBQUMsbUJBQW1CLEVBQUUsR0FBRyxDQUFDLENBQUM7Z0JBQy9DLE1BQU0sSUFBSSxHQUFHLHFCQUFxQixDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUMsQ0FBQztnQkFDeEQsTUFBTSxPQUFPLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQ3ZDLElBQUksQ0FBQyxRQUFRLE9BQU8sTUFBTSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1lBQ3BDLENBQUM7WUFFRCxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDVCxJQUFJLENBQUMsYUFBYSxXQUFXLEVBQUUsQ0FBQyxDQUFDO1lBQ2pDLElBQUksQ0FBQyxVQUFVLEtBQUssS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLHVCQUF1QixDQUFDLENBQUMsQ0FBQyxrQkFBa0IsRUFBRSxDQUFDLENBQUM7WUFFcEYsSUFBSSxZQUFZLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3JCLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDVCxJQUFJLENBQUMsU0FBUyxZQUFZLDhEQUE4RCxDQUFDLENBQUM7Z0JBQzFGLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsRUFBRSxFQUFFO29CQUN4QyxJQUFJLENBQUMsT0FBTyxJQUFJLEtBQUssTUFBTSxHQUFHLENBQUMsQ0FBQztnQkFDbEMsQ0FBQyxDQUFDLENBQUM7Z0JBQ0gsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUNULElBQUksQ0FBQyx3RUFBd0UsQ0FBQyxDQUFDO1lBQ2pGLENBQUM7UUFFSCxDQUFDO1FBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztZQUNiLEtBQUssQ0FBQyxpQ0FBaUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7WUFDdEQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ1QsSUFBSSxDQUFDLGtCQUFrQixDQUFDLENBQUM7WUFDekIsSUFBSSxDQUFDLHFEQUFxRCxDQUFDLENBQUM7WUFDNUQsSUFBSSxDQUFDLDRCQUE0QixDQUFDLENBQUM7WUFDbkMsSUFBSSxDQUFDLHdEQUF3RCxDQUFDLENBQUM7WUFDL0QsT0FBTztRQUNULENBQUM7UUFFRCxZQUFZO1FBQ1osT0FBTyx5QkFBeUIsQ0FBQztJQUNuQyxDQUFDLENBQUE7Q0FDRixDQUFDO0FBRUYsa0JBQWUsVUFBVSxDQUFDIn0=
|