MindPeeker provides a comprehensive suite of developer tools to streamline integration, testing, and deployment. These tools help you build, test, and maintain your psychic intelligence applications efficiently.
npm install -g @mindpeeker/cli
yarn global add @mindpeeker/cli
pip install mindpeeker-cli
brew install mindpeeker/tap/mindpeeker-cli
mindpeeker auth login
mindpeeker auth set --key your_api_key_here
mindpeeker auth status
mindpeeker auth logout
mindpeeker sessions create \
--type remote_viewing \
--target "Missing person investigation" \
--modality visual \
--duration 30
mindpeeker sessions list --limit 10 --status completed
mindpeeker sessions get sess_123456789
mindpeeker sessions results sess_123456789
mindpeeker sessions watch sess_123456789
mindpeeker analysis submit \
--target-type location \
--reference photos.jpg,coordinates.json \
--analysis-type comprehensive
mindpeeker analysis list --status completed
mindpeeker analysis results anal_123456789
mindpeeker analysis export anal_123456789 --format json --output results.json
mindpeeker dowsing query \
--type location \
--question "Find water source" \
--location "40.7128,-74.0060" \
--radius 1000
mindpeeker dowsing batch --file queries.json
mindpeeker dowsing interactive
mindpeeker webhooks create \
--url https://your-app.com/webhook \
--events session.completed,analysis.completed \
--secret your_webhook_secret
mindpeeker webhooks list
mindpeeker webhooks test webhook_123
mindpeeker webhooks delete webhook_123
mindpeeker config set api_url https://api.mindpeeker.com/v1
mindpeeker config set timeout 30000
mindpeeker config set retry_attempts 3
mindpeeker config get api_url
mindpeeker config list
mindpeeker config reset
FROM node:18-alpine
RUN npm install -g @mindpeeker/cli
RUN npm install -g nodemon typescript ts-node
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
environment:
- NODE_ENV=development
- MINDPEEKER_API_KEY=${MINDPEEKER_API_KEY}
- MINDPEEKER_WEBHOOK_SECRET=${MINDPEEKER_WEBHOOK_SECRET}
volumes:
- .:/app
- /app/node_modules
depends_on:
- redis
- postgres
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
postgres:
image: postgres:15-alpine
ports:
- "5432:5432"
environment:
- POSTGRES_DB=mindpeeker_dev
- POSTGRES_USER=dev
- POSTGRES_PASSWORD=dev123
volumes:
- postgres_data:/var/lib/postgresql/data
webhook-proxy:
image: ngrok/ngrok:latest
command: http 3000
ports:
- "4040:4040"
environment:
- NGROK_AUTHTOKEN=${NGROK_AUTHTOKEN}
volumes:
redis_data:
postgres_data:
#!/bin/bash
echo "Setting up MindPeeker development environment..."
command -v node >/dev/null 2>&1 || { echo "Node.js is required"; exit 1; }
command -v docker >/dev/null 2>&1 || { echo "Docker is required"; exit 1; }
echo "Installing dependencies..."
npm install
echo "Installing MindPeeker CLI..."
npm install -g @mindpeeker/cli
if [ ! -f .env ]; then
echo "Creating .env file..."
cp .env.example .env
echo "Please edit .env with your API keys"
fi
echo "Starting development services..."
docker-compose -f docker-compose.dev.yml up -d
echo "Waiting for services to start..."
sleep 10
echo "Running database migrations..."
npm run migrate
echo "Seeding test data..."
npm run seed
echo "Development environment ready!"
echo "Webhook tunnel URL: $(curl -s http://localhost:4040/api/tunnels | jq -r '.tunnels[0].public_url')"
// tests/utils/mindpeeker-mock.js
const { MindPeekerClient } = require('@mindpeeker/javascript');
class MockMindPeekerClient {
constructor(options = {}) {
this.apiKey = options.apiKey || 'test_key';
this.responses = new Map();
this.requests = [];
}
// Mock response setup
setMockResponse(method, response) {
this.responses.set(method, response);
}
// Session methods
async sessions() {
return {
create: async (params) => {
this.requests.push({ method: 'sessions.create', params });
return this.responses.get('sessions.create') || {
sessionId: 'test_session_123',
status: 'initiated',
createdAt: new Date().toISOString()
};
},
getResults: async (sessionId) => {
this.requests.push({ method: 'sessions.getResults', params: { sessionId } });
return this.responses.get('sessions.getResults') || {
sessionId,
status: 'completed',
confidenceScore: 0.85,
results: {
coordinates: { latitude: 40.7128, longitude: -74.0060 },
descriptors: ['test descriptor']
}
};
}
};
}
// Analysis methods
async analysis() {
return {
submitTarget: async (params) => {
this.requests.push({ method: 'analysis.submitTarget', params });
return this.responses.get('analysis.submitTarget') || {
analysisId: 'test_analysis_123',
status: 'queued'
};
}
};
}
// Dowsing methods
async dowsing() {
return {
query: async (params) => {
this.requests.push({ method: 'dowsing.query', params });
return this.responses.get('dowsing.query') || {
queryId: 'test_query_123',
answer: 'positive',
confidence: 0.9
};
}
};
}
// Get request history for testing
getRequests() {
return this.requests;
}
// Clear request history
clearRequests() {
this.requests = [];
}
}
module.exports = { MockMindPeekerClient };
// tests/integration/psychic-integration.test.js
const request = require('supertest');
const app = require('../../app');
const { MockMindPeekerClient } = require('../utils/mindpeeker-mock');
describe('Psychic Integration API', () => {
let mockClient;
beforeEach(() => {
mockClient = new MockMindPeekerClient();
app.setMindPeekerClient(mockClient);
});
afterEach(() => {
mockClient.clearRequests();
});
describe('POST /api/investigation', () => {
it('should create a new psychic investigation', async () => {
// Setup mock response
mockClient.setMockResponse('sessions.create', {
sessionId: 'investigation_123',
status: 'initiated',
createdAt: '2025-01-15T10:30:00Z'
});
const response = await request(app)
.post('/api/investigation')
.send({
type: 'remote_viewing',
target: 'Test investigation',
modality: 'visual'
})
.expect(200);
expect(response.body.sessionId).toBe('investigation_123');
expect(response.body.status).toBe('initiated');
// Verify API was called correctly
const requests = mockClient.getRequests();
expect(requests).toHaveLength(1);
expect(requests[0].method).toBe('sessions.create');
expect(requests[0].params.type).toBe('remote_viewing');
});
});
describe('GET /api/investigation/:sessionId/results', () => {
it('should return investigation results', async () => {
// Setup mock response
mockClient.setMockResponse('sessions.getResults', {
sessionId: 'investigation_123',
status: 'completed',
confidenceScore: 0.92,
results: {
coordinates: { latitude: 40.7128, longitude: -74.0060 },
descriptors: ['urban environment', 'water nearby']
}
});
const response = await request(app)
.get('/api/investigation/investigation_123/results')
.expect(200);
expect(response.body.status).toBe('completed');
expect(response.body.confidenceScore).toBe(0.92);
expect(response.body.results.descriptors).toContain('urban environment');
});
});
});
// tools/load-test.js
import { MindPeekerClient } from '@mindpeeker/javascript';
import { performance } from 'perf_hooks';
class LoadTester {
constructor(apiKey, concurrency = 10) {
this.client = new MindPeekerClient({ apiKey });
this.concurrency = concurrency;
this.results = [];
}
async runLoadTest(testType, iterations = 100) {
console.log(`Starting load test: ${testType} (${iterations} iterations)`);
const startTime = performance.now();
const promises = [];
for (let i = 0; i < iterations; i++) {
if (promises.length >= this.concurrency) {
await Promise.race(promises);
promises.splice(promises.findIndex(p => p.settled), 1);
}
const promise = this.runSingleTest(testType, i);
promises.push(promise);
}
await Promise.all(promises);
const endTime = performance.now();
this.analyzeResults(endTime - startTime);
}
async runSingleTest(testType, iteration) {
const startTime = performance.now();
try {
let result;
switch (testType) {
case 'session_create':
result = await this.client.sessions.create({
type: 'remote_viewing',
target: `Load test ${iteration}`,
modality: 'visual'
});
break;
case 'dowsing_query':
result = await this.client.dowsing.query({
query_type: 'yes_no',
question: `Load test question ${iteration}?`
});
break;
case 'analysis_submit':
result = await this.client.analysis.submitTarget({
target_type: 'location',
reference_material: { test: true },
analysis_type: 'quick_scan'
});
break;
}
const endTime = performance.now();
const duration = endTime - startTime;
this.results.push({
iteration,
success: true,
duration,
result: result.sessionId || result.queryId || result.analysisId
});
} catch (error) {
const endTime = performance.now();
const duration = endTime - startTime;
this.results.push({
iteration,
success: false,
duration,
error: error.message
});
}
}
analyzeResults(totalTime) {
const successful = this.results.filter(r => r.success);
const failed = this.results.filter(r => !r.success);
const durations = successful.map(r => r.duration);
const avgDuration = durations.reduce((a, b) => a + b, 0) / durations.length;
const minDuration = Math.min(...durations);
const maxDuration = Math.max(...durations);
console.log('\n=== Load Test Results ===');
console.log(`Total iterations: ${this.results.length}`);
console.log(`Successful: ${successful.length}`);
console.log(`Failed: ${failed.length}`);
console.log(`Success rate: ${((successful.length / this.results.length) * 100).toFixed(2)}%`);
console.log(`Total time: ${totalTime.toFixed(2)}ms`);
console.log(`Average response time: ${avgDuration.toFixed(2)}ms`);
console.log(`Min response time: ${minDuration.toFixed(2)}ms`);
console.log(`Max response time: ${maxDuration.toFixed(2)}ms`);
console.log(`Requests per second: ${(this.results.length / (totalTime / 1000)).toFixed(2)}`);
if (failed.length > 0) {
console.log('\n=== Failed Requests ===');
failed.forEach(f => {
console.log(`Iteration ${f.iteration}: ${f.error}`);
});
}
}
}
// Usage
const tester = new LoadTester(process.env.MINDPEEKER_API_KEY, 5);
await tester.runLoadTest('session_create', 50);
await tester.runLoadTest('dowsing_query', 50);
await tester.runLoadTest('analysis_submit', 50);
// utils/api-logger.js
class APILogger {
constructor(logLevel = 'info') {
this.logLevel = logLevel;
this.requests = [];
this.maxLogSize = 1000;
}
logRequest(method, url, headers, body, response, duration) {
const logEntry = {
timestamp: new Date().toISOString(),
method,
url,
headers: this.sanitizeHeaders(headers),
body: this.sanitizeBody(body),
response: {
status: response.status,
headers: response.headers
},
duration,
success: response.status >= 200 && response.status < 300
};
this.requests.push(logEntry);
// Keep log size manageable
if (this.requests.length > this.maxLogSize) {
this.requests.shift();
}
this.outputLog(logEntry);
}
sanitizeHeaders(headers) {
const sanitized = { ...headers };
const sensitiveHeaders = ['authorization', 'x-api-key', 'cookie'];
sensitiveHeaders.forEach(header => {
if (sanitized[header]) {
sanitized[header] = '[REDACTED]';
}
});
return sanitized;
}
sanitizeBody(body) {
if (!body) return null;
const sensitiveFields = ['api_key', 'password', 'token', 'secret'];
const sanitized = { ...body };
sensitiveFields.forEach(field => {
if (sanitized[field]) {
sanitized[field] = '[REDACTED]';
}
});
return sanitized;
}
outputLog(entry) {
const logLevel = entry.success ? 'info' : 'error';
if (this.shouldLog(logLevel)) {
console.log(`[${entry.timestamp}] ${entry.method} ${entry.url} - ${entry.response.status} (${entry.duration}ms)`);
if (!entry.success) {
console.error(`Request failed: ${JSON.stringify(entry.body)}`);
}
}
}
shouldLog(level) {
const levels = ['error', 'warn', 'info', 'debug'];
const currentLevelIndex = levels.indexOf(this.logLevel);
const messageLevelIndex = levels.indexOf(level);
return messageLevelIndex <= currentLevelIndex;
}
getRequests(filter = {}) {
let filtered = this.requests;
if (filter.method) {
filtered = filtered.filter(r => r.method === filter.method);
}
if (filter.success !== undefined) {
filtered = filtered.filter(r => r.success === filter.success);
}
if (filter.since) {
const since = new Date(filter.since);
filtered = filtered.filter(r => new Date(r.timestamp) >= since);
}
return filtered;
}
exportLogs(format = 'json') {
switch (format) {
case 'json':
return JSON.stringify(this.requests, null, 2);
case 'csv':
const headers = ['timestamp', 'method', 'url', 'status', 'duration', 'success'];
const csvData = this.requests.map(r => [
r.timestamp,
r.method,
r.url,
r.response.status,
r.duration,
r.success
]);
return [headers, ...csvData].map(row => row.join(',')).join('\n');
default:
return this.requests;
}
}
}
module.exports = APILogger;
// utils/performance-monitor.js
class PerformanceMonitor {
constructor() {
this.metrics = {
requests: {
total: 0,
successful: 0,
failed: 0,
averageResponseTime: 0
},
sessions: {
created: 0,
completed: 0,
failed: 0,
averageCompletionTime: 0
},
errors: {
rateLimitErrors: 0,
authenticationErrors: 0,
validationErrors: 0,
serverErrors: 0
}
};
this.responseTimes = [];
this.completionTimes = [];
}
recordRequest(duration, success, statusCode) {
this.metrics.requests.total++;
if (success) {
this.metrics.requests.successful++;
} else {
this.metrics.requests.failed++;
// Categorize errors
if (statusCode === 429) {
this.metrics.errors.rateLimitErrors++;
} else if (statusCode === 401 || statusCode === 403) {
this.metrics.errors.authenticationErrors++;
} else if (statusCode >= 400 && statusCode < 500) {
this.metrics.errors.validationErrors++;
} else if (statusCode >= 500) {
this.metrics.errors.serverErrors++;
}
}
this.responseTimes.push(duration);
this.updateAverageResponseTime();
}
recordSession(action, duration = null) {
switch (action) {
case 'created':
this.metrics.sessions.created++;
break;
case 'completed':
this.metrics.sessions.completed++;
if (duration) {
this.completionTimes.push(duration);
this.updateAverageCompletionTime();
}
break;
case 'failed':
this.metrics.sessions.failed++;
break;
}
}
updateAverageResponseTime() {
if (this.responseTimes.length === 0) return;
const sum = this.responseTimes.reduce((a, b) => a + b, 0);
this.metrics.requests.averageResponseTime = sum / this.responseTimes.length;
}
updateAverageCompletionTime() {
if (this.completionTimes.length === 0) return;
const sum = this.completionTimes.reduce((a, b) => a + b, 0);
this.metrics.sessions.averageCompletionTime = sum / this.completionTimes.length;
}
getMetrics() {
return {
...this.metrics,
successRate: this.metrics.requests.total > 0
? (this.metrics.requests.successful / this.metrics.requests.total) * 100
: 0,
sessionSuccessRate: this.metrics.sessions.created > 0
? (this.metrics.sessions.completed / this.metrics.sessions.created) * 100
: 0
};
}
reset() {
this.metrics = {
requests: { total: 0, successful: 0, failed: 0, averageResponseTime: 0 },
sessions: { created: 0, completed: 0, failed: 0, averageCompletionTime: 0 },
errors: { rateLimitErrors: 0, authenticationErrors: 0, validationErrors: 0, serverErrors: 0 }
};
this.responseTimes = [];
this.completionTimes = [];
}
exportMetrics() {
return {
timestamp: new Date().toISOString(),
metrics: this.getMetrics(),
responseTimeDistribution: this.getResponseTimeDistribution(),
completionTimeDistribution: this.getCompletionTimeDistribution()
};
}
getResponseTimeDistribution() {
if (this.responseTimes.length === 0) return {};
const sorted = [...this.responseTimes].sort((a, b) => a - b);
return {
min: sorted[0],
max: sorted[sorted.length - 1],
p50: sorted[Math.floor(sorted.length * 0.5)],
p90: sorted[Math.floor(sorted.length * 0.9)],
p95: sorted[Math.floor(sorted.length * 0.95)],
p99: sorted[Math.floor(sorted.length * 0.99)]
};
}
getCompletionTimeDistribution() {
if (this.completionTimes.length === 0) return {};
const sorted = [...this.completionTimes].sort((a, b) => a - b);
return {
min: sorted[0],
max: sorted[sorted.length - 1],
p50: sorted[Math.floor(sorted.length * 0.5)],
p90: sorted[Math.floor(sorted.length * 0.9)],
p95: sorted[Math.floor(sorted.length * 0.95)],
p99: sorted[Math.floor(sorted.length * 0.99)]
};
}
}
module.exports = PerformanceMonitor;
// .vscode/extensions.json
{
"recommendations": [
"mindpeeker.mindpeeker-vscode",
"ms-vscode.vscode-typescript-next",
"esbenp.prettier-vscode",
"ms-vscode.vscode-eslint",
"bradlc.vscode-tailwindcss"
]
}
// .vscode/settings.json
{
"mindpeeker.apiKey": "${env:MINDPEEKER_API_KEY}",
"mindpeeker.defaultEnvironment": "sandbox",
"mindpeeker.autoComplete": true,
"mindpeeker.syntaxHighlighting": true,
"mindpeeker.debugMode": false,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}
name: MindPeeker CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
services:
redis:
image: redis:7
ports:
- 6379:6379
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install MindPeeker CLI
run: npm install -g @mindpeeker/cli
- name: Run linting
run: npm run lint
- name: Run type checking
run: npm run typecheck
- name: Run unit tests
run: npm run test:unit
- name: Run integration tests
env:
MINDPEEKER_API_KEY: ${{ secrets.MINDPEEKER_TEST_API_KEY }}
run: npm run test:integration
- name: Test CLI functionality
env:
MINDPEEKER_API_KEY: ${{ secrets.MINDPEEKER_TEST_API_KEY }}
run: |
mindpeeker auth login --key $MINDPEEKER_API_KEY
mindpeeker sessions create --type dowsing --question "CI test"
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v3
- name: Deploy to production
env:
MINDPEEKER_API_KEY: ${{ secrets.MINDPEEKER_PROD_API_KEY }}
run: |
npm run build
npm run deploy