gsd-agent 1.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/README.md +221 -0
- package/bin/cli.js +313 -0
- package/dist/auth-flow.d.ts +50 -0
- package/dist/auth-flow.d.ts.map +1 -0
- package/dist/auth-flow.js +233 -0
- package/dist/auth-flow.js.map +1 -0
- package/dist/auth.d.ts +42 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +117 -0
- package/dist/auth.js.map +1 -0
- package/dist/command-executor.d.ts +44 -0
- package/dist/command-executor.d.ts.map +1 -0
- package/dist/command-executor.js +193 -0
- package/dist/command-executor.js.map +1 -0
- package/dist/command-executor.test.d.ts +8 -0
- package/dist/command-executor.test.d.ts.map +1 -0
- package/dist/command-executor.test.js +87 -0
- package/dist/command-executor.test.js.map +1 -0
- package/dist/command-queue.d.ts +44 -0
- package/dist/command-queue.d.ts.map +1 -0
- package/dist/command-queue.js +184 -0
- package/dist/command-queue.js.map +1 -0
- package/dist/command-queue.test.d.ts +7 -0
- package/dist/command-queue.test.d.ts.map +1 -0
- package/dist/command-queue.test.js +220 -0
- package/dist/command-queue.test.js.map +1 -0
- package/dist/config.d.ts +25 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +103 -0
- package/dist/config.js.map +1 -0
- package/dist/conflict-resolver.d.ts +43 -0
- package/dist/conflict-resolver.d.ts.map +1 -0
- package/dist/conflict-resolver.js +91 -0
- package/dist/conflict-resolver.js.map +1 -0
- package/dist/conflict-resolver.test.d.ts +7 -0
- package/dist/conflict-resolver.test.d.ts.map +1 -0
- package/dist/conflict-resolver.test.js +123 -0
- package/dist/conflict-resolver.test.js.map +1 -0
- package/dist/discovery.d.ts +59 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +180 -0
- package/dist/discovery.js.map +1 -0
- package/dist/discovery.test.d.ts +8 -0
- package/dist/discovery.test.d.ts.map +1 -0
- package/dist/discovery.test.js +132 -0
- package/dist/discovery.test.js.map +1 -0
- package/dist/hash.d.ts +20 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +35 -0
- package/dist/hash.js.map +1 -0
- package/dist/hash.test.d.ts +7 -0
- package/dist/hash.test.d.ts.map +1 -0
- package/dist/hash.test.js +58 -0
- package/dist/hash.test.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +202 -0
- package/dist/index.js.map +1 -0
- package/dist/integration.test.d.ts +8 -0
- package/dist/integration.test.d.ts.map +1 -0
- package/dist/integration.test.js +37 -0
- package/dist/integration.test.js.map +1 -0
- package/dist/logger.d.ts +68 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +159 -0
- package/dist/logger.js.map +1 -0
- package/dist/output-streamer.d.ts +27 -0
- package/dist/output-streamer.d.ts.map +1 -0
- package/dist/output-streamer.js +71 -0
- package/dist/output-streamer.js.map +1 -0
- package/dist/output-streamer.test.d.ts +7 -0
- package/dist/output-streamer.test.d.ts.map +1 -0
- package/dist/output-streamer.test.js +90 -0
- package/dist/output-streamer.test.js.map +1 -0
- package/dist/realtime-subscriber.d.ts +63 -0
- package/dist/realtime-subscriber.d.ts.map +1 -0
- package/dist/realtime-subscriber.js +201 -0
- package/dist/realtime-subscriber.js.map +1 -0
- package/dist/realtime-subscriber.test.d.ts +7 -0
- package/dist/realtime-subscriber.test.d.ts.map +1 -0
- package/dist/realtime-subscriber.test.js +183 -0
- package/dist/realtime-subscriber.test.js.map +1 -0
- package/dist/reconnection-manager.d.ts +88 -0
- package/dist/reconnection-manager.d.ts.map +1 -0
- package/dist/reconnection-manager.js +229 -0
- package/dist/reconnection-manager.js.map +1 -0
- package/dist/reconnection-manager.test.d.ts +8 -0
- package/dist/reconnection-manager.test.d.ts.map +1 -0
- package/dist/reconnection-manager.test.js +151 -0
- package/dist/reconnection-manager.test.js.map +1 -0
- package/dist/remote-sync-handler.d.ts +61 -0
- package/dist/remote-sync-handler.d.ts.map +1 -0
- package/dist/remote-sync-handler.js +197 -0
- package/dist/remote-sync-handler.js.map +1 -0
- package/dist/remote-sync-handler.test.d.ts +7 -0
- package/dist/remote-sync-handler.test.d.ts.map +1 -0
- package/dist/remote-sync-handler.test.js +212 -0
- package/dist/remote-sync-handler.test.js.map +1 -0
- package/dist/retry.d.ts +35 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +63 -0
- package/dist/retry.js.map +1 -0
- package/dist/retry.test.d.ts +5 -0
- package/dist/retry.test.d.ts.map +1 -0
- package/dist/retry.test.js +84 -0
- package/dist/retry.test.js.map +1 -0
- package/dist/storage-client.d.ts +69 -0
- package/dist/storage-client.d.ts.map +1 -0
- package/dist/storage-client.js +168 -0
- package/dist/storage-client.js.map +1 -0
- package/dist/storage-client.test.d.ts +7 -0
- package/dist/storage-client.test.d.ts.map +1 -0
- package/dist/storage-client.test.js +126 -0
- package/dist/storage-client.test.js.map +1 -0
- package/dist/supabase.d.ts +82 -0
- package/dist/supabase.d.ts.map +1 -0
- package/dist/supabase.js +341 -0
- package/dist/supabase.js.map +1 -0
- package/dist/supabase.test.d.ts +7 -0
- package/dist/supabase.test.d.ts.map +1 -0
- package/dist/supabase.test.js +273 -0
- package/dist/supabase.test.js.map +1 -0
- package/dist/sync-engine.d.ts +84 -0
- package/dist/sync-engine.d.ts.map +1 -0
- package/dist/sync-engine.js +251 -0
- package/dist/sync-engine.js.map +1 -0
- package/dist/sync-engine.test.d.ts +7 -0
- package/dist/sync-engine.test.d.ts.map +1 -0
- package/dist/sync-engine.test.js +241 -0
- package/dist/sync-engine.test.js.map +1 -0
- package/dist/sync-state.d.ts +82 -0
- package/dist/sync-state.d.ts.map +1 -0
- package/dist/sync-state.js +145 -0
- package/dist/sync-state.js.map +1 -0
- package/dist/sync-state.test.d.ts +7 -0
- package/dist/sync-state.test.d.ts.map +1 -0
- package/dist/sync-state.test.js +129 -0
- package/dist/sync-state.test.js.map +1 -0
- package/dist/types.d.ts +148 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/types.test.d.ts +7 -0
- package/dist/types.test.d.ts.map +1 -0
- package/dist/types.test.js +73 -0
- package/dist/types.test.js.map +1 -0
- package/dist/watcher.d.ts +55 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +214 -0
- package/dist/watcher.js.map +1 -0
- package/dist/watcher.test.d.ts +8 -0
- package/dist/watcher.test.d.ts.map +1 -0
- package/dist/watcher.test.js +164 -0
- package/dist/watcher.test.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for workspace discovery
|
|
3
|
+
*
|
|
4
|
+
* Verifies that the agent can find .planning/ directories, extract project names,
|
|
5
|
+
* and register workspaces with proper metadata.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import os from 'os';
|
|
11
|
+
import { WorkspaceDiscovery } from './discovery.js';
|
|
12
|
+
import { Logger } from './logger.js';
|
|
13
|
+
describe('WorkspaceDiscovery', () => {
|
|
14
|
+
let tempDir;
|
|
15
|
+
let config;
|
|
16
|
+
let logger;
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
// Create temporary test directory
|
|
19
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-discovery-test-'));
|
|
20
|
+
config = {
|
|
21
|
+
supabase_url: '',
|
|
22
|
+
supabase_key: '',
|
|
23
|
+
watch_dirs: [tempDir],
|
|
24
|
+
ignored_patterns: ['node_modules/', '.git/', 'dist/', 'build/'],
|
|
25
|
+
debounce_ms: 300,
|
|
26
|
+
batch_size: 50,
|
|
27
|
+
log_level: 'ERROR',
|
|
28
|
+
log_file: path.join(tempDir, 'test.log'),
|
|
29
|
+
log_rotation_days: 7
|
|
30
|
+
};
|
|
31
|
+
logger = new Logger(config);
|
|
32
|
+
});
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
// Clean up temporary directory
|
|
35
|
+
if (fs.existsSync(tempDir)) {
|
|
36
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
it('should find workspace when .planning/ directory exists', async () => {
|
|
40
|
+
// Create test workspace structure
|
|
41
|
+
const projectDir = path.join(tempDir, 'myapp');
|
|
42
|
+
const planningDir = path.join(projectDir, '.planning');
|
|
43
|
+
fs.mkdirSync(planningDir, { recursive: true });
|
|
44
|
+
// Create PROJECT.md
|
|
45
|
+
const projectMd = path.join(planningDir, 'PROJECT.md');
|
|
46
|
+
fs.writeFileSync(projectMd, '# My Test Project\n\nDescription here.');
|
|
47
|
+
const discovery = new WorkspaceDiscovery(config, logger);
|
|
48
|
+
const workspaces = await discovery.scan();
|
|
49
|
+
expect(workspaces).toHaveLength(1);
|
|
50
|
+
expect(workspaces[0].root_path).toBe(projectDir);
|
|
51
|
+
expect(workspaces[0].name).toBe('My Test Project');
|
|
52
|
+
expect(workspaces[0].status).toBe('active');
|
|
53
|
+
expect(workspaces[0].id).toBeTruthy();
|
|
54
|
+
expect(workspaces[0].discovered_at).toBeTruthy();
|
|
55
|
+
expect(workspaces[0].last_sync).toBeTruthy();
|
|
56
|
+
});
|
|
57
|
+
it('should ignore node_modules when scanning', async () => {
|
|
58
|
+
// Create workspace in node_modules (should be ignored)
|
|
59
|
+
const nodeModulesDir = path.join(tempDir, 'node_modules', 'some-package');
|
|
60
|
+
const planningDir = path.join(nodeModulesDir, '.planning');
|
|
61
|
+
fs.mkdirSync(planningDir, { recursive: true });
|
|
62
|
+
fs.writeFileSync(path.join(planningDir, 'PROJECT.md'), '# Package Project');
|
|
63
|
+
const discovery = new WorkspaceDiscovery(config, logger);
|
|
64
|
+
const workspaces = await discovery.scan();
|
|
65
|
+
expect(workspaces).toHaveLength(0);
|
|
66
|
+
});
|
|
67
|
+
it('should extract project name from PROJECT.md', async () => {
|
|
68
|
+
const projectDir = path.join(tempDir, 'test-project');
|
|
69
|
+
const planningDir = path.join(projectDir, '.planning');
|
|
70
|
+
fs.mkdirSync(planningDir, { recursive: true });
|
|
71
|
+
const projectMd = path.join(planningDir, 'PROJECT.md');
|
|
72
|
+
fs.writeFileSync(projectMd, '# GSD Project Manager\n\nSome content.');
|
|
73
|
+
const discovery = new WorkspaceDiscovery(config, logger);
|
|
74
|
+
const result = discovery.parseProjectFile(projectMd);
|
|
75
|
+
expect(result.name).toBe('GSD Project Manager');
|
|
76
|
+
});
|
|
77
|
+
it('should use directory name when PROJECT.md is missing', async () => {
|
|
78
|
+
const projectDir = path.join(tempDir, 'fallback-project');
|
|
79
|
+
const planningDir = path.join(projectDir, '.planning');
|
|
80
|
+
fs.mkdirSync(planningDir, { recursive: true });
|
|
81
|
+
const discovery = new WorkspaceDiscovery(config, logger);
|
|
82
|
+
const workspaces = await discovery.scan();
|
|
83
|
+
expect(workspaces).toHaveLength(1);
|
|
84
|
+
expect(workspaces[0].name).toBe('fallback-project');
|
|
85
|
+
});
|
|
86
|
+
it('should not register duplicate workspaces', async () => {
|
|
87
|
+
const projectDir = path.join(tempDir, 'unique-project');
|
|
88
|
+
const planningDir = path.join(projectDir, '.planning');
|
|
89
|
+
fs.mkdirSync(planningDir, { recursive: true });
|
|
90
|
+
fs.writeFileSync(path.join(planningDir, 'PROJECT.md'), '# Unique Project');
|
|
91
|
+
const discovery = new WorkspaceDiscovery(config, logger);
|
|
92
|
+
// First scan finds the workspace
|
|
93
|
+
const firstScan = await discovery.scan();
|
|
94
|
+
expect(firstScan).toHaveLength(1);
|
|
95
|
+
expect(firstScan[0].name).toBe('Unique Project');
|
|
96
|
+
// Second scan should not return it again (already discovered)
|
|
97
|
+
const secondScan = await discovery.scan();
|
|
98
|
+
expect(secondScan).toHaveLength(0);
|
|
99
|
+
});
|
|
100
|
+
it('should handle multiple workspaces in different directories', async () => {
|
|
101
|
+
// Create two separate workspaces
|
|
102
|
+
const project1 = path.join(tempDir, 'project1');
|
|
103
|
+
const project2 = path.join(tempDir, 'project2');
|
|
104
|
+
fs.mkdirSync(path.join(project1, '.planning'), { recursive: true });
|
|
105
|
+
fs.mkdirSync(path.join(project2, '.planning'), { recursive: true });
|
|
106
|
+
fs.writeFileSync(path.join(project1, '.planning', 'PROJECT.md'), '# Project One');
|
|
107
|
+
fs.writeFileSync(path.join(project2, '.planning', 'PROJECT.md'), '# Project Two');
|
|
108
|
+
const discovery = new WorkspaceDiscovery(config, logger);
|
|
109
|
+
const workspaces = await discovery.scan();
|
|
110
|
+
expect(workspaces).toHaveLength(2);
|
|
111
|
+
const names = workspaces.map(w => w.name).sort();
|
|
112
|
+
expect(names).toEqual(['Project One', 'Project Two']);
|
|
113
|
+
});
|
|
114
|
+
it('should skip directories without read permissions', async () => {
|
|
115
|
+
const restrictedDir = path.join(tempDir, 'restricted');
|
|
116
|
+
const planningDir = path.join(restrictedDir, '.planning');
|
|
117
|
+
fs.mkdirSync(planningDir, { recursive: true });
|
|
118
|
+
// Remove read permissions (Unix only)
|
|
119
|
+
if (process.platform !== 'win32') {
|
|
120
|
+
fs.chmodSync(restrictedDir, 0o000);
|
|
121
|
+
}
|
|
122
|
+
const discovery = new WorkspaceDiscovery(config, logger);
|
|
123
|
+
const workspaces = await discovery.scan();
|
|
124
|
+
// Should not throw, just skip the directory
|
|
125
|
+
expect(workspaces).toHaveLength(0);
|
|
126
|
+
// Restore permissions for cleanup
|
|
127
|
+
if (process.platform !== 'win32') {
|
|
128
|
+
fs.chmodSync(restrictedDir, 0o755);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
//# sourceMappingURL=discovery.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.test.js","sourceRoot":"","sources":["../src/discovery.test.ts"],"names":[],"mappings":"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"}
|
package/dist/hash.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content hashing utilities for GSD Agent
|
|
3
|
+
*
|
|
4
|
+
* Provides SHA-256 hashing for file content to detect changes and prevent
|
|
5
|
+
* redundant syncs. Used by FileWatcher to compute content_hash field.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Compute SHA-256 hash of string content
|
|
9
|
+
* @param content String content to hash
|
|
10
|
+
* @returns Lowercase hex string (64 characters)
|
|
11
|
+
*/
|
|
12
|
+
export declare function computeHash(content: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Read file and compute SHA-256 hash of its content
|
|
15
|
+
* @param filePath Absolute path to file
|
|
16
|
+
* @returns Lowercase hex string (64 characters)
|
|
17
|
+
* @throws Error if file doesn't exist or cannot be read
|
|
18
|
+
*/
|
|
19
|
+
export declare function hashFile(filePath: string): Promise<string>;
|
|
20
|
+
//# sourceMappingURL=hash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUhE"}
|
package/dist/hash.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content hashing utilities for GSD Agent
|
|
3
|
+
*
|
|
4
|
+
* Provides SHA-256 hashing for file content to detect changes and prevent
|
|
5
|
+
* redundant syncs. Used by FileWatcher to compute content_hash field.
|
|
6
|
+
*/
|
|
7
|
+
import { createHash } from 'crypto';
|
|
8
|
+
import fs from 'fs/promises';
|
|
9
|
+
/**
|
|
10
|
+
* Compute SHA-256 hash of string content
|
|
11
|
+
* @param content String content to hash
|
|
12
|
+
* @returns Lowercase hex string (64 characters)
|
|
13
|
+
*/
|
|
14
|
+
export function computeHash(content) {
|
|
15
|
+
return createHash('sha256').update(content).digest('hex');
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Read file and compute SHA-256 hash of its content
|
|
19
|
+
* @param filePath Absolute path to file
|
|
20
|
+
* @returns Lowercase hex string (64 characters)
|
|
21
|
+
* @throws Error if file doesn't exist or cannot be read
|
|
22
|
+
*/
|
|
23
|
+
export async function hashFile(filePath) {
|
|
24
|
+
try {
|
|
25
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
26
|
+
return computeHash(content);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
if (error.code === 'ENOENT') {
|
|
30
|
+
throw new Error(`File not found: ${filePath}`);
|
|
31
|
+
}
|
|
32
|
+
throw new Error(`Failed to read file: ${filePath}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=hash.js.map
|
package/dist/hash.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EAAE,MAAM,aAAa,CAAA;AAE5B;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAC3D,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAAgB;IAC7C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QACpD,OAAO,WAAW,CAAC,OAAO,CAAC,CAAA;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAA;QAChD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,wBAAwB,QAAQ,EAAE,CAAC,CAAA;IACrD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.test.d.ts","sourceRoot":"","sources":["../src/hash.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for content hashing utilities
|
|
3
|
+
*
|
|
4
|
+
* Verifies SHA-256 hash computation for strings and files.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import os from 'os';
|
|
10
|
+
import { computeHash, hashFile } from './hash.js';
|
|
11
|
+
describe('Hash utilities', () => {
|
|
12
|
+
let tempDir;
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-hash-test-'));
|
|
15
|
+
});
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
if (fs.existsSync(tempDir)) {
|
|
18
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
it('should compute SHA-256 hash of string', () => {
|
|
22
|
+
const hash = computeHash('hello');
|
|
23
|
+
// Expected SHA-256 hash of "hello"
|
|
24
|
+
expect(hash).toBe('2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824');
|
|
25
|
+
expect(hash).toHaveLength(64);
|
|
26
|
+
});
|
|
27
|
+
it('should compute hash of empty string', () => {
|
|
28
|
+
const hash = computeHash('');
|
|
29
|
+
// Expected SHA-256 hash of empty string
|
|
30
|
+
expect(hash).toBe('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855');
|
|
31
|
+
expect(hash).toHaveLength(64);
|
|
32
|
+
});
|
|
33
|
+
it('should compute different hashes for different content', () => {
|
|
34
|
+
const hash1 = computeHash('hello');
|
|
35
|
+
const hash2 = computeHash('world');
|
|
36
|
+
expect(hash1).not.toBe(hash2);
|
|
37
|
+
});
|
|
38
|
+
it('should read file and compute hash', async () => {
|
|
39
|
+
const testFile = path.join(tempDir, 'test.txt');
|
|
40
|
+
fs.writeFileSync(testFile, 'hello');
|
|
41
|
+
const hash = await hashFile(testFile);
|
|
42
|
+
expect(hash).toBe('2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824');
|
|
43
|
+
expect(hash).toHaveLength(64);
|
|
44
|
+
});
|
|
45
|
+
it('should throw error for non-existent file', async () => {
|
|
46
|
+
const nonExistentFile = path.join(tempDir, 'does-not-exist.txt');
|
|
47
|
+
await expect(hashFile(nonExistentFile)).rejects.toThrow('File not found');
|
|
48
|
+
});
|
|
49
|
+
it('should handle multiline file content', async () => {
|
|
50
|
+
const testFile = path.join(tempDir, 'multiline.txt');
|
|
51
|
+
const content = 'line 1\nline 2\nline 3';
|
|
52
|
+
fs.writeFileSync(testFile, content);
|
|
53
|
+
const fileHash = await hashFile(testFile);
|
|
54
|
+
const stringHash = computeHash(content);
|
|
55
|
+
expect(fileHash).toBe(stringHash);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=hash.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.test.js","sourceRoot":"","sources":["../src/hash.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GSD Agent - Main Entry Point
|
|
3
|
+
*
|
|
4
|
+
* Initializes and runs the local filesystem sync daemon.
|
|
5
|
+
* Discovers workspaces, connects to Supabase, starts file watcher and sync engine.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Main function - initializes and runs the agent daemon
|
|
9
|
+
*/
|
|
10
|
+
export declare function main(): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiDH;;GAEG;AACH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAyM1C"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GSD Agent - Main Entry Point
|
|
3
|
+
*
|
|
4
|
+
* Initializes and runs the local filesystem sync daemon.
|
|
5
|
+
* Discovers workspaces, connects to Supabase, starts file watcher and sync engine.
|
|
6
|
+
*/
|
|
7
|
+
import { loadConfig } from './config.js';
|
|
8
|
+
import { createLogger } from './logger.js';
|
|
9
|
+
import { WorkspaceDiscovery } from './discovery.js';
|
|
10
|
+
import { FileWatcher } from './watcher.js';
|
|
11
|
+
import { createSupabaseClient } from './supabase.js';
|
|
12
|
+
import { createStorageClient } from './storage-client.js';
|
|
13
|
+
import { SyncEngine } from './sync-engine.js';
|
|
14
|
+
import { createRealtimeSubscriber } from './realtime-subscriber.js';
|
|
15
|
+
import { createRemoteSyncHandler } from './remote-sync-handler.js';
|
|
16
|
+
import { createConflictResolver } from './conflict-resolver.js';
|
|
17
|
+
import { createSyncStateManager } from './sync-state.js';
|
|
18
|
+
import { createReconnectionManager } from './reconnection-manager.js';
|
|
19
|
+
import { CommandQueue } from './command-queue.js';
|
|
20
|
+
import { createClient } from '@supabase/supabase-js';
|
|
21
|
+
import os from 'os';
|
|
22
|
+
import path from 'path';
|
|
23
|
+
/**
|
|
24
|
+
* Check if agent is authenticated
|
|
25
|
+
*/
|
|
26
|
+
function isAuthenticated() {
|
|
27
|
+
try {
|
|
28
|
+
const configDir = path.join(os.homedir(), '.gsd-agent');
|
|
29
|
+
const credentialsPath = path.join(configDir, 'credentials.json');
|
|
30
|
+
if (!require('fs').existsSync(credentialsPath)) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
const credentials = JSON.parse(require('fs').readFileSync(credentialsPath, 'utf-8'));
|
|
34
|
+
if (!credentials.access_token || !credentials.user_id) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
// Check if token is expired
|
|
38
|
+
const expiresAt = new Date(credentials.expires_at);
|
|
39
|
+
if (expiresAt < new Date()) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Main function - initializes and runs the agent daemon
|
|
50
|
+
*/
|
|
51
|
+
export async function main() {
|
|
52
|
+
// Check authentication first
|
|
53
|
+
if (!isAuthenticated()) {
|
|
54
|
+
console.error('GSD Agent not authenticated.');
|
|
55
|
+
console.error('Run: gsd-agent auth');
|
|
56
|
+
console.error('Before starting the agent daemon.');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
// 1. Load configuration
|
|
60
|
+
const config = loadConfig();
|
|
61
|
+
// 2. Create logger
|
|
62
|
+
const logger = createLogger(config);
|
|
63
|
+
logger.info('GSD Agent starting', { version: '1.0.0' });
|
|
64
|
+
try {
|
|
65
|
+
// 3. Create SyncStateManager and load state
|
|
66
|
+
const configDir = path.join(os.homedir(), '.gsd-agent');
|
|
67
|
+
const syncStateManager = createSyncStateManager(configDir, logger);
|
|
68
|
+
syncStateManager.loadState();
|
|
69
|
+
logger.info('Loaded sync state', {
|
|
70
|
+
workspace_count: syncStateManager.getAllWorkspaceStates().length
|
|
71
|
+
});
|
|
72
|
+
// 4. Discover workspaces
|
|
73
|
+
logger.info('Scanning for workspaces', { watch_dirs: config.watch_dirs });
|
|
74
|
+
const discovery = new WorkspaceDiscovery(config, logger);
|
|
75
|
+
const workspaces = await discovery.scan();
|
|
76
|
+
logger.info(`Found ${workspaces.length} workspace(s)`, { count: workspaces.length });
|
|
77
|
+
if (workspaces.length === 0) {
|
|
78
|
+
logger.warn('No workspaces found. Create a GSD project with /gsd:new-project');
|
|
79
|
+
// Continue running to detect new workspaces
|
|
80
|
+
}
|
|
81
|
+
// 5. Connect to Supabase with user credentials
|
|
82
|
+
logger.info('Connecting to Supabase');
|
|
83
|
+
const credentialsPath = path.join(configDir, 'credentials.json');
|
|
84
|
+
const credentials = JSON.parse(require('fs').readFileSync(credentialsPath, 'utf-8'));
|
|
85
|
+
const supabaseJsClient = createClient(config.supabase_url, credentials.access_token, {
|
|
86
|
+
auth: {
|
|
87
|
+
persistSession: false,
|
|
88
|
+
autoRefreshToken: false
|
|
89
|
+
},
|
|
90
|
+
db: {
|
|
91
|
+
schema: 'public'
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
// 6. Create StorageClient
|
|
95
|
+
const storageClient = createStorageClient(supabaseJsClient, logger);
|
|
96
|
+
// 7. Create SupabaseClient with StorageClient
|
|
97
|
+
const supabase = createSupabaseClient(config, logger, storageClient, credentials.user_id);
|
|
98
|
+
const connectResult = await supabase.connect();
|
|
99
|
+
if (!connectResult.success) {
|
|
100
|
+
logger.error('Failed to connect to Supabase', { error: connectResult.error });
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
logger.info('Connected to Supabase');
|
|
104
|
+
// 8. Sync discovered workspaces (MUST succeed before file sync)
|
|
105
|
+
const syncedWorkspaces = [];
|
|
106
|
+
for (const workspace of workspaces) {
|
|
107
|
+
logger.info('Syncing workspace', { name: workspace.name, path: workspace.root_path });
|
|
108
|
+
// Add user_id to workspace for multi-user support
|
|
109
|
+
const workspaceWithUser = {
|
|
110
|
+
...workspace,
|
|
111
|
+
user_id: credentials.user_id
|
|
112
|
+
};
|
|
113
|
+
const syncResult = await supabase.syncWorkspace(workspaceWithUser);
|
|
114
|
+
if (!syncResult.success) {
|
|
115
|
+
logger.error('Failed to sync workspace, skipping', {
|
|
116
|
+
name: workspace.name,
|
|
117
|
+
error: syncResult.error
|
|
118
|
+
});
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
syncedWorkspaces.push(workspace);
|
|
122
|
+
}
|
|
123
|
+
if (syncedWorkspaces.length === 0) {
|
|
124
|
+
logger.error('No workspaces successfully synced to database');
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
logger.info(`Successfully synced ${syncedWorkspaces.length} workspace(s) to database`);
|
|
128
|
+
// 9. Create file watcher (only for successfully synced workspaces)
|
|
129
|
+
logger.info('Starting filesystem watcher');
|
|
130
|
+
const watcher = new FileWatcher(syncedWorkspaces, config, logger);
|
|
131
|
+
logger.info('FileWatcher created');
|
|
132
|
+
// 10. Create sync engine
|
|
133
|
+
logger.info('Creating SyncEngine');
|
|
134
|
+
const syncEngine = new SyncEngine(watcher, supabase, config, logger);
|
|
135
|
+
logger.info('SyncEngine created');
|
|
136
|
+
// 11. Create RealtimeSubscriber
|
|
137
|
+
logger.info('Creating RealtimeSubscriber');
|
|
138
|
+
const subscriber = createRealtimeSubscriber(supabaseJsClient, config, logger);
|
|
139
|
+
logger.info('RealtimeSubscriber created');
|
|
140
|
+
// 12. Create ConflictResolver
|
|
141
|
+
const conflictResolver = createConflictResolver(logger);
|
|
142
|
+
// 13. Create workspace map for handlers (only synced workspaces)
|
|
143
|
+
const workspaceMap = new Map(syncedWorkspaces.map(w => [w.id, w]));
|
|
144
|
+
// 14. Create RemoteSyncHandler
|
|
145
|
+
const remoteSyncHandler = createRemoteSyncHandler(subscriber, conflictResolver, workspaceMap, logger);
|
|
146
|
+
// 15. Create ReconnectionManager
|
|
147
|
+
const reconnectionManager = createReconnectionManager(supabase, subscriber, remoteSyncHandler, syncEngine, syncStateManager, workspaceMap, logger);
|
|
148
|
+
// 16. Start ReconnectionManager
|
|
149
|
+
reconnectionManager.start();
|
|
150
|
+
logger.info('ReconnectionManager started');
|
|
151
|
+
// 17. Start SyncEngine
|
|
152
|
+
syncEngine.start();
|
|
153
|
+
logger.info('SyncEngine started');
|
|
154
|
+
// 18. Subscribe to Realtime for each synced workspace
|
|
155
|
+
for (const workspace of syncedWorkspaces) {
|
|
156
|
+
subscriber.subscribe(workspace.id);
|
|
157
|
+
logger.info('Subscribed to Realtime', { workspace_id: workspace.id });
|
|
158
|
+
}
|
|
159
|
+
// 19. Start RemoteSyncHandler
|
|
160
|
+
remoteSyncHandler.start();
|
|
161
|
+
logger.info('RemoteSyncHandler started');
|
|
162
|
+
// 20. Create and start CommandQueue
|
|
163
|
+
logger.info('Creating CommandQueue');
|
|
164
|
+
const commandQueue = new CommandQueue(supabaseJsClient);
|
|
165
|
+
commandQueue.start();
|
|
166
|
+
logger.info('Command execution enabled');
|
|
167
|
+
logger.info('Agent running', { workspaces: syncedWorkspaces.length });
|
|
168
|
+
// 20. Handle graceful shutdown
|
|
169
|
+
const shutdown = async (signal) => {
|
|
170
|
+
logger.info(`Received ${signal}, shutting down gracefully`);
|
|
171
|
+
// Stop CommandQueue
|
|
172
|
+
commandQueue.stop();
|
|
173
|
+
logger.info('Command queue stopped');
|
|
174
|
+
// Stop ReconnectionManager
|
|
175
|
+
reconnectionManager.stop();
|
|
176
|
+
// Stop RemoteSyncHandler
|
|
177
|
+
remoteSyncHandler.stop();
|
|
178
|
+
// Unsubscribe from all Realtime channels
|
|
179
|
+
await subscriber.unsubscribeAll();
|
|
180
|
+
// Stop SyncEngine
|
|
181
|
+
await syncEngine.stop();
|
|
182
|
+
// Save sync state to disk
|
|
183
|
+
syncStateManager.saveState();
|
|
184
|
+
logger.info('Saved sync state');
|
|
185
|
+
// Disconnect from Supabase
|
|
186
|
+
await supabase.disconnect();
|
|
187
|
+
logger.info('Agent stopped');
|
|
188
|
+
process.exit(0);
|
|
189
|
+
};
|
|
190
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
191
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
192
|
+
// Keep process alive
|
|
193
|
+
await new Promise(() => { }); // Never resolves
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
logger.error('Agent failed to start', { error });
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Run main function
|
|
201
|
+
main().catch(console.error);
|
|
202
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for GSD Agent
|
|
3
|
+
*
|
|
4
|
+
* Tests the full agent workflow including workspace discovery, Supabase connection,
|
|
5
|
+
* and component initialization. Full integration requires Supabase instance.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=integration.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration.test.d.ts","sourceRoot":"","sources":["../src/integration.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for GSD Agent
|
|
3
|
+
*
|
|
4
|
+
* Tests the full agent workflow including workspace discovery, Supabase connection,
|
|
5
|
+
* and component initialization. Full integration requires Supabase instance.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
8
|
+
import { main } from './index.js';
|
|
9
|
+
import fs from 'fs/promises';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import os from 'os';
|
|
12
|
+
describe('Agent Integration', () => {
|
|
13
|
+
let testDir;
|
|
14
|
+
beforeAll(async () => {
|
|
15
|
+
// Create temporary test workspace
|
|
16
|
+
testDir = path.join(os.tmpdir(), 'gsd-agent-test-' + Date.now());
|
|
17
|
+
await fs.mkdir(testDir, { recursive: true });
|
|
18
|
+
await fs.mkdir(path.join(testDir, '.planning'), { recursive: true });
|
|
19
|
+
// Create PROJECT.md
|
|
20
|
+
await fs.writeFile(path.join(testDir, '.planning', 'PROJECT.md'), '# Test Project\n\nTest workspace for agent integration test');
|
|
21
|
+
// Set test config
|
|
22
|
+
process.env.SUPABASE_URL = 'https://test.supabase.co';
|
|
23
|
+
process.env.SUPABASE_SERVICE_ROLE_KEY = 'eyJtest';
|
|
24
|
+
});
|
|
25
|
+
afterAll(async () => {
|
|
26
|
+
// Cleanup
|
|
27
|
+
await fs.rm(testDir, { recursive: true, force: true });
|
|
28
|
+
});
|
|
29
|
+
it('should discover test workspace', async () => {
|
|
30
|
+
// This test verifies workspace discovery works
|
|
31
|
+
// Full integration test requires Supabase connection
|
|
32
|
+
// For now, just verify imports and types
|
|
33
|
+
expect(main).toBeDefined();
|
|
34
|
+
expect(typeof main).toBe('function');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration.test.js","sourceRoot":"","sources":["../src/integration.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,MAAM,aAAa,CAAA;AAC5B,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,IAAI,OAAe,CAAA;IAEnB,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,kCAAkC;QAClC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;QAChE,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAEpE,oBAAoB;QACpB,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,YAAY,CAAC,EAC7C,6DAA6D,CAC9D,CAAA;QAED,kBAAkB;QAClB,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,0BAA0B,CAAA;QACrD,OAAO,CAAC,GAAG,CAAC,yBAAyB,GAAG,SAAS,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,KAAK,IAAI,EAAE;QAClB,UAAU;QACV,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACxD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,+CAA+C;QAC/C,qDAAqD;QACrD,yCAAyC;QACzC,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAA;QAC1B,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACtC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured logging with file rotation for GSD Agent
|
|
3
|
+
*
|
|
4
|
+
* Provides console and file logging with configurable levels, timestamps,
|
|
5
|
+
* and automatic daily log rotation with cleanup of old logs.
|
|
6
|
+
*/
|
|
7
|
+
import { SyncConfig } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Logger class for structured logging
|
|
10
|
+
*
|
|
11
|
+
* Writes to both console and file with timestamps, level prefixes, and optional metadata.
|
|
12
|
+
* Respects configured log level to filter messages.
|
|
13
|
+
*/
|
|
14
|
+
export declare class Logger {
|
|
15
|
+
private logLevel;
|
|
16
|
+
private logFile;
|
|
17
|
+
private logDir;
|
|
18
|
+
private rotationDays;
|
|
19
|
+
private currentDate;
|
|
20
|
+
constructor(config: SyncConfig);
|
|
21
|
+
/**
|
|
22
|
+
* Get current date string for log rotation (YYYY-MM-DD)
|
|
23
|
+
*/
|
|
24
|
+
private getDateString;
|
|
25
|
+
/**
|
|
26
|
+
* Get rotated log file path for a specific date
|
|
27
|
+
*/
|
|
28
|
+
private getRotatedLogPath;
|
|
29
|
+
/**
|
|
30
|
+
* Check if log rotation is needed and rotate if necessary
|
|
31
|
+
*/
|
|
32
|
+
private checkRotation;
|
|
33
|
+
/**
|
|
34
|
+
* Delete logs older than rotation_days
|
|
35
|
+
*/
|
|
36
|
+
private cleanupOldLogs;
|
|
37
|
+
/**
|
|
38
|
+
* Check if a message at the given level should be logged
|
|
39
|
+
*/
|
|
40
|
+
private shouldLog;
|
|
41
|
+
/**
|
|
42
|
+
* Format and write log message to console and file
|
|
43
|
+
*/
|
|
44
|
+
private log;
|
|
45
|
+
/**
|
|
46
|
+
* Log error message
|
|
47
|
+
*/
|
|
48
|
+
error(message: string, meta?: Record<string, any>): void;
|
|
49
|
+
/**
|
|
50
|
+
* Log warning message
|
|
51
|
+
*/
|
|
52
|
+
warn(message: string, meta?: Record<string, any>): void;
|
|
53
|
+
/**
|
|
54
|
+
* Log info message
|
|
55
|
+
*/
|
|
56
|
+
info(message: string, meta?: Record<string, any>): void;
|
|
57
|
+
/**
|
|
58
|
+
* Log debug message
|
|
59
|
+
*/
|
|
60
|
+
debug(message: string, meta?: Record<string, any>): void;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Create a logger instance with the given configuration
|
|
64
|
+
* @param config SyncConfig containing log settings
|
|
65
|
+
* @returns Logger instance
|
|
66
|
+
*/
|
|
67
|
+
export declare function createLogger(config: SyncConfig): Logger;
|
|
68
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAWvC;;;;;GAKG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,WAAW,CAAQ;gBAEf,MAAM,EAAE,UAAU;IAgB9B;;OAEG;IACH,OAAO,CAAC,aAAa;IAKrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;OAEG;IACH,OAAO,CAAC,aAAa;IAiBrB;;OAEG;IACH,OAAO,CAAC,cAAc;IAsBtB;;OAEG;IACH,OAAO,CAAC,SAAS;IAIjB;;OAEG;IACH,OAAO,CAAC,GAAG;IAuBX;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAIxD;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAIvD;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAIvD;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;CAGzD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAEvD"}
|