start-command 0.3.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/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.changeset/isolation-support.md +30 -0
- package/.github/workflows/release.yml +292 -0
- package/.husky/pre-commit +1 -0
- package/.prettierignore +6 -0
- package/.prettierrc +10 -0
- package/CHANGELOG.md +24 -0
- package/LICENSE +24 -0
- package/README.md +249 -0
- package/REQUIREMENTS.md +229 -0
- package/bun.lock +453 -0
- package/bunfig.toml +3 -0
- package/eslint.config.mjs +122 -0
- package/experiments/debug-regex.js +49 -0
- package/experiments/isolation-design.md +142 -0
- package/experiments/test-cli.sh +42 -0
- package/experiments/test-substitution.js +143 -0
- package/package.json +63 -0
- package/scripts/changeset-version.mjs +38 -0
- package/scripts/check-file-size.mjs +103 -0
- package/scripts/create-github-release.mjs +93 -0
- package/scripts/create-manual-changeset.mjs +89 -0
- package/scripts/format-github-release.mjs +83 -0
- package/scripts/format-release-notes.mjs +219 -0
- package/scripts/instant-version-bump.mjs +121 -0
- package/scripts/publish-to-npm.mjs +129 -0
- package/scripts/setup-npm.mjs +37 -0
- package/scripts/validate-changeset.mjs +107 -0
- package/scripts/version-and-commit.mjs +237 -0
- package/src/bin/cli.js +670 -0
- package/src/lib/args-parser.js +259 -0
- package/src/lib/isolation.js +419 -0
- package/src/lib/substitution.js +323 -0
- package/src/lib/substitutions.lino +308 -0
- package/test/args-parser.test.js +389 -0
- package/test/isolation.test.js +248 -0
- package/test/substitution.test.js +236 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Substitution Engine for start-command
|
|
3
|
+
* Parses .lino files and matches natural language commands to shell commands
|
|
4
|
+
*
|
|
5
|
+
* Uses Links Notation style patterns with variables like $packageName, $version
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
// Debug mode from environment
|
|
12
|
+
const DEBUG =
|
|
13
|
+
process.env.START_DEBUG === '1' || process.env.START_DEBUG === 'true';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parse a .lino substitutions file
|
|
17
|
+
* @param {string} filePath - Path to the .lino file
|
|
18
|
+
* @returns {Array<{pattern: string, replacement: string, regex: RegExp, variables: string[]}>}
|
|
19
|
+
*/
|
|
20
|
+
function parseLinoFile(filePath) {
|
|
21
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
22
|
+
return parseLinoContent(content);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Parse .lino content string
|
|
27
|
+
* @param {string} content - Content of the .lino file
|
|
28
|
+
* @returns {Array<{pattern: string, replacement: string, regex: RegExp, variables: string[]}>}
|
|
29
|
+
*/
|
|
30
|
+
function parseLinoContent(content) {
|
|
31
|
+
const rules = [];
|
|
32
|
+
const lines = content.split('\n');
|
|
33
|
+
|
|
34
|
+
let i = 0;
|
|
35
|
+
while (i < lines.length) {
|
|
36
|
+
const line = lines[i].trim();
|
|
37
|
+
|
|
38
|
+
// Skip empty lines and comments
|
|
39
|
+
if (!line || line.startsWith('#')) {
|
|
40
|
+
i++;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Look for opening parenthesis of doublet link
|
|
45
|
+
if (line === '(') {
|
|
46
|
+
i++;
|
|
47
|
+
|
|
48
|
+
// Find the pattern line (first non-empty, non-comment line)
|
|
49
|
+
let pattern = null;
|
|
50
|
+
while (i < lines.length) {
|
|
51
|
+
const patternLine = lines[i].trim();
|
|
52
|
+
if (
|
|
53
|
+
patternLine &&
|
|
54
|
+
!patternLine.startsWith('#') &&
|
|
55
|
+
patternLine !== ')'
|
|
56
|
+
) {
|
|
57
|
+
pattern = patternLine;
|
|
58
|
+
i++;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
i++;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Find the replacement line (second non-empty, non-comment line)
|
|
65
|
+
let replacement = null;
|
|
66
|
+
while (i < lines.length) {
|
|
67
|
+
const replacementLine = lines[i].trim();
|
|
68
|
+
if (
|
|
69
|
+
replacementLine &&
|
|
70
|
+
!replacementLine.startsWith('#') &&
|
|
71
|
+
replacementLine !== ')'
|
|
72
|
+
) {
|
|
73
|
+
replacement = replacementLine;
|
|
74
|
+
i++;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
i++;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Find closing parenthesis
|
|
81
|
+
while (i < lines.length) {
|
|
82
|
+
const closeLine = lines[i].trim();
|
|
83
|
+
if (closeLine === ')') {
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
i++;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Create rule if both pattern and replacement found
|
|
90
|
+
if (pattern && replacement) {
|
|
91
|
+
const rule = createRule(pattern, replacement);
|
|
92
|
+
if (rule) {
|
|
93
|
+
rules.push(rule);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
i++;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return rules;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Create a rule object from pattern and replacement strings
|
|
106
|
+
* @param {string} pattern - The matching pattern with variables
|
|
107
|
+
* @param {string} replacement - The replacement pattern
|
|
108
|
+
* @returns {{pattern: string, replacement: string, regex: RegExp, variables: string[]}|null}
|
|
109
|
+
*/
|
|
110
|
+
function createRule(pattern, replacement) {
|
|
111
|
+
// Extract variables from pattern (words starting with $)
|
|
112
|
+
const variables = [];
|
|
113
|
+
const variablePattern = /\$(\w+)/g;
|
|
114
|
+
let match;
|
|
115
|
+
|
|
116
|
+
while ((match = variablePattern.exec(pattern)) !== null) {
|
|
117
|
+
variables.push(match[1]);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Convert pattern to regex
|
|
121
|
+
// First, replace $variables with placeholders
|
|
122
|
+
let tempPattern = pattern;
|
|
123
|
+
const placeholders = [];
|
|
124
|
+
|
|
125
|
+
for (let i = 0; i < variables.length; i++) {
|
|
126
|
+
const varName = variables[i];
|
|
127
|
+
const placeholder = `__VAR_${i}__`;
|
|
128
|
+
placeholders.push({ placeholder, varName });
|
|
129
|
+
// Replace first occurrence of this variable
|
|
130
|
+
tempPattern = tempPattern.replace(`$${varName}`, placeholder);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Escape special regex characters in the remaining text
|
|
134
|
+
let regexStr = tempPattern.replace(/[.*+?^{}()|[\]\\]/g, '\\$&');
|
|
135
|
+
|
|
136
|
+
// Replace placeholders with named capture groups
|
|
137
|
+
// Use .+? for greedy-enough matching but not too greedy
|
|
138
|
+
for (const { placeholder, varName } of placeholders) {
|
|
139
|
+
regexStr = regexStr.replace(placeholder, `(?<${varName}>.+?)`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Make the regex match the entire string with optional whitespace
|
|
143
|
+
regexStr = `^\\s*${regexStr}\\s*$`;
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const regex = new RegExp(regexStr, 'i'); // Case insensitive
|
|
147
|
+
return { pattern, replacement, regex, variables };
|
|
148
|
+
} catch (err) {
|
|
149
|
+
if (DEBUG) {
|
|
150
|
+
console.error(`Invalid pattern: ${pattern} - ${err.message}`);
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Sort rules so more specific patterns (more variables, longer patterns) match first
|
|
158
|
+
* @param {Array} rules - Array of rule objects
|
|
159
|
+
* @returns {Array} Sorted rules
|
|
160
|
+
*/
|
|
161
|
+
function sortRulesBySpecificity(rules) {
|
|
162
|
+
return [...rules].sort((a, b) => {
|
|
163
|
+
// More variables = more specific, should come first
|
|
164
|
+
if (b.variables.length !== a.variables.length) {
|
|
165
|
+
return b.variables.length - a.variables.length;
|
|
166
|
+
}
|
|
167
|
+
// Longer patterns = more specific
|
|
168
|
+
return b.pattern.length - a.pattern.length;
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Match input against rules and return the substituted command
|
|
174
|
+
* @param {string} input - The user input command
|
|
175
|
+
* @param {Array} rules - Array of rule objects
|
|
176
|
+
* @returns {{matched: boolean, original: string, command: string, rule: object|null}}
|
|
177
|
+
*/
|
|
178
|
+
function matchAndSubstitute(input, rules) {
|
|
179
|
+
const trimmedInput = input.trim();
|
|
180
|
+
|
|
181
|
+
// Sort rules by specificity (more specific patterns first)
|
|
182
|
+
const sortedRules = sortRulesBySpecificity(rules);
|
|
183
|
+
|
|
184
|
+
for (const rule of sortedRules) {
|
|
185
|
+
const match = trimmedInput.match(rule.regex);
|
|
186
|
+
|
|
187
|
+
if (match) {
|
|
188
|
+
// Build the substituted command
|
|
189
|
+
let command = rule.replacement;
|
|
190
|
+
|
|
191
|
+
// Replace variables with captured values
|
|
192
|
+
for (const varName of rule.variables) {
|
|
193
|
+
const value = match.groups[varName];
|
|
194
|
+
if (value !== undefined) {
|
|
195
|
+
command = command.replace(new RegExp(`\\$${varName}`, 'g'), value);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
matched: true,
|
|
201
|
+
original: input,
|
|
202
|
+
command,
|
|
203
|
+
rule,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// No match found - return original input
|
|
209
|
+
return {
|
|
210
|
+
matched: false,
|
|
211
|
+
original: input,
|
|
212
|
+
command: input,
|
|
213
|
+
rule: null,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Load default substitutions from the package's substitutions.lino file
|
|
219
|
+
* @returns {Array} Array of rules
|
|
220
|
+
*/
|
|
221
|
+
function loadDefaultSubstitutions() {
|
|
222
|
+
// Look for substitutions.lino in the same directory as this file (src/lib)
|
|
223
|
+
// __dirname is src/lib, substitutions.lino is in the same directory
|
|
224
|
+
const defaultLinoPath = path.join(__dirname, 'substitutions.lino');
|
|
225
|
+
|
|
226
|
+
if (fs.existsSync(defaultLinoPath)) {
|
|
227
|
+
try {
|
|
228
|
+
return parseLinoFile(defaultLinoPath);
|
|
229
|
+
} catch (err) {
|
|
230
|
+
if (DEBUG) {
|
|
231
|
+
console.error(`Failed to load default substitutions: ${err.message}`);
|
|
232
|
+
}
|
|
233
|
+
return [];
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return [];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Load user substitutions from custom path or home directory
|
|
242
|
+
* @param {string} customPath - Optional custom path to .lino file
|
|
243
|
+
* @returns {Array} Array of rules
|
|
244
|
+
*/
|
|
245
|
+
function loadUserSubstitutions(customPath) {
|
|
246
|
+
// If custom path provided, use it
|
|
247
|
+
if (customPath && fs.existsSync(customPath)) {
|
|
248
|
+
try {
|
|
249
|
+
return parseLinoFile(customPath);
|
|
250
|
+
} catch (err) {
|
|
251
|
+
if (DEBUG) {
|
|
252
|
+
console.error(`Failed to load user substitutions: ${err.message}`);
|
|
253
|
+
}
|
|
254
|
+
return [];
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Look in home directory for .start-command/substitutions.lino
|
|
259
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
260
|
+
if (homeDir) {
|
|
261
|
+
const userLinoPath = path.join(
|
|
262
|
+
homeDir,
|
|
263
|
+
'.start-command',
|
|
264
|
+
'substitutions.lino'
|
|
265
|
+
);
|
|
266
|
+
if (fs.existsSync(userLinoPath)) {
|
|
267
|
+
try {
|
|
268
|
+
return parseLinoFile(userLinoPath);
|
|
269
|
+
} catch (err) {
|
|
270
|
+
if (DEBUG) {
|
|
271
|
+
console.error(`Failed to load user substitutions: ${err.message}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return [];
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Process a command through the substitution engine
|
|
282
|
+
* @param {string} input - The input command
|
|
283
|
+
* @param {object} options - Options { customLinoPath, verbose }
|
|
284
|
+
* @returns {{matched: boolean, original: string, command: string, rule: object|null}}
|
|
285
|
+
*/
|
|
286
|
+
function processCommand(input, options = {}) {
|
|
287
|
+
const { customLinoPath, verbose } = options;
|
|
288
|
+
|
|
289
|
+
// Load rules: user rules take precedence
|
|
290
|
+
const userRules = loadUserSubstitutions(customLinoPath);
|
|
291
|
+
const defaultRules = loadDefaultSubstitutions();
|
|
292
|
+
|
|
293
|
+
// User rules first, then default rules
|
|
294
|
+
const allRules = [...userRules, ...defaultRules];
|
|
295
|
+
|
|
296
|
+
if (allRules.length === 0) {
|
|
297
|
+
return {
|
|
298
|
+
matched: false,
|
|
299
|
+
original: input,
|
|
300
|
+
command: input,
|
|
301
|
+
rule: null,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const result = matchAndSubstitute(input, allRules);
|
|
306
|
+
|
|
307
|
+
if (verbose && result.matched) {
|
|
308
|
+
console.log(`Pattern matched: "${result.rule.pattern}"`);
|
|
309
|
+
console.log(`Translated to: ${result.command}`);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return result;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
module.exports = {
|
|
316
|
+
parseLinoFile,
|
|
317
|
+
parseLinoContent,
|
|
318
|
+
createRule,
|
|
319
|
+
matchAndSubstitute,
|
|
320
|
+
loadDefaultSubstitutions,
|
|
321
|
+
loadUserSubstitutions,
|
|
322
|
+
processCommand,
|
|
323
|
+
};
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# Substitutions file for start-command
|
|
2
|
+
# Format: Each rule is a doublet link (pattern, replacement)
|
|
3
|
+
# Variables: $packageName, $version, $repository, $url, $path, $branch, etc.
|
|
4
|
+
#
|
|
5
|
+
# This file uses Links Notation style patterns for matching natural language commands
|
|
6
|
+
# and translating them to actual shell commands.
|
|
7
|
+
|
|
8
|
+
# === NPM Package Installation ===
|
|
9
|
+
|
|
10
|
+
# install {packageName} npm package
|
|
11
|
+
(
|
|
12
|
+
install $packageName npm package
|
|
13
|
+
npm install $packageName
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# install {version} version of {packageName} npm package
|
|
17
|
+
(
|
|
18
|
+
install $version version of $packageName npm package
|
|
19
|
+
npm install $packageName@$version
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# install {packageName} npm package globally
|
|
23
|
+
(
|
|
24
|
+
install $packageName npm package globally
|
|
25
|
+
npm install -g $packageName
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# install {packageName} globally
|
|
29
|
+
(
|
|
30
|
+
install $packageName globally
|
|
31
|
+
npm install -g $packageName
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# install {version} version of {packageName} npm package globally
|
|
35
|
+
(
|
|
36
|
+
install $version version of $packageName npm package globally
|
|
37
|
+
npm install -g $packageName@$version
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# uninstall {packageName} npm package
|
|
41
|
+
(
|
|
42
|
+
uninstall $packageName npm package
|
|
43
|
+
npm uninstall $packageName
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# uninstall {packageName} npm package globally
|
|
47
|
+
(
|
|
48
|
+
uninstall $packageName npm package globally
|
|
49
|
+
npm uninstall -g $packageName
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# remove {packageName} npm package
|
|
53
|
+
(
|
|
54
|
+
remove $packageName npm package
|
|
55
|
+
npm uninstall $packageName
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# update {packageName} npm package
|
|
59
|
+
(
|
|
60
|
+
update $packageName npm package
|
|
61
|
+
npm update $packageName
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# === Git Repository Operations ===
|
|
65
|
+
|
|
66
|
+
# clone {repository} repository
|
|
67
|
+
(
|
|
68
|
+
clone $repository repository
|
|
69
|
+
git clone $repository
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# clone {url}
|
|
73
|
+
(
|
|
74
|
+
clone $url
|
|
75
|
+
git clone $url
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# clone {repository} repository to {path}
|
|
79
|
+
(
|
|
80
|
+
clone $repository repository to $path
|
|
81
|
+
git clone $repository $path
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# clone {repository} repository into {path}
|
|
85
|
+
(
|
|
86
|
+
clone $repository repository into $path
|
|
87
|
+
git clone $repository $path
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# checkout {branch} branch
|
|
91
|
+
(
|
|
92
|
+
checkout $branch branch
|
|
93
|
+
git checkout $branch
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# create {branch} branch
|
|
97
|
+
(
|
|
98
|
+
create $branch branch
|
|
99
|
+
git checkout -b $branch
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# switch to {branch} branch
|
|
103
|
+
(
|
|
104
|
+
switch to $branch branch
|
|
105
|
+
git checkout $branch
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# push to {remote}
|
|
109
|
+
(
|
|
110
|
+
push to $remote
|
|
111
|
+
git push $remote
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# push to {remote} {branch}
|
|
115
|
+
(
|
|
116
|
+
push to $remote $branch
|
|
117
|
+
git push $remote $branch
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# pull from {remote}
|
|
121
|
+
(
|
|
122
|
+
pull from $remote
|
|
123
|
+
git pull $remote
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# pull from {remote} {branch}
|
|
127
|
+
(
|
|
128
|
+
pull from $remote $branch
|
|
129
|
+
git pull $remote $branch
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# === Common Operations ===
|
|
133
|
+
|
|
134
|
+
# list files
|
|
135
|
+
(
|
|
136
|
+
list files
|
|
137
|
+
ls -la
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# list files in {path}
|
|
141
|
+
(
|
|
142
|
+
list files in $path
|
|
143
|
+
ls -la $path
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# show current directory
|
|
147
|
+
(
|
|
148
|
+
show current directory
|
|
149
|
+
pwd
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# show working directory
|
|
153
|
+
(
|
|
154
|
+
show working directory
|
|
155
|
+
pwd
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# create {name} directory
|
|
159
|
+
(
|
|
160
|
+
create $name directory
|
|
161
|
+
mkdir -p $name
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# create directory {name}
|
|
165
|
+
(
|
|
166
|
+
create directory $name
|
|
167
|
+
mkdir -p $name
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
# remove {name} directory
|
|
171
|
+
(
|
|
172
|
+
remove $name directory
|
|
173
|
+
rm -rf $name
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# delete {name} directory
|
|
177
|
+
(
|
|
178
|
+
delete $name directory
|
|
179
|
+
rm -rf $name
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# remove {name} file
|
|
183
|
+
(
|
|
184
|
+
remove $name file
|
|
185
|
+
rm $name
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# delete {name} file
|
|
189
|
+
(
|
|
190
|
+
delete $name file
|
|
191
|
+
rm $name
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# show {file} contents
|
|
195
|
+
(
|
|
196
|
+
show $file contents
|
|
197
|
+
cat $file
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# read {file}
|
|
201
|
+
(
|
|
202
|
+
read $file
|
|
203
|
+
cat $file
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
# === Process/System Operations ===
|
|
207
|
+
|
|
208
|
+
# show running processes
|
|
209
|
+
(
|
|
210
|
+
show running processes
|
|
211
|
+
ps aux
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# find process {name}
|
|
215
|
+
(
|
|
216
|
+
find process $name
|
|
217
|
+
ps aux | grep $name
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# kill process {pid}
|
|
221
|
+
(
|
|
222
|
+
kill process $pid
|
|
223
|
+
kill $pid
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
# === Docker Operations ===
|
|
227
|
+
|
|
228
|
+
# list docker containers
|
|
229
|
+
(
|
|
230
|
+
list docker containers
|
|
231
|
+
docker ps
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
# list all docker containers
|
|
235
|
+
(
|
|
236
|
+
list all docker containers
|
|
237
|
+
docker ps -a
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# start {container} container
|
|
241
|
+
(
|
|
242
|
+
start $container container
|
|
243
|
+
docker start $container
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
# stop {container} container
|
|
247
|
+
(
|
|
248
|
+
stop $container container
|
|
249
|
+
docker stop $container
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# remove {container} container
|
|
253
|
+
(
|
|
254
|
+
remove $container container
|
|
255
|
+
docker rm $container
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
# build docker image from {path}
|
|
259
|
+
(
|
|
260
|
+
build docker image from $path
|
|
261
|
+
docker build $path
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
# build docker image {name} from {path}
|
|
265
|
+
(
|
|
266
|
+
build docker image $name from $path
|
|
267
|
+
docker build -t $name $path
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
# === Python/Pip Operations ===
|
|
271
|
+
|
|
272
|
+
# install {packageName} python package
|
|
273
|
+
(
|
|
274
|
+
install $packageName python package
|
|
275
|
+
pip install $packageName
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
# install {packageName} pip package
|
|
279
|
+
(
|
|
280
|
+
install $packageName pip package
|
|
281
|
+
pip install $packageName
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
# install {version} version of {packageName} python package
|
|
285
|
+
(
|
|
286
|
+
install $version version of $packageName python package
|
|
287
|
+
pip install $packageName==$version
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
# uninstall {packageName} python package
|
|
291
|
+
(
|
|
292
|
+
uninstall $packageName python package
|
|
293
|
+
pip uninstall $packageName
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
# === Help Patterns ===
|
|
297
|
+
|
|
298
|
+
# show help
|
|
299
|
+
(
|
|
300
|
+
show help
|
|
301
|
+
$ --help
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
# help
|
|
305
|
+
(
|
|
306
|
+
help
|
|
307
|
+
$ --help
|
|
308
|
+
)
|