@tertium/hlpr 0.1.11 → 0.1.13

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.
@@ -0,0 +1,35 @@
1
+ name: Publish Package
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Install Bun
15
+ run: curl -fsSL https://bun.sh/install | bash
16
+
17
+ - name: Add Bun to PATH
18
+ run: echo "$HOME/.bun/bin" >> $GITHUB_PATH
19
+
20
+ - name: Use Node.js
21
+ uses: actions/setup-node@v4
22
+ with:
23
+ node-version: "22"
24
+ registry-url: "https://registry.npmjs.org/"
25
+
26
+ - name: Install dependencies
27
+ run: bun install
28
+
29
+ - name: Install dependencies
30
+ run: bun run build
31
+
32
+ - name: Publish to npm (with Bun)
33
+ run: npm publish --access public
34
+ env:
35
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env sh
2
+ . "$(dirname -- "$0")/_/husky.sh"
3
+
4
+ echo "Running build before commit..."
5
+ bun run build
6
+ git add bin/hlpr.js
@@ -0,0 +1,3 @@
1
+ {
2
+ "cSpell.words": ["hlpr"]
3
+ }
package/bun.lockb ADDED
Binary file
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@tertium/hlpr",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "Windows and *Nix utility for typical programming activity",
5
5
  "author": "Vitalii Balabanov",
6
6
  "email": "tertiumnon@gmail.com",
7
- "main": "bin/hlpr.js",
8
- "type": "commonjs",
7
+ "main": "index.js",
8
+ "type": "module",
9
9
  "scripts": {
10
10
  "build": "bun build ./src/index.ts --outfile ./index.js --target node",
11
11
  "prepublishOnly": "npm run build",
@@ -23,11 +23,6 @@
23
23
  "bin": {
24
24
  "hlpr": "./bin/hlpr.js"
25
25
  },
26
- "files": [
27
- "bin",
28
- "commands",
29
- "index.js"
30
- ],
31
26
  "keywords": [
32
27
  "cli",
33
28
  "utility",
package/src/index.ts ADDED
@@ -0,0 +1,179 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { exec } from "node:child_process";
3
+ import * as path from "node:path";
4
+ import * as fs from "node:fs";
5
+ import * as readline from "node:readline";
6
+ import * as os from "node:os";
7
+
8
+ // Get package version from package.json
9
+ async function getVersion(): Promise<string> {
10
+ try {
11
+ const packagePath = path.join(path.dirname(path.dirname(__dirname)), 'package.json');
12
+ const packageJson = JSON.parse(await readFile(packagePath, 'utf-8'));
13
+ return packageJson.version;
14
+ } catch (error) {
15
+ console.error('Error reading package.json:', error);
16
+ return '0.0.0'; // Fallback version
17
+ }
18
+ }
19
+
20
+ // Detect shell type
21
+ function detectShell(): string {
22
+ const isWindows = os.platform() === "win32";
23
+ if (isWindows) {
24
+ return "powershell";
25
+ }
26
+ return "bash"; // Default to bash for Unix-like systems
27
+ }
28
+
29
+ // Parse command line arguments
30
+ const args = process.argv.slice(2);
31
+ let forceFlag = false;
32
+ let commandArgs: string[] = [];
33
+
34
+ // Check for -f flag
35
+ if (args[0] === "-f") {
36
+ forceFlag = true;
37
+ commandArgs = args.slice(1);
38
+ } else {
39
+ commandArgs = args;
40
+ }
41
+
42
+ // Create readline interface for user input
43
+ const rl = readline.createInterface({
44
+ input: process.stdin,
45
+ output: process.stdout
46
+ });
47
+
48
+ // Prompt for user input
49
+ function prompt(question: string): Promise<string> {
50
+ return new Promise((resolve) => {
51
+ rl.question(question, (answer) => {
52
+ resolve(answer);
53
+ });
54
+ });
55
+ }
56
+
57
+ // Execute a command with variable substitution
58
+ async function executeCommand(command: string, variables: Record<string, string>): Promise<boolean> {
59
+ // Replace variables in the command
60
+ let processedCommand = command;
61
+ for (const [key, value] of Object.entries(variables)) {
62
+ processedCommand = processedCommand.replace(new RegExp(`{{${key}}}`, 'g'), value);
63
+ }
64
+
65
+ return new Promise((resolve) => {
66
+ console.log(`Executing: ${processedCommand}`);
67
+ const childProcess = exec(processedCommand);
68
+
69
+ if (childProcess.stdout) {
70
+ childProcess.stdout.on("data", (data: string) => {
71
+ console.log(data.toString().trim());
72
+ });
73
+ }
74
+
75
+ if (childProcess.stderr) {
76
+ childProcess.stderr.on("data", (data: string) => {
77
+ console.error(data.toString().trim());
78
+ });
79
+ }
80
+
81
+ childProcess.on("exit", (code: number | null) => {
82
+ if (code === 0) {
83
+ resolve(true);
84
+ } else {
85
+ console.error(`Command failed with exit code ${code}`);
86
+ resolve(false);
87
+ }
88
+ });
89
+ });
90
+ }
91
+
92
+ export async function main() {
93
+ // Check for version flag
94
+ if (commandArgs[0] === "--version" || commandArgs[0] === "-v") {
95
+ const version = await getVersion();
96
+ console.log(`hlpr version ${version}`);
97
+ process.exit(0);
98
+ }
99
+
100
+ if (commandArgs.length === 0) {
101
+ console.error("Please provide a command. Example: hlpr ssh init-dir");
102
+ process.exit(1);
103
+ }
104
+
105
+ try {
106
+ // Get the category (first argument) and the rest of the command
107
+ const category = commandArgs[0];
108
+ const restArgs = commandArgs.slice(1);
109
+
110
+ // Join the rest of the arguments without hyphens
111
+ const scriptName = restArgs.join("");
112
+
113
+ // Get the directory where the hlpr script is installed
114
+ const scriptDir = path.dirname(path.dirname(__dirname));
115
+ const scriptPath = path.join(scriptDir, "commands", category, `${scriptName}.sh`);
116
+
117
+ // Check if the script exists
118
+ if (!fs.existsSync(scriptPath)) {
119
+ console.error(`Script not found: ${scriptPath}`);
120
+ process.exit(1);
121
+ }
122
+
123
+ // Read the script content
124
+ const scriptContent = await readFile(scriptPath, "utf-8");
125
+
126
+ // Extract variables from the script (anything in {{variable}})
127
+ const variableRegex = /{{([^}]+)}}/g;
128
+ const variables: Record<string, string> = {};
129
+ const uniqueVars = new Set<string>();
130
+
131
+ let match;
132
+ while ((match = variableRegex.exec(scriptContent)) !== null) {
133
+ uniqueVars.add(match[1]);
134
+ }
135
+
136
+ // Prompt for each variable
137
+ for (const varName of uniqueVars) {
138
+ const value = await prompt(`Enter ${varName}: `);
139
+ variables[varName] = value;
140
+ }
141
+
142
+ // Create a temporary script with variables substituted
143
+ let processedScript = scriptContent;
144
+ for (const [key, value] of Object.entries(variables)) {
145
+ processedScript = processedScript.replace(new RegExp(`{{${key}}}`, 'g'), value);
146
+ }
147
+
148
+ const tempScriptPath = path.join(path.dirname(scriptPath), `_temp_${path.basename(scriptPath)}`);
149
+ fs.writeFileSync(tempScriptPath, processedScript);
150
+
151
+ // Execute the temporary script with appropriate shell
152
+ const shell = detectShell();
153
+ const command = shell === "powershell"
154
+ ? `powershell -File "${tempScriptPath}"`
155
+ : `bash "${tempScriptPath}"`;
156
+ const success = await executeCommand(command, {});
157
+
158
+ // Clean up the temporary script
159
+ fs.unlinkSync(tempScriptPath);
160
+
161
+ // If command failed and force flag is not set, exit
162
+ if (!success && !forceFlag) {
163
+ console.error("Command failed, stopping execution.");
164
+ process.exit(1);
165
+ }
166
+
167
+ console.log("Command completed successfully!");
168
+ } catch (error) {
169
+ console.error("Error:", error);
170
+ process.exit(1);
171
+ } finally {
172
+ rl.close();
173
+ }
174
+ }
175
+
176
+ // If this file is run directly, execute main
177
+ if (require.main === module) {
178
+ main();
179
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "CommonJS",
5
+ "moduleResolution": "node",
6
+ "esModuleInterop": true,
7
+ "outDir": "./bin",
8
+ "rootDir": "./",
9
+ "strict": true,
10
+ "declaration": false,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true
13
+ },
14
+ "include": ["src/**/*"],
15
+ "exclude": ["node_modules", "dist"]
16
+ }