@traisetech/autopilot 0.1.7 → 2.0.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.
- package/CHANGELOG.md +121 -67
- package/README.md +214 -226
- package/bin/autopilot.js +130 -72
- package/docs/CONFIGURATION.md +100 -82
- package/docs/TEAM-MODE.md +51 -0
- package/package.json +69 -58
- package/src/commands/dashboard.mjs +142 -0
- package/src/commands/doctor.js +121 -121
- package/src/commands/init.js +214 -129
- package/src/commands/insights.js +231 -0
- package/src/commands/leaderboard.js +70 -0
- package/src/commands/pause.js +18 -0
- package/src/commands/preset.js +121 -0
- package/src/commands/resume.js +17 -0
- package/src/commands/undo.js +84 -0
- package/src/config/defaults.js +54 -36
- package/src/config/ignore.js +153 -136
- package/src/core/commit.js +346 -308
- package/src/core/focus.js +197 -0
- package/src/core/gemini.js +121 -0
- package/src/core/git.js +259 -177
- package/src/core/history.js +69 -0
- package/src/core/safety.js +204 -38
- package/src/core/state.js +71 -0
- package/src/core/watcher.js +405 -277
- package/src/index.js +40 -0
- package/src/integrations/base.js +23 -0
- package/src/integrations/calendar.js +23 -0
- package/src/integrations/manager.js +48 -0
- package/src/utils/logger.js +9 -0
- package/src/utils/update-check.js +151 -151
package/src/index.js
CHANGED
|
@@ -3,7 +3,13 @@ const { initRepo } = require('./commands/init');
|
|
|
3
3
|
const { startWatcher } = require('./commands/start');
|
|
4
4
|
const { stopWatcher } = require('./commands/stop');
|
|
5
5
|
const { statusWatcher } = require('./commands/status');
|
|
6
|
+
const undoCommand = require('./commands/undo');
|
|
6
7
|
const { doctor } = require('./commands/doctor');
|
|
8
|
+
const { insights } = require('./commands/insights');
|
|
9
|
+
const pauseCommand = require('./commands/pause');
|
|
10
|
+
const resumeCommand = require('./commands/resume');
|
|
11
|
+
const runDashboard = require('./commands/dashboard');
|
|
12
|
+
const { leaderboard } = require('./commands/leaderboard');
|
|
7
13
|
const pkg = require('../package.json');
|
|
8
14
|
|
|
9
15
|
function run() {
|
|
@@ -14,6 +20,12 @@ function run() {
|
|
|
14
20
|
.description('Git automation with safety rails')
|
|
15
21
|
.version(pkg.version, '-v, --version', 'Show version');
|
|
16
22
|
|
|
23
|
+
program
|
|
24
|
+
.command('leaderboard')
|
|
25
|
+
.description('View or sync with the global leaderboard')
|
|
26
|
+
.option('--sync', 'Sync your local stats to the leaderboard')
|
|
27
|
+
.action(leaderboard);
|
|
28
|
+
|
|
17
29
|
program
|
|
18
30
|
.command('init')
|
|
19
31
|
.description('Initialize autopilot configuration in repository')
|
|
@@ -34,11 +46,39 @@ function run() {
|
|
|
34
46
|
.description('Show autopilot watcher status')
|
|
35
47
|
.action(statusWatcher);
|
|
36
48
|
|
|
49
|
+
program
|
|
50
|
+
.command('undo')
|
|
51
|
+
.description('Undo the last Autopilot commit')
|
|
52
|
+
.option('-c, --count <n>', 'Number of commits to undo', '1')
|
|
53
|
+
.action(undoCommand);
|
|
54
|
+
|
|
55
|
+
program
|
|
56
|
+
.command('pause [reason]')
|
|
57
|
+
.description('Pause Autopilot watcher')
|
|
58
|
+
.action(pauseCommand);
|
|
59
|
+
|
|
60
|
+
program
|
|
61
|
+
.command('resume')
|
|
62
|
+
.description('Resume Autopilot watcher')
|
|
63
|
+
.action(resumeCommand);
|
|
64
|
+
|
|
65
|
+
program
|
|
66
|
+
.command('dashboard')
|
|
67
|
+
.description('View real-time Autopilot dashboard')
|
|
68
|
+
.action(runDashboard);
|
|
69
|
+
|
|
37
70
|
program
|
|
38
71
|
.command('doctor')
|
|
39
72
|
.description('Diagnose and validate autopilot setup')
|
|
40
73
|
.action(doctor);
|
|
41
74
|
|
|
75
|
+
program
|
|
76
|
+
.command('insights')
|
|
77
|
+
.description('View productivity insights and focus analytics')
|
|
78
|
+
.option('-f, --format <type>', 'Output format (json, text)', 'text')
|
|
79
|
+
.option('-e, --export <type>', 'Export insights (csv)')
|
|
80
|
+
.action(insights);
|
|
81
|
+
|
|
42
82
|
program
|
|
43
83
|
.addHelpText('after', '\nBuilt by Praise Masunga (PraiseTechzw)')
|
|
44
84
|
.addHelpCommand(true, 'Show help for command')
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Integration Class
|
|
3
|
+
*/
|
|
4
|
+
class Integration {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.config = config;
|
|
7
|
+
this.name = 'base';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async connect() {
|
|
11
|
+
throw new Error('Not implemented');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async onFocusStart(session) {
|
|
15
|
+
// Optional
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async onFocusEnd(session) {
|
|
19
|
+
// Optional
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = Integration;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar Integration (Mock)
|
|
3
|
+
*/
|
|
4
|
+
const Integration = require('./base');
|
|
5
|
+
const logger = require('../utils/logger');
|
|
6
|
+
|
|
7
|
+
class CalendarIntegration extends Integration {
|
|
8
|
+
constructor(config) {
|
|
9
|
+
super(config);
|
|
10
|
+
this.name = 'calendar';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async onFocusStart(session) {
|
|
14
|
+
logger.info('📅 Blocking calendar for focus time...');
|
|
15
|
+
// Implementation would go here (e.g. Google Calendar API)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async onFocusEnd(session) {
|
|
19
|
+
logger.info('📅 Releasing calendar block.');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = CalendarIntegration;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration Manager
|
|
3
|
+
* Handles communication with external tools
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const logger = require('../utils/logger');
|
|
7
|
+
|
|
8
|
+
class IntegrationManager {
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.config = config || {};
|
|
11
|
+
this.integrations = [];
|
|
12
|
+
this.active = false;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
register(integration) {
|
|
16
|
+
this.integrations.push(integration);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async notifyFocusStart(file) {
|
|
20
|
+
if (!this.config.integrationsEnabled) return;
|
|
21
|
+
|
|
22
|
+
logger.debug('[Integrations] Notifying focus start...');
|
|
23
|
+
this.active = true;
|
|
24
|
+
|
|
25
|
+
await Promise.all(this.integrations.map(async (integration) => {
|
|
26
|
+
try {
|
|
27
|
+
await integration.onFocusStart({ file, startTime: Date.now() });
|
|
28
|
+
} catch (err) {
|
|
29
|
+
logger.warn(`Integration ${integration.name} failed: ${err.message}`);
|
|
30
|
+
}
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async notifyFocusEnd() {
|
|
35
|
+
if (!this.active) return;
|
|
36
|
+
this.active = false;
|
|
37
|
+
|
|
38
|
+
await Promise.all(this.integrations.map(async (integration) => {
|
|
39
|
+
try {
|
|
40
|
+
await integration.onFocusEnd({ endTime: Date.now() });
|
|
41
|
+
} catch (err) {
|
|
42
|
+
logger.warn(`Integration ${integration.name} failed: ${err.message}`);
|
|
43
|
+
}
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = IntegrationManager;
|
package/src/utils/logger.js
CHANGED
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
const logger = {
|
|
7
|
+
colors: {
|
|
8
|
+
cyan: (text) => `\x1b[36m${text}\x1b[0m`,
|
|
9
|
+
green: (text) => `\x1b[32m${text}\x1b[0m`,
|
|
10
|
+
yellow: (text) => `\x1b[33m${text}\x1b[0m`,
|
|
11
|
+
red: (text) => `\x1b[31m${text}\x1b[0m`,
|
|
12
|
+
blue: (text) => `\x1b[34m${text}\x1b[0m`,
|
|
13
|
+
bold: (text) => `\x1b[1m${text}\x1b[0m`
|
|
14
|
+
},
|
|
15
|
+
|
|
7
16
|
/**
|
|
8
17
|
* Log informational message
|
|
9
18
|
* @param {string} message - Message to log
|
|
@@ -1,151 +1,151 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Update checker utility
|
|
3
|
-
* Checks for new versions on npm registry
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const https = require('https');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const fs = require('fs-extra');
|
|
9
|
-
const { getConfigDir, ensureConfigDir } = require('./paths');
|
|
10
|
-
const pkg = require('../../package.json');
|
|
11
|
-
|
|
12
|
-
const CHECK_INTERVAL = 1000 * 60 * 60 * 24; // 24 hours
|
|
13
|
-
const REGISTRY_URL = 'https://registry.npmjs.org';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Fetch latest version from npm registry
|
|
17
|
-
* @param {string} packageName
|
|
18
|
-
* @returns {Promise<string>}
|
|
19
|
-
*/
|
|
20
|
-
async function getLatestVersion(packageName) {
|
|
21
|
-
return new Promise((resolve, reject) => {
|
|
22
|
-
const url = `${REGISTRY_URL}/${packageName}/latest`;
|
|
23
|
-
|
|
24
|
-
const req = https.get(url, {
|
|
25
|
-
timeout: 1500, // Short timeout to avoid hanging
|
|
26
|
-
headers: {
|
|
27
|
-
'User-Agent': `autopilot-cli/${pkg.version}`
|
|
28
|
-
}
|
|
29
|
-
}, (res) => {
|
|
30
|
-
if (res.statusCode !== 200) {
|
|
31
|
-
res.resume();
|
|
32
|
-
return reject(new Error(`Status code: ${res.statusCode}`));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
let data = '';
|
|
36
|
-
res.on('data', (chunk) => data += chunk);
|
|
37
|
-
res.on('end', () => {
|
|
38
|
-
try {
|
|
39
|
-
const json = JSON.parse(data);
|
|
40
|
-
resolve(json.version);
|
|
41
|
-
} catch (e) {
|
|
42
|
-
reject(e);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
req.on('error', reject);
|
|
48
|
-
req.on('timeout', () => {
|
|
49
|
-
req.destroy();
|
|
50
|
-
reject(new Error('Timeout'));
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Compare two semver strings
|
|
57
|
-
* @param {string} latest
|
|
58
|
-
* @param {string} current
|
|
59
|
-
* @returns {boolean} true if latest > current
|
|
60
|
-
*/
|
|
61
|
-
function isNewer(latest, current) {
|
|
62
|
-
if (!latest || !current) return false;
|
|
63
|
-
|
|
64
|
-
const l = latest.split(/[\.-]/).map(n => parseInt(n, 10) || 0);
|
|
65
|
-
const c = current.split(/[\.-]/).map(n => parseInt(n, 10) || 0);
|
|
66
|
-
|
|
67
|
-
// Compare major, minor, patch
|
|
68
|
-
for (let i = 0; i < 3; i++) {
|
|
69
|
-
if (l[i] > c[i]) return true;
|
|
70
|
-
if (l[i] < c[i]) return false;
|
|
71
|
-
}
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function center(text, width) {
|
|
76
|
-
const visibleLen = text.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
77
|
-
const padding = Math.max(0, width - visibleLen);
|
|
78
|
-
const left = Math.floor(padding / 2);
|
|
79
|
-
const right = padding - left;
|
|
80
|
-
return ' '.repeat(left) + text + ' '.repeat(right);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Check for updates and notify user
|
|
85
|
-
*/
|
|
86
|
-
async function checkForUpdate() {
|
|
87
|
-
try {
|
|
88
|
-
await ensureConfigDir();
|
|
89
|
-
const configDir = getConfigDir();
|
|
90
|
-
const cachePath = path.join(configDir, 'update-check.json');
|
|
91
|
-
|
|
92
|
-
let cache = { lastCheck: 0, latestVersion: null, hasUpdate: false };
|
|
93
|
-
|
|
94
|
-
try {
|
|
95
|
-
if (await fs.pathExists(cachePath)) {
|
|
96
|
-
cache = await fs.readJson(cachePath);
|
|
97
|
-
}
|
|
98
|
-
} catch (e) {
|
|
99
|
-
// Ignore cache read errors
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const now = Date.now();
|
|
103
|
-
const shouldCheck = !cache.lastCheck || (now - cache.lastCheck > CHECK_INTERVAL);
|
|
104
|
-
|
|
105
|
-
if (shouldCheck) {
|
|
106
|
-
try {
|
|
107
|
-
const latestVersion = await getLatestVersion(pkg.name);
|
|
108
|
-
const hasUpdate = isNewer(latestVersion, pkg.version);
|
|
109
|
-
|
|
110
|
-
cache = {
|
|
111
|
-
lastCheck: now,
|
|
112
|
-
latestVersion,
|
|
113
|
-
hasUpdate
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
// Save cache without awaiting to not block if FS is slow?
|
|
117
|
-
// Better to await to ensure it saves.
|
|
118
|
-
await fs.writeJson(cachePath, cache);
|
|
119
|
-
} catch (e) {
|
|
120
|
-
// Failed to check, maybe offline.
|
|
121
|
-
// Just update lastCheck to avoid retrying immediately on next run?
|
|
122
|
-
// Or leave it to retry next time.
|
|
123
|
-
// Let's leave it so we retry next run.
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (cache.hasUpdate && cache.latestVersion) {
|
|
128
|
-
const v = pkg.version;
|
|
129
|
-
const latest = cache.latestVersion;
|
|
130
|
-
|
|
131
|
-
// Boxed notification
|
|
132
|
-
console.log('\n');
|
|
133
|
-
console.log(' ╭──────────────────────────────────────────────────╮');
|
|
134
|
-
console.log(' │ │');
|
|
135
|
-
console.log(` │ Update available ${v.dim()} → ${latest.green()} │`);
|
|
136
|
-
console.log(` │ Run ${('npm i -g ' + pkg.name).cyan()} to update │`);
|
|
137
|
-
console.log(' │ │');
|
|
138
|
-
console.log(' ╰──────────────────────────────────────────────────╯');
|
|
139
|
-
console.log('\n');
|
|
140
|
-
}
|
|
141
|
-
} catch (error) {
|
|
142
|
-
// Fail silently
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Add simple color support since we don't have chalk
|
|
147
|
-
String.prototype.green = function() { return `\x1b[32m${this}\x1b[0m`; };
|
|
148
|
-
String.prototype.cyan = function() { return `\x1b[36m${this}\x1b[0m`; };
|
|
149
|
-
String.prototype.dim = function() { return `\x1b[2m${this}\x1b[0m`; };
|
|
150
|
-
|
|
151
|
-
module.exports = { checkForUpdate };
|
|
1
|
+
/**
|
|
2
|
+
* Update checker utility
|
|
3
|
+
* Checks for new versions on npm registry
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const https = require('https');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const fs = require('fs-extra');
|
|
9
|
+
const { getConfigDir, ensureConfigDir } = require('./paths');
|
|
10
|
+
const pkg = require('../../package.json');
|
|
11
|
+
|
|
12
|
+
const CHECK_INTERVAL = 1000 * 60 * 60 * 24; // 24 hours
|
|
13
|
+
const REGISTRY_URL = 'https://registry.npmjs.org';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Fetch latest version from npm registry
|
|
17
|
+
* @param {string} packageName
|
|
18
|
+
* @returns {Promise<string>}
|
|
19
|
+
*/
|
|
20
|
+
async function getLatestVersion(packageName) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const url = `${REGISTRY_URL}/${packageName}/latest`;
|
|
23
|
+
|
|
24
|
+
const req = https.get(url, {
|
|
25
|
+
timeout: 1500, // Short timeout to avoid hanging
|
|
26
|
+
headers: {
|
|
27
|
+
'User-Agent': `autopilot-cli/${pkg.version}`
|
|
28
|
+
}
|
|
29
|
+
}, (res) => {
|
|
30
|
+
if (res.statusCode !== 200) {
|
|
31
|
+
res.resume();
|
|
32
|
+
return reject(new Error(`Status code: ${res.statusCode}`));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let data = '';
|
|
36
|
+
res.on('data', (chunk) => data += chunk);
|
|
37
|
+
res.on('end', () => {
|
|
38
|
+
try {
|
|
39
|
+
const json = JSON.parse(data);
|
|
40
|
+
resolve(json.version);
|
|
41
|
+
} catch (e) {
|
|
42
|
+
reject(e);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
req.on('error', reject);
|
|
48
|
+
req.on('timeout', () => {
|
|
49
|
+
req.destroy();
|
|
50
|
+
reject(new Error('Timeout'));
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Compare two semver strings
|
|
57
|
+
* @param {string} latest
|
|
58
|
+
* @param {string} current
|
|
59
|
+
* @returns {boolean} true if latest > current
|
|
60
|
+
*/
|
|
61
|
+
function isNewer(latest, current) {
|
|
62
|
+
if (!latest || !current) return false;
|
|
63
|
+
|
|
64
|
+
const l = latest.split(/[\.-]/).map(n => parseInt(n, 10) || 0);
|
|
65
|
+
const c = current.split(/[\.-]/).map(n => parseInt(n, 10) || 0);
|
|
66
|
+
|
|
67
|
+
// Compare major, minor, patch
|
|
68
|
+
for (let i = 0; i < 3; i++) {
|
|
69
|
+
if (l[i] > c[i]) return true;
|
|
70
|
+
if (l[i] < c[i]) return false;
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function center(text, width) {
|
|
76
|
+
const visibleLen = text.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
77
|
+
const padding = Math.max(0, width - visibleLen);
|
|
78
|
+
const left = Math.floor(padding / 2);
|
|
79
|
+
const right = padding - left;
|
|
80
|
+
return ' '.repeat(left) + text + ' '.repeat(right);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Check for updates and notify user
|
|
85
|
+
*/
|
|
86
|
+
async function checkForUpdate() {
|
|
87
|
+
try {
|
|
88
|
+
await ensureConfigDir();
|
|
89
|
+
const configDir = getConfigDir();
|
|
90
|
+
const cachePath = path.join(configDir, 'update-check.json');
|
|
91
|
+
|
|
92
|
+
let cache = { lastCheck: 0, latestVersion: null, hasUpdate: false };
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
if (await fs.pathExists(cachePath)) {
|
|
96
|
+
cache = await fs.readJson(cachePath);
|
|
97
|
+
}
|
|
98
|
+
} catch (e) {
|
|
99
|
+
// Ignore cache read errors
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const now = Date.now();
|
|
103
|
+
const shouldCheck = !cache.lastCheck || (now - cache.lastCheck > CHECK_INTERVAL);
|
|
104
|
+
|
|
105
|
+
if (shouldCheck) {
|
|
106
|
+
try {
|
|
107
|
+
const latestVersion = await getLatestVersion(pkg.name);
|
|
108
|
+
const hasUpdate = isNewer(latestVersion, pkg.version);
|
|
109
|
+
|
|
110
|
+
cache = {
|
|
111
|
+
lastCheck: now,
|
|
112
|
+
latestVersion,
|
|
113
|
+
hasUpdate
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Save cache without awaiting to not block if FS is slow?
|
|
117
|
+
// Better to await to ensure it saves.
|
|
118
|
+
await fs.writeJson(cachePath, cache);
|
|
119
|
+
} catch (e) {
|
|
120
|
+
// Failed to check, maybe offline.
|
|
121
|
+
// Just update lastCheck to avoid retrying immediately on next run?
|
|
122
|
+
// Or leave it to retry next time.
|
|
123
|
+
// Let's leave it so we retry next run.
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (cache.hasUpdate && cache.latestVersion) {
|
|
128
|
+
const v = pkg.version;
|
|
129
|
+
const latest = cache.latestVersion;
|
|
130
|
+
|
|
131
|
+
// Boxed notification
|
|
132
|
+
console.log('\n');
|
|
133
|
+
console.log(' ╭──────────────────────────────────────────────────╮');
|
|
134
|
+
console.log(' │ │');
|
|
135
|
+
console.log(` │ Update available ${v.dim()} → ${latest.green()} │`);
|
|
136
|
+
console.log(` │ Run ${('npm i -g ' + pkg.name).cyan()} to update │`);
|
|
137
|
+
console.log(' │ │');
|
|
138
|
+
console.log(' ╰──────────────────────────────────────────────────╯');
|
|
139
|
+
console.log('\n');
|
|
140
|
+
}
|
|
141
|
+
} catch (error) {
|
|
142
|
+
// Fail silently
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Add simple color support since we don't have chalk
|
|
147
|
+
String.prototype.green = function() { return `\x1b[32m${this}\x1b[0m`; };
|
|
148
|
+
String.prototype.cyan = function() { return `\x1b[36m${this}\x1b[0m`; };
|
|
149
|
+
String.prototype.dim = function() { return `\x1b[2m${this}\x1b[0m`; };
|
|
150
|
+
|
|
151
|
+
module.exports = { checkForUpdate };
|