@amiable-dev/docusaurus-plugin-stentorosaur 0.17.0 → 0.19.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.
@@ -19,19 +19,19 @@
19
19
  .cells {
20
20
  display: flex;
21
21
  gap: 2px;
22
- max-width: 100%;
22
+ width: 100%;
23
23
  margin-bottom: 0.75rem;
24
- overflow-x: auto;
24
+ overflow: hidden;
25
25
  }
26
26
 
27
27
  .cell {
28
- width: 3px;
29
- height: 30px;
30
- border-radius: 1px;
28
+ flex: 1;
29
+ min-width: 0;
30
+ height: 40px;
31
+ border-radius: 2px;
31
32
  cursor: pointer;
32
- transition: transform 0.2s ease, opacity 0.2s ease;
33
+ transition: opacity 0.2s ease;
33
34
  position: relative;
34
- flex-shrink: 0;
35
35
  }
36
36
 
37
37
  .cell.hasIncident {
@@ -74,9 +74,8 @@
74
74
  }
75
75
 
76
76
  .cell:hover {
77
- transform: scale(1.3);
78
- opacity: 0.8;
79
- z-index: 1;
77
+ opacity: 0.7;
78
+ filter: brightness(1.1);
80
79
  }
81
80
 
82
81
  .legend {
@@ -135,8 +134,7 @@
135
134
  }
136
135
 
137
136
  .cell {
138
- width: 2px;
139
- height: 20px;
137
+ height: 30px;
140
138
  }
141
139
 
142
140
  .uptimeStats {
package/lib/version.d.ts CHANGED
@@ -2,5 +2,5 @@
2
2
  * Plugin version - auto-generated during build
3
3
  * DO NOT EDIT MANUALLY - This file is generated from package.json
4
4
  */
5
- export declare const PLUGIN_VERSION = "0.17.0";
5
+ export declare const PLUGIN_VERSION = "0.19.0";
6
6
  //# sourceMappingURL=version.d.ts.map
package/lib/version.js CHANGED
@@ -5,4 +5,4 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.PLUGIN_VERSION = void 0;
8
- exports.PLUGIN_VERSION = '0.17.0';
8
+ exports.PLUGIN_VERSION = '0.19.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amiable-dev/docusaurus-plugin-stentorosaur",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "description": "A Docusaurus plugin for displaying status monitoring dashboard powered by GitHub Issues and Actions, similar to Upptime",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/plugin-status.d.ts",
@@ -11,8 +11,16 @@
11
11
  "stentorosaur-setup-status-branch": "scripts/setup-status-branch.js",
12
12
  "stentorosaur-migrate-to-status-branch": "scripts/migrate-to-status-branch.js",
13
13
  "stentorosaur-cleanup-status-branch": "scripts/cleanup-status-branch.js",
14
- "stentorosaur-bootstrap-summary": "scripts/bootstrap-summary.js"
14
+ "stentorosaur-bootstrap-summary": "scripts/bootstrap-summary.js",
15
+ "stentorosaur-init": "scripts/init.js",
16
+ "stentorosaur-config": "scripts/config.js"
15
17
  },
18
+ "files": [
19
+ "lib",
20
+ "scripts",
21
+ "templates",
22
+ "src/plugin-status.d.ts"
23
+ ],
16
24
  "keywords": [
17
25
  "docusaurus",
18
26
  "plugin",
@@ -37,6 +45,7 @@
37
45
  "watch": "tsc --build --watch",
38
46
  "dev": "tsc --build --watch",
39
47
  "prebuild": "node scripts/generate-version.js",
48
+ "postinstall": "node scripts/postinstall.js",
40
49
  "update-status": "node scripts/update-status.js",
41
50
  "setup-status-branch": "node scripts/setup-status-branch.js",
42
51
  "migrate-to-status-branch": "node scripts/migrate-to-status-branch.js",
File without changes
@@ -0,0 +1,359 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Stentorosaur configuration management CLI
5
+ * Manages .monitorrc.json and docusaurus.config plugin options
6
+ */
7
+
8
+ const fs = require('fs-extra');
9
+ const path = require('path');
10
+
11
+ const CONFIG_FILE = '.monitorrc.json';
12
+ const ENTITIES_FILE = '.stentorosaur-entities.json';
13
+
14
+ // Parse command line arguments
15
+ function parseArgs(args) {
16
+ const result = { command: args[0], options: {} };
17
+
18
+ for (let i = 1; i < args.length; i++) {
19
+ const arg = args[i];
20
+ if (arg.startsWith('--')) {
21
+ const key = arg.slice(2);
22
+ const nextArg = args[i + 1];
23
+ if (nextArg && !nextArg.startsWith('--')) {
24
+ result.options[key] = nextArg;
25
+ i++;
26
+ } else {
27
+ result.options[key] = true;
28
+ }
29
+ }
30
+ }
31
+
32
+ return result;
33
+ }
34
+
35
+ // Load monitor config
36
+ async function loadConfig() {
37
+ const configPath = path.join(process.cwd(), CONFIG_FILE);
38
+
39
+ if (!await fs.pathExists(configPath)) {
40
+ return {
41
+ "$schema": "https://json-schema.org/draft-07/schema#",
42
+ "description": "Configuration file for status monitoring script",
43
+ "systems": []
44
+ };
45
+ }
46
+
47
+ return await fs.readJson(configPath);
48
+ }
49
+
50
+ // Save monitor config
51
+ async function saveConfig(config) {
52
+ const configPath = path.join(process.cwd(), CONFIG_FILE);
53
+ await fs.writeJson(configPath, config, { spaces: 2 });
54
+ }
55
+
56
+ // Load entities config (for processes and additional metadata)
57
+ async function loadEntities() {
58
+ const entitiesPath = path.join(process.cwd(), ENTITIES_FILE);
59
+
60
+ if (!await fs.pathExists(entitiesPath)) {
61
+ return { systems: [], processes: [] };
62
+ }
63
+
64
+ return await fs.readJson(entitiesPath);
65
+ }
66
+
67
+ // Save entities config
68
+ async function saveEntities(entities) {
69
+ const entitiesPath = path.join(process.cwd(), ENTITIES_FILE);
70
+ await fs.writeJson(entitiesPath, entities, { spaces: 2 });
71
+ }
72
+
73
+ // Add a system to monitor
74
+ async function addSystem(options) {
75
+ const name = options.name;
76
+ const url = options.url;
77
+ const method = options.method || 'GET';
78
+ const timeout = options.timeout || '10000';
79
+ const expectedCodes = options['expected-codes'] || '200';
80
+
81
+ if (!name || !url) {
82
+ console.error('\x1b[31mError:\x1b[0m Both --name and --url are required');
83
+ console.log('\nUsage: stentorosaur-config add-system --name api --url https://api.example.com/health');
84
+ process.exit(1);
85
+ }
86
+
87
+ const config = await loadConfig();
88
+
89
+ // Check if system already exists
90
+ const existingIndex = config.systems.findIndex(s => s.system === name);
91
+
92
+ const newSystem = {
93
+ system: name,
94
+ url: url,
95
+ method: method.toUpperCase(),
96
+ timeout: parseInt(timeout, 10),
97
+ expectedCodes: expectedCodes.split(',').map(c => parseInt(c.trim(), 10)),
98
+ maxResponseTime: 30000
99
+ };
100
+
101
+ if (existingIndex >= 0) {
102
+ config.systems[existingIndex] = newSystem;
103
+ console.log(`\x1b[33mUpdated:\x1b[0m System '${name}' configuration updated`);
104
+ } else {
105
+ config.systems.push(newSystem);
106
+ console.log(`\x1b[32mAdded:\x1b[0m System '${name}' added to ${CONFIG_FILE}`);
107
+ }
108
+
109
+ await saveConfig(config);
110
+
111
+ // Also add to entities for docusaurus config reference
112
+ const entities = await loadEntities();
113
+ if (!entities.systems.find(s => s.name === name)) {
114
+ entities.systems.push({ name, type: 'system', url });
115
+ await saveEntities(entities);
116
+ }
117
+
118
+ console.log(`\n URL: ${url}`);
119
+ console.log(` Method: ${method.toUpperCase()}`);
120
+ console.log(` Timeout: ${timeout}ms`);
121
+ console.log(` Expected codes: ${expectedCodes}`);
122
+ }
123
+
124
+ // Add a business process
125
+ async function addProcess(options) {
126
+ const name = options.name;
127
+ const description = options.description || '';
128
+
129
+ if (!name) {
130
+ console.error('\x1b[31mError:\x1b[0m --name is required');
131
+ console.log('\nUsage: stentorosaur-config add-process --name deployments --description "Deployment pipeline"');
132
+ process.exit(1);
133
+ }
134
+
135
+ const entities = await loadEntities();
136
+
137
+ // Check if process already exists
138
+ const existingIndex = entities.processes.findIndex(p => p.name === name);
139
+
140
+ const newProcess = {
141
+ name,
142
+ type: 'process',
143
+ description: description || `${name} process tracking`
144
+ };
145
+
146
+ if (existingIndex >= 0) {
147
+ entities.processes[existingIndex] = newProcess;
148
+ console.log(`\x1b[33mUpdated:\x1b[0m Process '${name}' configuration updated`);
149
+ } else {
150
+ entities.processes.push(newProcess);
151
+ console.log(`\x1b[32mAdded:\x1b[0m Process '${name}' added to ${ENTITIES_FILE}`);
152
+ }
153
+
154
+ await saveEntities(entities);
155
+
156
+ console.log(`\n Description: ${newProcess.description}`);
157
+ console.log(`\n\x1b[33mNote:\x1b[0m Add 'process:${name}' label to GitHub Issues to track this process.`);
158
+ }
159
+
160
+ // Remove a system
161
+ async function removeSystem(options) {
162
+ const name = options.name;
163
+
164
+ if (!name) {
165
+ console.error('\x1b[31mError:\x1b[0m --name is required');
166
+ console.log('\nUsage: stentorosaur-config remove-system --name api');
167
+ process.exit(1);
168
+ }
169
+
170
+ const config = await loadConfig();
171
+ const originalLength = config.systems.length;
172
+ config.systems = config.systems.filter(s => s.system !== name);
173
+
174
+ if (config.systems.length === originalLength) {
175
+ console.log(`\x1b[33mWarning:\x1b[0m System '${name}' not found in ${CONFIG_FILE}`);
176
+ } else {
177
+ await saveConfig(config);
178
+ console.log(`\x1b[32mRemoved:\x1b[0m System '${name}' from ${CONFIG_FILE}`);
179
+ }
180
+
181
+ // Also remove from entities
182
+ const entities = await loadEntities();
183
+ entities.systems = entities.systems.filter(s => s.name !== name);
184
+ await saveEntities(entities);
185
+ }
186
+
187
+ // List all configured systems and processes
188
+ async function list() {
189
+ const config = await loadConfig();
190
+ const entities = await loadEntities();
191
+
192
+ console.log('\n\x1b[32mMonitored Systems:\x1b[0m');
193
+ console.log('─'.repeat(60));
194
+
195
+ if (config.systems.length === 0) {
196
+ console.log(' No systems configured');
197
+ console.log(' Run: make status-add-system name=api url=https://...');
198
+ } else {
199
+ for (const system of config.systems) {
200
+ console.log(`\n \x1b[36m${system.system}\x1b[0m`);
201
+ console.log(` URL: ${system.url}`);
202
+ console.log(` Method: ${system.method}`);
203
+ console.log(` Timeout: ${system.timeout}ms`);
204
+ console.log(` Expected: ${system.expectedCodes.join(', ')}`);
205
+ }
206
+ }
207
+
208
+ console.log('\n\n\x1b[32mBusiness Processes:\x1b[0m');
209
+ console.log('─'.repeat(60));
210
+
211
+ if (!entities.processes || entities.processes.length === 0) {
212
+ console.log(' No processes configured');
213
+ console.log(' Run: make status-add-process name=deployments');
214
+ } else {
215
+ for (const process of entities.processes) {
216
+ console.log(`\n \x1b[36m${process.name}\x1b[0m`);
217
+ console.log(` Label: process:${process.name}`);
218
+ if (process.description) {
219
+ console.log(` Description: ${process.description}`);
220
+ }
221
+ }
222
+ }
223
+
224
+ console.log('\n');
225
+ }
226
+
227
+ // Validate configuration
228
+ async function validate() {
229
+ const configPath = path.join(process.cwd(), CONFIG_FILE);
230
+
231
+ if (!await fs.pathExists(configPath)) {
232
+ console.error(`\x1b[31mError:\x1b[0m ${CONFIG_FILE} not found`);
233
+ console.log('Run: make status-init');
234
+ process.exit(1);
235
+ }
236
+
237
+ try {
238
+ const config = await fs.readJson(configPath);
239
+
240
+ const errors = [];
241
+ const warnings = [];
242
+
243
+ if (!config.systems || !Array.isArray(config.systems)) {
244
+ errors.push('Missing or invalid "systems" array');
245
+ } else {
246
+ for (let i = 0; i < config.systems.length; i++) {
247
+ const system = config.systems[i];
248
+
249
+ if (!system.system) {
250
+ errors.push(`System ${i + 1}: Missing "system" name`);
251
+ }
252
+ if (!system.url) {
253
+ errors.push(`System ${i + 1}: Missing "url"`);
254
+ } else {
255
+ try {
256
+ new URL(system.url);
257
+ } catch {
258
+ errors.push(`System ${i + 1}: Invalid URL "${system.url}"`);
259
+ }
260
+ }
261
+ if (system.timeout && (typeof system.timeout !== 'number' || system.timeout < 0)) {
262
+ warnings.push(`System ${i + 1}: Invalid timeout value`);
263
+ }
264
+ }
265
+ }
266
+
267
+ if (errors.length > 0) {
268
+ console.log('\x1b[31mValidation failed:\x1b[0m\n');
269
+ errors.forEach(e => console.log(` - ${e}`));
270
+ process.exit(1);
271
+ }
272
+
273
+ if (warnings.length > 0) {
274
+ console.log('\x1b[33mWarnings:\x1b[0m\n');
275
+ warnings.forEach(w => console.log(` - ${w}`));
276
+ }
277
+
278
+ console.log(`\x1b[32mConfiguration valid!\x1b[0m`);
279
+ console.log(` ${config.systems.length} system(s) configured`);
280
+
281
+ } catch (err) {
282
+ console.error(`\x1b[31mError:\x1b[0m Failed to parse ${CONFIG_FILE}`);
283
+ console.error(err.message);
284
+ process.exit(1);
285
+ }
286
+ }
287
+
288
+ // Generate docusaurus config snippet
289
+ async function generateConfig() {
290
+ const entities = await loadEntities();
291
+
292
+ const allEntities = [
293
+ ...entities.systems.map(s => ({ name: s.name, type: 'system' })),
294
+ ...entities.processes.map(p => ({ name: p.name, type: 'process' }))
295
+ ];
296
+
297
+ console.log('\n\x1b[32mDocusaurus Config Snippet:\x1b[0m');
298
+ console.log('─'.repeat(60));
299
+ console.log(`
300
+ // Add to docusaurus.config.js plugins array:
301
+ [
302
+ '@amiable-dev/docusaurus-plugin-stentorosaur',
303
+ {
304
+ owner: 'your-org',
305
+ repo: 'your-repo',
306
+ entities: ${JSON.stringify(allEntities, null, 6).replace(/\n/g, '\n ')},
307
+ },
308
+ ],
309
+ `);
310
+ }
311
+
312
+ // Main CLI
313
+ async function main() {
314
+ const args = process.argv.slice(2);
315
+
316
+ if (args.length === 0) {
317
+ console.log('Stentorosaur Configuration Manager\n');
318
+ console.log('Commands:');
319
+ console.log(' add-system Add a system to monitor');
320
+ console.log(' add-process Add a business process');
321
+ console.log(' remove-system Remove a system');
322
+ console.log(' list List all configured systems and processes');
323
+ console.log(' validate Validate configuration files');
324
+ console.log(' generate Generate docusaurus.config.js snippet');
325
+ console.log('\nRun with --help for more info');
326
+ process.exit(0);
327
+ }
328
+
329
+ const { command, options } = parseArgs(args);
330
+
331
+ switch (command) {
332
+ case 'add-system':
333
+ await addSystem(options);
334
+ break;
335
+ case 'add-process':
336
+ await addProcess(options);
337
+ break;
338
+ case 'remove-system':
339
+ await removeSystem(options);
340
+ break;
341
+ case 'list':
342
+ await list();
343
+ break;
344
+ case 'validate':
345
+ await validate();
346
+ break;
347
+ case 'generate':
348
+ await generateConfig();
349
+ break;
350
+ default:
351
+ console.error(`\x1b[31mError:\x1b[0m Unknown command '${command}'`);
352
+ process.exit(1);
353
+ }
354
+ }
355
+
356
+ main().catch(err => {
357
+ console.error('\x1b[31mError:\x1b[0m', err.message);
358
+ process.exit(1);
359
+ });
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Initialize Stentorosaur status monitoring in a consuming project
5
+ * Creates .monitorrc.json and status-data directory
6
+ */
7
+
8
+ const fs = require('fs-extra');
9
+ const path = require('path');
10
+
11
+ const CONFIG_FILE = '.monitorrc.json';
12
+ const STATUS_DATA_DIR = 'status-data';
13
+
14
+ const DEFAULT_CONFIG = {
15
+ "$schema": "https://json-schema.org/draft-07/schema#",
16
+ "description": "Configuration file for status monitoring script",
17
+ "systems": []
18
+ };
19
+
20
+ async function init() {
21
+ const cwd = process.cwd();
22
+ const configPath = path.join(cwd, CONFIG_FILE);
23
+ const statusDataPath = path.join(cwd, STATUS_DATA_DIR);
24
+
25
+ console.log('Initializing Stentorosaur status monitoring...\n');
26
+
27
+ // Create .monitorrc.json if it doesn't exist
28
+ if (await fs.pathExists(configPath)) {
29
+ console.log(`\x1b[33mWarning:\x1b[0m ${CONFIG_FILE} already exists. Skipping...`);
30
+ } else {
31
+ await fs.writeJson(configPath, DEFAULT_CONFIG, { spaces: 2 });
32
+ console.log(`\x1b[32mCreated:\x1b[0m ${CONFIG_FILE}`);
33
+ }
34
+
35
+ // Create status-data directory
36
+ await fs.ensureDir(statusDataPath);
37
+ console.log(`\x1b[32mCreated:\x1b[0m ${STATUS_DATA_DIR}/`);
38
+
39
+ // Create .gitkeep in status-data
40
+ const gitkeepPath = path.join(statusDataPath, '.gitkeep');
41
+ if (!await fs.pathExists(gitkeepPath)) {
42
+ await fs.writeFile(gitkeepPath, '');
43
+ }
44
+
45
+ console.log('\n\x1b[32mStatus monitoring initialized!\x1b[0m\n');
46
+ console.log('Next steps:');
47
+ console.log(' 1. Add systems to monitor:');
48
+ console.log(' make status-add-system name=api url=https://api.example.com/health\n');
49
+ console.log(' 2. Copy GitHub Actions workflows:');
50
+ console.log(' make status-workflows\n');
51
+ console.log(' 3. Test your configuration:');
52
+ console.log(' make status-test\n');
53
+ }
54
+
55
+ init().catch(err => {
56
+ console.error('\x1b[31mError:\x1b[0m', err.message);
57
+ process.exit(1);
58
+ });
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Postinstall script for @amiable-dev/docusaurus-plugin-stentorosaur
5
+ * Automatically integrates status monitoring commands into the consuming project's Makefile
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ // Find the consuming project root (go up from node_modules)
12
+ function findProjectRoot() {
13
+ let current = process.cwd();
14
+
15
+ // If we're in node_modules, go up to find project root
16
+ while (current.includes('node_modules')) {
17
+ current = path.dirname(current);
18
+ }
19
+
20
+ // Verify this looks like a project root
21
+ if (fs.existsSync(path.join(current, 'package.json'))) {
22
+ return current;
23
+ }
24
+
25
+ return null;
26
+ }
27
+
28
+ // Status monitoring section to add to help
29
+ const STATUS_HELP_SECTION = `
30
+ @echo ""
31
+ @echo "$(GREEN)Status Monitoring:$(NC) (run 'make status-help' for full list)"
32
+ @echo " $(YELLOW)status-add-system $(NC) Add endpoint to monitor (name=x url=y)"
33
+ @echo " $(YELLOW)status-list $(NC) List all monitored systems"
34
+ @echo " $(YELLOW)status-test $(NC) Test monitoring configuration"
35
+ @echo " $(YELLOW)status-help $(NC) Show all status commands"`;
36
+
37
+ // Include statement
38
+ const INCLUDE_STATEMENT = '-include node_modules/@amiable-dev/docusaurus-plugin-stentorosaur/templates/Makefile.status';
39
+
40
+ function patchMakefile(projectRoot) {
41
+ const makefilePath = path.join(projectRoot, 'Makefile');
42
+
43
+ if (!fs.existsSync(makefilePath)) {
44
+ console.log('[stentorosaur] No Makefile found - skipping integration');
45
+ console.log('[stentorosaur] Run "make status-help" after creating a Makefile with the include statement');
46
+ return false;
47
+ }
48
+
49
+ let content = fs.readFileSync(makefilePath, 'utf8');
50
+ let modified = false;
51
+
52
+ // Check if include statement already exists
53
+ if (!content.includes('docusaurus-plugin-stentorosaur/templates/Makefile.status')) {
54
+ // Add include at the end
55
+ content = content.trimEnd() + '\n\n# Status Monitoring (Stentorosaur)\n' + INCLUDE_STATEMENT + '\n';
56
+ modified = true;
57
+ console.log('[stentorosaur] Added Makefile.status include statement');
58
+ }
59
+
60
+ // Check if status help section exists in help target
61
+ if (content.includes('help:') && !content.includes('Status Monitoring:')) {
62
+ // Find the help target and add status section before the next target or end
63
+ // Look for pattern: help target ends with empty @echo "" line
64
+ const helpPattern = /(help:.*?@echo\s+["']["']\s*\n)(\n*#|\n*[a-zA-Z_-]+:|$)/s;
65
+ const match = content.match(helpPattern);
66
+
67
+ if (match) {
68
+ // Insert status help section after the last @echo "" in help target
69
+ const insertPoint = match.index + match[1].length;
70
+ content = content.slice(0, insertPoint) + STATUS_HELP_SECTION + '\n' + content.slice(insertPoint);
71
+ modified = true;
72
+ console.log('[stentorosaur] Added Status Monitoring section to make help');
73
+ }
74
+ }
75
+
76
+ if (modified) {
77
+ fs.writeFileSync(makefilePath, content);
78
+ console.log('[stentorosaur] Makefile updated successfully');
79
+ return true;
80
+ } else {
81
+ console.log('[stentorosaur] Makefile already configured');
82
+ return false;
83
+ }
84
+ }
85
+
86
+ function main() {
87
+ // Skip if running in CI or during npm publish
88
+ if (process.env.CI || process.env.npm_config_ignore_scripts) {
89
+ return;
90
+ }
91
+
92
+ const projectRoot = findProjectRoot();
93
+
94
+ if (!projectRoot) {
95
+ // Likely running during development of the plugin itself
96
+ return;
97
+ }
98
+
99
+ // Don't run if this is the plugin's own directory
100
+ const pkgPath = path.join(projectRoot, 'package.json');
101
+ if (fs.existsSync(pkgPath)) {
102
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
103
+ if (pkg.name === '@amiable-dev/docusaurus-plugin-stentorosaur') {
104
+ return;
105
+ }
106
+ }
107
+
108
+ try {
109
+ patchMakefile(projectRoot);
110
+ } catch (err) {
111
+ console.error('[stentorosaur] Warning: Could not patch Makefile:', err.message);
112
+ }
113
+ }
114
+
115
+ main();