@vibescope/mcp-server 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,11 +9,102 @@
9
9
  * - get_token_usage
10
10
  */
11
11
  import os from 'os';
12
+ import crypto from 'crypto';
12
13
  import { parseArgs, createEnumValidator } from '../validators.js';
13
14
  import { getApiClient } from '../api-client.js';
14
15
  import { getAgentGuidelinesTemplate, getAgentGuidelinesSummary } from '../templates/agent-guidelines.js';
15
16
  import { getFallbackHelpContent, getAvailableHelpTopics } from '../templates/help-content.js';
16
17
  import { normalizeGitUrl } from '../utils.js';
18
+ /**
19
+ * Simple hash for content change detection.
20
+ */
21
+ function simpleHash(content) {
22
+ return crypto.createHash('md5').update(content).digest('hex').slice(0, 12);
23
+ }
24
+ /**
25
+ * Build the full CLAUDE.md content from dynamic rules + project instructions.
26
+ * This is what gets persisted to .claude/CLAUDE.md by the agent.
27
+ */
28
+ function buildPersistContent(agentRules, workflow, project, agentInstructions) {
29
+ const lines = [];
30
+ lines.push('<!-- hash:{{HASH}} -->');
31
+ lines.push('<!-- AUTO-GENERATED by Vibescope MCP. Do not edit manually — changes will be overwritten on next start_work_session. -->');
32
+ lines.push('');
33
+ lines.push('# Vibescope Agent Guidelines');
34
+ lines.push('');
35
+ // Quick start
36
+ lines.push('## Quick Start');
37
+ lines.push('');
38
+ lines.push('```');
39
+ lines.push('start_work_session(git_url: "https://github.com/YOUR/REPO", model: "opus", agent_type: "claude", agent_name: "YOUR_NAME")');
40
+ lines.push('```');
41
+ lines.push('');
42
+ // Mandatory rules
43
+ lines.push('## MANDATORY Workflow Rules (NON-NEGOTIABLE)');
44
+ lines.push('');
45
+ for (const rule of agentRules) {
46
+ lines.push(`- ${rule}`);
47
+ }
48
+ lines.push('');
49
+ // Session ID reminder
50
+ lines.push('### Session ID');
51
+ lines.push('');
52
+ lines.push('Save the `session_id` from `start_work_session` and pass it on EVERY `update_task`, `complete_task`, and `get_next_task` call. Without it, task claiming fails and your name won\'t show on completed tasks.');
53
+ lines.push('');
54
+ // Workflow
55
+ const workflowContinuous = workflow.continuous_work;
56
+ if (workflowContinuous) {
57
+ lines.push('## Continuous Work Loop');
58
+ lines.push('');
59
+ if (workflowContinuous.steps) {
60
+ for (const step of workflowContinuous.steps) {
61
+ lines.push(`1. ${step}`);
62
+ }
63
+ }
64
+ if (workflowContinuous.rule) {
65
+ lines.push('');
66
+ lines.push(`**${workflowContinuous.rule}**`);
67
+ }
68
+ lines.push('');
69
+ }
70
+ const workflowValidation = workflow.validation;
71
+ if (workflowValidation?.steps) {
72
+ lines.push('## Validation Workflow');
73
+ lines.push('');
74
+ for (const step of workflowValidation.steps) {
75
+ lines.push(`1. ${step}`);
76
+ }
77
+ lines.push('');
78
+ }
79
+ // Context management
80
+ lines.push('## Context Management');
81
+ lines.push('');
82
+ lines.push('When context grows large or responses slow:');
83
+ lines.push('1. Run `/clear`');
84
+ lines.push('2. Call `start_work_session(...)` again immediately');
85
+ lines.push('3. Continue with `next_task` — do NOT ask permission');
86
+ lines.push('');
87
+ // MCP connection
88
+ lines.push('## MCP Connection Required');
89
+ lines.push('');
90
+ lines.push('**If MCP connection fails, end session immediately.** Never work without task tracking.');
91
+ lines.push('');
92
+ // Project-specific instructions from template
93
+ if (agentInstructions.trim()) {
94
+ lines.push('## Project-Specific Instructions');
95
+ lines.push('');
96
+ lines.push(agentInstructions.trim());
97
+ lines.push('');
98
+ }
99
+ // Help topics
100
+ lines.push('## Help Topics');
101
+ lines.push('');
102
+ lines.push('`get_help(topic)` for: `getting_started`, `tasks`, `validation`, `deployment`, `git`, `blockers`, `milestones`, `fallback`, `session`, `topics`');
103
+ const content = lines.join('\n');
104
+ // Replace hash placeholder with actual hash
105
+ const hash = simpleHash(content.replace('<!-- hash:{{HASH}} -->', ''));
106
+ return content.replace('{{HASH}}', hash);
107
+ }
17
108
  // Auto-detect machine hostname for worktree tracking
18
109
  const MACHINE_HOSTNAME = os.hostname();
19
110
  const VALID_MODES = ['lite', 'full'];
@@ -370,6 +461,21 @@ export const startWorkSession = async (args, ctx) => {
370
461
  rule: 'Don\'t block tasks waiting for deployment — investigation is complete when you identify the resolution.',
371
462
  };
372
463
  result.WORKFLOW = workflow;
464
+ // Build PERSIST_INSTRUCTIONS — tells the agent to write rules to .claude/CLAUDE.md
465
+ // This ensures instructions survive context clears and persist across the whole session.
466
+ // Content comes from: admin templates + project settings (fully customizable from dashboard).
467
+ const agentInstructions = data.project?.agent_instructions || '';
468
+ const persistContent = buildPersistContent(agentRules, workflow, data.project, agentInstructions);
469
+ // Extract hash from the generated content (it's embedded in the first line)
470
+ const hashMatch = persistContent.match(/<!-- hash:(\w+) -->/);
471
+ const contentHash = hashMatch?.[1] || simpleHash(persistContent);
472
+ result.PERSIST_INSTRUCTIONS = {
473
+ action: 'Write the content below to .claude/CLAUDE.md (overwrite existing). This ensures your instructions persist across context clears.',
474
+ path: '.claude/CLAUDE.md',
475
+ content: persistContent,
476
+ hash: contentHash,
477
+ skip_if_hash_matches: `Only write if the file doesn't exist or its content has changed. Check for "<!-- hash:${contentHash} -->" at the top.`,
478
+ };
373
479
  // Add next action at end - pending requests take priority over validation, then regular tasks
374
480
  if (hasUrgentQuestions) {
375
481
  const firstQuestion = data.URGENT_QUESTIONS?.requests?.[0] || data.pending_requests?.[0];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibescope/mcp-server",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "MCP server for Vibescope - AI project tracking tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -10,6 +10,7 @@
10
10
  */
11
11
 
12
12
  import os from 'os';
13
+ import crypto from 'crypto';
13
14
  import type { Handler, HandlerRegistry, TokenUsage } from './types.js';
14
15
  import { parseArgs, createEnumValidator } from '../validators.js';
15
16
  import { getApiClient } from '../api-client.js';
@@ -17,6 +18,114 @@ import { getAgentGuidelinesTemplate, getAgentGuidelinesSummary } from '../templa
17
18
  import { getFallbackHelpContent, getAvailableHelpTopics } from '../templates/help-content.js';
18
19
  import { normalizeGitUrl } from '../utils.js';
19
20
 
21
+ /**
22
+ * Simple hash for content change detection.
23
+ */
24
+ function simpleHash(content: string): string {
25
+ return crypto.createHash('md5').update(content).digest('hex').slice(0, 12);
26
+ }
27
+
28
+ /**
29
+ * Build the full CLAUDE.md content from dynamic rules + project instructions.
30
+ * This is what gets persisted to .claude/CLAUDE.md by the agent.
31
+ */
32
+ function buildPersistContent(
33
+ agentRules: string[],
34
+ workflow: Record<string, unknown>,
35
+ project: Record<string, unknown> | undefined,
36
+ agentInstructions: string
37
+ ): string {
38
+ const lines: string[] = [];
39
+
40
+ lines.push('<!-- hash:{{HASH}} -->');
41
+ lines.push('<!-- AUTO-GENERATED by Vibescope MCP. Do not edit manually — changes will be overwritten on next start_work_session. -->');
42
+ lines.push('');
43
+ lines.push('# Vibescope Agent Guidelines');
44
+ lines.push('');
45
+
46
+ // Quick start
47
+ lines.push('## Quick Start');
48
+ lines.push('');
49
+ lines.push('```');
50
+ lines.push('start_work_session(git_url: "https://github.com/YOUR/REPO", model: "opus", agent_type: "claude", agent_name: "YOUR_NAME")');
51
+ lines.push('```');
52
+ lines.push('');
53
+
54
+ // Mandatory rules
55
+ lines.push('## MANDATORY Workflow Rules (NON-NEGOTIABLE)');
56
+ lines.push('');
57
+ for (const rule of agentRules) {
58
+ lines.push(`- ${rule}`);
59
+ }
60
+ lines.push('');
61
+
62
+ // Session ID reminder
63
+ lines.push('### Session ID');
64
+ lines.push('');
65
+ lines.push('Save the `session_id` from `start_work_session` and pass it on EVERY `update_task`, `complete_task`, and `get_next_task` call. Without it, task claiming fails and your name won\'t show on completed tasks.');
66
+ lines.push('');
67
+
68
+ // Workflow
69
+ const workflowContinuous = workflow.continuous_work as { steps?: string[]; rule?: string } | undefined;
70
+ if (workflowContinuous) {
71
+ lines.push('## Continuous Work Loop');
72
+ lines.push('');
73
+ if (workflowContinuous.steps) {
74
+ for (const step of workflowContinuous.steps) {
75
+ lines.push(`1. ${step}`);
76
+ }
77
+ }
78
+ if (workflowContinuous.rule) {
79
+ lines.push('');
80
+ lines.push(`**${workflowContinuous.rule}**`);
81
+ }
82
+ lines.push('');
83
+ }
84
+
85
+ const workflowValidation = workflow.validation as { steps?: string[] } | undefined;
86
+ if (workflowValidation?.steps) {
87
+ lines.push('## Validation Workflow');
88
+ lines.push('');
89
+ for (const step of workflowValidation.steps) {
90
+ lines.push(`1. ${step}`);
91
+ }
92
+ lines.push('');
93
+ }
94
+
95
+ // Context management
96
+ lines.push('## Context Management');
97
+ lines.push('');
98
+ lines.push('When context grows large or responses slow:');
99
+ lines.push('1. Run `/clear`');
100
+ lines.push('2. Call `start_work_session(...)` again immediately');
101
+ lines.push('3. Continue with `next_task` — do NOT ask permission');
102
+ lines.push('');
103
+
104
+ // MCP connection
105
+ lines.push('## MCP Connection Required');
106
+ lines.push('');
107
+ lines.push('**If MCP connection fails, end session immediately.** Never work without task tracking.');
108
+ lines.push('');
109
+
110
+ // Project-specific instructions from template
111
+ if (agentInstructions.trim()) {
112
+ lines.push('## Project-Specific Instructions');
113
+ lines.push('');
114
+ lines.push(agentInstructions.trim());
115
+ lines.push('');
116
+ }
117
+
118
+ // Help topics
119
+ lines.push('## Help Topics');
120
+ lines.push('');
121
+ lines.push('`get_help(topic)` for: `getting_started`, `tasks`, `validation`, `deployment`, `git`, `blockers`, `milestones`, `fallback`, `session`, `topics`');
122
+
123
+ const content = lines.join('\n');
124
+ // Replace hash placeholder with actual hash
125
+ const hash = simpleHash(content.replace('<!-- hash:{{HASH}} -->', ''));
126
+ return content.replace('{{HASH}}', hash);
127
+ }
128
+
20
129
  // Auto-detect machine hostname for worktree tracking
21
130
  const MACHINE_HOSTNAME = os.hostname();
22
131
 
@@ -426,6 +535,23 @@ export const startWorkSession: Handler = async (args, ctx) => {
426
535
 
427
536
  result.WORKFLOW = workflow;
428
537
 
538
+ // Build PERSIST_INSTRUCTIONS — tells the agent to write rules to .claude/CLAUDE.md
539
+ // This ensures instructions survive context clears and persist across the whole session.
540
+ // Content comes from: admin templates + project settings (fully customizable from dashboard).
541
+ const agentInstructions = data.project?.agent_instructions || '';
542
+ const persistContent = buildPersistContent(agentRules, workflow, data.project as Record<string, unknown> | undefined, agentInstructions);
543
+ // Extract hash from the generated content (it's embedded in the first line)
544
+ const hashMatch = persistContent.match(/<!-- hash:(\w+) -->/);
545
+ const contentHash = hashMatch?.[1] || simpleHash(persistContent);
546
+
547
+ result.PERSIST_INSTRUCTIONS = {
548
+ action: 'Write the content below to .claude/CLAUDE.md (overwrite existing). This ensures your instructions persist across context clears.',
549
+ path: '.claude/CLAUDE.md',
550
+ content: persistContent,
551
+ hash: contentHash,
552
+ skip_if_hash_matches: `Only write if the file doesn't exist or its content has changed. Check for "<!-- hash:${contentHash} -->" at the top.`,
553
+ };
554
+
429
555
  // Add next action at end - pending requests take priority over validation, then regular tasks
430
556
  if (hasUrgentQuestions) {
431
557
  const firstQuestion = data.URGENT_QUESTIONS?.requests?.[0] || data.pending_requests?.[0];