kaimon-cli 0.1.41 → 0.1.44

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 (74) hide show
  1. package/README.md +56 -0
  2. package/dist/__tests__/commands/pull.test.d.ts +2 -0
  3. package/dist/__tests__/commands/pull.test.d.ts.map +1 -0
  4. package/dist/__tests__/commands/pull.test.js +182 -0
  5. package/dist/__tests__/commands/pull.test.js.map +1 -0
  6. package/dist/__tests__/commands/push.test.d.ts +2 -0
  7. package/dist/__tests__/commands/push.test.d.ts.map +1 -0
  8. package/dist/__tests__/commands/push.test.js +255 -0
  9. package/dist/__tests__/commands/push.test.js.map +1 -0
  10. package/dist/__tests__/helpers.d.ts +49 -0
  11. package/dist/__tests__/helpers.d.ts.map +1 -0
  12. package/dist/__tests__/helpers.js +151 -0
  13. package/dist/__tests__/helpers.js.map +1 -0
  14. package/dist/__tests__/integration/full-workflow.test.d.ts +2 -0
  15. package/dist/__tests__/integration/full-workflow.test.d.ts.map +1 -0
  16. package/dist/__tests__/integration/full-workflow.test.js +213 -0
  17. package/dist/__tests__/integration/full-workflow.test.js.map +1 -0
  18. package/dist/__tests__/setup.d.ts +2 -0
  19. package/dist/__tests__/setup.d.ts.map +1 -0
  20. package/dist/__tests__/setup.js +24 -0
  21. package/dist/__tests__/setup.js.map +1 -0
  22. package/dist/__tests__/unit/utils/config.test.d.ts +2 -0
  23. package/dist/__tests__/unit/utils/config.test.d.ts.map +1 -0
  24. package/dist/__tests__/unit/utils/config.test.js +171 -0
  25. package/dist/__tests__/unit/utils/config.test.js.map +1 -0
  26. package/dist/__tests__/unit/utils/frontmatter.test.d.ts +2 -0
  27. package/dist/__tests__/unit/utils/frontmatter.test.d.ts.map +1 -0
  28. package/dist/__tests__/unit/utils/frontmatter.test.js +231 -0
  29. package/dist/__tests__/unit/utils/frontmatter.test.js.map +1 -0
  30. package/dist/__tests__/unit/utils/markdown.test.d.ts +2 -0
  31. package/dist/__tests__/unit/utils/markdown.test.d.ts.map +1 -0
  32. package/dist/__tests__/unit/utils/markdown.test.js +296 -0
  33. package/dist/__tests__/unit/utils/markdown.test.js.map +1 -0
  34. package/dist/__tests__/unit/utils/projectConfig.test.d.ts +2 -0
  35. package/dist/__tests__/unit/utils/projectConfig.test.d.ts.map +1 -0
  36. package/dist/__tests__/unit/utils/projectConfig.test.js +160 -0
  37. package/dist/__tests__/unit/utils/projectConfig.test.js.map +1 -0
  38. package/dist/__tests__/unit/utils/requireAuth.test.d.ts +2 -0
  39. package/dist/__tests__/unit/utils/requireAuth.test.d.ts.map +1 -0
  40. package/dist/__tests__/unit/utils/requireAuth.test.js +96 -0
  41. package/dist/__tests__/unit/utils/requireAuth.test.js.map +1 -0
  42. package/dist/__tests__/unit/utils/tokenRefresh.test.d.ts +2 -0
  43. package/dist/__tests__/unit/utils/tokenRefresh.test.d.ts.map +1 -0
  44. package/dist/__tests__/unit/utils/tokenRefresh.test.js +170 -0
  45. package/dist/__tests__/unit/utils/tokenRefresh.test.js.map +1 -0
  46. package/dist/__tests__/unit/utils/versionCheck.test.d.ts +2 -0
  47. package/dist/__tests__/unit/utils/versionCheck.test.d.ts.map +1 -0
  48. package/dist/__tests__/unit/utils/versionCheck.test.js +105 -0
  49. package/dist/__tests__/unit/utils/versionCheck.test.js.map +1 -0
  50. package/dist/commands/pull.d.ts.map +1 -1
  51. package/dist/commands/pull.js +2 -1
  52. package/dist/commands/pull.js.map +1 -1
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +9 -0
  55. package/dist/index.js.map +1 -1
  56. package/dist/utils/frontmatter.d.ts +28 -0
  57. package/dist/utils/frontmatter.d.ts.map +1 -0
  58. package/dist/utils/frontmatter.js +79 -0
  59. package/dist/utils/frontmatter.js.map +1 -0
  60. package/dist/utils/projectConfig.d.ts.map +1 -1
  61. package/dist/utils/projectConfig.js +9 -1
  62. package/dist/utils/projectConfig.js.map +1 -1
  63. package/dist/utils/pushOperations.d.ts.map +1 -1
  64. package/dist/utils/pushOperations.js +242 -19
  65. package/dist/utils/pushOperations.js.map +1 -1
  66. package/dist/utils/syncOperations.d.ts +2 -1
  67. package/dist/utils/syncOperations.d.ts.map +1 -1
  68. package/dist/utils/syncOperations.js +153 -43
  69. package/dist/utils/syncOperations.js.map +1 -1
  70. package/dist/utils/versionCheck.d.ts +6 -0
  71. package/dist/utils/versionCheck.d.ts.map +1 -0
  72. package/dist/utils/versionCheck.js +61 -0
  73. package/dist/utils/versionCheck.js.map +1 -0
  74. package/package.json +2 -1
@@ -0,0 +1,160 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ import { isProjectInitialized, loadProjectConfig, saveProjectConfig, validateProjectConfig, findProjectConfig, getProjectConfigPath } from '../../../utils/projectConfig.js';
6
+ import * as config from '../../../utils/config.js';
7
+ import { createTempDir, cleanupTempDir, mockConfig, mockProjectConfig } from '../../helpers.js';
8
+ describe('projectConfig.ts', () => {
9
+ let tempDir;
10
+ let projectDir;
11
+ beforeEach(() => {
12
+ tempDir = createTempDir();
13
+ projectDir = path.join(tempDir, 'project');
14
+ fs.mkdirSync(projectDir, { recursive: true });
15
+ // Mock home directory for global config
16
+ vi.spyOn(os, 'homedir').mockReturnValue(tempDir);
17
+ });
18
+ afterEach(() => {
19
+ cleanupTempDir(tempDir);
20
+ vi.restoreAllMocks();
21
+ });
22
+ describe('isProjectInitialized', () => {
23
+ it('should return false if config does not exist', () => {
24
+ expect(isProjectInitialized(projectDir)).toBe(false);
25
+ });
26
+ it('should return true if config exists', () => {
27
+ saveProjectConfig(mockProjectConfig(), projectDir);
28
+ expect(isProjectInitialized(projectDir)).toBe(true);
29
+ });
30
+ });
31
+ describe('loadProjectConfig', () => {
32
+ it('should return null if config does not exist', () => {
33
+ const result = loadProjectConfig(projectDir);
34
+ expect(result).toBeNull();
35
+ });
36
+ it('should load valid config', () => {
37
+ const projectConfig = mockProjectConfig();
38
+ saveProjectConfig(projectConfig, projectDir);
39
+ const loaded = loadProjectConfig(projectDir);
40
+ expect(loaded).toEqual(projectConfig);
41
+ });
42
+ it('should throw on corrupted JSON', () => {
43
+ const configPath = getProjectConfigPath(projectDir);
44
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
45
+ fs.writeFileSync(configPath, 'invalid json', 'utf-8');
46
+ expect(() => loadProjectConfig(projectDir)).toThrow();
47
+ });
48
+ });
49
+ describe('saveProjectConfig', () => {
50
+ it('should create directory and save config', () => {
51
+ const projectConfig = mockProjectConfig();
52
+ saveProjectConfig(projectConfig, projectDir);
53
+ const configPath = getProjectConfigPath(projectDir);
54
+ expect(fs.existsSync(configPath)).toBe(true);
55
+ const loaded = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
56
+ expect(loaded).toEqual(projectConfig);
57
+ });
58
+ it('should create nested directories if needed', () => {
59
+ const deepDir = path.join(projectDir, 'deep', 'nested', 'path');
60
+ const projectConfig = mockProjectConfig();
61
+ saveProjectConfig(projectConfig, deepDir);
62
+ expect(fs.existsSync(getProjectConfigPath(deepDir))).toBe(true);
63
+ });
64
+ it('should overwrite existing config', () => {
65
+ const first = mockProjectConfig({ user_id: 'first@example.com' });
66
+ saveProjectConfig(first, projectDir);
67
+ const second = mockProjectConfig({ user_id: 'second@example.com' });
68
+ saveProjectConfig(second, projectDir);
69
+ const loaded = loadProjectConfig(projectDir);
70
+ expect(loaded?.user_id).toBe('second@example.com');
71
+ });
72
+ });
73
+ describe('validateProjectConfig', () => {
74
+ it('should validate correct config', () => {
75
+ const projectConfig = mockProjectConfig();
76
+ const result = validateProjectConfig(projectConfig);
77
+ expect(result.valid).toBe(true);
78
+ expect(result.errors).toHaveLength(0);
79
+ });
80
+ it('should detect missing version', () => {
81
+ const projectConfig = mockProjectConfig({ version: undefined });
82
+ const result = validateProjectConfig(projectConfig);
83
+ expect(result.valid).toBe(false);
84
+ expect(result.errors).toContain('Missing version field');
85
+ });
86
+ it('should detect missing user_id', () => {
87
+ const projectConfig = mockProjectConfig({ user_id: undefined });
88
+ const result = validateProjectConfig(projectConfig);
89
+ expect(result.valid).toBe(false);
90
+ expect(result.errors).toContain('Missing user_id field');
91
+ });
92
+ it('should detect multiple missing fields', () => {
93
+ const projectConfig = { sync_patterns: {} };
94
+ const result = validateProjectConfig(projectConfig);
95
+ expect(result.valid).toBe(false);
96
+ expect(result.errors.length).toBeGreaterThan(1);
97
+ });
98
+ });
99
+ describe('findProjectConfig', () => {
100
+ it('should find config in current directory', () => {
101
+ const projectConfig = mockProjectConfig();
102
+ saveProjectConfig(projectConfig, projectDir);
103
+ const found = findProjectConfig(projectDir);
104
+ expect(found).not.toBeNull();
105
+ expect(found?.path).toBe(projectDir);
106
+ expect(found?.config).toEqual(projectConfig);
107
+ });
108
+ it('should find config in parent directory', () => {
109
+ const projectConfig = mockProjectConfig();
110
+ saveProjectConfig(projectConfig, projectDir);
111
+ const subDir = path.join(projectDir, 'sub', 'nested');
112
+ fs.mkdirSync(subDir, { recursive: true });
113
+ const found = findProjectConfig(subDir);
114
+ expect(found).not.toBeNull();
115
+ expect(found?.path).toBe(projectDir);
116
+ });
117
+ it('should return null if no config found', () => {
118
+ // Use a path that definitely doesn't exist
119
+ const nonExistentPath = path.join(tempDir, 'definitely-not-exists-' + Date.now());
120
+ const found = findProjectConfig(nonExistentPath);
121
+ expect(found).toBeNull();
122
+ });
123
+ it('should stop at root directory', () => {
124
+ const found = findProjectConfig('/nonexistent/deep/path');
125
+ expect(found).toBeNull();
126
+ });
127
+ it('should find nearest config in nested structure', () => {
128
+ const rootConfig = mockProjectConfig({ user_id: 'root@example.com' });
129
+ saveProjectConfig(rootConfig, projectDir);
130
+ const subDir = path.join(projectDir, 'sub');
131
+ fs.mkdirSync(subDir, { recursive: true });
132
+ const subConfig = mockProjectConfig({ user_id: 'sub@example.com' });
133
+ saveProjectConfig(subConfig, subDir);
134
+ const deepDir = path.join(subDir, 'deep');
135
+ fs.mkdirSync(deepDir, { recursive: true });
136
+ const found = findProjectConfig(deepDir);
137
+ expect(found?.config.user_id).toBe('sub@example.com');
138
+ expect(found?.path).toBe(subDir);
139
+ });
140
+ });
141
+ describe('initProjectConfig', () => {
142
+ it('should require authentication', async () => {
143
+ const { initProjectConfig } = await import('../../../utils/projectConfig.js');
144
+ // No auth config
145
+ await expect(initProjectConfig(projectDir)).rejects.toThrow();
146
+ });
147
+ it('should create config with authenticated user', async () => {
148
+ // Set up global auth
149
+ config.saveConfig(mockConfig({ user_email: 'test@example.com' }));
150
+ // Note: initProjectConfig uses readline which is hard to mock in ESM
151
+ // This test verifies the auth requirement is checked
152
+ // Full interactive testing would require different approach
153
+ const { initProjectConfig } = await import('../../../utils/projectConfig.js');
154
+ // Verify it doesn't throw with auth present
155
+ // (Interactive prompt would block, but that's expected behavior)
156
+ expect(config.loadConfig().access_token).toBeDefined();
157
+ });
158
+ });
159
+ });
160
+ //# sourceMappingURL=projectConfig.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectConfig.test.js","sourceRoot":"","sources":["../../../../src/__tests__/unit/utils/projectConfig.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=requireAuth.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requireAuth.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/unit/utils/requireAuth.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,96 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import os from 'os';
3
+ import { requireAuth, checkAuth } from '../../../utils/requireAuth.js';
4
+ import * as config from '../../../utils/config.js';
5
+ import { createTempDir, cleanupTempDir, mockConfig } from '../../helpers.js';
6
+ describe('requireAuth.ts', () => {
7
+ let tempDir;
8
+ beforeEach(() => {
9
+ tempDir = createTempDir();
10
+ vi.spyOn(os, 'homedir').mockReturnValue(tempDir);
11
+ });
12
+ afterEach(() => {
13
+ cleanupTempDir(tempDir);
14
+ vi.restoreAllMocks();
15
+ });
16
+ describe('requireAuth', () => {
17
+ it('should return token if authenticated and valid', async () => {
18
+ const configData = mockConfig();
19
+ config.saveConfig(configData);
20
+ const token = await requireAuth();
21
+ expect(token).toBe(configData.access_token);
22
+ });
23
+ it('should exit if no token exists', async () => {
24
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => { }));
25
+ await requireAuth();
26
+ expect(exitSpy).toHaveBeenCalledWith(1);
27
+ });
28
+ it('should exit if token is expired', async () => {
29
+ const expiredConfig = mockConfig({
30
+ expires_at: new Date(Date.now() - 3600000).toISOString() // 1 hour ago
31
+ });
32
+ config.saveConfig(expiredConfig);
33
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => { }));
34
+ await requireAuth();
35
+ expect(exitSpy).toHaveBeenCalledWith(1);
36
+ });
37
+ it('should warn if token expires soon', async () => {
38
+ const soonExpiring = mockConfig({
39
+ expires_at: new Date(Date.now() + 2 * 60 * 1000).toISOString() // 2 minutes from now
40
+ });
41
+ config.saveConfig(soonExpiring);
42
+ const consoleSpy = vi.spyOn(console, 'log');
43
+ const token = await requireAuth();
44
+ expect(token).toBe(soonExpiring.access_token);
45
+ expect(consoleSpy).toHaveBeenCalled();
46
+ });
47
+ it('should not warn if token has plenty of time', async () => {
48
+ const validConfig = mockConfig({
49
+ expires_at: new Date(Date.now() + 30 * 60 * 1000).toISOString() // 30 minutes from now
50
+ });
51
+ config.saveConfig(validConfig);
52
+ const consoleSpy = vi.spyOn(console, 'log');
53
+ const token = await requireAuth();
54
+ expect(token).toBe(validConfig.access_token);
55
+ // Should not have warning about expiration
56
+ const calls = consoleSpy.mock.calls.map(call => call.join(' '));
57
+ const hasExpiryWarning = calls.some(call => call.includes('expires in'));
58
+ expect(hasExpiryWarning).toBe(false);
59
+ });
60
+ it('should work if expires_at is not set', async () => {
61
+ const configWithoutExpiry = {
62
+ access_token: 'test-token'
63
+ };
64
+ config.saveConfig(configWithoutExpiry);
65
+ const token = await requireAuth();
66
+ expect(token).toBe('test-token');
67
+ });
68
+ });
69
+ describe('checkAuth', () => {
70
+ it('should return false if no token exists', () => {
71
+ expect(checkAuth()).toBe(false);
72
+ });
73
+ it('should return false if token is expired', () => {
74
+ const expiredConfig = mockConfig({
75
+ expires_at: new Date(Date.now() - 3600000).toISOString()
76
+ });
77
+ config.saveConfig(expiredConfig);
78
+ expect(checkAuth()).toBe(false);
79
+ });
80
+ it('should return true if token is valid', () => {
81
+ const validConfig = mockConfig();
82
+ config.saveConfig(validConfig);
83
+ expect(checkAuth()).toBe(true);
84
+ });
85
+ it('should return true if expires_at is not set but token exists', () => {
86
+ config.saveConfig({ access_token: 'test-token' });
87
+ expect(checkAuth()).toBe(true);
88
+ });
89
+ it('should not exit process (unlike requireAuth)', () => {
90
+ const exitSpy = vi.spyOn(process, 'exit');
91
+ checkAuth();
92
+ expect(exitSpy).not.toHaveBeenCalled();
93
+ });
94
+ });
95
+ });
96
+ //# sourceMappingURL=requireAuth.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requireAuth.test.js","sourceRoot":"","sources":["../../../../src/__tests__/unit/utils/requireAuth.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tokenRefresh.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenRefresh.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/unit/utils/tokenRefresh.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,170 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import os from 'os';
3
+ import { refreshAccessToken, ensureValidToken } from '../../../utils/tokenRefresh.js';
4
+ import * as config from '../../../utils/config.js';
5
+ import * as supabaseClient from '../../../utils/supabaseClient.js';
6
+ import { createTempDir, cleanupTempDir, mockConfig, createMockSupabaseClient } from '../../helpers.js';
7
+ describe('tokenRefresh.ts', () => {
8
+ let tempDir;
9
+ beforeEach(() => {
10
+ tempDir = createTempDir();
11
+ vi.spyOn(os, 'homedir').mockReturnValue(tempDir);
12
+ });
13
+ afterEach(() => {
14
+ cleanupTempDir(tempDir);
15
+ vi.restoreAllMocks();
16
+ });
17
+ describe('refreshAccessToken', () => {
18
+ it('should return false if no access token exists', async () => {
19
+ const result = await refreshAccessToken();
20
+ expect(result).toBe(false);
21
+ });
22
+ it('should return true if token is still valid', async () => {
23
+ const validConfig = mockConfig({
24
+ expires_at: new Date(Date.now() + 30 * 60 * 1000).toISOString() // 30 mins from now
25
+ });
26
+ config.saveConfig(validConfig);
27
+ const result = await refreshAccessToken();
28
+ expect(result).toBe(true);
29
+ });
30
+ it('should return false if no refresh token available', async () => {
31
+ const expiredConfig = mockConfig({
32
+ expires_at: new Date(Date.now() - 1000).toISOString(), // expired
33
+ refresh_token: undefined
34
+ });
35
+ config.saveConfig(expiredConfig);
36
+ const result = await refreshAccessToken();
37
+ expect(result).toBe(false);
38
+ });
39
+ it('should refresh token if expired and refresh token exists', async () => {
40
+ const expiredConfig = mockConfig({
41
+ expires_at: new Date(Date.now() - 1000).toISOString(),
42
+ refresh_token: 'old-refresh-token'
43
+ });
44
+ config.saveConfig(expiredConfig);
45
+ const mockSupabase = createMockSupabaseClient();
46
+ mockSupabase.auth.refreshSession.mockResolvedValue({
47
+ data: {
48
+ session: {
49
+ access_token: 'new-access-token',
50
+ refresh_token: 'new-refresh-token',
51
+ expires_in: 3600
52
+ }
53
+ },
54
+ error: null
55
+ });
56
+ vi.spyOn(supabaseClient, 'getSupabaseClient').mockReturnValue(mockSupabase);
57
+ const result = await refreshAccessToken();
58
+ expect(result).toBe(true);
59
+ expect(mockSupabase.auth.refreshSession).toHaveBeenCalledWith({
60
+ refresh_token: 'old-refresh-token'
61
+ });
62
+ // Verify config was updated
63
+ const updatedConfig = config.loadConfig();
64
+ expect(updatedConfig.access_token).toBe('new-access-token');
65
+ expect(updatedConfig.refresh_token).toBe('new-refresh-token');
66
+ });
67
+ it('should return false if refresh fails', async () => {
68
+ const expiredConfig = mockConfig({
69
+ expires_at: new Date(Date.now() - 1000).toISOString(),
70
+ refresh_token: 'old-refresh-token'
71
+ });
72
+ config.saveConfig(expiredConfig);
73
+ const mockSupabase = createMockSupabaseClient();
74
+ mockSupabase.auth.refreshSession.mockResolvedValue({
75
+ data: { session: null },
76
+ error: { message: 'Invalid refresh token' }
77
+ });
78
+ vi.spyOn(supabaseClient, 'getSupabaseClient').mockReturnValue(mockSupabase);
79
+ const result = await refreshAccessToken();
80
+ expect(result).toBe(false);
81
+ });
82
+ it('should handle refresh errors gracefully', async () => {
83
+ const expiredConfig = mockConfig({
84
+ expires_at: new Date(Date.now() - 1000).toISOString(),
85
+ refresh_token: 'old-refresh-token'
86
+ });
87
+ config.saveConfig(expiredConfig);
88
+ const mockSupabase = createMockSupabaseClient();
89
+ mockSupabase.auth.refreshSession.mockRejectedValue(new Error('Network error'));
90
+ vi.spyOn(supabaseClient, 'getSupabaseClient').mockReturnValue(mockSupabase);
91
+ const result = await refreshAccessToken();
92
+ expect(result).toBe(false);
93
+ });
94
+ it('should preserve user_email when refreshing', async () => {
95
+ const expiredConfig = mockConfig({
96
+ expires_at: new Date(Date.now() - 1000).toISOString(),
97
+ refresh_token: 'old-refresh-token',
98
+ user_email: 'user@example.com'
99
+ });
100
+ config.saveConfig(expiredConfig);
101
+ const mockSupabase = createMockSupabaseClient();
102
+ mockSupabase.auth.refreshSession.mockResolvedValue({
103
+ data: {
104
+ session: {
105
+ access_token: 'new-access-token',
106
+ refresh_token: 'new-refresh-token',
107
+ expires_in: 3600
108
+ }
109
+ },
110
+ error: null
111
+ });
112
+ vi.spyOn(supabaseClient, 'getSupabaseClient').mockReturnValue(mockSupabase);
113
+ await refreshAccessToken();
114
+ const updatedConfig = config.loadConfig();
115
+ expect(updatedConfig.user_email).toBe('user@example.com');
116
+ });
117
+ });
118
+ describe('ensureValidToken', () => {
119
+ it('should return false if no token exists', async () => {
120
+ const result = await ensureValidToken();
121
+ expect(result).toBe(false);
122
+ });
123
+ it('should return true if token is valid', async () => {
124
+ const validConfig = mockConfig({
125
+ expires_at: new Date(Date.now() + 30 * 60 * 1000).toISOString()
126
+ });
127
+ config.saveConfig(validConfig);
128
+ const result = await ensureValidToken();
129
+ expect(result).toBe(true);
130
+ });
131
+ it('should attempt refresh if token is expired', async () => {
132
+ const expiredConfig = mockConfig({
133
+ expires_at: new Date(Date.now() - 1000).toISOString(),
134
+ refresh_token: 'old-refresh-token'
135
+ });
136
+ config.saveConfig(expiredConfig);
137
+ const mockSupabase = createMockSupabaseClient();
138
+ mockSupabase.auth.refreshSession.mockResolvedValue({
139
+ data: {
140
+ session: {
141
+ access_token: 'new-access-token',
142
+ refresh_token: 'new-refresh-token',
143
+ expires_in: 3600
144
+ }
145
+ },
146
+ error: null
147
+ });
148
+ vi.spyOn(supabaseClient, 'getSupabaseClient').mockReturnValue(mockSupabase);
149
+ const result = await ensureValidToken();
150
+ expect(result).toBe(true);
151
+ expect(mockSupabase.auth.refreshSession).toHaveBeenCalled();
152
+ });
153
+ it('should return false if refresh fails', async () => {
154
+ const expiredConfig = mockConfig({
155
+ expires_at: new Date(Date.now() - 1000).toISOString(),
156
+ refresh_token: 'old-refresh-token'
157
+ });
158
+ config.saveConfig(expiredConfig);
159
+ const mockSupabase = createMockSupabaseClient();
160
+ mockSupabase.auth.refreshSession.mockResolvedValue({
161
+ data: { session: null },
162
+ error: { message: 'Invalid refresh token' }
163
+ });
164
+ vi.spyOn(supabaseClient, 'getSupabaseClient').mockReturnValue(mockSupabase);
165
+ const result = await ensureValidToken();
166
+ expect(result).toBe(false);
167
+ });
168
+ });
169
+ });
170
+ //# sourceMappingURL=tokenRefresh.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenRefresh.test.js","sourceRoot":"","sources":["../../../../src/__tests__/unit/utils/tokenRefresh.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACtF,OAAO,KAAK,MAAM,MAAM,0BAA0B,CAAC;AACnD,OAAO,KAAK,cAAc,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAEvG,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,IAAI,OAAe,CAAC;IAEpB,UAAU,CAAC,GAAG,EAAE;QACd,OAAO,GAAG,aAAa,EAAE,CAAC;QAC1B,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,cAAc,CAAC,OAAO,CAAC,CAAC;QACxB,EAAE,CAAC,eAAe,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,MAAM,GAAG,MAAM,kBAAkB,EAAE,CAAC;YAC1C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC1D,MAAM,WAAW,GAAG,UAAU,CAAC;gBAC7B,UAAU,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,mBAAmB;aACpF,CAAC,CAAC;YACH,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;YAE/B,MAAM,MAAM,GAAG,MAAM,kBAAkB,EAAE,CAAC;YAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YACjE,MAAM,aAAa,GAAG,UAAU,CAAC;gBAC/B,UAAU,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,UAAU;gBACjE,aAAa,EAAE,SAAS;aACzB,CAAC,CAAC;YACH,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;YAEjC,MAAM,MAAM,GAAG,MAAM,kBAAkB,EAAE,CAAC;YAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;YACxE,MAAM,aAAa,GAAG,UAAU,CAAC;gBAC/B,UAAU,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;gBACrD,aAAa,EAAE,mBAAmB;aACnC,CAAC,CAAC;YACH,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;YAEjC,MAAM,YAAY,GAAG,wBAAwB,EAAE,CAAC;YAChD,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC;gBACjD,IAAI,EAAE;oBACJ,OAAO,EAAE;wBACP,YAAY,EAAE,kBAAkB;wBAChC,aAAa,EAAE,mBAAmB;wBAClC,UAAU,EAAE,IAAI;qBACjB;iBACF;gBACD,KAAK,EAAE,IAAI;aACZ,CAAC,CAAC;YAEH,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC,eAAe,CAAC,YAAmB,CAAC,CAAC;YAEnF,MAAM,MAAM,GAAG,MAAM,kBAAkB,EAAE,CAAC;YAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1B,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,oBAAoB,CAAC;gBAC5D,aAAa,EAAE,mBAAmB;aACnC,CAAC,CAAC;YAEH,4BAA4B;YAC5B,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;YAC1C,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;YAC5D,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;YACpD,MAAM,aAAa,GAAG,UAAU,CAAC;gBAC/B,UAAU,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;gBACrD,aAAa,EAAE,mBAAmB;aACnC,CAAC,CAAC;YACH,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;YAEjC,MAAM,YAAY,GAAG,wBAAwB,EAAE,CAAC;YAChD,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC;gBACjD,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;gBACvB,KAAK,EAAE,EAAE,OAAO,EAAE,uBAAuB,EAAE;aAC5C,CAAC,CAAC;YAEH,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC,eAAe,CAAC,YAAmB,CAAC,CAAC;YAEnF,MAAM,MAAM,GAAG,MAAM,kBAAkB,EAAE,CAAC;YAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;YACvD,MAAM,aAAa,GAAG,UAAU,CAAC;gBAC/B,UAAU,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;gBACrD,aAAa,EAAE,mBAAmB;aACnC,CAAC,CAAC;YACH,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;YAEjC,MAAM,YAAY,GAAG,wBAAwB,EAAE,CAAC;YAChD,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;YAE/E,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC,eAAe,CAAC,YAAmB,CAAC,CAAC;YAEnF,MAAM,MAAM,GAAG,MAAM,kBAAkB,EAAE,CAAC;YAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC1D,MAAM,aAAa,GAAG,UAAU,CAAC;gBAC/B,UAAU,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;gBACrD,aAAa,EAAE,mBAAmB;gBAClC,UAAU,EAAE,kBAAkB;aAC/B,CAAC,CAAC;YACH,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;YAEjC,MAAM,YAAY,GAAG,wBAAwB,EAAE,CAAC;YAChD,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC;gBACjD,IAAI,EAAE;oBACJ,OAAO,EAAE;wBACP,YAAY,EAAE,kBAAkB;wBAChC,aAAa,EAAE,mBAAmB;wBAClC,UAAU,EAAE,IAAI;qBACjB;iBACF;gBACD,KAAK,EAAE,IAAI;aACZ,CAAC,CAAC;YAEH,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC,eAAe,CAAC,YAAmB,CAAC,CAAC;YAEnF,MAAM,kBAAkB,EAAE,CAAC;YAE3B,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;YAC1C,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;YACxC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;YACpD,MAAM,WAAW,GAAG,UAAU,CAAC;gBAC7B,UAAU,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;aAChE,CAAC,CAAC;YACH,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;YAE/B,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;YAExC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC1D,MAAM,aAAa,GAAG,UAAU,CAAC;gBAC/B,UAAU,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;gBACrD,aAAa,EAAE,mBAAmB;aACnC,CAAC,CAAC;YACH,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;YAEjC,MAAM,YAAY,GAAG,wBAAwB,EAAE,CAAC;YAChD,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC;gBACjD,IAAI,EAAE;oBACJ,OAAO,EAAE;wBACP,YAAY,EAAE,kBAAkB;wBAChC,aAAa,EAAE,mBAAmB;wBAClC,UAAU,EAAE,IAAI;qBACjB;iBACF;gBACD,KAAK,EAAE,IAAI;aACZ,CAAC,CAAC;YAEH,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC,eAAe,CAAC,YAAmB,CAAC,CAAC;YAEnF,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;YAExC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1B,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,gBAAgB,EAAE,CAAC;QAC9D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;YACpD,MAAM,aAAa,GAAG,UAAU,CAAC;gBAC/B,UAAU,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;gBACrD,aAAa,EAAE,mBAAmB;aACnC,CAAC,CAAC;YACH,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;YAEjC,MAAM,YAAY,GAAG,wBAAwB,EAAE,CAAC;YAChD,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC;gBACjD,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;gBACvB,KAAK,EAAE,EAAE,OAAO,EAAE,uBAAuB,EAAE;aAC5C,CAAC,CAAC;YAEH,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC,eAAe,CAAC,YAAmB,CAAC,CAAC;YAEnF,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;YAExC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=versionCheck.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versionCheck.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/unit/utils/versionCheck.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,105 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { checkVersion } from '../../../utils/versionCheck.js';
3
+ import fs from 'fs';
4
+ describe('versionCheck.ts', () => {
5
+ const mockPackageJson = (version, minimumVersion) => {
6
+ return JSON.stringify({
7
+ version,
8
+ minimumVersion: minimumVersion || version
9
+ });
10
+ };
11
+ beforeEach(() => {
12
+ vi.clearAllMocks();
13
+ });
14
+ afterEach(() => {
15
+ vi.restoreAllMocks();
16
+ });
17
+ // Helper to mock file reading for version check
18
+ const mockVersionFiles = (currentVersion, minimumVersion) => {
19
+ vi.spyOn(fs, 'readFileSync').mockImplementation((filepath) => {
20
+ // Return appropriate version based on which package.json is requested
21
+ return mockPackageJson(currentVersion, minimumVersion);
22
+ });
23
+ };
24
+ describe('checkVersion', () => {
25
+ it('should exit if current version is outdated', async () => {
26
+ // Mock reading package.json with outdated version
27
+ mockVersionFiles('0.1.0', '0.2.0');
28
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => { }));
29
+ await checkVersion();
30
+ // Version check attempts exit
31
+ expect(exitSpy).toHaveBeenCalledWith(1);
32
+ // Console.error is already mocked in setup.ts
33
+ expect(console.error).toHaveBeenCalled();
34
+ });
35
+ it('should succeed if current version matches minimum', async () => {
36
+ mockVersionFiles('1.0.0', '1.0.0');
37
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => { }));
38
+ await checkVersion();
39
+ expect(exitSpy).not.toHaveBeenCalled();
40
+ });
41
+ it('should succeed if current version is newer', async () => {
42
+ mockVersionFiles('1.2.0', '1.0.0');
43
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => { }));
44
+ await checkVersion();
45
+ expect(exitSpy).not.toHaveBeenCalled();
46
+ });
47
+ it('should use version as minimumVersion if not specified', async () => {
48
+ vi.spyOn(fs, 'readFileSync').mockReturnValue(JSON.stringify({ version: '1.0.0' }));
49
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => { }));
50
+ await checkVersion();
51
+ expect(exitSpy).not.toHaveBeenCalled();
52
+ });
53
+ it('should fail silently on errors', async () => {
54
+ vi.spyOn(fs, 'readFileSync').mockImplementation(() => {
55
+ throw new Error('File not found');
56
+ });
57
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => { }));
58
+ await checkVersion();
59
+ // Should not exit on error
60
+ expect(exitSpy).not.toHaveBeenCalled();
61
+ });
62
+ it('should handle malformed package.json', async () => {
63
+ vi.spyOn(fs, 'readFileSync').mockReturnValue('invalid json {');
64
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => { }));
65
+ await checkVersion();
66
+ expect(exitSpy).not.toHaveBeenCalled();
67
+ });
68
+ it('should handle missing version field', async () => {
69
+ vi.spyOn(fs, 'readFileSync').mockReturnValue(JSON.stringify({ name: 'kaimon-cli' }));
70
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => { }));
71
+ await checkVersion();
72
+ expect(exitSpy).not.toHaveBeenCalled();
73
+ });
74
+ });
75
+ describe('version comparison logic', () => {
76
+ it('should handle major version differences', async () => {
77
+ mockVersionFiles('1.0.0', '2.0.0');
78
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => { }));
79
+ await checkVersion();
80
+ expect(console.error).toHaveBeenCalled();
81
+ expect(exitSpy).toHaveBeenCalledWith(1);
82
+ });
83
+ it('should handle minor version differences', async () => {
84
+ mockVersionFiles('1.1.0', '1.2.0');
85
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => { }));
86
+ await checkVersion();
87
+ expect(console.error).toHaveBeenCalled();
88
+ expect(exitSpy).toHaveBeenCalledWith(1);
89
+ });
90
+ it('should handle patch version differences', async () => {
91
+ mockVersionFiles('1.0.1', '1.0.2');
92
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => { }));
93
+ await checkVersion();
94
+ expect(console.error).toHaveBeenCalled();
95
+ expect(exitSpy).toHaveBeenCalledWith(1);
96
+ });
97
+ it('should accept newer major version', async () => {
98
+ mockVersionFiles('2.0.0', '1.0.0');
99
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => { }));
100
+ await checkVersion();
101
+ expect(exitSpy).not.toHaveBeenCalled();
102
+ });
103
+ });
104
+ });
105
+ //# sourceMappingURL=versionCheck.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versionCheck.test.js","sourceRoot":"","sources":["../../../../src/__tests__/unit/utils/versionCheck.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,QAAA,MAAM,IAAI,SAeN,CAAC;AAEL,OAAO,EAAE,IAAI,EAAE,CAAC"}
1
+ {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,QAAA,MAAM,IAAI,SAgBN,CAAC;AAEL,OAAO,EAAE,IAAI,EAAE,CAAC"}
@@ -4,12 +4,13 @@ import { requireAuth } from '../utils/requireAuth.js';
4
4
  const pull = new Command('pull')
5
5
  .description('Pull all documents from Kaimon as markdown files')
6
6
  .option('--flat', 'Save documents directly to current folder instead of KaimonDocs/ subfolder')
7
+ .option('-y, --yes', 'Skip confirmation and pull all documents')
7
8
  .action(async (options) => {
8
9
  try {
9
10
  // Validate authentication first
10
11
  await requireAuth();
11
12
  const { pullDocuments } = await import('../utils/syncOperations.js');
12
- await pullDocuments(options.flat);
13
+ await pullDocuments(options.flat, options.yes || false);
13
14
  }
14
15
  catch (error) {
15
16
  console.error(chalk.red('❌ Pull failed:'), error.message);
@@ -1 +1 @@
1
- {"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,MAAM,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC7B,WAAW,CAAC,kDAAkD,CAAC;KAC/D,MAAM,CAAC,QAAQ,EAAE,4EAA4E,CAAC;KAC9F,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,gCAAgC;QAChC,MAAM,WAAW,EAAE,CAAC;QAEpB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,4BAA4B,CAAC,CAAC;QACrE,MAAM,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpC,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,EAAE,IAAI,EAAE,CAAC"}
1
+ {"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,MAAM,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC7B,WAAW,CAAC,kDAAkD,CAAC;KAC/D,MAAM,CAAC,QAAQ,EAAE,4EAA4E,CAAC;KAC9F,MAAM,CAAC,WAAW,EAAE,0CAA0C,CAAC;KAC/D,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,gCAAgC;QAChC,MAAM,WAAW,EAAE,CAAC;QAEpB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,4BAA4B,CAAC,CAAC;QACrE,MAAM,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC;IAE1D,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,EAAE,IAAI,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAqBA,wBAAsB,IAAI,kBAEzB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA8BA,wBAAsB,IAAI,kBAGzB"}