@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/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;
@@ -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 };