@memoire-ai/collector 0.1.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.
Files changed (97) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.turbo/turbo-test.log +45 -0
  3. package/cursor-hooks/README.md +119 -0
  4. package/cursor-hooks/context-inject.sh +118 -0
  5. package/cursor-hooks/hooks.json +39 -0
  6. package/cursor-hooks/save-file-edit.sh +130 -0
  7. package/cursor-hooks/save-observation.sh +116 -0
  8. package/cursor-hooks/save-shell-execution.sh +121 -0
  9. package/cursor-hooks/session-summary.sh +142 -0
  10. package/dist/capture.d.ts +111 -0
  11. package/dist/capture.d.ts.map +1 -0
  12. package/dist/capture.integration.d.ts +2 -0
  13. package/dist/capture.integration.d.ts.map +1 -0
  14. package/dist/capture.integration.js +67 -0
  15. package/dist/capture.integration.js.map +1 -0
  16. package/dist/capture.js +264 -0
  17. package/dist/capture.js.map +1 -0
  18. package/dist/client-summarizer.d.ts +59 -0
  19. package/dist/client-summarizer.d.ts.map +1 -0
  20. package/dist/client-summarizer.js +211 -0
  21. package/dist/client-summarizer.js.map +1 -0
  22. package/dist/client-summarizer.test.d.ts +2 -0
  23. package/dist/client-summarizer.test.d.ts.map +1 -0
  24. package/dist/client-summarizer.test.js +127 -0
  25. package/dist/client-summarizer.test.js.map +1 -0
  26. package/dist/config.d.ts +13 -0
  27. package/dist/config.d.ts.map +1 -0
  28. package/dist/config.js +131 -0
  29. package/dist/config.js.map +1 -0
  30. package/dist/config.test.d.ts +2 -0
  31. package/dist/config.test.d.ts.map +1 -0
  32. package/dist/config.test.js +182 -0
  33. package/dist/config.test.js.map +1 -0
  34. package/dist/cursor-hooks.d.ts +46 -0
  35. package/dist/cursor-hooks.d.ts.map +1 -0
  36. package/dist/cursor-hooks.js +251 -0
  37. package/dist/cursor-hooks.js.map +1 -0
  38. package/dist/cursor-rules.d.ts +42 -0
  39. package/dist/cursor-rules.d.ts.map +1 -0
  40. package/dist/cursor-rules.js +229 -0
  41. package/dist/cursor-rules.js.map +1 -0
  42. package/dist/cursor-rules.test.d.ts +2 -0
  43. package/dist/cursor-rules.test.d.ts.map +1 -0
  44. package/dist/cursor-rules.test.js +55 -0
  45. package/dist/cursor-rules.test.js.map +1 -0
  46. package/dist/dedup.d.ts +22 -0
  47. package/dist/dedup.d.ts.map +1 -0
  48. package/dist/dedup.js +60 -0
  49. package/dist/dedup.js.map +1 -0
  50. package/dist/dedup.test.d.ts +2 -0
  51. package/dist/dedup.test.d.ts.map +1 -0
  52. package/dist/dedup.test.js +83 -0
  53. package/dist/dedup.test.js.map +1 -0
  54. package/dist/hooks/index.d.ts +52 -0
  55. package/dist/hooks/index.d.ts.map +1 -0
  56. package/dist/hooks/index.js +136 -0
  57. package/dist/hooks/index.js.map +1 -0
  58. package/dist/hooks.test.d.ts +2 -0
  59. package/dist/hooks.test.d.ts.map +1 -0
  60. package/dist/hooks.test.js +94 -0
  61. package/dist/hooks.test.js.map +1 -0
  62. package/dist/index.d.ts +9 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +9 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/strip-private.d.ts +12 -0
  67. package/dist/strip-private.d.ts.map +1 -0
  68. package/dist/strip-private.js +28 -0
  69. package/dist/strip-private.js.map +1 -0
  70. package/dist/strip-private.test.d.ts +2 -0
  71. package/dist/strip-private.test.d.ts.map +1 -0
  72. package/dist/strip-private.test.js +37 -0
  73. package/dist/strip-private.test.js.map +1 -0
  74. package/dist/utils.d.ts +3 -0
  75. package/dist/utils.d.ts.map +1 -0
  76. package/dist/utils.js +11 -0
  77. package/dist/utils.js.map +1 -0
  78. package/package.json +28 -0
  79. package/src/capture.integration.ts +98 -0
  80. package/src/capture.ts +352 -0
  81. package/src/client-summarizer.test.ts +144 -0
  82. package/src/client-summarizer.ts +338 -0
  83. package/src/config.test.ts +211 -0
  84. package/src/config.ts +157 -0
  85. package/src/cursor-hooks.ts +309 -0
  86. package/src/cursor-rules.test.ts +63 -0
  87. package/src/cursor-rules.ts +313 -0
  88. package/src/dedup.test.ts +84 -0
  89. package/src/dedup.ts +67 -0
  90. package/src/hooks/index.ts +226 -0
  91. package/src/hooks.test.ts +111 -0
  92. package/src/index.ts +32 -0
  93. package/src/strip-private.test.ts +57 -0
  94. package/src/strip-private.ts +34 -0
  95. package/src/utils.ts +10 -0
  96. package/tsconfig.json +12 -0
  97. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,121 @@
1
+ #!/bin/sh
2
+ # Memoire shell execution hook for Cursor IDE
3
+ # Called via afterShellExecution — records shell commands as observation events
4
+ # so Memoire can track what tools/commands the developer is running.
5
+ #
6
+ # Usage: sh save-shell-execution.sh ["command"] ["exit_code"]
7
+ #
8
+ # Arguments:
9
+ # $1 - Shell command that was executed
10
+ # $2 - Exit code (0 = success, non-zero = failure)
11
+ #
12
+ # Environment:
13
+ # MEMOIRE_API_URL - API base URL (default: http://127.0.0.1:3100)
14
+ # MEMOIRE_API_KEY - API key for authentication
15
+ # MEMOIRE_ORG_ID - Organization ID
16
+ # MEMOIRE_PROJECT_ID - Project ID
17
+ # MEMOIRE_USER_ID - User ID
18
+ # MEMOIRE_SESSION_ID - Session ID (auto-generated if unset)
19
+ #
20
+ # Falls back to ~/.memoire/config for any unset values.
21
+ # Fails silently — never blocks the IDE.
22
+
23
+ set -e
24
+
25
+ COMMAND="${1:-unknown}"
26
+ EXIT_CODE="${2:-0}"
27
+
28
+ # ---------------------------------------------------------------------------
29
+ # Config loading (shared pattern with save-observation.sh)
30
+ # ---------------------------------------------------------------------------
31
+
32
+ CONFIG_FILE="${MEMOIRE_CONFIG_FILE:-$HOME/.memoire/config}"
33
+
34
+ load_config() {
35
+ if [ -f "$CONFIG_FILE" ]; then
36
+ while IFS='=' read -r key value; do
37
+ case "$key" in
38
+ ''|\#*) continue ;;
39
+ esac
40
+ value=$(printf '%s' "$value" | sed "s/^[[:space:]]*[\"']\\{0,1\\}//;s/[\"']\\{0,1\\}[[:space:]]*$//")
41
+ case "$key" in
42
+ MEMOIRE_API_URL) [ -z "$MEMOIRE_API_URL" ] && MEMOIRE_API_URL="$value" ;;
43
+ MEMOIRE_API_KEY) [ -z "$MEMOIRE_API_KEY" ] && MEMOIRE_API_KEY="$value" ;;
44
+ MEMOIRE_ORG_ID) [ -z "$MEMOIRE_ORG_ID" ] && MEMOIRE_ORG_ID="$value" ;;
45
+ MEMOIRE_PROJECT_ID) [ -z "$MEMOIRE_PROJECT_ID" ] && MEMOIRE_PROJECT_ID="$value" ;;
46
+ MEMOIRE_USER_ID) [ -z "$MEMOIRE_USER_ID" ] && MEMOIRE_USER_ID="$value" ;;
47
+ MEMOIRE_SESSION_ID) [ -z "$MEMOIRE_SESSION_ID" ] && MEMOIRE_SESSION_ID="$value" ;;
48
+ MEMOIRE_CLIENT) [ -z "$MEMOIRE_CLIENT" ] && MEMOIRE_CLIENT="$value" ;;
49
+ esac
50
+ done < "$CONFIG_FILE"
51
+ fi
52
+ }
53
+
54
+ load_config
55
+
56
+ API_URL="${MEMOIRE_API_URL:-http://127.0.0.1:3100}"
57
+ API_KEY="${MEMOIRE_API_KEY:-}"
58
+ ORG_ID="${MEMOIRE_ORG_ID:-}"
59
+ PROJECT_ID="${MEMOIRE_PROJECT_ID:-}"
60
+ USER_ID="${MEMOIRE_USER_ID:-}"
61
+ SESSION_ID="${MEMOIRE_SESSION_ID:-cursor-$(date +%s)-$$}"
62
+ CLIENT="${MEMOIRE_CLIENT:-cursor}"
63
+
64
+ if [ -z "$ORG_ID" ] || [ -z "$PROJECT_ID" ] || [ -z "$USER_ID" ]; then
65
+ exit 0
66
+ fi
67
+
68
+ # ---------------------------------------------------------------------------
69
+ # Classify event based on exit code
70
+ # ---------------------------------------------------------------------------
71
+
72
+ if [ "$EXIT_CODE" != "0" ]; then
73
+ EVENT_TYPE="attempt"
74
+ CONTENT="Shell command failed (exit ${EXIT_CODE}): ${COMMAND}"
75
+ else
76
+ EVENT_TYPE="observation"
77
+ CONTENT="Shell command executed: ${COMMAND}"
78
+ fi
79
+
80
+ # Truncate very long commands (keep first 500 chars)
81
+ if [ ${#CONTENT} -gt 500 ]; then
82
+ CONTENT=$(printf '%.500s…' "$CONTENT")
83
+ fi
84
+
85
+ # ---------------------------------------------------------------------------
86
+ # Send event to Memoire API
87
+ # ---------------------------------------------------------------------------
88
+
89
+ AUTH_HEADER=""
90
+ if [ -n "$API_KEY" ]; then
91
+ AUTH_HEADER="Authorization: Bearer ${API_KEY}"
92
+ fi
93
+
94
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
95
+ IDEMPOTENCY_KEY="shell-${SESSION_ID}-$(date +%s)"
96
+
97
+ # Escape command for safe JSON embedding
98
+ SAFE_CONTENT=$(printf '%s' "$CONTENT" | sed 's/\\/\\\\/g; s/"/\\"/g; s/ /\\t/g')
99
+
100
+ curl -sf --max-time 3 \
101
+ -X POST \
102
+ -H "Content-Type: application/json" \
103
+ ${AUTH_HEADER:+-H "$AUTH_HEADER"} \
104
+ -d "{
105
+ \"events\": [{
106
+ \"org_id\": \"${ORG_ID}\",
107
+ \"project_id\": \"${PROJECT_ID}\",
108
+ \"user_id\": \"${USER_ID}\",
109
+ \"session_id\": \"${SESSION_ID}\",
110
+ \"client\": \"${CLIENT}\",
111
+ \"event_type\": \"${EVENT_TYPE}\",
112
+ \"content\": \"${SAFE_CONTENT}\",
113
+ \"concepts\": [\"shell\", \"command\"],
114
+ \"created_at\": \"${TIMESTAMP}\",
115
+ \"idempotency_key\": \"${IDEMPOTENCY_KEY}\",
116
+ \"private\": false
117
+ }]
118
+ }" \
119
+ "${API_URL}/v1/events" >/dev/null 2>&1 || true
120
+
121
+ exit 0
@@ -0,0 +1,142 @@
1
+ #!/bin/sh
2
+ # Memoire session summary hook for Cursor IDE
3
+ # Called via the stop hook — tells Memoire the session ended so it can
4
+ # generate a summary and update the project profile.
5
+ #
6
+ # Usage: sh session-summary.sh
7
+ #
8
+ # Environment:
9
+ # MEMOIRE_API_URL - API base URL (default: http://127.0.0.1:3100)
10
+ # MEMOIRE_API_KEY - API key for authentication
11
+ # MEMOIRE_ORG_ID - Organization ID
12
+ # MEMOIRE_PROJECT_ID - Project ID
13
+ # MEMOIRE_USER_ID - User ID
14
+ # MEMOIRE_SESSION_ID - Session ID (auto-generated if unset)
15
+ #
16
+ # Falls back to ~/.memoire/config for any unset values.
17
+ # Fails silently — never blocks the IDE.
18
+
19
+ set -e
20
+
21
+ # ---------------------------------------------------------------------------
22
+ # Config loading
23
+ # ---------------------------------------------------------------------------
24
+
25
+ CONFIG_FILE="${MEMOIRE_CONFIG_FILE:-$HOME/.memoire/config}"
26
+
27
+ load_config() {
28
+ if [ -f "$CONFIG_FILE" ]; then
29
+ while IFS='=' read -r key value; do
30
+ case "$key" in
31
+ ''|\#*) continue ;;
32
+ esac
33
+ value=$(printf '%s' "$value" | sed "s/^[[:space:]]*[\"']\\{0,1\\}//;s/[\"']\\{0,1\\}[[:space:]]*$//")
34
+ case "$key" in
35
+ MEMOIRE_API_URL) [ -z "$MEMOIRE_API_URL" ] && MEMOIRE_API_URL="$value" ;;
36
+ MEMOIRE_API_KEY) [ -z "$MEMOIRE_API_KEY" ] && MEMOIRE_API_KEY="$value" ;;
37
+ MEMOIRE_ORG_ID) [ -z "$MEMOIRE_ORG_ID" ] && MEMOIRE_ORG_ID="$value" ;;
38
+ MEMOIRE_PROJECT_ID) [ -z "$MEMOIRE_PROJECT_ID" ] && MEMOIRE_PROJECT_ID="$value" ;;
39
+ MEMOIRE_USER_ID) [ -z "$MEMOIRE_USER_ID" ] && MEMOIRE_USER_ID="$value" ;;
40
+ MEMOIRE_SESSION_ID) [ -z "$MEMOIRE_SESSION_ID" ] && MEMOIRE_SESSION_ID="$value" ;;
41
+ MEMOIRE_CLIENT) [ -z "$MEMOIRE_CLIENT" ] && MEMOIRE_CLIENT="$value" ;;
42
+ esac
43
+ done < "$CONFIG_FILE"
44
+ fi
45
+ }
46
+
47
+ load_config
48
+
49
+ API_URL="${MEMOIRE_API_URL:-http://127.0.0.1:3100}"
50
+ API_KEY="${MEMOIRE_API_KEY:-}"
51
+ ORG_ID="${MEMOIRE_ORG_ID:-}"
52
+ PROJECT_ID="${MEMOIRE_PROJECT_ID:-}"
53
+ USER_ID="${MEMOIRE_USER_ID:-}"
54
+ SESSION_ID="${MEMOIRE_SESSION_ID:-cursor-$(date +%s)-$$}"
55
+ CLIENT="${MEMOIRE_CLIENT:-cursor}"
56
+
57
+ if [ -z "$ORG_ID" ] || [ -z "$PROJECT_ID" ] || [ -z "$USER_ID" ]; then
58
+ exit 0
59
+ fi
60
+
61
+ # ---------------------------------------------------------------------------
62
+ # Send session_summary event
63
+ # ---------------------------------------------------------------------------
64
+
65
+ AUTH_HEADER=""
66
+ if [ -n "$API_KEY" ]; then
67
+ AUTH_HEADER="Authorization: Bearer ${API_KEY}"
68
+ fi
69
+
70
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
71
+ IDEMPOTENCY_KEY="session-end-${SESSION_ID}-$(date +%s)"
72
+
73
+ curl -sf --max-time 3 \
74
+ -X POST \
75
+ -H "Content-Type: application/json" \
76
+ ${AUTH_HEADER:+-H "$AUTH_HEADER"} \
77
+ -d "{
78
+ \"events\": [{
79
+ \"org_id\": \"${ORG_ID}\",
80
+ \"project_id\": \"${PROJECT_ID}\",
81
+ \"user_id\": \"${USER_ID}\",
82
+ \"session_id\": \"${SESSION_ID}\",
83
+ \"client\": \"${CLIENT}\",
84
+ \"event_type\": \"session_summary\",
85
+ \"content\": \"Cursor session ended (hook-generated)\",
86
+ \"created_at\": \"${TIMESTAMP}\",
87
+ \"idempotency_key\": \"${IDEMPOTENCY_KEY}\",
88
+ \"private\": false
89
+ }]
90
+ }" \
91
+ "${API_URL}/v1/events" >/dev/null 2>&1 || true
92
+
93
+ # ---------------------------------------------------------------------------
94
+ # Fetch and update dashboard summary for context file refresh
95
+ # ---------------------------------------------------------------------------
96
+
97
+ SUMMARY_RESPONSE=$(curl -sf --max-time 3 \
98
+ -X POST \
99
+ -H "Content-Type: application/json" \
100
+ ${AUTH_HEADER:+-H "$AUTH_HEADER"} \
101
+ -d "{
102
+ \"org_id\": \"${ORG_ID}\",
103
+ \"project_id\": \"${PROJECT_ID}\",
104
+ \"viewer_user_id\": \"${USER_ID}\",
105
+ \"recent_limit\": 10,
106
+ \"recent_hours\": 24
107
+ }" \
108
+ "${API_URL}/v1/dashboard/summary" 2>/dev/null) || exit 0
109
+
110
+ # Extract a brief summary text for the context file
111
+ SUMMARY_TEXT=$(printf '%s' "$SUMMARY_RESPONSE" | sed -n 's/.*"summary"[[:space:]]*:[[:space:]]*"//p' | sed 's/".*//' | sed 's/\\n/\
112
+ /g; s/\\"/"/g; s/\\\\/\\/g')
113
+
114
+ if [ -z "$SUMMARY_TEXT" ]; then
115
+ exit 0
116
+ fi
117
+
118
+ # Update the cursor rules file with latest summary
119
+ RULES_DIR=".cursor/rules"
120
+ RULES_FILE="${RULES_DIR}/memoire-context.mdc"
121
+ TEMP_FILE="${RULES_FILE}.tmp"
122
+
123
+ mkdir -p "$RULES_DIR"
124
+
125
+ cat > "$TEMP_FILE" << 'FRONTMATTER'
126
+ ---
127
+ alwaysApply: true
128
+ description: "Memoire shared memory context (auto-updated by hook)"
129
+ ---
130
+ FRONTMATTER
131
+
132
+ printf '\n# Memoire Context\n\n' >> "$TEMP_FILE"
133
+ printf '> Auto-updated by Memoire session-summary hook.\n' >> "$TEMP_FILE"
134
+ printf '> Use Memoire MCP tools for deeper queries.\n\n' >> "$TEMP_FILE"
135
+ printf '## Recent Session Summary\n\n' >> "$TEMP_FILE"
136
+ printf '%s\n' "$SUMMARY_TEXT" >> "$TEMP_FILE"
137
+ printf '\n---\n' >> "$TEMP_FILE"
138
+ printf '*Use Memoire MCP tools (`search_context`, `project_profile`, `oracle_research`) for detailed queries.*\n' >> "$TEMP_FILE"
139
+
140
+ mv "$TEMP_FILE" "$RULES_FILE"
141
+
142
+ exit 0
@@ -0,0 +1,111 @@
1
+ import type { MemoireClient as ClientType } from '@memoire-ai/shared';
2
+ import { type ClientSummarizerConfig } from './client-summarizer.js';
3
+ export interface CollectorConfig {
4
+ apiUrl: string;
5
+ apiKey: string;
6
+ orgId: string;
7
+ projectId: string;
8
+ userId: string;
9
+ client: ClientType;
10
+ repoId?: string;
11
+ clientId?: string;
12
+ /** Workspace root path — if set, auto-writes .cursor/rules/ context */
13
+ workspacePath?: string;
14
+ /** Project name for cursor rules */
15
+ projectName?: string;
16
+ /** Dedup window in ms (default 30000). Set to 0 to disable. */
17
+ dedupWindowMs?: number;
18
+ /** Edge/native summarization config. When set, events are pre-summarized
19
+ * before reaching the API, saving server-side summarization cost. */
20
+ summarizer?: ClientSummarizerConfig;
21
+ }
22
+ /** Structured session summary matching claude-mem's summary schema */
23
+ export interface SessionSummary {
24
+ /** What the user requested */
25
+ request: string;
26
+ /** What was explored / investigated */
27
+ investigated?: string[];
28
+ /** Key learnings and discoveries */
29
+ learned?: string[];
30
+ /** What was delivered / completed */
31
+ completed?: string[];
32
+ /** Suggested follow-up work */
33
+ next_steps?: string[];
34
+ /** Additional notes */
35
+ notes?: string;
36
+ }
37
+ /**
38
+ * Collector captures events from IDE environments and forwards them
39
+ * to the Memoire API. If the API is unavailable, events are queued
40
+ * locally and retried.
41
+ *
42
+ * Follows the claude-mem hook lifecycle pattern:
43
+ * SessionStart → PostToolUse → SessionEnd
44
+ *
45
+ * Edge processing:
46
+ * - Privacy: <private> tags are stripped before storage
47
+ * - Dedup: Content-hash deduplication within a 30s sliding window
48
+ * - Structured summaries: Session end accepts typed summary objects
49
+ */
50
+ export declare class Collector {
51
+ private memoireClient;
52
+ private queue;
53
+ private config;
54
+ private sessionId;
55
+ private dedup;
56
+ private summarizer;
57
+ constructor(config: CollectorConfig);
58
+ /** Start a new session */
59
+ sessionStart(): Promise<void>;
60
+ /** Record an observation from a tool use */
61
+ observation(content: string, opts?: {
62
+ filesRead?: string[];
63
+ filesModified?: string[];
64
+ concepts?: string[];
65
+ branchName?: string;
66
+ }): Promise<void>;
67
+ /** Record a user prompt */
68
+ prompt(content: string, opts?: {
69
+ filesRead?: string[];
70
+ filesModified?: string[];
71
+ concepts?: string[];
72
+ branchName?: string;
73
+ }): Promise<void>;
74
+ /** Record a decision */
75
+ decision(content: string, opts?: {
76
+ filesModified?: string[];
77
+ concepts?: string[];
78
+ branchName?: string;
79
+ }): Promise<void>;
80
+ /** Record a failed attempt */
81
+ attempt(content: string, opts?: {
82
+ filesModified?: string[];
83
+ concepts?: string[];
84
+ branchName?: string;
85
+ }): Promise<void>;
86
+ /** Record a convention or standard */
87
+ convention(content: string, opts?: {
88
+ filesModified?: string[];
89
+ concepts?: string[];
90
+ branchName?: string;
91
+ }): Promise<void>;
92
+ /** Record a branch lifecycle event */
93
+ branchEvent(content: string, opts?: {
94
+ filesModified?: string[];
95
+ concepts?: string[];
96
+ branchName?: string;
97
+ }): Promise<void>;
98
+ /** End a session with a structured or plain-text summary */
99
+ sessionEnd(summary: string | SessionSummary): Promise<void>;
100
+ /**
101
+ * Update .cursor/rules/memoire-context.mdc with latest project context.
102
+ * Called automatically on session end for Cursor clients.
103
+ */
104
+ private updateCursorRules;
105
+ /** Emit a raw event — applies privacy stripping, dedup, and optional client-side summarization */
106
+ private emit;
107
+ /** Get the number of pending events in the offline queue */
108
+ get pendingEvents(): number;
109
+ destroy(): void;
110
+ }
111
+ //# sourceMappingURL=capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=capture.integration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.integration.d.ts","sourceRoot":"","sources":["../src/capture.integration.ts"],"names":[],"mappings":""}
@@ -0,0 +1,67 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import postgres from 'postgres';
4
+ import { Collector } from './capture.js';
5
+ const integrationEnv = {
6
+ apiUrl: process.env.MEMOIRE_INTEGRATION_API_URL,
7
+ apiKey: process.env.MEMOIRE_INTEGRATION_API_KEY,
8
+ orgId: process.env.MEMOIRE_INTEGRATION_ORG_ID,
9
+ projectId: process.env.MEMOIRE_INTEGRATION_PROJECT_ID,
10
+ userId: process.env.MEMOIRE_INTEGRATION_USER_ID,
11
+ databaseUrl: process.env.MEMOIRE_INTEGRATION_DATABASE_URL,
12
+ };
13
+ const missingEnv = Object.entries(integrationEnv)
14
+ .filter(([, value]) => !value)
15
+ .map(([key]) => key);
16
+ test('collector forwards captured events to the API and persists them', { skip: missingEnv.length > 0 ? `missing env: ${missingEnv.join(', ')}` : false }, async () => {
17
+ const collector = new Collector({
18
+ apiUrl: integrationEnv.apiUrl,
19
+ apiKey: integrationEnv.apiKey,
20
+ orgId: integrationEnv.orgId,
21
+ projectId: integrationEnv.projectId,
22
+ userId: integrationEnv.userId,
23
+ client: 'cursor',
24
+ repoId: 'memoire/integration',
25
+ });
26
+ const sql = postgres(integrationEnv.databaseUrl);
27
+ const content = `collector integration ${Date.now()}`;
28
+ try {
29
+ await collector.observation(content, {
30
+ branchName: 'integration/collector',
31
+ filesModified: ['src/auth/config.ts'],
32
+ concepts: ['integration-test'],
33
+ });
34
+ const row = await waitForEvent(sql, {
35
+ content,
36
+ projectId: integrationEnv.projectId,
37
+ });
38
+ assert.ok(row, 'expected collector event to be persisted');
39
+ assert.equal(row.event_type, 'observation');
40
+ assert.equal(row.client, 'cursor');
41
+ assert.equal(row.project_id, integrationEnv.projectId);
42
+ assert.match(row.files_modified, /src\/auth\/config\.ts/);
43
+ await sql `delete from events where id = ${row.id}`;
44
+ }
45
+ finally {
46
+ collector.destroy();
47
+ await sql.end({ timeout: 5 });
48
+ }
49
+ });
50
+ async function waitForEvent(sql, input) {
51
+ for (let attempt = 0; attempt < 20; attempt++) {
52
+ const rows = await sql `
53
+ select id, project_id, event_type, client, files_modified::text as files_modified
54
+ from events
55
+ where project_id = ${input.projectId}
56
+ and content = ${input.content}
57
+ order by inserted_at desc
58
+ limit 1
59
+ `;
60
+ if (rows[0]) {
61
+ return rows[0];
62
+ }
63
+ await new Promise((resolve) => setTimeout(resolve, 100));
64
+ }
65
+ return undefined;
66
+ }
67
+ //# sourceMappingURL=capture.integration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.integration.js","sourceRoot":"","sources":["../src/capture.integration.ts"],"names":[],"mappings":"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"}