launchr-cli 1.0.0 → 1.1.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/.github/workflows/deploy-pages.yml +41 -0
- package/.github/workflows/publish-npm.yml +53 -6
- package/CONTRIBUTION.md +79 -0
- package/README.md +35 -92
- package/RELEASE_NOTES_v1.1.0.md +15 -0
- package/assets/_launchr-logo.png +0 -0
- package/assets/launchr-logo.png +0 -0
- package/docs/assets/__launchr-logo.png +0 -0
- package/docs/assets/_launchr-logo.png +0 -0
- package/docs/assets/launchr-logo.png +0 -0
- package/docs/index.html +322 -0
- package/docs/site.js +53 -0
- package/docs/styles.css +503 -0
- package/package.json +5 -1
- package/src/cli.mjs +7 -1
- package/src/commands/help.mjs +3 -2
- package/src/commands/list.mjs +1 -1
- package/src/constants.mjs +1 -1
- package/test/cli.integration.test.mjs +81 -1
- package/RELEASE_NOTES_v1.0.0.md +0 -11
package/docs/index.html
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>launchr CLI | Config-Driven URL Launcher</title>
|
|
7
|
+
<meta
|
|
8
|
+
name="description"
|
|
9
|
+
content="launchr is a Node.js CLI that turns typed flags into URLs and opens them in your browser."
|
|
10
|
+
/>
|
|
11
|
+
<link rel="stylesheet" href="./styles.css" />
|
|
12
|
+
<script defer src="./site.js"></script>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<div class="page-backdrop" aria-hidden="true"></div>
|
|
16
|
+
|
|
17
|
+
<header class="topbar">
|
|
18
|
+
<div class="container topbar-inner">
|
|
19
|
+
<a href="#top" class="brand">
|
|
20
|
+
<!-- <img src="./assets/launchr-logo.png" alt="launchr logo" /> -->
|
|
21
|
+
<span>launchr</span>
|
|
22
|
+
</a>
|
|
23
|
+
<nav class="nav-links" aria-label="Primary">
|
|
24
|
+
<a href="#quick-start">Quick Start</a>
|
|
25
|
+
<a href="#features">Features</a>
|
|
26
|
+
<a href="#commands">Commands</a>
|
|
27
|
+
<a href="#configuration">Configuration</a>
|
|
28
|
+
<a href="#release-notes">Release Notes</a>
|
|
29
|
+
<a
|
|
30
|
+
class="github-link"
|
|
31
|
+
href="https://github.com/volkanto/launchr"
|
|
32
|
+
target="_blank"
|
|
33
|
+
rel="noopener noreferrer"
|
|
34
|
+
aria-label="Open launchr repository on GitHub"
|
|
35
|
+
>
|
|
36
|
+
<svg
|
|
37
|
+
aria-hidden="true"
|
|
38
|
+
viewBox="0 0 16 16"
|
|
39
|
+
width="16"
|
|
40
|
+
height="16"
|
|
41
|
+
focusable="false"
|
|
42
|
+
>
|
|
43
|
+
<path
|
|
44
|
+
fill="currentColor"
|
|
45
|
+
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82a7.65 7.65 0 0 1 4 0c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z"
|
|
46
|
+
></path>
|
|
47
|
+
</svg>
|
|
48
|
+
<span>GitHub</span>
|
|
49
|
+
</a>
|
|
50
|
+
</nav>
|
|
51
|
+
</div>
|
|
52
|
+
</header>
|
|
53
|
+
|
|
54
|
+
<main id="top">
|
|
55
|
+
<section class="container hero" data-animate="1">
|
|
56
|
+
<div class="hero-copy">
|
|
57
|
+
<p class="eyebrow">Config-Driven URL Launcher</p>
|
|
58
|
+
<h1>Turn short flags into full URLs in seconds.</h1>
|
|
59
|
+
<p class="hero-lead">
|
|
60
|
+
<code>launchr</code> helps teams open dashboards, logs, and runbook
|
|
61
|
+
links from reusable command templates. Keep links typed, validated,
|
|
62
|
+
and fast to execute.
|
|
63
|
+
</p>
|
|
64
|
+
<div class="hero-actions">
|
|
65
|
+
<a class="button button-primary" href="#quick-start">Start in 2 minutes</a>
|
|
66
|
+
<a class="button button-secondary" href="#commands">Explore command syntax</a>
|
|
67
|
+
</div>
|
|
68
|
+
<ul class="hero-bullets">
|
|
69
|
+
<li>Node.js 20+ CLI shipped on npm as <code>launchr-cli</code></li>
|
|
70
|
+
<li>Typed parameters: string, integer, boolean, single-choice-list</li>
|
|
71
|
+
<li>Built for repeatable operational workflows</li>
|
|
72
|
+
</ul>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<aside class="hero-panel">
|
|
76
|
+
<h2>Install + run</h2>
|
|
77
|
+
<p>Copy these commands to try launchr immediately.</p>
|
|
78
|
+
<div class="terminal">
|
|
79
|
+
<div class="terminal-line">
|
|
80
|
+
<code id="cmd-install">npm install -g launchr-cli</code>
|
|
81
|
+
<button type="button" data-copy-target="cmd-install">Copy</button>
|
|
82
|
+
</div>
|
|
83
|
+
<div class="terminal-line">
|
|
84
|
+
<code id="cmd-help">launchr help</code>
|
|
85
|
+
<button type="button" data-copy-target="cmd-help">Copy</button>
|
|
86
|
+
</div>
|
|
87
|
+
<div class="terminal-line">
|
|
88
|
+
<code id="cmd-list">launchr list</code>
|
|
89
|
+
<button type="button" data-copy-target="cmd-list">Copy</button>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</aside>
|
|
93
|
+
</section>
|
|
94
|
+
|
|
95
|
+
<section id="quick-start" class="container section" data-animate="2">
|
|
96
|
+
<div class="section-head">
|
|
97
|
+
<p class="eyebrow">Quick Start</p>
|
|
98
|
+
<h2>From install to first custom command</h2>
|
|
99
|
+
</div>
|
|
100
|
+
<div class="grid grid-3">
|
|
101
|
+
<article class="card">
|
|
102
|
+
<p class="step">01</p>
|
|
103
|
+
<h3>Install the CLI</h3>
|
|
104
|
+
<pre><code id="quick-install">npm install -g launchr-cli</code></pre>
|
|
105
|
+
<button type="button" class="small-copy" data-copy-target="quick-install">
|
|
106
|
+
Copy command
|
|
107
|
+
</button>
|
|
108
|
+
</article>
|
|
109
|
+
<article class="card">
|
|
110
|
+
<p class="step">02</p>
|
|
111
|
+
<h3>Create a command interactively</h3>
|
|
112
|
+
<pre><code id="quick-add">launchr add</code></pre>
|
|
113
|
+
<button type="button" class="small-copy" data-copy-target="quick-add">
|
|
114
|
+
Copy command
|
|
115
|
+
</button>
|
|
116
|
+
</article>
|
|
117
|
+
<article class="card">
|
|
118
|
+
<p class="step">03</p>
|
|
119
|
+
<h3>Run your command with flags</h3>
|
|
120
|
+
<pre><code id="quick-run">launchr grafana -e production -q error -t 5m</code></pre>
|
|
121
|
+
<button type="button" class="small-copy" data-copy-target="quick-run">
|
|
122
|
+
Copy command
|
|
123
|
+
</button>
|
|
124
|
+
</article>
|
|
125
|
+
</div>
|
|
126
|
+
</section>
|
|
127
|
+
|
|
128
|
+
<section id="features" class="container section" data-animate="3">
|
|
129
|
+
<div class="section-head">
|
|
130
|
+
<p class="eyebrow">Features</p>
|
|
131
|
+
<h2>Made for repeatable command workflows</h2>
|
|
132
|
+
</div>
|
|
133
|
+
<div class="grid grid-2">
|
|
134
|
+
<article class="card">
|
|
135
|
+
<h3>Declarative command templates</h3>
|
|
136
|
+
<p>
|
|
137
|
+
Define URL templates once, then reuse them with typed parameters and
|
|
138
|
+
short flags.
|
|
139
|
+
</p>
|
|
140
|
+
</article>
|
|
141
|
+
<article class="card">
|
|
142
|
+
<h3>Strong runtime validation</h3>
|
|
143
|
+
<p>
|
|
144
|
+
launchr validates command schema, placeholders, missing required
|
|
145
|
+
values, and allowed choices.
|
|
146
|
+
</p>
|
|
147
|
+
</article>
|
|
148
|
+
<article class="card">
|
|
149
|
+
<h3>Fast command discovery</h3>
|
|
150
|
+
<p>
|
|
151
|
+
Use <code>launchr list</code> and built-in help to inspect custom
|
|
152
|
+
commands and their expected options.
|
|
153
|
+
</p>
|
|
154
|
+
</article>
|
|
155
|
+
<article class="card">
|
|
156
|
+
<h3>Backward-compatible transition</h3>
|
|
157
|
+
<p>
|
|
158
|
+
Version 1.x supports both <code>launchr add</code> and deprecated
|
|
159
|
+
alias <code>launchr init</code>.
|
|
160
|
+
</p>
|
|
161
|
+
</article>
|
|
162
|
+
</div>
|
|
163
|
+
</section>
|
|
164
|
+
|
|
165
|
+
<section id="commands" class="container section" data-animate="4">
|
|
166
|
+
<div class="section-head">
|
|
167
|
+
<p class="eyebrow">Commands</p>
|
|
168
|
+
<h2>Built-in command reference</h2>
|
|
169
|
+
</div>
|
|
170
|
+
<div class="table-wrap">
|
|
171
|
+
<table>
|
|
172
|
+
<thead>
|
|
173
|
+
<tr>
|
|
174
|
+
<th>Command</th>
|
|
175
|
+
<th>Purpose</th>
|
|
176
|
+
</tr>
|
|
177
|
+
</thead>
|
|
178
|
+
<tbody>
|
|
179
|
+
<tr>
|
|
180
|
+
<td><code>launchr</code></td>
|
|
181
|
+
<td>Starts CLI entrypoint and prints guidance.</td>
|
|
182
|
+
</tr>
|
|
183
|
+
<tr>
|
|
184
|
+
<td><code>launchr help</code></td>
|
|
185
|
+
<td>Shows built-in help and usage details.</td>
|
|
186
|
+
</tr>
|
|
187
|
+
<tr>
|
|
188
|
+
<td><code>launchr list</code></td>
|
|
189
|
+
<td>Lists configured custom commands from your JSON config file.</td>
|
|
190
|
+
</tr>
|
|
191
|
+
<tr>
|
|
192
|
+
<td><code>launchr add</code></td>
|
|
193
|
+
<td>Interactive flow for creating a new custom command.</td>
|
|
194
|
+
</tr>
|
|
195
|
+
<tr>
|
|
196
|
+
<td><code>launchr init</code></td>
|
|
197
|
+
<td>Deprecated alias for <code>add</code> in v1.x.</td>
|
|
198
|
+
</tr>
|
|
199
|
+
<tr>
|
|
200
|
+
<td><code>launchr <custom> help</code></td>
|
|
201
|
+
<td>Shows usage for one configured custom command.</td>
|
|
202
|
+
</tr>
|
|
203
|
+
<tr>
|
|
204
|
+
<td><code>launchr <custom> [flags]</code></td>
|
|
205
|
+
<td>Builds URL from template and opens it in your browser.</td>
|
|
206
|
+
</tr>
|
|
207
|
+
</tbody>
|
|
208
|
+
</table>
|
|
209
|
+
</div>
|
|
210
|
+
</section>
|
|
211
|
+
|
|
212
|
+
<section id="configuration" class="container section" data-animate="5">
|
|
213
|
+
<div class="section-head">
|
|
214
|
+
<p class="eyebrow">Configuration</p>
|
|
215
|
+
<h2>Command definition structure</h2>
|
|
216
|
+
</div>
|
|
217
|
+
<p class="section-copy">
|
|
218
|
+
launchr stores command definitions at
|
|
219
|
+
<code>~/.launchr-configurations/launchr-commands.json</code>.
|
|
220
|
+
</p>
|
|
221
|
+
<article class="code-card">
|
|
222
|
+
<div class="code-title">Example: grafana command</div>
|
|
223
|
+
<pre><code>{
|
|
224
|
+
"grafana": {
|
|
225
|
+
"description": "Open Grafana with typed parameters",
|
|
226
|
+
"url": "https://grafana.com/{environment}/{query}/{timeframe}",
|
|
227
|
+
"parameters": {
|
|
228
|
+
"environment": {
|
|
229
|
+
"type": "single-choice-list",
|
|
230
|
+
"flag": "e",
|
|
231
|
+
"defaultValue": "staging",
|
|
232
|
+
"required": true,
|
|
233
|
+
"values": ["staging", "production"]
|
|
234
|
+
},
|
|
235
|
+
"query": {
|
|
236
|
+
"type": "string",
|
|
237
|
+
"flag": "q",
|
|
238
|
+
"defaultValue": "error",
|
|
239
|
+
"required": true
|
|
240
|
+
},
|
|
241
|
+
"timeframe": {
|
|
242
|
+
"type": "single-choice-list",
|
|
243
|
+
"flag": "t",
|
|
244
|
+
"defaultValue": "5m",
|
|
245
|
+
"required": true,
|
|
246
|
+
"values": ["5m", "10m", "1h", "6h"]
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}</code></pre>
|
|
251
|
+
</article>
|
|
252
|
+
</section>
|
|
253
|
+
|
|
254
|
+
<section id="release-notes" class="container section" data-animate="6">
|
|
255
|
+
<div class="section-head">
|
|
256
|
+
<p class="eyebrow">Release Notes</p>
|
|
257
|
+
<h2>Recent updates</h2>
|
|
258
|
+
</div>
|
|
259
|
+
<div class="timeline">
|
|
260
|
+
<article class="timeline-item">
|
|
261
|
+
<p class="timeline-version">v1.1.0</p>
|
|
262
|
+
<h3>Command naming transition</h3>
|
|
263
|
+
<ul>
|
|
264
|
+
<li><code>launchr add</code> is now the canonical command.</li>
|
|
265
|
+
<li><code>launchr init</code> remains as a deprecated alias in v1.x.</li>
|
|
266
|
+
<li>Help text updated to guide users toward <code>add</code>.</li>
|
|
267
|
+
</ul>
|
|
268
|
+
</article>
|
|
269
|
+
<article class="timeline-item">
|
|
270
|
+
<p class="timeline-version">v1.0.0</p>
|
|
271
|
+
<h3>Stable initial release</h3>
|
|
272
|
+
<ul>
|
|
273
|
+
<li>Typed URL template commands with JSON-based configuration.</li>
|
|
274
|
+
<li>Interactive command creation and detailed runtime validation.</li>
|
|
275
|
+
<li>npm package publishing workflow with test gating.</li>
|
|
276
|
+
</ul>
|
|
277
|
+
</article>
|
|
278
|
+
</div>
|
|
279
|
+
</section>
|
|
280
|
+
|
|
281
|
+
<section class="container section section-compact" data-animate="7">
|
|
282
|
+
<div class="section-head">
|
|
283
|
+
<p class="eyebrow">Development</p>
|
|
284
|
+
<h2>Local contributor workflow</h2>
|
|
285
|
+
</div>
|
|
286
|
+
<div class="grid grid-2">
|
|
287
|
+
<article class="card">
|
|
288
|
+
<h3>Run from source</h3>
|
|
289
|
+
<pre><code id="dev-start">npm install
|
|
290
|
+
npm start -- help</code></pre>
|
|
291
|
+
<button type="button" class="small-copy" data-copy-target="dev-start">
|
|
292
|
+
Copy commands
|
|
293
|
+
</button>
|
|
294
|
+
</article>
|
|
295
|
+
<article class="card">
|
|
296
|
+
<h3>Run tests</h3>
|
|
297
|
+
<pre><code id="dev-test">npm test</code></pre>
|
|
298
|
+
<button type="button" class="small-copy" data-copy-target="dev-test">
|
|
299
|
+
Copy command
|
|
300
|
+
</button>
|
|
301
|
+
</article>
|
|
302
|
+
</div>
|
|
303
|
+
</section>
|
|
304
|
+
</main>
|
|
305
|
+
|
|
306
|
+
<footer class="footer">
|
|
307
|
+
<div class="container footer-inner">
|
|
308
|
+
<p>
|
|
309
|
+
launchr CLI • Node.js 20+ • <span id="year"></span>
|
|
310
|
+
</p>
|
|
311
|
+
<a
|
|
312
|
+
class="footer-github"
|
|
313
|
+
href="https://github.com/volkanto/launchr"
|
|
314
|
+
target="_blank"
|
|
315
|
+
rel="noopener noreferrer"
|
|
316
|
+
>
|
|
317
|
+
View on GitHub
|
|
318
|
+
</a>
|
|
319
|
+
</div>
|
|
320
|
+
</footer>
|
|
321
|
+
</body>
|
|
322
|
+
</html>
|
package/docs/site.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const buttons = Array.from(document.querySelectorAll("[data-copy-target]"));
|
|
2
|
+
|
|
3
|
+
function setButtonState(button, message) {
|
|
4
|
+
const original = button.dataset.originalLabel || button.textContent;
|
|
5
|
+
if (!button.dataset.originalLabel) {
|
|
6
|
+
button.dataset.originalLabel = original;
|
|
7
|
+
}
|
|
8
|
+
button.textContent = message;
|
|
9
|
+
window.setTimeout(() => {
|
|
10
|
+
button.textContent = original;
|
|
11
|
+
}, 1300);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function copyText(text) {
|
|
15
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
16
|
+
await navigator.clipboard.writeText(text);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const textarea = document.createElement("textarea");
|
|
21
|
+
textarea.value = text;
|
|
22
|
+
textarea.setAttribute("readonly", "");
|
|
23
|
+
textarea.style.position = "absolute";
|
|
24
|
+
textarea.style.left = "-9999px";
|
|
25
|
+
document.body.appendChild(textarea);
|
|
26
|
+
textarea.select();
|
|
27
|
+
document.execCommand("copy");
|
|
28
|
+
document.body.removeChild(textarea);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
buttons.forEach((button) => {
|
|
32
|
+
button.addEventListener("click", async () => {
|
|
33
|
+
const targetId = button.getAttribute("data-copy-target");
|
|
34
|
+
const source = targetId ? document.getElementById(targetId) : null;
|
|
35
|
+
const text = source ? source.textContent : "";
|
|
36
|
+
if (!text) {
|
|
37
|
+
setButtonState(button, "Unavailable");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
await copyText(text.trim());
|
|
43
|
+
setButtonState(button, "Copied");
|
|
44
|
+
} catch {
|
|
45
|
+
setButtonState(button, "Failed");
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const year = document.getElementById("year");
|
|
51
|
+
if (year) {
|
|
52
|
+
year.textContent = String(new Date().getFullYear());
|
|
53
|
+
}
|