daeda-mcp 1.0.3 → 1.0.4
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.
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": [
|
|
3
|
+
"Copy this file to ~/.daeda-mcp/export_override.json to use export override.",
|
|
4
|
+
"Set skipExports=true to skip HubSpot exports entirely and rely on seeding only.",
|
|
5
|
+
"Set skipExports=false and provide export IDs to use existing exports (avoids hitting 30/day limit).",
|
|
6
|
+
"Export IDs can be found from init_state.json or HubSpot API exports list."
|
|
7
|
+
],
|
|
8
|
+
"skipExports": true,
|
|
9
|
+
"exports": {
|
|
10
|
+
"contacts": {
|
|
11
|
+
"exportId": null,
|
|
12
|
+
"status": "synced",
|
|
13
|
+
"error": null
|
|
14
|
+
},
|
|
15
|
+
"companies": {
|
|
16
|
+
"exportId": null,
|
|
17
|
+
"status": "synced",
|
|
18
|
+
"error": null
|
|
19
|
+
},
|
|
20
|
+
"deals": {
|
|
21
|
+
"exportId": null,
|
|
22
|
+
"status": "synced",
|
|
23
|
+
"error": null
|
|
24
|
+
},
|
|
25
|
+
"contact_company": {
|
|
26
|
+
"exportId": null,
|
|
27
|
+
"status": "synced",
|
|
28
|
+
"error": null
|
|
29
|
+
},
|
|
30
|
+
"deal_contact": {
|
|
31
|
+
"exportId": null,
|
|
32
|
+
"status": "synced",
|
|
33
|
+
"error": null
|
|
34
|
+
},
|
|
35
|
+
"deal_company": {
|
|
36
|
+
"exportId": null,
|
|
37
|
+
"status": "synced",
|
|
38
|
+
"error": null
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -56,10 +56,20 @@ export async function startInitialization(force = false) {
|
|
|
56
56
|
writeInitState(newState);
|
|
57
57
|
console.error("[init-manager] Starting seeding first, then export requests...");
|
|
58
58
|
try {
|
|
59
|
-
runSeeding(token).catch((err) => {
|
|
59
|
+
const seedingPromise = runSeeding(token).catch((err) => {
|
|
60
60
|
console.error("[init-manager] Seeding failed (non-fatal):", err);
|
|
61
61
|
});
|
|
62
|
-
await fireAllExportRequests(token, newState);
|
|
62
|
+
const skipPolling = await fireAllExportRequests(token, newState);
|
|
63
|
+
if (skipPolling) {
|
|
64
|
+
console.error("[init-manager] Override specifies skip exports or all synced - waiting for seeding only");
|
|
65
|
+
await seedingPromise;
|
|
66
|
+
newState.status = "ready";
|
|
67
|
+
await setMetadata("last_synced", new Date().toISOString());
|
|
68
|
+
await setMetadata("initialized_at", newState.startedAt || new Date().toISOString());
|
|
69
|
+
writeInitState(newState);
|
|
70
|
+
console.error("[init-manager] Initialization complete (seeding only mode)");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
63
73
|
newState.status = "polling_exports";
|
|
64
74
|
newState.seedingStatus = "pending";
|
|
65
75
|
writeInitState(newState);
|
|
@@ -77,17 +87,30 @@ async function fireAllExportRequests(token, state) {
|
|
|
77
87
|
const override = readExportOverride();
|
|
78
88
|
if (override) {
|
|
79
89
|
console.error("[init-manager] Using export override file");
|
|
90
|
+
if (override.skipExports) {
|
|
91
|
+
console.error("[init-manager] skipExports=true - skipping export setup, using seeding only");
|
|
92
|
+
for (const exportName of ALL_EXPORTS) {
|
|
93
|
+
state.exports[exportName].status = "synced";
|
|
94
|
+
}
|
|
95
|
+
writeInitState(state);
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
80
98
|
for (const exportName of ALL_EXPORTS) {
|
|
81
|
-
const overrideExport = override[exportName];
|
|
99
|
+
const overrideExport = override.exports[exportName];
|
|
82
100
|
if (overrideExport?.exportId) {
|
|
83
101
|
state.exports[exportName].exportId = overrideExport.exportId;
|
|
84
102
|
state.exports[exportName].status = overrideExport.status;
|
|
85
103
|
state.exports[exportName].error = overrideExport.error;
|
|
86
|
-
console.error(`[init-manager] Override ${exportName}: ${overrideExport.exportId}`);
|
|
104
|
+
console.error(`[init-manager] Override ${exportName}: ${overrideExport.exportId} (${overrideExport.status})`);
|
|
87
105
|
}
|
|
88
106
|
}
|
|
89
107
|
writeInitState(state);
|
|
90
|
-
|
|
108
|
+
const allSynced = ALL_EXPORTS.every(name => state.exports[name].status === "synced");
|
|
109
|
+
if (allSynced) {
|
|
110
|
+
console.error("[init-manager] All exports marked as synced in override - skipping poll loop");
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
91
114
|
}
|
|
92
115
|
console.error("[init-manager] Checking for reusable exports from the past week...");
|
|
93
116
|
let reusableExports;
|
|
@@ -132,6 +155,7 @@ async function fireAllExportRequests(token, state) {
|
|
|
132
155
|
writeInitState(state);
|
|
133
156
|
console.error(`[init-manager] Started new ${assoc.name} export: ${exportId}`);
|
|
134
157
|
}
|
|
158
|
+
return false;
|
|
135
159
|
}
|
|
136
160
|
function startPollLoop() {
|
|
137
161
|
if (pollLoopRunning) {
|
|
@@ -29,4 +29,13 @@ export declare function resetInitState(): void;
|
|
|
29
29
|
export declare function getSyncedCount(state: InitState): number;
|
|
30
30
|
export declare function isFullySynced(state: InitState): boolean;
|
|
31
31
|
export declare function getStateFilePath(): string;
|
|
32
|
-
export
|
|
32
|
+
export interface ExportOverride {
|
|
33
|
+
exports: Record<ExportName, ExportState>;
|
|
34
|
+
skipExports?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export declare function readExportOverride(): ExportOverride | null;
|
|
37
|
+
export declare function getOverrideFileLocations(): {
|
|
38
|
+
env: string | undefined;
|
|
39
|
+
user: string;
|
|
40
|
+
package: string;
|
|
41
|
+
};
|
package/dist/sync/init-state.js
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
2
2
|
import { join, dirname } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { homedir } from "node:os";
|
|
4
5
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
6
|
+
const PACKAGE_DATA_DIR = join(__dirname, "..", "..", "data");
|
|
7
|
+
const USER_DATA_DIR = join(homedir(), ".daeda-mcp");
|
|
8
|
+
const STATE_FILE = join(PACKAGE_DATA_DIR, "init_state.json");
|
|
9
|
+
function getOverrideFilePath() {
|
|
10
|
+
if (process.env.DAEDA_EXPORT_OVERRIDE) {
|
|
11
|
+
return process.env.DAEDA_EXPORT_OVERRIDE;
|
|
12
|
+
}
|
|
13
|
+
const userOverride = join(USER_DATA_DIR, "export_override.json");
|
|
14
|
+
if (existsSync(userOverride)) {
|
|
15
|
+
return userOverride;
|
|
16
|
+
}
|
|
17
|
+
const packageOverride = join(PACKAGE_DATA_DIR, "export_override.json");
|
|
18
|
+
if (existsSync(packageOverride)) {
|
|
19
|
+
return packageOverride;
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
8
23
|
export const ALL_EXPORTS = [
|
|
9
24
|
"contacts",
|
|
10
25
|
"companies",
|
|
@@ -48,7 +63,7 @@ export function readInitState() {
|
|
|
48
63
|
}
|
|
49
64
|
}
|
|
50
65
|
export function writeInitState(state) {
|
|
51
|
-
mkdirSync(
|
|
66
|
+
mkdirSync(PACKAGE_DATA_DIR, { recursive: true });
|
|
52
67
|
writeFileSync(STATE_FILE, JSON.stringify(state, null, 2), "utf-8");
|
|
53
68
|
}
|
|
54
69
|
export function resetInitState() {
|
|
@@ -65,13 +80,27 @@ export function getStateFilePath() {
|
|
|
65
80
|
}
|
|
66
81
|
export function readExportOverride() {
|
|
67
82
|
try {
|
|
68
|
-
|
|
83
|
+
const overridePath = getOverrideFilePath();
|
|
84
|
+
if (!overridePath || !existsSync(overridePath)) {
|
|
69
85
|
return null;
|
|
70
86
|
}
|
|
71
|
-
|
|
72
|
-
|
|
87
|
+
console.error(`[init-state] Found override file at: ${overridePath}`);
|
|
88
|
+
const content = readFileSync(overridePath, "utf-8");
|
|
89
|
+
const parsed = JSON.parse(content);
|
|
90
|
+
if (parsed.exports) {
|
|
91
|
+
return parsed;
|
|
92
|
+
}
|
|
93
|
+
return { exports: parsed };
|
|
73
94
|
}
|
|
74
|
-
catch {
|
|
95
|
+
catch (err) {
|
|
96
|
+
console.error(`[init-state] Failed to read override file:`, err);
|
|
75
97
|
return null;
|
|
76
98
|
}
|
|
77
99
|
}
|
|
100
|
+
export function getOverrideFileLocations() {
|
|
101
|
+
return {
|
|
102
|
+
env: process.env.DAEDA_EXPORT_OVERRIDE,
|
|
103
|
+
user: join(USER_DATA_DIR, "export_override.json"),
|
|
104
|
+
package: join(PACKAGE_DATA_DIR, "export_override.json"),
|
|
105
|
+
};
|
|
106
|
+
}
|
package/dist/tools/auth.d.ts
CHANGED
package/dist/tools/auth.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getHubSpotToken } from "../db/keychain.js";
|
|
2
2
|
import { dbExists, isDbHealthy, getRecordCount, getAllMetadata, } from "../db/sqlite.js";
|
|
3
3
|
import { getInitStatus, forceReinitialize, } from "../sync/init-manager.js";
|
|
4
|
-
import { getSyncedCount, ALL_EXPORTS } from "../sync/init-state.js";
|
|
4
|
+
import { getSyncedCount, ALL_EXPORTS, readExportOverride } from "../sync/init-state.js";
|
|
5
5
|
export async function dbStatus(forceReinit = false) {
|
|
6
6
|
if (forceReinit) {
|
|
7
7
|
forceReinitialize();
|
|
@@ -102,9 +102,10 @@ export async function dbStatus(forceReinit = false) {
|
|
|
102
102
|
getRecordCount("deals"),
|
|
103
103
|
]);
|
|
104
104
|
const metadata = await getAllMetadata();
|
|
105
|
+
const override = readExportOverride();
|
|
105
106
|
const result = {
|
|
106
107
|
status: "ready",
|
|
107
|
-
syncProgress: "6/6 exports synced",
|
|
108
|
+
syncProgress: override?.skipExports ? "seeding only (exports skipped)" : "6/6 exports synced",
|
|
108
109
|
hasToken,
|
|
109
110
|
lastSynced: metadata.last_synced || null,
|
|
110
111
|
initializedAt: metadata.initialized_at || initState.startedAt || null,
|
|
@@ -117,6 +118,10 @@ export async function dbStatus(forceReinit = false) {
|
|
|
117
118
|
deal_company: parseInt(metadata.deal_company_count || "0"),
|
|
118
119
|
},
|
|
119
120
|
};
|
|
121
|
+
if (override) {
|
|
122
|
+
result.overrideActive = true;
|
|
123
|
+
result.skipExportsMode = override.skipExports ?? false;
|
|
124
|
+
}
|
|
120
125
|
if (initState.seedingStatus) {
|
|
121
126
|
result.seedingStatus = initState.seedingStatus;
|
|
122
127
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "daeda-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "MCP server for HubSpot CRM data sync",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
"daeda-mcp": "./dist/index.js"
|
|
26
26
|
},
|
|
27
27
|
"files": [
|
|
28
|
-
"dist"
|
|
28
|
+
"dist",
|
|
29
|
+
"data/export_override.sample.json"
|
|
29
30
|
],
|
|
30
31
|
"scripts": {
|
|
31
32
|
"build": "tsc",
|