couchloop-eq-mcp 2.0.3 → 2.0.5
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/dist/clients/shrinkChatClient.d.ts +28 -28
- package/dist/db/client.d.ts +16 -19
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +52 -62
- package/dist/db/client.js.map +1 -1
- package/dist/resources/journey-status.d.ts.map +1 -1
- package/dist/resources/journey-status.js +10 -12
- package/dist/resources/journey-status.js.map +1 -1
- package/dist/resources/session-summary.d.ts.map +1 -1
- package/dist/resources/session-summary.js +33 -33
- package/dist/resources/session-summary.js.map +1 -1
- package/dist/resources/user-context.d.ts.map +1 -1
- package/dist/resources/user-context.js +26 -41
- package/dist/resources/user-context.js.map +1 -1
- package/dist/server/sse.d.ts.map +1 -1
- package/dist/server/sse.js +55 -27
- package/dist/server/sse.js.map +1 -1
- package/dist/tools/checkpoint.d.ts +1 -8
- package/dist/tools/checkpoint.d.ts.map +1 -1
- package/dist/tools/checkpoint.js +47 -49
- package/dist/tools/checkpoint.js.map +1 -1
- package/dist/tools/correction-flow.d.ts +74 -0
- package/dist/tools/correction-flow.d.ts.map +1 -0
- package/dist/tools/correction-flow.js +205 -0
- package/dist/tools/correction-flow.js.map +1 -0
- package/dist/tools/generate-upgrade-report.d.ts +2 -2
- package/dist/tools/guard.d.ts +3 -3
- package/dist/tools/index.d.ts +2 -4
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -4
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/insight.d.ts +10 -49
- package/dist/tools/insight.d.ts.map +1 -1
- package/dist/tools/insight.js +78 -91
- package/dist/tools/insight.js.map +1 -1
- package/dist/tools/journey.d.ts +5 -5
- package/dist/tools/journey.d.ts.map +1 -1
- package/dist/tools/journey.js +47 -39
- package/dist/tools/journey.js.map +1 -1
- package/dist/tools/pre-review-code.d.ts +2 -2
- package/dist/tools/prevent-ai-errors.d.ts +1 -1
- package/dist/tools/primary-tools.d.ts +20 -0
- package/dist/tools/primary-tools.d.ts.map +1 -1
- package/dist/tools/primary-tools.js +179 -32
- package/dist/tools/primary-tools.js.map +1 -1
- package/dist/tools/protect-files.d.ts +1 -1
- package/dist/tools/sendMessage.d.ts.map +1 -1
- package/dist/tools/sendMessage.js +52 -38
- package/dist/tools/sendMessage.js.map +1 -1
- package/dist/tools/session-manager.d.ts.map +1 -1
- package/dist/tools/session-manager.js +88 -70
- package/dist/tools/session-manager.js.map +1 -1
- package/dist/tools/session.d.ts +7 -86
- package/dist/tools/session.d.ts.map +1 -1
- package/dist/tools/session.js +68 -72
- package/dist/tools/session.js.map +1 -1
- package/dist/tools/smart-context.d.ts +1 -1
- package/dist/tools/status.d.ts +9 -2
- package/dist/tools/status.d.ts.map +1 -1
- package/dist/tools/status.js +112 -63
- package/dist/tools/status.js.map +1 -1
- package/dist/tools/verify.d.ts +2 -2
- package/dist/tools/verify.js.map +1 -1
- package/dist/types/auth.d.ts +2 -2
- package/dist/types/checkpoint.d.ts +4 -4
- package/dist/types/file-protection.d.ts +2 -2
- package/dist/types/insight.d.ts +10 -10
- package/dist/types/journey.d.ts +40 -12
- package/dist/types/journey.d.ts.map +1 -1
- package/dist/types/journey.js +2 -0
- package/dist/types/journey.js.map +1 -1
- package/dist/types/session.d.ts +8 -8
- package/dist/workflows/engine.d.ts +2 -2
- package/dist/workflows/engine.d.ts.map +1 -1
- package/dist/workflows/engine.js +81 -82
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/index.d.ts +4 -4
- package/package.json +2 -10
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Correction Flow — Stateful error correction for AI mistakes.
|
|
3
|
+
*
|
|
4
|
+
* State machine:
|
|
5
|
+
* PENDING_ACKNOWLEDGMENT → user confirms issue → PENDING_FIX_APPROVAL → user approves fix → APPLIED
|
|
6
|
+
* → user says "no" → DISMISSED (ask user to explain)
|
|
7
|
+
*
|
|
8
|
+
* Memory auto-save happens at PENDING_FIX_APPROVAL (after user confirms the issue is correct),
|
|
9
|
+
* not at detection time — because until the user confirms, we don't know if we caught the right problem.
|
|
10
|
+
*
|
|
11
|
+
* SECURITY: Corrections are scoped by session_id. All lookups and mutations
|
|
12
|
+
* require a session_id to prevent cross-user state leakage in shared processes.
|
|
13
|
+
*/
|
|
14
|
+
import { handleSmartContext } from './smart-context.js';
|
|
15
|
+
import { sanitizeText } from '../utils/inputSanitize.js';
|
|
16
|
+
import { logger } from '../utils/logger.js';
|
|
17
|
+
/**
|
|
18
|
+
* Redact common secret patterns from content before persisting.
|
|
19
|
+
* Catches API keys, tokens, passwords, and connection strings.
|
|
20
|
+
*/
|
|
21
|
+
function redactSecrets(content) {
|
|
22
|
+
return content
|
|
23
|
+
.replace(/(?:key|token|secret|password|apikey|api_key|auth)[\s]*[=:]\s*['"]?[^\s'"]{8,}/gi, '[REDACTED_SECRET]')
|
|
24
|
+
.replace(/(?:sk|pk)[-_](?:live|test)[-_][a-zA-Z0-9]{20,}/g, '[REDACTED_KEY]')
|
|
25
|
+
.replace(/eyJ[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}/g, '[REDACTED_JWT]')
|
|
26
|
+
.replace(/(?:postgres|mysql|mongodb|redis):\/\/[^\s]{10,}/gi, '[REDACTED_CONNECTION_STRING]');
|
|
27
|
+
}
|
|
28
|
+
// ── Types ──────────────────────────────────────────────────────────────────────
|
|
29
|
+
export var CorrectionState;
|
|
30
|
+
(function (CorrectionState) {
|
|
31
|
+
CorrectionState["PENDING_ACKNOWLEDGMENT"] = "pending_acknowledgment";
|
|
32
|
+
CorrectionState["PENDING_FIX_APPROVAL"] = "pending_fix_approval";
|
|
33
|
+
CorrectionState["APPLIED"] = "applied";
|
|
34
|
+
CorrectionState["DISMISSED"] = "dismissed";
|
|
35
|
+
})(CorrectionState || (CorrectionState = {}));
|
|
36
|
+
// ── In-memory store keyed by correction ID, scoped by session_id ───────────────
|
|
37
|
+
const pendingCorrections = new Map();
|
|
38
|
+
let correctionCounter = 0;
|
|
39
|
+
function generateCorrectionId() {
|
|
40
|
+
correctionCounter++;
|
|
41
|
+
return `correction_${Date.now()}_${correctionCounter}`;
|
|
42
|
+
}
|
|
43
|
+
// ── Public API ─────────────────────────────────────────────────────────────────
|
|
44
|
+
/**
|
|
45
|
+
* Create a new correction from verify results.
|
|
46
|
+
* Returns the correction in PENDING_ACKNOWLEDGMENT state.
|
|
47
|
+
*/
|
|
48
|
+
export function createCorrection(issues, fixes, content, sessionId, fixedCode, auth) {
|
|
49
|
+
const id = generateCorrectionId();
|
|
50
|
+
const now = Date.now();
|
|
51
|
+
const entry = {
|
|
52
|
+
id,
|
|
53
|
+
session_id: sessionId,
|
|
54
|
+
state: CorrectionState.PENDING_ACKNOWLEDGMENT,
|
|
55
|
+
created_at: new Date(now).toISOString(),
|
|
56
|
+
created_at_ms: now,
|
|
57
|
+
issues_detected: issues,
|
|
58
|
+
proposed_fixes: fixes,
|
|
59
|
+
verified_content: redactSecrets(sanitizeText(content.substring(0, 500))),
|
|
60
|
+
fixed_code: fixedCode,
|
|
61
|
+
user_confirmed_issue: false,
|
|
62
|
+
user_approved_fix: false,
|
|
63
|
+
saved_to_memory: false,
|
|
64
|
+
auth,
|
|
65
|
+
};
|
|
66
|
+
pendingCorrections.set(id, entry);
|
|
67
|
+
logger.info(`[Correction] Created ${id} for session ${sessionId} in PENDING_ACKNOWLEDGMENT state`);
|
|
68
|
+
return entry;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* User confirms the detected issue is correct.
|
|
72
|
+
* Transitions to PENDING_FIX_APPROVAL and auto-saves to memory.
|
|
73
|
+
* Requires session_id to prevent cross-user confirmation.
|
|
74
|
+
*/
|
|
75
|
+
export async function confirmIssue(correctionId, sessionId) {
|
|
76
|
+
const entry = pendingCorrections.get(correctionId);
|
|
77
|
+
if (!entry) {
|
|
78
|
+
throw new Error(`Correction ${correctionId} not found. It may have expired.`);
|
|
79
|
+
}
|
|
80
|
+
if (entry.session_id !== sessionId) {
|
|
81
|
+
throw new Error(`Correction ${correctionId} does not belong to this session.`);
|
|
82
|
+
}
|
|
83
|
+
if (entry.state !== CorrectionState.PENDING_ACKNOWLEDGMENT) {
|
|
84
|
+
throw new Error(`Correction ${correctionId} is in state ${entry.state}, expected ${CorrectionState.PENDING_ACKNOWLEDGMENT}.`);
|
|
85
|
+
}
|
|
86
|
+
entry.state = CorrectionState.PENDING_FIX_APPROVAL;
|
|
87
|
+
entry.user_confirmed_issue = true;
|
|
88
|
+
// Now that the user confirmed the issue is real, save to memory with auth context
|
|
89
|
+
try {
|
|
90
|
+
await handleSmartContext({
|
|
91
|
+
content: `AI mistake confirmed by user: ${entry.issues_detected.join('; ')}. Original content: ${entry.verified_content}`,
|
|
92
|
+
type: 'constraint',
|
|
93
|
+
tags: ['ai-mistake', 'do-not-repeat'],
|
|
94
|
+
session_id: entry.session_id,
|
|
95
|
+
auth: entry.auth,
|
|
96
|
+
});
|
|
97
|
+
entry.saved_to_memory = true;
|
|
98
|
+
logger.info(`[Correction] ${correctionId} → PENDING_FIX_APPROVAL, saved to memory`);
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
logger.warn(`[Correction] Failed to save mistake to memory:`, err);
|
|
102
|
+
entry.memory_save_error = err instanceof Error ? err.message : 'Unknown error';
|
|
103
|
+
}
|
|
104
|
+
return entry;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* User approves the proposed fix.
|
|
108
|
+
* Transitions to APPLIED and cleans up.
|
|
109
|
+
* Requires session_id to prevent cross-user approval.
|
|
110
|
+
*/
|
|
111
|
+
export function approveFix(correctionId, sessionId) {
|
|
112
|
+
const entry = pendingCorrections.get(correctionId);
|
|
113
|
+
if (!entry) {
|
|
114
|
+
throw new Error(`Correction ${correctionId} not found. It may have expired.`);
|
|
115
|
+
}
|
|
116
|
+
if (entry.session_id !== sessionId) {
|
|
117
|
+
throw new Error(`Correction ${correctionId} does not belong to this session.`);
|
|
118
|
+
}
|
|
119
|
+
if (entry.state !== CorrectionState.PENDING_FIX_APPROVAL) {
|
|
120
|
+
throw new Error(`Correction ${correctionId} is in state ${entry.state}, expected ${CorrectionState.PENDING_FIX_APPROVAL}. Did you call confirm first?`);
|
|
121
|
+
}
|
|
122
|
+
entry.state = CorrectionState.APPLIED;
|
|
123
|
+
entry.user_approved_fix = true;
|
|
124
|
+
logger.info(`[Correction] ${correctionId} → APPLIED`);
|
|
125
|
+
// Clean up after a short delay (let the response be read first)
|
|
126
|
+
setTimeout(() => pendingCorrections.delete(correctionId), 60000);
|
|
127
|
+
return entry;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* User says "no, that's not the issue".
|
|
131
|
+
* Can only dismiss from PENDING_ACKNOWLEDGMENT or PENDING_FIX_APPROVAL — not terminal states.
|
|
132
|
+
* Requires session_id to prevent cross-user dismissal.
|
|
133
|
+
*/
|
|
134
|
+
export function dismissCorrection(correctionId, sessionId) {
|
|
135
|
+
const entry = pendingCorrections.get(correctionId);
|
|
136
|
+
if (!entry) {
|
|
137
|
+
throw new Error(`Correction ${correctionId} not found. It may have expired.`);
|
|
138
|
+
}
|
|
139
|
+
if (entry.session_id !== sessionId) {
|
|
140
|
+
throw new Error(`Correction ${correctionId} does not belong to this session.`);
|
|
141
|
+
}
|
|
142
|
+
if (entry.state === CorrectionState.APPLIED || entry.state === CorrectionState.DISMISSED) {
|
|
143
|
+
throw new Error(`Correction ${correctionId} is already in terminal state ${entry.state} and cannot be dismissed.`);
|
|
144
|
+
}
|
|
145
|
+
entry.state = CorrectionState.DISMISSED;
|
|
146
|
+
logger.info(`[Correction] ${correctionId} → DISMISSED`);
|
|
147
|
+
// Clean up after a delay
|
|
148
|
+
setTimeout(() => pendingCorrections.delete(correctionId), 60000);
|
|
149
|
+
return entry;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Get a pending correction by ID.
|
|
153
|
+
*/
|
|
154
|
+
export function getCorrection(correctionId) {
|
|
155
|
+
return pendingCorrections.get(correctionId);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get the most recent pending correction for a specific session.
|
|
159
|
+
* Only returns corrections belonging to the given session_id.
|
|
160
|
+
* Optionally filter by expected state to avoid returning entries
|
|
161
|
+
* that the caller's operation would immediately reject.
|
|
162
|
+
*/
|
|
163
|
+
export function getMostRecentPendingCorrection(sessionId, expectedState) {
|
|
164
|
+
let latest;
|
|
165
|
+
for (const entry of pendingCorrections.values()) {
|
|
166
|
+
if (entry.session_id !== sessionId)
|
|
167
|
+
continue;
|
|
168
|
+
if (expectedState) {
|
|
169
|
+
if (entry.state !== expectedState)
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
// Default: return any non-terminal correction
|
|
174
|
+
if (entry.state !== CorrectionState.PENDING_ACKNOWLEDGMENT &&
|
|
175
|
+
entry.state !== CorrectionState.PENDING_FIX_APPROVAL)
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (!latest || entry.created_at_ms > latest.created_at_ms) {
|
|
179
|
+
latest = entry;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return latest;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Clear all corrections. Used in tests to isolate state between test cases.
|
|
186
|
+
*/
|
|
187
|
+
export function clearAllCorrections() {
|
|
188
|
+
pendingCorrections.clear();
|
|
189
|
+
}
|
|
190
|
+
// ── Cleanup expired corrections (older than 30 minutes) ────────────────────────
|
|
191
|
+
const cleanupInterval = setInterval(() => {
|
|
192
|
+
const cutoff = Date.now() - 30 * 60 * 1000;
|
|
193
|
+
let cleaned = 0;
|
|
194
|
+
for (const [id, entry] of pendingCorrections.entries()) {
|
|
195
|
+
if (entry.created_at_ms < cutoff) {
|
|
196
|
+
pendingCorrections.delete(id);
|
|
197
|
+
cleaned++;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (cleaned > 0) {
|
|
201
|
+
logger.info(`[Correction] Cleaned up ${cleaned} expired corrections`);
|
|
202
|
+
}
|
|
203
|
+
}, 5 * 60 * 1000);
|
|
204
|
+
cleanupInterval.unref();
|
|
205
|
+
//# sourceMappingURL=correction-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"correction-flow.js","sourceRoot":"","sources":["../../src/tools/correction-flow.ts"],"names":[],"mappings":"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"}
|
|
@@ -58,7 +58,7 @@ export declare function handleGenerateUpgradeReport(args: unknown): Promise<{
|
|
|
58
58
|
package: string;
|
|
59
59
|
from_version: string | undefined;
|
|
60
60
|
to_version: string;
|
|
61
|
-
complexity: "
|
|
61
|
+
complexity: "low" | "medium" | "high";
|
|
62
62
|
estimated_time: string;
|
|
63
63
|
upgrade_command: string;
|
|
64
64
|
install_command: string;
|
|
@@ -75,7 +75,7 @@ export declare function handleGenerateUpgradeReport(args: unknown): Promise<{
|
|
|
75
75
|
testing_strategy: string[];
|
|
76
76
|
rollback_strategy: string;
|
|
77
77
|
risks: {
|
|
78
|
-
level: "
|
|
78
|
+
level: "low" | "medium" | "high" | "critical";
|
|
79
79
|
factors: string[];
|
|
80
80
|
mitigations: string[];
|
|
81
81
|
};
|
package/dist/tools/guard.d.ts
CHANGED
|
@@ -42,22 +42,22 @@ declare const GuardInputSchema: z.ZodObject<{
|
|
|
42
42
|
session_id: z.ZodOptional<z.ZodString>;
|
|
43
43
|
mode: z.ZodDefault<z.ZodOptional<z.ZodEnum<["enforce", "shadow", "bypass"]>>>;
|
|
44
44
|
}, "strip", z.ZodTypeAny, {
|
|
45
|
-
mode: "enforce" | "shadow" | "bypass";
|
|
46
|
-
response: string;
|
|
47
45
|
conversation: {
|
|
48
46
|
content: string;
|
|
49
47
|
role: "user" | "assistant";
|
|
50
48
|
}[];
|
|
49
|
+
mode: "enforce" | "shadow" | "bypass";
|
|
50
|
+
response: string;
|
|
51
51
|
domain: "clinical" | "auto" | "dev";
|
|
52
52
|
session_id?: string | undefined;
|
|
53
53
|
}, {
|
|
54
54
|
response: string;
|
|
55
|
-
mode?: "enforce" | "shadow" | "bypass" | undefined;
|
|
56
55
|
session_id?: string | undefined;
|
|
57
56
|
conversation?: {
|
|
58
57
|
content: string;
|
|
59
58
|
role: "user" | "assistant";
|
|
60
59
|
}[] | undefined;
|
|
60
|
+
mode?: "enforce" | "shadow" | "bypass" | undefined;
|
|
61
61
|
domain?: "clinical" | "auto" | "dev" | undefined;
|
|
62
62
|
}>;
|
|
63
63
|
export type GuardInput = z.infer<typeof GuardInputSchema>;
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
* MCP Tools - Main Export
|
|
3
3
|
*
|
|
4
4
|
* This module provides two modes:
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Set MCP_TOOL_MODE=full in environment for full mode
|
|
5
|
+
* 4 primary tools: memory, conversation, review, status
|
|
6
|
+
* Consolidated from 10 → 4 in v2.1.0
|
|
9
7
|
*/
|
|
10
8
|
export { setupTools } from "./primary-tools.js";
|
|
11
9
|
export { handleCheckVersions } from "./check-versions.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EACH,eAAe,EAAE,eAAe,EAAE,YAAY,EACjD,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/tools/index.js
CHANGED
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
* MCP Tools - Main Export
|
|
3
3
|
*
|
|
4
4
|
* This module provides two modes:
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Set MCP_TOOL_MODE=full in environment for full mode
|
|
5
|
+
* 4 primary tools: memory, conversation, review, status
|
|
6
|
+
* Consolidated from 10 → 4 in v2.1.0
|
|
9
7
|
*/
|
|
10
8
|
// Re-export the primary tools setup as default
|
|
11
9
|
export { setupTools } from "./primary-tools.js";
|
package/dist/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,+CAA+C;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,8CAA8C;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EACH,eAAe,EAAE,eAAe,EAAE,YAAY,EACjD,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/tools/insight.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import type { Insight } from '../db/schema.js';
|
|
1
2
|
import { type SaveInsightInput, type GetUserContextInput } from '../types/insight.js';
|
|
2
3
|
export interface RecentSession {
|
|
3
4
|
id: string;
|
|
4
5
|
status: string;
|
|
5
|
-
started_at:
|
|
6
|
-
completed_at:
|
|
6
|
+
started_at: string;
|
|
7
|
+
completed_at: string | null;
|
|
7
8
|
journey_id: string | null;
|
|
8
9
|
}
|
|
9
10
|
export declare function saveInsight(args: SaveInsightInput): Promise<{
|
|
@@ -21,65 +22,25 @@ export declare function getInsights(args: {
|
|
|
21
22
|
error: string;
|
|
22
23
|
details?: Record<string, unknown>;
|
|
23
24
|
} | {
|
|
24
|
-
insights:
|
|
25
|
-
id: string;
|
|
26
|
-
createdAt: Date;
|
|
27
|
-
tags: string[];
|
|
28
|
-
userId: string;
|
|
29
|
-
sessionId: string | null;
|
|
30
|
-
content: string;
|
|
31
|
-
}[];
|
|
25
|
+
insights: any[];
|
|
32
26
|
count: number;
|
|
33
27
|
}>;
|
|
34
28
|
export declare function getUserContext(args: GetUserContextInput): Promise<{
|
|
35
29
|
error: string;
|
|
36
30
|
details?: Record<string, unknown>;
|
|
37
31
|
} | {
|
|
38
|
-
user:
|
|
39
|
-
id: string;
|
|
40
|
-
externalId: string;
|
|
41
|
-
isTestAccount: boolean;
|
|
42
|
-
createdAt: Date;
|
|
43
|
-
updatedAt: Date;
|
|
44
|
-
preferences: {
|
|
45
|
-
timezone?: string;
|
|
46
|
-
preferredJourneyLength?: "short" | "medium" | "long";
|
|
47
|
-
} | null;
|
|
48
|
-
} | undefined;
|
|
32
|
+
user: any;
|
|
49
33
|
recent_insights: never[];
|
|
50
34
|
recent_sessions: never[];
|
|
51
35
|
active_session: null;
|
|
52
36
|
} | {
|
|
53
37
|
user: {
|
|
54
|
-
id:
|
|
55
|
-
preferences:
|
|
56
|
-
|
|
57
|
-
preferredJourneyLength?: "short" | "medium" | "long";
|
|
58
|
-
} | null;
|
|
59
|
-
created_at: Date;
|
|
38
|
+
id: any;
|
|
39
|
+
preferences: any;
|
|
40
|
+
created_at: any;
|
|
60
41
|
};
|
|
61
|
-
recent_insights:
|
|
62
|
-
id: string;
|
|
63
|
-
createdAt: Date;
|
|
64
|
-
tags: string[];
|
|
65
|
-
userId: string;
|
|
66
|
-
sessionId: string | null;
|
|
67
|
-
content: string;
|
|
68
|
-
}[];
|
|
42
|
+
recent_insights: Insight[];
|
|
69
43
|
recent_sessions: RecentSession[];
|
|
70
|
-
active_session:
|
|
71
|
-
id: string;
|
|
72
|
-
updatedAt: Date;
|
|
73
|
-
userId: string;
|
|
74
|
-
journeyId: string | null;
|
|
75
|
-
status: "active" | "paused" | "completed" | "abandoned";
|
|
76
|
-
currentStep: number;
|
|
77
|
-
startedAt: Date;
|
|
78
|
-
lastActiveAt: Date;
|
|
79
|
-
completedAt: Date | null;
|
|
80
|
-
metadata: unknown;
|
|
81
|
-
threadId: string | null;
|
|
82
|
-
lastSyncedAt: Date | null;
|
|
83
|
-
} | undefined;
|
|
44
|
+
active_session: any;
|
|
84
45
|
}>;
|
|
85
46
|
//# sourceMappingURL=insight.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insight.d.ts","sourceRoot":"","sources":["../../src/tools/insight.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"insight.d.ts","sourceRoot":"","sources":["../../src/tools/insight.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAA2C,KAAK,gBAAgB,EAAE,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAM/H,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,gBAAgB;;;;;;GA+DvD;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE;;;;;;GA0D9G;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,mBAAmB;;;;;;;;;;;;;;;;;GAwF7D"}
|
package/dist/tools/insight.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { insights, users, sessions } from '../db/schema.js';
|
|
3
|
-
import { eq, desc, and } from 'drizzle-orm';
|
|
1
|
+
import { getSupabaseClient, throwOnError } from '../db/supabase-helpers.js';
|
|
4
2
|
import { SaveInsightSchema, GetUserContextSchema } from '../types/insight.js';
|
|
5
3
|
import { extractUserFromContext } from '../types/auth.js';
|
|
6
4
|
import { handleError, NotFoundError } from '../utils/errors.js';
|
|
@@ -8,43 +6,41 @@ import { logger } from '../utils/logger.js';
|
|
|
8
6
|
export async function saveInsight(args) {
|
|
9
7
|
try {
|
|
10
8
|
const input = SaveInsightSchema.parse(args);
|
|
11
|
-
const
|
|
9
|
+
const supabase = getSupabaseClient();
|
|
12
10
|
// Extract user ID from auth context or generate anonymous user
|
|
13
11
|
const externalUserId = await extractUserFromContext(input.auth);
|
|
14
|
-
const
|
|
15
|
-
.
|
|
16
|
-
.
|
|
17
|
-
|
|
12
|
+
const user = throwOnError(await supabase
|
|
13
|
+
.from('users')
|
|
14
|
+
.upsert({
|
|
15
|
+
external_id: externalUserId,
|
|
18
16
|
preferences: {},
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
})
|
|
24
|
-
.returning();
|
|
25
|
-
const user = userResult[0];
|
|
17
|
+
updated_at: new Date().toISOString(),
|
|
18
|
+
}, { onConflict: 'external_id' })
|
|
19
|
+
.select()
|
|
20
|
+
.single());
|
|
26
21
|
// Verify session if provided
|
|
27
22
|
if (input.session_id) {
|
|
28
|
-
const
|
|
29
|
-
.
|
|
30
|
-
.
|
|
31
|
-
.
|
|
32
|
-
.
|
|
23
|
+
const session = throwOnError(await supabase
|
|
24
|
+
.from('sessions')
|
|
25
|
+
.select('*')
|
|
26
|
+
.eq('id', input.session_id)
|
|
27
|
+
.eq('user_id', user.id)
|
|
28
|
+
.maybeSingle());
|
|
33
29
|
if (!session) {
|
|
34
30
|
throw new NotFoundError('Session', input.session_id);
|
|
35
31
|
}
|
|
36
32
|
}
|
|
37
33
|
// Save insight
|
|
38
|
-
const
|
|
39
|
-
.
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
const insight = throwOnError(await supabase
|
|
35
|
+
.from('insights')
|
|
36
|
+
.insert({
|
|
37
|
+
user_id: user.id,
|
|
38
|
+
session_id: input.session_id || null,
|
|
43
39
|
content: input.content,
|
|
44
40
|
tags: input.tags || [],
|
|
45
41
|
})
|
|
46
|
-
.
|
|
47
|
-
|
|
42
|
+
.select()
|
|
43
|
+
.single());
|
|
48
44
|
logger.info(`Saved insight: ${insight.id}`);
|
|
49
45
|
// Return sanitized response (no internal IDs)
|
|
50
46
|
return {
|
|
@@ -60,23 +56,24 @@ export async function saveInsight(args) {
|
|
|
60
56
|
export async function getInsights(args) {
|
|
61
57
|
try {
|
|
62
58
|
const { session_id, limit = 10, auth } = args;
|
|
63
|
-
const
|
|
59
|
+
const supabase = getSupabaseClient();
|
|
64
60
|
// Extract user ID from auth context or generate anonymous user
|
|
65
61
|
const externalUserId = await extractUserFromContext(auth);
|
|
66
|
-
const
|
|
67
|
-
.
|
|
68
|
-
.
|
|
69
|
-
.
|
|
70
|
-
.
|
|
62
|
+
const user = throwOnError(await supabase
|
|
63
|
+
.from('users')
|
|
64
|
+
.select('*')
|
|
65
|
+
.eq('external_id', externalUserId)
|
|
66
|
+
.maybeSingle());
|
|
71
67
|
if (!user) {
|
|
72
68
|
// Create user if doesn't exist
|
|
73
|
-
const
|
|
74
|
-
.
|
|
75
|
-
.
|
|
76
|
-
|
|
69
|
+
const newUser = throwOnError(await supabase
|
|
70
|
+
.from('users')
|
|
71
|
+
.insert({
|
|
72
|
+
external_id: externalUserId,
|
|
77
73
|
preferences: {},
|
|
78
74
|
})
|
|
79
|
-
.
|
|
75
|
+
.select()
|
|
76
|
+
.single());
|
|
80
77
|
if (!newUser) {
|
|
81
78
|
throw new NotFoundError('User');
|
|
82
79
|
}
|
|
@@ -85,26 +82,19 @@ export async function getInsights(args) {
|
|
|
85
82
|
count: 0,
|
|
86
83
|
};
|
|
87
84
|
}
|
|
88
|
-
let
|
|
85
|
+
let query = supabase
|
|
86
|
+
.from('insights')
|
|
87
|
+
.select('*')
|
|
88
|
+
.eq('user_id', user.id)
|
|
89
|
+
.order('created_at', { ascending: false })
|
|
90
|
+
.limit(limit);
|
|
89
91
|
if (session_id) {
|
|
90
|
-
|
|
91
|
-
.select()
|
|
92
|
-
.from(insights)
|
|
93
|
-
.where(and(eq(insights.userId, user.id), eq(insights.sessionId, session_id)))
|
|
94
|
-
.orderBy(desc(insights.createdAt))
|
|
95
|
-
.limit(limit);
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
userInsights = await db
|
|
99
|
-
.select()
|
|
100
|
-
.from(insights)
|
|
101
|
-
.where(eq(insights.userId, user.id))
|
|
102
|
-
.orderBy(desc(insights.createdAt))
|
|
103
|
-
.limit(limit);
|
|
92
|
+
query = query.eq('session_id', session_id);
|
|
104
93
|
}
|
|
94
|
+
const userInsights = throwOnError(await query);
|
|
105
95
|
return {
|
|
106
|
-
insights: userInsights,
|
|
107
|
-
count: userInsights.length,
|
|
96
|
+
insights: userInsights ?? [],
|
|
97
|
+
count: (userInsights ?? []).length,
|
|
108
98
|
};
|
|
109
99
|
}
|
|
110
100
|
catch (error) {
|
|
@@ -115,23 +105,24 @@ export async function getInsights(args) {
|
|
|
115
105
|
export async function getUserContext(args) {
|
|
116
106
|
try {
|
|
117
107
|
const input = GetUserContextSchema.parse(args);
|
|
118
|
-
const
|
|
108
|
+
const supabase = getSupabaseClient();
|
|
119
109
|
// Extract user ID from auth context or generate anonymous user
|
|
120
110
|
const externalUserId = await extractUserFromContext(input.auth);
|
|
121
|
-
const
|
|
122
|
-
.
|
|
123
|
-
.
|
|
124
|
-
.
|
|
125
|
-
.
|
|
111
|
+
const user = throwOnError(await supabase
|
|
112
|
+
.from('users')
|
|
113
|
+
.select('*')
|
|
114
|
+
.eq('external_id', externalUserId)
|
|
115
|
+
.maybeSingle());
|
|
126
116
|
if (!user) {
|
|
127
117
|
// Create user if doesn't exist
|
|
128
|
-
const
|
|
129
|
-
.
|
|
130
|
-
.
|
|
131
|
-
|
|
118
|
+
const newUser = throwOnError(await supabase
|
|
119
|
+
.from('users')
|
|
120
|
+
.insert({
|
|
121
|
+
external_id: externalUserId,
|
|
132
122
|
preferences: {},
|
|
133
123
|
})
|
|
134
|
-
.
|
|
124
|
+
.select()
|
|
125
|
+
.single());
|
|
135
126
|
return {
|
|
136
127
|
user: newUser,
|
|
137
128
|
recent_insights: [],
|
|
@@ -142,41 +133,37 @@ export async function getUserContext(args) {
|
|
|
142
133
|
// Get recent insights if requested
|
|
143
134
|
let recentInsights = [];
|
|
144
135
|
if (input.include_recent_insights) {
|
|
145
|
-
recentInsights = await
|
|
146
|
-
.
|
|
147
|
-
.
|
|
148
|
-
.
|
|
149
|
-
.
|
|
150
|
-
.limit(5);
|
|
136
|
+
recentInsights = throwOnError(await supabase
|
|
137
|
+
.from('insights')
|
|
138
|
+
.select('*')
|
|
139
|
+
.eq('user_id', user.id)
|
|
140
|
+
.order('created_at', { ascending: false })
|
|
141
|
+
.limit(5)) ?? [];
|
|
151
142
|
}
|
|
152
143
|
// Get recent sessions if requested
|
|
153
144
|
let recentSessions = [];
|
|
154
145
|
if (input.include_session_history) {
|
|
155
|
-
recentSessions = await
|
|
156
|
-
.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
started_at:
|
|
160
|
-
|
|
161
|
-
journey_id: sessions.journeyId,
|
|
162
|
-
})
|
|
163
|
-
.from(sessions)
|
|
164
|
-
.where(eq(sessions.userId, user.id))
|
|
165
|
-
.orderBy(desc(sessions.startedAt))
|
|
166
|
-
.limit(5);
|
|
146
|
+
recentSessions = throwOnError(await supabase
|
|
147
|
+
.from('sessions')
|
|
148
|
+
.select('id, status, started_at, completed_at, journey_id')
|
|
149
|
+
.eq('user_id', user.id)
|
|
150
|
+
.order('started_at', { ascending: false })
|
|
151
|
+
.limit(5)) ?? [];
|
|
167
152
|
}
|
|
168
153
|
// Get active session
|
|
169
|
-
const
|
|
170
|
-
.
|
|
171
|
-
.
|
|
172
|
-
.
|
|
173
|
-
.
|
|
174
|
-
.
|
|
154
|
+
const activeSession = throwOnError(await supabase
|
|
155
|
+
.from('sessions')
|
|
156
|
+
.select('*')
|
|
157
|
+
.eq('user_id', user.id)
|
|
158
|
+
.eq('status', 'active')
|
|
159
|
+
.order('last_active_at', { ascending: false })
|
|
160
|
+
.limit(1)
|
|
161
|
+
.maybeSingle());
|
|
175
162
|
return {
|
|
176
163
|
user: {
|
|
177
164
|
id: user.id,
|
|
178
165
|
preferences: user.preferences,
|
|
179
|
-
created_at: user.
|
|
166
|
+
created_at: user.created_at,
|
|
180
167
|
},
|
|
181
168
|
recent_insights: recentInsights,
|
|
182
169
|
recent_sessions: recentSessions,
|