@everstateai/mcp 1.3.2 → 1.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 (70) hide show
  1. package/dist/index.d.ts +5 -3
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +32 -5
  4. package/dist/index.js.map +1 -1
  5. package/dist/setup/auto-update.d.ts +20 -0
  6. package/dist/setup/auto-update.d.ts.map +1 -0
  7. package/dist/setup/auto-update.js +295 -0
  8. package/dist/setup/auto-update.js.map +1 -0
  9. package/dist/setup/commands/doctor.d.ts +15 -0
  10. package/dist/setup/commands/doctor.d.ts.map +1 -0
  11. package/dist/setup/commands/doctor.js +264 -0
  12. package/dist/setup/commands/doctor.js.map +1 -0
  13. package/dist/setup/commands/repair.d.ts +14 -0
  14. package/dist/setup/commands/repair.d.ts.map +1 -0
  15. package/dist/setup/commands/repair.js +252 -0
  16. package/dist/setup/commands/repair.js.map +1 -0
  17. package/dist/setup/hooks/templates.d.ts +30 -0
  18. package/dist/setup/hooks/templates.d.ts.map +1 -0
  19. package/dist/setup/hooks/templates.js +237 -0
  20. package/dist/setup/hooks/templates.js.map +1 -0
  21. package/dist/setup/types.d.ts +120 -0
  22. package/dist/setup/types.d.ts.map +1 -0
  23. package/dist/setup/types.js +58 -0
  24. package/dist/setup/types.js.map +1 -0
  25. package/dist/setup/validators/api-key.d.ts +8 -0
  26. package/dist/setup/validators/api-key.d.ts.map +1 -0
  27. package/dist/setup/validators/api-key.js +233 -0
  28. package/dist/setup/validators/api-key.js.map +1 -0
  29. package/dist/setup/validators/connectivity.d.ts +8 -0
  30. package/dist/setup/validators/connectivity.d.ts.map +1 -0
  31. package/dist/setup/validators/connectivity.js +150 -0
  32. package/dist/setup/validators/connectivity.js.map +1 -0
  33. package/dist/setup/validators/hooks.d.ts +8 -0
  34. package/dist/setup/validators/hooks.d.ts.map +1 -0
  35. package/dist/setup/validators/hooks.js +431 -0
  36. package/dist/setup/validators/hooks.js.map +1 -0
  37. package/dist/setup/validators/index.d.ts +18 -0
  38. package/dist/setup/validators/index.d.ts.map +1 -0
  39. package/dist/setup/validators/index.js +123 -0
  40. package/dist/setup/validators/index.js.map +1 -0
  41. package/dist/setup/validators/mcp-config.d.ts +8 -0
  42. package/dist/setup/validators/mcp-config.d.ts.map +1 -0
  43. package/dist/setup/validators/mcp-config.js +333 -0
  44. package/dist/setup/validators/mcp-config.js.map +1 -0
  45. package/dist/setup/validators/project.d.ts +8 -0
  46. package/dist/setup/validators/project.d.ts.map +1 -0
  47. package/dist/setup/validators/project.js +202 -0
  48. package/dist/setup/validators/project.js.map +1 -0
  49. package/dist/setup/version.d.ts +58 -0
  50. package/dist/setup/version.d.ts.map +1 -0
  51. package/dist/setup/version.js +262 -0
  52. package/dist/setup/version.js.map +1 -0
  53. package/dist/setup.d.ts.map +1 -1
  54. package/dist/setup.js +207 -27
  55. package/dist/setup.js.map +1 -1
  56. package/package.json +1 -1
  57. package/src/index.ts +32 -5
  58. package/src/setup/auto-update.ts +328 -0
  59. package/src/setup/commands/doctor.ts +266 -0
  60. package/src/setup/commands/repair.ts +260 -0
  61. package/src/setup/hooks/templates.ts +239 -0
  62. package/src/setup/types.ts +199 -0
  63. package/src/setup/validators/api-key.ts +218 -0
  64. package/src/setup/validators/connectivity.ts +176 -0
  65. package/src/setup/validators/hooks.ts +447 -0
  66. package/src/setup/validators/index.ts +137 -0
  67. package/src/setup/validators/mcp-config.ts +329 -0
  68. package/src/setup/validators/project.ts +179 -0
  69. package/src/setup/version.ts +267 -0
  70. package/src/setup.ts +229 -27
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Repair Command
3
+ *
4
+ * Automatically fixes detected Everstate issues.
5
+ *
6
+ * Usage:
7
+ * npx @everstateai/mcp repair
8
+ * npx @everstateai/mcp repair --include-warnings
9
+ * npx @everstateai/mcp repair --force
10
+ */
11
+
12
+ import * as fs from 'fs';
13
+ import {
14
+ ValidationContext,
15
+ ValidationResult,
16
+ RepairOptions,
17
+ c,
18
+ getEverstateDir,
19
+ } from '../types.js';
20
+ import { validateAll, repairResult } from '../validators/index.js';
21
+ import { updateVersionFile, createVersionFile, getMcpProxyVersion, HOOK_VERSIONS } from '../version.js';
22
+
23
+ interface RepairSummary {
24
+ attempted: number;
25
+ succeeded: number;
26
+ failed: number;
27
+ skipped: number;
28
+ details: Array<{
29
+ check: string;
30
+ result: 'fixed' | 'failed' | 'skipped' | 'manual';
31
+ }>;
32
+ }
33
+
34
+ export async function repair(options: RepairOptions = {}): Promise<void> {
35
+ const context = buildContext(options);
36
+
37
+ console.log('');
38
+ console.log(c('bold', 'Everstate Repair'));
39
+ console.log(c('dim', '─'.repeat(40)));
40
+ console.log('');
41
+
42
+ // Run validation first
43
+ console.log('Checking installation...');
44
+ const summary = await validateAll(context);
45
+
46
+ // Find issues to repair
47
+ const toRepair = summary.results.filter((r) => {
48
+ if (r.status === 'fail') return true;
49
+ if (r.status === 'warn' && options.includeWarnings) return true;
50
+ return false;
51
+ });
52
+
53
+ if (toRepair.length === 0) {
54
+ console.log('');
55
+ console.log(c('green', '✓ No issues to repair'));
56
+ console.log('');
57
+ return;
58
+ }
59
+
60
+ console.log('');
61
+ console.log(`Found ${toRepair.length} issue(s) to repair:`);
62
+ for (const issue of toRepair) {
63
+ console.log(` ${c('yellow', '•')} ${issue.component}: ${issue.check}`);
64
+ }
65
+ console.log('');
66
+
67
+ // Perform repairs
68
+ const repairSummary = await performRepairs(toRepair, context, options);
69
+
70
+ // Update version file on success
71
+ if (repairSummary.succeeded > 0) {
72
+ updateVersionFile({
73
+ components: {
74
+ mcpProxy: getMcpProxyVersion(),
75
+ hooks: HOOK_VERSIONS,
76
+ },
77
+ });
78
+ }
79
+
80
+ // Output summary
81
+ outputRepairSummary(repairSummary);
82
+
83
+ // Exit code
84
+ if (repairSummary.failed > 0) {
85
+ process.exit(1);
86
+ }
87
+ }
88
+
89
+ function buildContext(options: RepairOptions): ValidationContext {
90
+ const context: ValidationContext = {
91
+ projectDir: options.projectDir || process.cwd(),
92
+ };
93
+
94
+ // Try to load API key
95
+ const apiKeyPath = `${getEverstateDir()}/api-key`;
96
+ if (fs.existsSync(apiKeyPath)) {
97
+ try {
98
+ context.apiKey = fs.readFileSync(apiKeyPath, 'utf8').trim();
99
+ } catch {
100
+ // Will be handled during repair
101
+ }
102
+ }
103
+
104
+ return context;
105
+ }
106
+
107
+ async function performRepairs(
108
+ issues: ValidationResult[],
109
+ context: ValidationContext,
110
+ options: RepairOptions
111
+ ): Promise<RepairSummary> {
112
+ const summary: RepairSummary = {
113
+ attempted: 0,
114
+ succeeded: 0,
115
+ failed: 0,
116
+ skipped: 0,
117
+ details: [],
118
+ };
119
+
120
+ for (const issue of issues) {
121
+ const checkName = `${issue.component}: ${issue.check}`;
122
+
123
+ // Check if repair is available
124
+ if (!issue.repairAction) {
125
+ console.log(` ${c('dim', '○')} ${checkName}: ${c('dim', 'No automatic repair available')}`);
126
+ summary.skipped++;
127
+ summary.details.push({ check: checkName, result: 'manual' });
128
+ continue;
129
+ }
130
+
131
+ // Check if repair requires confirmation
132
+ if (!issue.repairAction.automatic && !options.force) {
133
+ console.log(` ${c('yellow', '?')} ${checkName}: Requires --force or manual intervention`);
134
+ summary.skipped++;
135
+ summary.details.push({ check: checkName, result: 'skipped' });
136
+ continue;
137
+ }
138
+
139
+ // Attempt repair
140
+ summary.attempted++;
141
+ console.log(` ${c('cyan', '→')} Repairing: ${checkName}...`);
142
+
143
+ try {
144
+ const success = await repairResult(issue, context);
145
+
146
+ if (success) {
147
+ console.log(` ${c('green', '✓')} Fixed`);
148
+ summary.succeeded++;
149
+ summary.details.push({ check: checkName, result: 'fixed' });
150
+ } else {
151
+ console.log(` ${c('red', '✗')} Failed`);
152
+ summary.failed++;
153
+ summary.details.push({ check: checkName, result: 'failed' });
154
+ }
155
+ } catch (error) {
156
+ console.log(` ${c('red', '✗')} Error: ${String(error)}`);
157
+ summary.failed++;
158
+ summary.details.push({ check: checkName, result: 'failed' });
159
+ }
160
+ }
161
+
162
+ return summary;
163
+ }
164
+
165
+ function outputRepairSummary(summary: RepairSummary): void {
166
+ console.log('');
167
+ console.log(c('bold', 'Repair Summary'));
168
+ console.log(c('dim', '─'.repeat(40)));
169
+
170
+ if (summary.succeeded > 0) {
171
+ console.log(` ${c('green', '✓')} ${summary.succeeded} fixed`);
172
+ }
173
+ if (summary.failed > 0) {
174
+ console.log(` ${c('red', '✗')} ${summary.failed} failed`);
175
+ }
176
+ if (summary.skipped > 0) {
177
+ console.log(` ${c('yellow', '○')} ${summary.skipped} skipped`);
178
+ }
179
+
180
+ console.log('');
181
+
182
+ if (summary.failed > 0) {
183
+ console.log(c('yellow', 'Some repairs failed. You may need to:'));
184
+ console.log(c('dim', ' 1. Run with --force for non-automatic repairs'));
185
+ console.log(c('dim', ' 2. Manually fix issues that cannot be auto-repaired'));
186
+ console.log(c('dim', ' 3. Re-run setup: npx @everstateai/mcp setup <api-key>'));
187
+ console.log('');
188
+ } else if (summary.succeeded > 0) {
189
+ console.log(c('green', 'All repairs completed successfully!'));
190
+ console.log(c('dim', 'Run `npx @everstateai/mcp doctor` to verify.'));
191
+ console.log('');
192
+ }
193
+ }
194
+
195
+ // CLI entry point
196
+ export async function repairCli(args: string[]): Promise<void> {
197
+ const options: RepairOptions = {};
198
+
199
+ for (let i = 0; i < args.length; i++) {
200
+ const arg = args[i];
201
+
202
+ switch (arg) {
203
+ case '--force':
204
+ case '-f':
205
+ options.force = true;
206
+ break;
207
+ case '--include-warnings':
208
+ case '-w':
209
+ options.includeWarnings = true;
210
+ break;
211
+ case '--component':
212
+ case '-c':
213
+ options.component = args[++i];
214
+ break;
215
+ case '--project':
216
+ case '-p':
217
+ options.projectDir = args[++i];
218
+ break;
219
+ case '--help':
220
+ case '-h':
221
+ printHelp();
222
+ process.exit(0);
223
+ }
224
+ }
225
+
226
+ await repair(options);
227
+ }
228
+
229
+ function printHelp(): void {
230
+ console.log(`
231
+ Everstate Repair - Fix installation issues
232
+
233
+ Usage:
234
+ npx @everstateai/mcp repair [options]
235
+
236
+ Options:
237
+ --force, -f Force non-automatic repairs
238
+ --include-warnings, -w Also repair warnings (not just failures)
239
+ --component, -c Repair only a specific component
240
+ --project, -p Specify project directory
241
+ --help, -h Show this help
242
+
243
+ What can be repaired:
244
+ • Missing API key file (if you provide it)
245
+ • Incorrect file permissions
246
+ • Missing or outdated hooks
247
+ • MCP configuration issues
248
+ • Hook registration in Claude config
249
+
250
+ What requires manual intervention:
251
+ • Invalid API key (get a new one from dashboard)
252
+ • Missing project configuration (run setup)
253
+ • Network connectivity issues
254
+
255
+ Examples:
256
+ npx @everstateai/mcp repair
257
+ npx @everstateai/mcp repair --force
258
+ npx @everstateai/mcp repair --include-warnings
259
+ `);
260
+ }
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Hook Templates
3
+ *
4
+ * Versioned hook templates for installation and updates.
5
+ * Each hook includes a VERSION header for validation.
6
+ */
7
+
8
+ import { HookConfig, HOOK_VERSIONS, EVERSTATE_API_URL, getEverstateDir } from '../types.js';
9
+
10
+ /**
11
+ * Get the sync-todos.js hook content
12
+ */
13
+ export function getSyncTodosHook(config?: Partial<HookConfig>): string {
14
+ const apiKeyPath = config?.apiKeyPath || `${getEverstateDir()}/api-key`;
15
+ const apiUrl = config?.apiUrl || EVERSTATE_API_URL;
16
+ const generatedAt = config?.generatedAt || new Date().toISOString();
17
+
18
+ return `#!/usr/bin/env node
19
+ /**
20
+ * Everstate Sync Todos Hook v${HOOK_VERSIONS.syncTodos}
21
+ * VERSION: ${HOOK_VERSIONS.syncTodos}
22
+ * GENERATED: ${generatedAt}
23
+ *
24
+ * Syncs Claude's TodoWrite tasks with Everstate.
25
+ * Runs after every TodoWrite tool call.
26
+ */
27
+
28
+ const fs = require('fs');
29
+ const path = require('path');
30
+
31
+ const API_KEY_PATH = '${apiKeyPath}';
32
+ const API_URL = '${apiUrl}';
33
+
34
+ async function main() {
35
+ try {
36
+ // Read API key
37
+ if (!fs.existsSync(API_KEY_PATH)) {
38
+ console.error('[everstate] API key not found at', API_KEY_PATH);
39
+ process.exit(0); // Don't block Claude
40
+ }
41
+ const apiKey = fs.readFileSync(API_KEY_PATH, 'utf8').trim();
42
+
43
+ // Parse input from Claude
44
+ const input = JSON.parse(process.env.TOOL_INPUT || '{}');
45
+ const todos = input.todos || [];
46
+
47
+ if (todos.length === 0) {
48
+ process.exit(0);
49
+ }
50
+
51
+ // Find project config
52
+ let projectId = null;
53
+ let cwd = process.cwd();
54
+ for (let i = 0; i < 10; i++) {
55
+ const configPath = path.join(cwd, '.everstate.json');
56
+ if (fs.existsSync(configPath)) {
57
+ try {
58
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
59
+ projectId = config.projectId;
60
+ break;
61
+ } catch {}
62
+ }
63
+ const parent = path.dirname(cwd);
64
+ if (parent === cwd) break;
65
+ cwd = parent;
66
+ }
67
+
68
+ if (!projectId) {
69
+ // No project config - skip sync
70
+ process.exit(0);
71
+ }
72
+
73
+ // Send to API for matching and storage
74
+ const response = await fetch(\`\${API_URL}/api/session/sync-todos\`, {
75
+ method: 'POST',
76
+ headers: {
77
+ 'Content-Type': 'application/json',
78
+ 'Authorization': \`Bearer \${apiKey}\`,
79
+ },
80
+ body: JSON.stringify({
81
+ projectId,
82
+ todos,
83
+ sessionId: process.env.SESSION_ID || null,
84
+ }),
85
+ });
86
+
87
+ if (!response.ok) {
88
+ const text = await response.text();
89
+ console.error('[everstate] Sync failed:', response.status, text);
90
+ }
91
+ } catch (error) {
92
+ console.error('[everstate] Hook error:', error.message);
93
+ }
94
+
95
+ process.exit(0);
96
+ }
97
+
98
+ main();
99
+ `;
100
+ }
101
+
102
+ /**
103
+ * Get the session-start.sh hook content
104
+ */
105
+ export function getSessionStartHook(config?: Partial<HookConfig>): string {
106
+ const generatedAt = config?.generatedAt || new Date().toISOString();
107
+
108
+ return `#!/bin/bash
109
+ # Everstate Session Start Hook v${HOOK_VERSIONS.sessionStart}
110
+ # VERSION: ${HOOK_VERSIONS.sessionStart}
111
+ # GENERATED: ${generatedAt}
112
+ #
113
+ # Loads context at session start.
114
+ # Place in .claude/hooks/ directory.
115
+
116
+ # Check for MCP - if available, tools handle context loading
117
+ if command -v claude &> /dev/null; then
118
+ # Claude Code detected - MCP tools will load context
119
+ exit 0
120
+ fi
121
+
122
+ # Fallback for environments without MCP
123
+ echo "[everstate] Session starting - use sync() to load context"
124
+ `;
125
+ }
126
+
127
+ /**
128
+ * Get the session-end.sh hook content
129
+ */
130
+ export function getSessionEndHook(config?: Partial<HookConfig>): string {
131
+ const apiKeyPath = config?.apiKeyPath || `${getEverstateDir()}/api-key`;
132
+ const apiUrl = config?.apiUrl || EVERSTATE_API_URL;
133
+ const generatedAt = config?.generatedAt || new Date().toISOString();
134
+
135
+ return `#!/bin/bash
136
+ # Everstate Session End Hook v${HOOK_VERSIONS.sessionEnd}
137
+ # VERSION: ${HOOK_VERSIONS.sessionEnd}
138
+ # GENERATED: ${generatedAt}
139
+ #
140
+ # Saves session summary when Claude session ends.
141
+
142
+ API_KEY_PATH="${apiKeyPath}"
143
+ API_URL="${apiUrl}"
144
+
145
+ # Read API key
146
+ if [ ! -f "$API_KEY_PATH" ]; then
147
+ exit 0
148
+ fi
149
+ API_KEY=$(cat "$API_KEY_PATH")
150
+
151
+ # Find project config
152
+ find_project_id() {
153
+ local dir="$PWD"
154
+ for i in {1..10}; do
155
+ if [ -f "$dir/.everstate.json" ]; then
156
+ grep -o '"projectId"[[:space:]]*:[[:space:]]*"[^"]*"' "$dir/.everstate.json" | cut -d'"' -f4
157
+ return
158
+ fi
159
+ dir=$(dirname "$dir")
160
+ [ "$dir" = "/" ] && break
161
+ done
162
+ }
163
+
164
+ PROJECT_ID=$(find_project_id)
165
+ if [ -z "$PROJECT_ID" ]; then
166
+ exit 0
167
+ fi
168
+
169
+ # Signal session end to API
170
+ curl -s -X POST "$API_URL/api/session/end" \\
171
+ -H "Content-Type: application/json" \\
172
+ -H "Authorization: Bearer $API_KEY" \\
173
+ -d "{\\"projectId\\": \\"$PROJECT_ID\\"}" > /dev/null 2>&1
174
+
175
+ exit 0
176
+ `;
177
+ }
178
+
179
+ /**
180
+ * Get the pre-compact.sh hook content (for context compaction)
181
+ */
182
+ export function getPreCompactHook(config?: Partial<HookConfig>): string {
183
+ const apiKeyPath = config?.apiKeyPath || `${getEverstateDir()}/api-key`;
184
+ const apiUrl = config?.apiUrl || EVERSTATE_API_URL;
185
+ const generatedAt = config?.generatedAt || new Date().toISOString();
186
+
187
+ return `#!/bin/bash
188
+ # Everstate Pre-Compact Hook v${HOOK_VERSIONS.sessionEnd}
189
+ # VERSION: ${HOOK_VERSIONS.sessionEnd}
190
+ # GENERATED: ${generatedAt}
191
+ #
192
+ # Saves session context before Claude's context compaction.
193
+
194
+ API_KEY_PATH="${apiKeyPath}"
195
+ API_URL="${apiUrl}"
196
+
197
+ # Read API key
198
+ if [ ! -f "$API_KEY_PATH" ]; then
199
+ exit 0
200
+ fi
201
+ API_KEY=$(cat "$API_KEY_PATH")
202
+
203
+ # Find project config
204
+ find_project_id() {
205
+ local dir="$PWD"
206
+ for i in {1..10}; do
207
+ if [ -f "$dir/.everstate.json" ]; then
208
+ grep -o '"projectId"[[:space:]]*:[[:space:]]*"[^"]*"' "$dir/.everstate.json" | cut -d'"' -f4
209
+ return
210
+ fi
211
+ dir=$(dirname "$dir")
212
+ [ "$dir" = "/" ] && break
213
+ done
214
+ }
215
+
216
+ PROJECT_ID=$(find_project_id)
217
+ if [ -z "$PROJECT_ID" ]; then
218
+ exit 0
219
+ fi
220
+
221
+ # Get transcript from environment if available
222
+ TRANSCRIPT="\${CLAUDE_TRANSCRIPT:-}"
223
+
224
+ # Signal pre-compact to API
225
+ curl -s -X POST "$API_URL/api/session/pre-compact" \\
226
+ -H "Content-Type: application/json" \\
227
+ -H "Authorization: Bearer $API_KEY" \\
228
+ -d "{\\"projectId\\": \\"$PROJECT_ID\\", \\"transcript\\": \\"\$TRANSCRIPT\\"}" > /dev/null 2>&1
229
+
230
+ exit 0
231
+ `;
232
+ }
233
+
234
+ export const hookTemplates = {
235
+ syncTodos: getSyncTodosHook,
236
+ sessionStart: getSessionStartHook,
237
+ sessionEnd: getSessionEndHook,
238
+ preCompact: getPreCompactHook,
239
+ };
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Everstate Setup Types
3
+ *
4
+ * Shared types for the setup, doctor, and repair commands.
5
+ */
6
+
7
+ // ============================================================================
8
+ // Validation Types
9
+ // ============================================================================
10
+
11
+ export type ValidationStatus = 'pass' | 'warn' | 'fail';
12
+
13
+ export type RepairType = 'install' | 'update' | 'configure' | 'delete' | 'chmod';
14
+
15
+ export interface RepairAction {
16
+ type: RepairType;
17
+ description: string;
18
+ automatic: boolean; // Can be auto-repaired without user input
19
+ }
20
+
21
+ export interface ValidationResult {
22
+ component: string;
23
+ check: string;
24
+ status: ValidationStatus;
25
+ message: string;
26
+ details?: Record<string, unknown>;
27
+ repairAction?: RepairAction;
28
+ }
29
+
30
+ export interface Validator {
31
+ name: string;
32
+ validate(context: ValidationContext): Promise<ValidationResult[]>;
33
+ repair?(result: ValidationResult, context: ValidationContext): Promise<boolean>;
34
+ }
35
+
36
+ export interface ValidationContext {
37
+ projectDir?: string;
38
+ apiKey?: string;
39
+ verbose?: boolean;
40
+ skipNetwork?: boolean;
41
+ }
42
+
43
+ export interface ValidationSummary {
44
+ passed: number;
45
+ warnings: number;
46
+ failed: number;
47
+ results: ValidationResult[];
48
+ }
49
+
50
+ // ============================================================================
51
+ // Version Tracking Types
52
+ // ============================================================================
53
+
54
+ export interface HookVersions {
55
+ sessionStart: string;
56
+ sessionEnd: string;
57
+ syncTodos: string;
58
+ }
59
+
60
+ export interface ComponentVersions {
61
+ mcpProxy: string;
62
+ hooks: HookVersions;
63
+ }
64
+
65
+ export interface ConfigPaths {
66
+ claudeCode: string;
67
+ claudeDesktop?: string;
68
+ apiKey: string;
69
+ globalHooks: string;
70
+ }
71
+
72
+ export interface ProjectInstallation {
73
+ projectId: string;
74
+ configVersion: string;
75
+ hooksVersion: string;
76
+ lastValidated: string;
77
+ }
78
+
79
+ export interface VersionFile {
80
+ installedAt: string;
81
+ installedBy: 'setup' | 'npx' | 'manual';
82
+ components: ComponentVersions;
83
+ configPaths: ConfigPaths;
84
+ projects: Record<string, ProjectInstallation>;
85
+ lastUpdateCheck?: string;
86
+ }
87
+
88
+ // ============================================================================
89
+ // Hook Types
90
+ // ============================================================================
91
+
92
+ export interface HookTemplate {
93
+ name: string;
94
+ version: string;
95
+ filename: string;
96
+ content: (config: HookConfig) => string;
97
+ }
98
+
99
+ export interface HookConfig {
100
+ apiKeyPath: string;
101
+ apiUrl: string;
102
+ generatedAt: string;
103
+ }
104
+
105
+ // ============================================================================
106
+ // Setup Types
107
+ // ============================================================================
108
+
109
+ export interface SetupOptions {
110
+ apiKey: string;
111
+ projectDir: string;
112
+ projectId?: string;
113
+ skipHooks?: boolean;
114
+ force?: boolean;
115
+ globalOnly?: boolean;
116
+ }
117
+
118
+ export interface DoctorOptions {
119
+ projectDir?: string;
120
+ json?: boolean;
121
+ verbose?: boolean;
122
+ component?: string;
123
+ }
124
+
125
+ export interface RepairOptions {
126
+ projectDir?: string;
127
+ force?: boolean;
128
+ component?: string;
129
+ includeWarnings?: boolean;
130
+ }
131
+
132
+ // ============================================================================
133
+ // Console Output Types
134
+ // ============================================================================
135
+
136
+ export interface Colors {
137
+ reset: string;
138
+ red: string;
139
+ green: string;
140
+ yellow: string;
141
+ blue: string;
142
+ cyan: string;
143
+ bold: string;
144
+ dim: string;
145
+ }
146
+
147
+ export const COLORS: Colors = {
148
+ reset: '\x1b[0m',
149
+ red: '\x1b[31m',
150
+ green: '\x1b[32m',
151
+ yellow: '\x1b[33m',
152
+ blue: '\x1b[34m',
153
+ cyan: '\x1b[36m',
154
+ bold: '\x1b[1m',
155
+ dim: '\x1b[2m',
156
+ };
157
+
158
+ export function supportsColor(): boolean {
159
+ return (
160
+ process.stdout.isTTY === true &&
161
+ process.env.FORCE_COLOR !== '0' &&
162
+ (process.platform !== 'win32' ||
163
+ process.env.TERM === 'xterm-256color' ||
164
+ !!process.env.WT_SESSION)
165
+ );
166
+ }
167
+
168
+ export function c(color: keyof Colors, text: string): string {
169
+ return supportsColor() ? `${COLORS[color]}${text}${COLORS.reset}` : text;
170
+ }
171
+
172
+ // ============================================================================
173
+ // Constants
174
+ // ============================================================================
175
+
176
+ export const HOOK_VERSIONS = {
177
+ sessionStart: '1.1.0',
178
+ sessionEnd: '1.1.0',
179
+ syncTodos: '5.0.0',
180
+ };
181
+
182
+ export const EVERSTATE_API_URL = 'https://www.everstate.ai';
183
+
184
+ export function getEverstateDir(): string {
185
+ return `${process.env.HOME}/.everstate`;
186
+ }
187
+
188
+ export function getClaudeConfigPath(): string {
189
+ return `${process.env.HOME}/.claude.json`;
190
+ }
191
+
192
+ export function getClaudeDesktopConfigPath(): string {
193
+ if (process.platform === 'darwin') {
194
+ return `${process.env.HOME}/Library/Application Support/Claude/claude_desktop_config.json`;
195
+ } else if (process.platform === 'win32') {
196
+ return `${process.env.APPDATA}/Claude/claude_desktop_config.json`;
197
+ }
198
+ return ''; // Linux - no known Claude Desktop location
199
+ }