pilot-ai 0.4.0 → 0.5.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.
Files changed (108) hide show
  1. package/README.md +75 -5
  2. package/dist/agent/claude.d.ts +7 -0
  3. package/dist/agent/claude.d.ts.map +1 -1
  4. package/dist/agent/claude.js +30 -2
  5. package/dist/agent/claude.js.map +1 -1
  6. package/dist/agent/core.d.ts +3 -0
  7. package/dist/agent/core.d.ts.map +1 -1
  8. package/dist/agent/core.js +87 -6
  9. package/dist/agent/core.js.map +1 -1
  10. package/dist/agent/queue.d.ts +12 -7
  11. package/dist/agent/queue.d.ts.map +1 -1
  12. package/dist/agent/queue.js +89 -0
  13. package/dist/agent/queue.js.map +1 -1
  14. package/dist/agent/session.d.ts +44 -0
  15. package/dist/agent/session.d.ts.map +1 -0
  16. package/dist/agent/session.js +131 -0
  17. package/dist/agent/session.js.map +1 -0
  18. package/dist/api/server.d.ts.map +1 -1
  19. package/dist/api/server.js +17 -2
  20. package/dist/api/server.js.map +1 -1
  21. package/dist/cli/doctor.d.ts +2 -0
  22. package/dist/cli/doctor.d.ts.map +1 -0
  23. package/dist/cli/doctor.js +198 -0
  24. package/dist/cli/doctor.js.map +1 -0
  25. package/dist/cli/init.d.ts.map +1 -1
  26. package/dist/cli/init.js +51 -1
  27. package/dist/cli/init.js.map +1 -1
  28. package/dist/config/schema.d.ts +6 -0
  29. package/dist/config/schema.d.ts.map +1 -1
  30. package/dist/config/schema.js +9 -0
  31. package/dist/config/schema.js.map +1 -1
  32. package/dist/index.js +7 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/messenger/slack.d.ts +1 -0
  35. package/dist/messenger/slack.d.ts.map +1 -1
  36. package/dist/messenger/slack.js +15 -6
  37. package/dist/messenger/slack.js.map +1 -1
  38. package/dist/messenger/split.d.ts +16 -0
  39. package/dist/messenger/split.d.ts.map +1 -0
  40. package/dist/messenger/split.js +66 -0
  41. package/dist/messenger/split.js.map +1 -0
  42. package/dist/messenger/telegram.d.ts +1 -0
  43. package/dist/messenger/telegram.d.ts.map +1 -1
  44. package/dist/messenger/telegram.js +14 -5
  45. package/dist/messenger/telegram.js.map +1 -1
  46. package/dist/security/permissions.d.ts +7 -0
  47. package/dist/security/permissions.d.ts.map +1 -1
  48. package/dist/security/permissions.js +57 -1
  49. package/dist/security/permissions.js.map +1 -1
  50. package/dist/security/sandbox.d.ts +1 -0
  51. package/dist/security/sandbox.d.ts.map +1 -1
  52. package/dist/security/sandbox.js +61 -4
  53. package/dist/security/sandbox.js.map +1 -1
  54. package/dist/tools/calendar.d.ts.map +1 -1
  55. package/dist/tools/calendar.js +9 -14
  56. package/dist/tools/calendar.js.map +1 -1
  57. package/dist/tools/clipboard.d.ts.map +1 -1
  58. package/dist/tools/clipboard.js +2 -2
  59. package/dist/tools/clipboard.js.map +1 -1
  60. package/dist/tools/email.d.ts +1 -0
  61. package/dist/tools/email.d.ts.map +1 -1
  62. package/dist/tools/email.js +26 -4
  63. package/dist/tools/email.js.map +1 -1
  64. package/dist/tools/filesystem.d.ts.map +1 -1
  65. package/dist/tools/filesystem.js +22 -6
  66. package/dist/tools/filesystem.js.map +1 -1
  67. package/dist/tools/github.d.ts.map +1 -1
  68. package/dist/tools/github.js +20 -0
  69. package/dist/tools/github.js.map +1 -1
  70. package/dist/tools/google-auth.d.ts +1 -0
  71. package/dist/tools/google-auth.d.ts.map +1 -1
  72. package/dist/tools/google-auth.js +26 -4
  73. package/dist/tools/google-auth.js.map +1 -1
  74. package/dist/tools/notification.d.ts.map +1 -1
  75. package/dist/tools/notification.js +2 -7
  76. package/dist/tools/notification.js.map +1 -1
  77. package/dist/tools/obsidian.d.ts.map +1 -1
  78. package/dist/tools/obsidian.js +23 -3
  79. package/dist/tools/obsidian.js.map +1 -1
  80. package/dist/utils/circuit-breaker.d.ts +30 -0
  81. package/dist/utils/circuit-breaker.d.ts.map +1 -0
  82. package/dist/utils/circuit-breaker.js +69 -0
  83. package/dist/utils/circuit-breaker.js.map +1 -0
  84. package/dist/utils/errors.d.ts +55 -0
  85. package/dist/utils/errors.d.ts.map +1 -0
  86. package/dist/utils/errors.js +79 -0
  87. package/dist/utils/errors.js.map +1 -0
  88. package/dist/utils/escape.d.ts +15 -0
  89. package/dist/utils/escape.d.ts.map +1 -0
  90. package/dist/utils/escape.js +23 -0
  91. package/dist/utils/escape.js.map +1 -0
  92. package/dist/utils/logger.d.ts +39 -0
  93. package/dist/utils/logger.d.ts.map +1 -0
  94. package/dist/utils/logger.js +119 -0
  95. package/dist/utils/logger.js.map +1 -0
  96. package/dist/utils/oauth-manager.d.ts +49 -0
  97. package/dist/utils/oauth-manager.d.ts.map +1 -0
  98. package/dist/utils/oauth-manager.js +112 -0
  99. package/dist/utils/oauth-manager.js.map +1 -0
  100. package/dist/utils/rate-limiter.d.ts +24 -0
  101. package/dist/utils/rate-limiter.d.ts.map +1 -0
  102. package/dist/utils/rate-limiter.js +52 -0
  103. package/dist/utils/rate-limiter.js.map +1 -0
  104. package/dist/utils/retry.d.ts +20 -0
  105. package/dist/utils/retry.d.ts.map +1 -0
  106. package/dist/utils/retry.js +45 -0
  107. package/dist/utils/retry.js.map +1 -0
  108. package/package.json +1 -1
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Structured JSON logger with correlation IDs, log levels, and file output.
3
+ * Replaces ad-hoc console.error() calls throughout the codebase.
4
+ */
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import { getPilotDir } from '../config/store.js';
8
+ const LEVEL_PRIORITY = {
9
+ debug: 0,
10
+ info: 1,
11
+ warn: 2,
12
+ error: 3,
13
+ };
14
+ let currentCorrelationId;
15
+ let minLevel = 'info';
16
+ /** Metrics counters */
17
+ const metrics = {
18
+ requestCount: 0,
19
+ errorCount: 0,
20
+ totalResponseTimeMs: 0,
21
+ };
22
+ /**
23
+ * Set the minimum log level (default: info).
24
+ */
25
+ export function setLogLevel(level) {
26
+ minLevel = level;
27
+ }
28
+ /**
29
+ * Set the current correlation ID for request tracing.
30
+ */
31
+ export function setCorrelationId(id) {
32
+ currentCorrelationId = id;
33
+ }
34
+ /**
35
+ * Generate a new correlation ID for a message processing cycle.
36
+ */
37
+ export function generateCorrelationId() {
38
+ const id = `req-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
39
+ currentCorrelationId = id;
40
+ return id;
41
+ }
42
+ /**
43
+ * Get the current correlation ID.
44
+ */
45
+ export function getCorrelationId() {
46
+ return currentCorrelationId;
47
+ }
48
+ function getLogDir() {
49
+ return path.join(getPilotDir(), 'logs');
50
+ }
51
+ function getLogFilePath() {
52
+ const today = new Date().toISOString().slice(0, 10);
53
+ return path.join(getLogDir(), `pilot-${today}.log`);
54
+ }
55
+ function writeLog(entry) {
56
+ if (LEVEL_PRIORITY[entry.level] < LEVEL_PRIORITY[minLevel])
57
+ return;
58
+ const line = JSON.stringify(entry);
59
+ // Write to file (sync append for reliability)
60
+ try {
61
+ const logDir = getLogDir();
62
+ fs.mkdirSync(logDir, { recursive: true });
63
+ fs.appendFileSync(getLogFilePath(), line + '\n');
64
+ }
65
+ catch {
66
+ // Best-effort logging
67
+ }
68
+ // Also write errors to stderr
69
+ if (entry.level === 'error') {
70
+ console.error(`[${entry.timestamp}] ERROR: ${entry.message}`);
71
+ }
72
+ }
73
+ export function log(level, message, extra) {
74
+ writeLog({
75
+ timestamp: new Date().toISOString(),
76
+ level,
77
+ message,
78
+ correlationId: currentCorrelationId,
79
+ ...extra,
80
+ });
81
+ }
82
+ export function debug(message, extra) {
83
+ log('debug', message, extra);
84
+ }
85
+ export function info(message, extra) {
86
+ log('info', message, extra);
87
+ }
88
+ export function warn(message, extra) {
89
+ log('warn', message, extra);
90
+ }
91
+ export function error(message, extra) {
92
+ log('error', message, extra);
93
+ }
94
+ // --- Metrics ---
95
+ export function recordRequest() {
96
+ metrics.requestCount++;
97
+ }
98
+ export function recordError() {
99
+ metrics.errorCount++;
100
+ }
101
+ export function recordResponseTime(ms) {
102
+ metrics.totalResponseTimeMs += ms;
103
+ }
104
+ export function getMetrics() {
105
+ return {
106
+ requestCount: metrics.requestCount,
107
+ errorCount: metrics.errorCount,
108
+ avgResponseTimeMs: metrics.requestCount > 0
109
+ ? Math.round(metrics.totalResponseTimeMs / metrics.requestCount)
110
+ : 0,
111
+ };
112
+ }
113
+ /**
114
+ * No-op for backward compatibility. Sync writes need no cleanup.
115
+ */
116
+ export function closeLogger() {
117
+ // No-op: using appendFileSync, no stream to close
118
+ }
119
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Unified OAuth token manager with Keychain storage and automatic refresh.
3
+ * Consolidates token lifecycle management for all Google services.
4
+ */
5
+ export interface OAuthTokens {
6
+ accessToken: string;
7
+ refreshToken: string;
8
+ expiresAt: number;
9
+ }
10
+ export interface OAuthManagerOptions {
11
+ /** Keychain key name for storing tokens */
12
+ keychainKey: string;
13
+ /** OAuth2 token endpoint URL */
14
+ tokenUrl: string;
15
+ /** OAuth2 client ID */
16
+ clientId: string;
17
+ /** OAuth2 client secret */
18
+ clientSecret: string;
19
+ /** Time in ms before expiry to trigger preemptive refresh (default: 5 minutes) */
20
+ refreshMarginMs?: number;
21
+ }
22
+ export declare class OAuthManager {
23
+ private tokens;
24
+ private readonly options;
25
+ constructor(options: OAuthManagerOptions);
26
+ /**
27
+ * Load tokens from Keychain.
28
+ */
29
+ loadTokens(): Promise<OAuthTokens | null>;
30
+ /**
31
+ * Save tokens to Keychain.
32
+ */
33
+ saveTokens(tokens: OAuthTokens): Promise<void>;
34
+ /**
35
+ * Delete tokens from Keychain.
36
+ */
37
+ deleteTokens(): Promise<void>;
38
+ /**
39
+ * Returns a valid access token, refreshing if expired or close to expiring.
40
+ * Uses retry with exponential backoff for refresh failures.
41
+ */
42
+ getAccessToken(): Promise<string>;
43
+ /**
44
+ * Exchange an authorization code for tokens.
45
+ */
46
+ exchangeCode(code: string, redirectUri: string, scopes?: string[]): Promise<OAuthTokens>;
47
+ private refreshToken;
48
+ }
49
+ //# sourceMappingURL=oauth-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-manager.d.ts","sourceRoot":"","sources":["../../src/utils/oauth-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,kFAAkF;IAClF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAID,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;gBAE5C,OAAO,EAAE,mBAAmB;IAOxC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAW/C;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpD;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAKnC;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAmBvC;;OAEG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;YA8BhF,YAAY;CA0B3B"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Unified OAuth token manager with Keychain storage and automatic refresh.
3
+ * Consolidates token lifecycle management for all Google services.
4
+ */
5
+ import { getSecret, setSecret, deleteSecret } from '../config/keychain.js';
6
+ import { withRetry } from './retry.js';
7
+ const DEFAULT_REFRESH_MARGIN_MS = 5 * 60 * 1000; // 5 minutes
8
+ export class OAuthManager {
9
+ tokens = null;
10
+ options;
11
+ constructor(options) {
12
+ this.options = {
13
+ ...options,
14
+ refreshMarginMs: options.refreshMarginMs ?? DEFAULT_REFRESH_MARGIN_MS,
15
+ };
16
+ }
17
+ /**
18
+ * Load tokens from Keychain.
19
+ */
20
+ async loadTokens() {
21
+ const secret = await getSecret(this.options.keychainKey);
22
+ if (!secret)
23
+ return null;
24
+ try {
25
+ this.tokens = JSON.parse(secret);
26
+ return this.tokens;
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ /**
33
+ * Save tokens to Keychain.
34
+ */
35
+ async saveTokens(tokens) {
36
+ this.tokens = tokens;
37
+ await setSecret(this.options.keychainKey, JSON.stringify(tokens));
38
+ }
39
+ /**
40
+ * Delete tokens from Keychain.
41
+ */
42
+ async deleteTokens() {
43
+ this.tokens = null;
44
+ await deleteSecret(this.options.keychainKey);
45
+ }
46
+ /**
47
+ * Returns a valid access token, refreshing if expired or close to expiring.
48
+ * Uses retry with exponential backoff for refresh failures.
49
+ */
50
+ async getAccessToken() {
51
+ if (!this.tokens) {
52
+ const loaded = await this.loadTokens();
53
+ if (!loaded)
54
+ throw new Error('No OAuth tokens available. Run OAuth flow first.');
55
+ this.tokens = loaded;
56
+ }
57
+ // Check if token is still valid (with margin for preemptive refresh)
58
+ if (Date.now() < this.tokens.expiresAt - this.options.refreshMarginMs) {
59
+ return this.tokens.accessToken;
60
+ }
61
+ // Refresh with retry
62
+ return withRetry(() => this.refreshToken(), { maxAttempts: 3, baseDelay: 1000, jitter: true });
63
+ }
64
+ /**
65
+ * Exchange an authorization code for tokens.
66
+ */
67
+ async exchangeCode(code, redirectUri, scopes) {
68
+ const res = await fetch(this.options.tokenUrl, {
69
+ method: 'POST',
70
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
71
+ body: new URLSearchParams({
72
+ code,
73
+ client_id: this.options.clientId,
74
+ client_secret: this.options.clientSecret,
75
+ redirect_uri: redirectUri,
76
+ grant_type: 'authorization_code',
77
+ }),
78
+ });
79
+ const data = (await res.json());
80
+ if (data.error)
81
+ throw new Error(`OAuth exchange error: ${data.error}`);
82
+ const tokens = {
83
+ accessToken: data.access_token,
84
+ refreshToken: data.refresh_token,
85
+ expiresAt: Date.now() + data.expires_in * 1000,
86
+ };
87
+ await this.saveTokens(tokens);
88
+ return tokens;
89
+ }
90
+ async refreshToken() {
91
+ if (!this.tokens)
92
+ throw new Error('No tokens to refresh');
93
+ const res = await fetch(this.options.tokenUrl, {
94
+ method: 'POST',
95
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
96
+ body: new URLSearchParams({
97
+ refresh_token: this.tokens.refreshToken,
98
+ client_id: this.options.clientId,
99
+ client_secret: this.options.clientSecret,
100
+ grant_type: 'refresh_token',
101
+ }),
102
+ });
103
+ const data = (await res.json());
104
+ if (data.error)
105
+ throw new Error(`OAuth refresh error: ${data.error}`);
106
+ this.tokens.accessToken = data.access_token;
107
+ this.tokens.expiresAt = Date.now() + data.expires_in * 1000;
108
+ await this.saveTokens(this.tokens);
109
+ return this.tokens.accessToken;
110
+ }
111
+ }
112
+ //# sourceMappingURL=oauth-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-manager.js","sourceRoot":"","sources":["../../src/utils/oauth-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Token bucket rate limiter for outbound message throttling.
3
+ */
4
+ export declare class RateLimiter {
5
+ private tokens;
6
+ private readonly maxTokens;
7
+ private readonly refillRate;
8
+ private lastRefill;
9
+ /**
10
+ * @param maxTokens Maximum burst capacity
11
+ * @param refillRate Tokens added per second
12
+ */
13
+ constructor(maxTokens: number, refillRate: number);
14
+ /**
15
+ * Waits until a token is available, then consumes it.
16
+ */
17
+ acquire(): Promise<void>;
18
+ /**
19
+ * Tries to consume a token without waiting. Returns false if none available.
20
+ */
21
+ tryAcquire(): boolean;
22
+ private refill;
23
+ }
24
+ //# sourceMappingURL=rate-limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/utils/rate-limiter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,UAAU,CAAS;IAE3B;;;OAGG;gBACS,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAOjD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAa9B;;OAEG;IACH,UAAU,IAAI,OAAO;IASrB,OAAO,CAAC,MAAM;CAMf"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Token bucket rate limiter for outbound message throttling.
3
+ */
4
+ export class RateLimiter {
5
+ tokens;
6
+ maxTokens;
7
+ refillRate; // tokens per second
8
+ lastRefill;
9
+ /**
10
+ * @param maxTokens Maximum burst capacity
11
+ * @param refillRate Tokens added per second
12
+ */
13
+ constructor(maxTokens, refillRate) {
14
+ this.maxTokens = maxTokens;
15
+ this.tokens = maxTokens;
16
+ this.refillRate = refillRate;
17
+ this.lastRefill = Date.now();
18
+ }
19
+ /**
20
+ * Waits until a token is available, then consumes it.
21
+ */
22
+ async acquire() {
23
+ this.refill();
24
+ if (this.tokens >= 1) {
25
+ this.tokens -= 1;
26
+ return;
27
+ }
28
+ // Wait until a token is available
29
+ const waitMs = ((1 - this.tokens) / this.refillRate) * 1000;
30
+ await new Promise((resolve) => setTimeout(resolve, Math.ceil(waitMs)));
31
+ this.refill();
32
+ this.tokens -= 1;
33
+ }
34
+ /**
35
+ * Tries to consume a token without waiting. Returns false if none available.
36
+ */
37
+ tryAcquire() {
38
+ this.refill();
39
+ if (this.tokens >= 1) {
40
+ this.tokens -= 1;
41
+ return true;
42
+ }
43
+ return false;
44
+ }
45
+ refill() {
46
+ const now = Date.now();
47
+ const elapsed = (now - this.lastRefill) / 1000;
48
+ this.tokens = Math.min(this.maxTokens, this.tokens + elapsed * this.refillRate);
49
+ this.lastRefill = now;
50
+ }
51
+ }
52
+ //# sourceMappingURL=rate-limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/utils/rate-limiter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,OAAO,WAAW;IACd,MAAM,CAAS;IACN,SAAS,CAAS;IAClB,UAAU,CAAS,CAAC,oBAAoB;IACjD,UAAU,CAAS;IAE3B;;;OAGG;IACH,YAAY,SAAiB,EAAE,UAAkB;QAC/C,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YACjB,OAAO;QACT,CAAC;QACD,kCAAkC;QAClC,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;QAC5D,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACvE,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;IACnB,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,MAAM;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;QAC/C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;QAChF,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC;IACxB,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Retry utility with exponential backoff and jitter.
3
+ */
4
+ export interface RetryOptions {
5
+ /** Maximum number of attempts (default: 3) */
6
+ maxAttempts?: number;
7
+ /** Base delay in ms (default: 1000) */
8
+ baseDelay?: number;
9
+ /** Maximum delay in ms (default: 30000) */
10
+ maxDelay?: number;
11
+ /** Whether to add jitter (default: true) */
12
+ jitter?: boolean;
13
+ /** Optional predicate to determine if the error is retryable */
14
+ isRetryable?: (error: unknown) => boolean;
15
+ }
16
+ /**
17
+ * Executes a function with retry logic using exponential backoff.
18
+ */
19
+ export declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
20
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gEAAgE;IAChE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;CAC3C;AAUD;;GAEG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,CAAC,CAAC,CAoBZ"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Retry utility with exponential backoff and jitter.
3
+ */
4
+ const DEFAULT_OPTIONS = {
5
+ maxAttempts: 3,
6
+ baseDelay: 1000,
7
+ maxDelay: 30_000,
8
+ jitter: true,
9
+ isRetryable: () => true,
10
+ };
11
+ /**
12
+ * Executes a function with retry logic using exponential backoff.
13
+ */
14
+ export async function withRetry(fn, options) {
15
+ const opts = { ...DEFAULT_OPTIONS, ...options };
16
+ let lastError;
17
+ for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {
18
+ try {
19
+ return await fn();
20
+ }
21
+ catch (error) {
22
+ lastError = error;
23
+ if (attempt >= opts.maxAttempts || !opts.isRetryable(error)) {
24
+ throw error;
25
+ }
26
+ const delay = calculateDelay(attempt, opts.baseDelay, opts.maxDelay, opts.jitter);
27
+ await sleep(delay);
28
+ }
29
+ }
30
+ throw lastError;
31
+ }
32
+ function calculateDelay(attempt, baseDelay, maxDelay, jitter) {
33
+ // Exponential backoff: base * 2^(attempt-1)
34
+ let delay = baseDelay * Math.pow(2, attempt - 1);
35
+ delay = Math.min(delay, maxDelay);
36
+ if (jitter) {
37
+ // Full jitter: random value between 0 and delay
38
+ delay = Math.random() * delay;
39
+ }
40
+ return delay;
41
+ }
42
+ function sleep(ms) {
43
+ return new Promise((resolve) => setTimeout(resolve, ms));
44
+ }
45
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH,MAAM,eAAe,GAA2B;IAC9C,WAAW,EAAE,CAAC;IACd,SAAS,EAAE,IAAI;IACf,QAAQ,EAAE,MAAM;IAChB,MAAM,EAAE,IAAI;IACZ,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI;CACxB,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,EAAoB,EACpB,OAAsB;IAEtB,MAAM,IAAI,GAAG,EAAE,GAAG,eAAe,EAAE,GAAG,OAAO,EAAE,CAAC;IAChD,IAAI,SAAkB,CAAC;IAEvB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QAC7D,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,KAAK,CAAC;YAElB,IAAI,OAAO,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5D,MAAM,KAAK,CAAC;YACd,CAAC;YAED,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAClF,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,MAAM,SAAS,CAAC;AAClB,CAAC;AAED,SAAS,cAAc,CACrB,OAAe,EACf,SAAiB,EACjB,QAAgB,EAChB,MAAe;IAEf,4CAA4C;IAC5C,IAAI,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC;IACjD,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAElC,IAAI,MAAM,EAAE,CAAC;QACX,gDAAgD;QAChD,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC;IAChC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pilot-ai",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Personal AI agent that controls your macOS via Slack or Telegram",
5
5
  "type": "module",
6
6
  "bin": {