@spool-lab/core 0.3.3

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 (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -0
  3. package/dist/connectors/capabilities/cookies-chrome.d.ts +19 -0
  4. package/dist/connectors/capabilities/cookies-chrome.d.ts.map +1 -0
  5. package/dist/connectors/capabilities/cookies-chrome.js +199 -0
  6. package/dist/connectors/capabilities/cookies-chrome.js.map +1 -0
  7. package/dist/connectors/capabilities/exec-impl.d.ts +3 -0
  8. package/dist/connectors/capabilities/exec-impl.d.ts.map +1 -0
  9. package/dist/connectors/capabilities/exec-impl.js +108 -0
  10. package/dist/connectors/capabilities/exec-impl.js.map +1 -0
  11. package/dist/connectors/capabilities/fetch-impl.d.ts +3 -0
  12. package/dist/connectors/capabilities/fetch-impl.d.ts.map +1 -0
  13. package/dist/connectors/capabilities/fetch-impl.js +4 -0
  14. package/dist/connectors/capabilities/fetch-impl.js.map +1 -0
  15. package/dist/connectors/capabilities/index.d.ts +6 -0
  16. package/dist/connectors/capabilities/index.d.ts.map +1 -0
  17. package/dist/connectors/capabilities/index.js +6 -0
  18. package/dist/connectors/capabilities/index.js.map +1 -0
  19. package/dist/connectors/capabilities/log-impl.d.ts +3 -0
  20. package/dist/connectors/capabilities/log-impl.d.ts.map +1 -0
  21. package/dist/connectors/capabilities/log-impl.js +26 -0
  22. package/dist/connectors/capabilities/log-impl.js.map +1 -0
  23. package/dist/connectors/capabilities/sqlite-impl.d.ts +3 -0
  24. package/dist/connectors/capabilities/sqlite-impl.d.ts.map +1 -0
  25. package/dist/connectors/capabilities/sqlite-impl.js +19 -0
  26. package/dist/connectors/capabilities/sqlite-impl.js.map +1 -0
  27. package/dist/connectors/loader.d.ts +47 -0
  28. package/dist/connectors/loader.d.ts.map +1 -0
  29. package/dist/connectors/loader.js +328 -0
  30. package/dist/connectors/loader.js.map +1 -0
  31. package/dist/connectors/npm-install.d.ts +26 -0
  32. package/dist/connectors/npm-install.d.ts.map +1 -0
  33. package/dist/connectors/npm-install.js +71 -0
  34. package/dist/connectors/npm-install.js.map +1 -0
  35. package/dist/connectors/prerequisites.d.ts +14 -0
  36. package/dist/connectors/prerequisites.d.ts.map +1 -0
  37. package/dist/connectors/prerequisites.js +109 -0
  38. package/dist/connectors/prerequisites.js.map +1 -0
  39. package/dist/connectors/registry-fetch.d.ts +22 -0
  40. package/dist/connectors/registry-fetch.d.ts.map +1 -0
  41. package/dist/connectors/registry-fetch.js +54 -0
  42. package/dist/connectors/registry-fetch.js.map +1 -0
  43. package/dist/connectors/registry.d.ts +23 -0
  44. package/dist/connectors/registry.d.ts.map +1 -0
  45. package/dist/connectors/registry.js +59 -0
  46. package/dist/connectors/registry.js.map +1 -0
  47. package/dist/connectors/sync-engine.d.ts +30 -0
  48. package/dist/connectors/sync-engine.d.ts.map +1 -0
  49. package/dist/connectors/sync-engine.js +589 -0
  50. package/dist/connectors/sync-engine.js.map +1 -0
  51. package/dist/connectors/sync-scheduler.d.ts +56 -0
  52. package/dist/connectors/sync-scheduler.d.ts.map +1 -0
  53. package/dist/connectors/sync-scheduler.js +238 -0
  54. package/dist/connectors/sync-scheduler.js.map +1 -0
  55. package/dist/connectors/trust-store.d.ts +13 -0
  56. package/dist/connectors/trust-store.d.ts.map +1 -0
  57. package/dist/connectors/trust-store.js +48 -0
  58. package/dist/connectors/trust-store.js.map +1 -0
  59. package/dist/connectors/types.d.ts +111 -0
  60. package/dist/connectors/types.d.ts.map +1 -0
  61. package/dist/connectors/types.js +50 -0
  62. package/dist/connectors/types.js.map +1 -0
  63. package/dist/db/db.d.ts +6 -0
  64. package/dist/db/db.d.ts.map +1 -0
  65. package/dist/db/db.js +347 -0
  66. package/dist/db/db.js.map +1 -0
  67. package/dist/db/queries.d.ts +68 -0
  68. package/dist/db/queries.d.ts.map +1 -0
  69. package/dist/db/queries.js +828 -0
  70. package/dist/db/queries.js.map +1 -0
  71. package/dist/db/search-query.d.ts +13 -0
  72. package/dist/db/search-query.d.ts.map +1 -0
  73. package/dist/db/search-query.js +62 -0
  74. package/dist/db/search-query.js.map +1 -0
  75. package/dist/index.d.ts +29 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +24 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/parsers/claude.d.ts +9 -0
  80. package/dist/parsers/claude.d.ts.map +1 -0
  81. package/dist/parsers/claude.js +153 -0
  82. package/dist/parsers/claude.js.map +1 -0
  83. package/dist/parsers/codex.d.ts +5 -0
  84. package/dist/parsers/codex.d.ts.map +1 -0
  85. package/dist/parsers/codex.js +192 -0
  86. package/dist/parsers/codex.js.map +1 -0
  87. package/dist/parsers/gemini.d.ts +4 -0
  88. package/dist/parsers/gemini.d.ts.map +1 -0
  89. package/dist/parsers/gemini.js +149 -0
  90. package/dist/parsers/gemini.js.map +1 -0
  91. package/dist/sync/source-paths.d.ts +5 -0
  92. package/dist/sync/source-paths.d.ts.map +1 -0
  93. package/dist/sync/source-paths.js +119 -0
  94. package/dist/sync/source-paths.js.map +1 -0
  95. package/dist/sync/syncer.d.ts +19 -0
  96. package/dist/sync/syncer.d.ts.map +1 -0
  97. package/dist/sync/syncer.js +308 -0
  98. package/dist/sync/syncer.js.map +1 -0
  99. package/dist/sync/watcher.d.ts +19 -0
  100. package/dist/sync/watcher.d.ts.map +1 -0
  101. package/dist/sync/watcher.js +67 -0
  102. package/dist/sync/watcher.js.map +1 -0
  103. package/dist/types.d.ts +112 -0
  104. package/dist/types.d.ts.map +1 -0
  105. package/dist/types.js +2 -0
  106. package/dist/types.js.map +1 -0
  107. package/dist/util/resolve-bin.d.ts +6 -0
  108. package/dist/util/resolve-bin.d.ts.map +1 -0
  109. package/dist/util/resolve-bin.js +66 -0
  110. package/dist/util/resolve-bin.js.map +1 -0
  111. package/package.json +43 -0
@@ -0,0 +1,19 @@
1
+ import type { Syncer } from './syncer.js';
2
+ export type WatcherEvent = 'new-sessions';
3
+ export type WatcherEventCallback = (event: WatcherEvent, data: {
4
+ count: number;
5
+ }) => void;
6
+ export declare class SpoolWatcher {
7
+ private syncer;
8
+ private watcher;
9
+ private listeners;
10
+ private pendingNew;
11
+ private flushTimer;
12
+ private sourceRoots;
13
+ constructor(syncer: Syncer);
14
+ start(): void;
15
+ stop(): void;
16
+ on(event: WatcherEvent, cb: WatcherEventCallback): void;
17
+ private handleFile;
18
+ }
19
+ //# sourceMappingURL=watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/sync/watcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAKzC,MAAM,MAAM,YAAY,GAAG,cAAc,CAAA;AACzC,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,CAAA;AAEzF,qBAAa,YAAY;IAWX,OAAO,CAAC,MAAM;IAV1B,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,UAAU,CAAI;IACtB,OAAO,CAAC,UAAU,CAA6C;IAC/D,OAAO,CAAC,WAAW,CAIlB;gBAEmB,MAAM,EAAE,MAAM;IAElC,KAAK,IAAI,IAAI;IA0Bb,IAAI,IAAI,IAAI;IAMZ,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,oBAAoB,GAAG,IAAI;IAIvD,OAAO,CAAC,UAAU;CAgBnB"}
@@ -0,0 +1,67 @@
1
+ import chokidar from 'chokidar';
2
+ import { detectSessionSource, getSessionRoots, getSessionWatchPatterns } from './source-paths.js';
3
+ export class SpoolWatcher {
4
+ syncer;
5
+ watcher = null;
6
+ listeners = [];
7
+ pendingNew = 0;
8
+ flushTimer = null;
9
+ sourceRoots = {
10
+ claude: [],
11
+ codex: [],
12
+ gemini: [],
13
+ };
14
+ constructor(syncer) {
15
+ this.syncer = syncer;
16
+ }
17
+ start() {
18
+ this.sourceRoots = {
19
+ claude: getSessionRoots('claude'),
20
+ codex: getSessionRoots('codex'),
21
+ gemini: getSessionRoots('gemini'),
22
+ };
23
+ const patterns = [
24
+ ...getSessionWatchPatterns('claude', this.sourceRoots.claude),
25
+ ...getSessionWatchPatterns('codex', this.sourceRoots.codex),
26
+ ...getSessionWatchPatterns('gemini', this.sourceRoots.gemini),
27
+ ];
28
+ this.watcher = chokidar.watch(patterns, {
29
+ persistent: true,
30
+ ignoreInitial: true, // initial sync is done by Syncer.syncAll()
31
+ awaitWriteFinish: {
32
+ stabilityThreshold: 2000,
33
+ pollInterval: 200,
34
+ },
35
+ });
36
+ this.watcher
37
+ .on('add', (path) => this.handleFile(path))
38
+ .on('change', (path) => this.handleFile(path));
39
+ }
40
+ stop() {
41
+ this.watcher?.close();
42
+ this.watcher = null;
43
+ if (this.flushTimer)
44
+ clearTimeout(this.flushTimer);
45
+ }
46
+ on(event, cb) {
47
+ this.listeners.push(cb);
48
+ }
49
+ handleFile(filePath) {
50
+ const source = detectSessionSource(filePath, this.sourceRoots);
51
+ if (!source)
52
+ return;
53
+ const result = this.syncer.syncFile(filePath, source);
54
+ if (result === 'added' || result === 'updated') {
55
+ this.pendingNew++;
56
+ // Debounce: flush all pending new-session events together
57
+ if (this.flushTimer)
58
+ clearTimeout(this.flushTimer);
59
+ this.flushTimer = setTimeout(() => {
60
+ const count = this.pendingNew;
61
+ this.pendingNew = 0;
62
+ this.listeners.forEach(cb => cb('new-sessions', { count }));
63
+ }, 500);
64
+ }
65
+ }
66
+ }
67
+ //# sourceMappingURL=watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/sync/watcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,112 @@
1
+ export type SessionSource = 'claude' | 'codex' | 'gemini';
2
+ export type Source = SessionSource;
3
+ export type SearchMatchType = 'fts' | 'phrase' | 'all_terms';
4
+ export interface ParsedMessage {
5
+ uuid: string;
6
+ parentUuid: string | null;
7
+ role: 'user' | 'assistant' | 'system';
8
+ contentText: string;
9
+ timestamp: string;
10
+ isSidechain: boolean;
11
+ toolNames: string[];
12
+ seq: number;
13
+ }
14
+ export interface ParsedSession {
15
+ source: SessionSource;
16
+ sessionUuid: string;
17
+ filePath: string;
18
+ title: string;
19
+ cwd: string;
20
+ model: string;
21
+ startedAt: string;
22
+ endedAt: string;
23
+ messages: ParsedMessage[];
24
+ }
25
+ export type ParseSessionResult = {
26
+ kind: 'parsed';
27
+ session: ParsedSession;
28
+ } | {
29
+ kind: 'filtered';
30
+ } | {
31
+ kind: 'skipped';
32
+ };
33
+ export interface Session {
34
+ id: number;
35
+ projectId: number;
36
+ sourceId: number;
37
+ sessionUuid: string;
38
+ filePath: string;
39
+ title: string | null;
40
+ startedAt: string;
41
+ endedAt: string;
42
+ messageCount: number;
43
+ hasToolUse: boolean;
44
+ cwd: string | null;
45
+ model: string | null;
46
+ source: SessionSource;
47
+ projectDisplayPath: string;
48
+ projectDisplayName: string;
49
+ }
50
+ export interface Message {
51
+ id: number;
52
+ sessionId: number;
53
+ msgUuid: string | null;
54
+ parentUuid: string | null;
55
+ role: 'user' | 'assistant' | 'system';
56
+ contentText: string;
57
+ timestamp: string;
58
+ isSidechain: boolean;
59
+ toolNames: string[];
60
+ seq: number;
61
+ }
62
+ export interface FragmentResult {
63
+ rank: number;
64
+ sessionId: number;
65
+ sessionUuid: string;
66
+ sessionTitle: string;
67
+ matchCount: number;
68
+ matchType: SearchMatchType;
69
+ source: SessionSource;
70
+ profileLabel?: string;
71
+ cwd?: string;
72
+ project: string;
73
+ startedAt: string;
74
+ snippet: string;
75
+ messageId: number;
76
+ messageRole: string;
77
+ messageTimestamp: string;
78
+ }
79
+ export interface StatusInfo {
80
+ dbPath: string;
81
+ totalSessions: number;
82
+ claudeSessions: number;
83
+ codexSessions: number;
84
+ geminiSessions: number;
85
+ lastSyncedAt: string | null;
86
+ dbSizeBytes: number;
87
+ }
88
+ export interface SyncResult {
89
+ added: number;
90
+ updated: number;
91
+ errors: number;
92
+ }
93
+ export interface CaptureResult {
94
+ rank: number;
95
+ captureId: number;
96
+ captureUuid: string;
97
+ matchType: SearchMatchType;
98
+ url: string;
99
+ title: string;
100
+ snippet: string;
101
+ platform: string;
102
+ contentType: string;
103
+ author: string | null;
104
+ capturedAt: string;
105
+ }
106
+ export type { CapturedItem } from './connectors/types.js';
107
+ export type SearchResult = (FragmentResult & {
108
+ kind: 'fragment';
109
+ }) | (CaptureResult & {
110
+ kind: 'capture';
111
+ });
112
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ export declare function resolveSystemBinary(name: string, extraSearchPaths?: string[]): string | null;
2
+ /** Cached version of resolveSystemBinary — result persists for process lifetime. */
3
+ export declare function cachedResolve(name: string, extras?: string[]): string | null;
4
+ /** Clear a cached resolve entry (e.g. after installing a new binary). */
5
+ export declare function clearResolveCache(name: string): void;
6
+ //# sourceMappingURL=resolve-bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-bin.d.ts","sourceRoot":"","sources":["../../src/util/resolve-bin.ts"],"names":[],"mappings":"AAuBA,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,GAAE,MAAM,EAAO,GAAG,MAAM,GAAG,IAAI,CA2BhG;AAID,oFAAoF;AACpF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,EAAO,GAAG,MAAM,GAAG,IAAI,CAKhF;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEpD"}
@@ -0,0 +1,66 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { existsSync, readdirSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ /**
6
+ * Resolve a binary path that works in both terminal-launched and
7
+ * GUI-launched (minimal PATH) contexts on macOS.
8
+ *
9
+ * Strategy: try `which` first, then login shell, then well-known paths.
10
+ */
11
+ function nvmVersionBins(home, name) {
12
+ const versionsDir = join(home, '.nvm', 'versions', 'node');
13
+ try {
14
+ return readdirSync(versionsDir)
15
+ .filter(d => d.startsWith('v'))
16
+ .sort().reverse()
17
+ .map(d => join(versionsDir, d, 'bin', name));
18
+ }
19
+ catch {
20
+ return [];
21
+ }
22
+ }
23
+ export function resolveSystemBinary(name, extraSearchPaths = []) {
24
+ // Try shell lookup first
25
+ try {
26
+ const p = execSync(`which ${name}`, { encoding: 'utf8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
27
+ if (p)
28
+ return p;
29
+ }
30
+ catch { }
31
+ // Try login shell — picks up nvm/fnm/etc even in GUI context
32
+ try {
33
+ const p = execSync(`bash -lc "which ${name}"`, { encoding: 'utf8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
34
+ if (p)
35
+ return p;
36
+ }
37
+ catch { }
38
+ // Check well-known paths directly
39
+ const home = homedir();
40
+ const searchPaths = [
41
+ ...extraSearchPaths,
42
+ `/usr/local/bin/${name}`,
43
+ `/opt/homebrew/bin/${name}`,
44
+ `${home}/.local/bin/${name}`,
45
+ `${home}/.nvm/current/bin/${name}`,
46
+ ...nvmVersionBins(home, name),
47
+ ];
48
+ for (const p of searchPaths) {
49
+ if (existsSync(p))
50
+ return p;
51
+ }
52
+ return null;
53
+ }
54
+ const resolvedPaths = {};
55
+ /** Cached version of resolveSystemBinary — result persists for process lifetime. */
56
+ export function cachedResolve(name, extras = []) {
57
+ if (!(name in resolvedPaths)) {
58
+ resolvedPaths[name] = resolveSystemBinary(name, extras);
59
+ }
60
+ return resolvedPaths[name] ?? null;
61
+ }
62
+ /** Clear a cached resolve entry (e.g. after installing a new binary). */
63
+ export function clearResolveCache(name) {
64
+ delete resolvedPaths[name];
65
+ }
66
+ //# sourceMappingURL=resolve-bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-bin.js","sourceRoot":"","sources":["../../src/util/resolve-bin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC;;;;;GAKG;AACH,SAAS,cAAc,CAAC,IAAY,EAAE,IAAY;IAChD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAA;IAC1D,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,WAAW,CAAC;aAC5B,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;aAC9B,IAAI,EAAE,CAAC,OAAO,EAAE;aAChB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAA;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,mBAA6B,EAAE;IAC/E,yBAAyB;IACzB,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,QAAQ,CAAC,SAAS,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;QAChH,IAAI,CAAC;YAAE,OAAO,CAAC,CAAA;IACjB,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,6DAA6D;IAC7D,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,QAAQ,CAAC,mBAAmB,IAAI,GAAG,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;QAC3H,IAAI,CAAC;YAAE,OAAO,CAAC,CAAA;IACjB,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,kCAAkC;IAClC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAA;IACtB,MAAM,WAAW,GAAG;QAClB,GAAG,gBAAgB;QACnB,kBAAkB,IAAI,EAAE;QACxB,qBAAqB,IAAI,EAAE;QAC3B,GAAG,IAAI,eAAe,IAAI,EAAE;QAC5B,GAAG,IAAI,qBAAqB,IAAI,EAAE;QAClC,GAAG,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC;KAC9B,CAAA;IACD,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5B,IAAI,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAA;IAC7B,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,aAAa,GAAkC,EAAE,CAAA;AAEvD,oFAAoF;AACpF,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,SAAmB,EAAE;IAC/D,IAAI,CAAC,CAAC,IAAI,IAAI,aAAa,CAAC,EAAE,CAAC;QAC7B,aAAa,CAAC,IAAI,CAAC,GAAG,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IACzD,CAAC;IACD,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,IAAI,CAAA;AACpC,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,aAAa,CAAC,IAAI,CAAC,CAAA;AAC5B,CAAC"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@spool-lab/core",
3
+ "version": "0.3.3",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "dependencies": {
21
+ "better-sqlite3": "^11.10.0",
22
+ "chokidar": "^4.0.3",
23
+ "effect": "^3.21.0",
24
+ "semver": "^7.7.4",
25
+ "tar": "^7.5.13",
26
+ "@spool-lab/connector-sdk": "^0.1.1"
27
+ },
28
+ "devDependencies": {
29
+ "@effect/vitest": "^0.29.0",
30
+ "@types/better-sqlite3": "^7.6.13",
31
+ "@types/node": "^22.19.17",
32
+ "@types/semver": "^7.7.1",
33
+ "vitest": "^3.2.4"
34
+ },
35
+ "scripts": {
36
+ "rebuild:native": "pnpm run rebuild:native:node",
37
+ "rebuild:native:node": "node ../../scripts/rebuild-better-sqlite3-node.mjs",
38
+ "build": "pnpm --filter @spool-lab/connector-sdk build && tsc",
39
+ "dev": "tsc --watch",
40
+ "test": "pnpm run rebuild:native && vitest run",
41
+ "clean": "rm -rf dist"
42
+ }
43
+ }