@sylphx/flow 1.1.1 → 1.2.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 (45) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/package.json +1 -1
  3. package/src/commands/hook-command.ts +10 -230
  4. package/src/composables/index.ts +0 -1
  5. package/src/config/servers.ts +35 -78
  6. package/src/core/interfaces.ts +0 -33
  7. package/src/domains/index.ts +0 -2
  8. package/src/index.ts +0 -4
  9. package/src/services/mcp-service.ts +0 -16
  10. package/src/targets/claude-code.ts +3 -9
  11. package/src/targets/functional/claude-code-logic.ts +4 -22
  12. package/src/targets/opencode.ts +0 -6
  13. package/src/types/mcp.types.ts +29 -38
  14. package/src/types/target.types.ts +0 -2
  15. package/src/types.ts +0 -1
  16. package/src/commands/codebase-command.ts +0 -168
  17. package/src/commands/knowledge-command.ts +0 -161
  18. package/src/composables/useTargetConfig.ts +0 -45
  19. package/src/core/formatting/bytes.test.ts +0 -115
  20. package/src/core/validation/limit.test.ts +0 -155
  21. package/src/core/validation/query.test.ts +0 -44
  22. package/src/domains/codebase/index.ts +0 -5
  23. package/src/domains/codebase/tools.ts +0 -139
  24. package/src/domains/knowledge/index.ts +0 -10
  25. package/src/domains/knowledge/resources.ts +0 -537
  26. package/src/domains/knowledge/tools.ts +0 -174
  27. package/src/services/search/base-indexer.ts +0 -156
  28. package/src/services/search/codebase-indexer-types.ts +0 -38
  29. package/src/services/search/codebase-indexer.ts +0 -647
  30. package/src/services/search/embeddings-provider.ts +0 -455
  31. package/src/services/search/embeddings.ts +0 -316
  32. package/src/services/search/functional-indexer.ts +0 -323
  33. package/src/services/search/index.ts +0 -27
  34. package/src/services/search/indexer.ts +0 -380
  35. package/src/services/search/knowledge-indexer.ts +0 -422
  36. package/src/services/search/semantic-search.ts +0 -244
  37. package/src/services/search/tfidf.ts +0 -559
  38. package/src/services/search/unified-search-service.ts +0 -888
  39. package/src/services/storage/cache-storage.ts +0 -487
  40. package/src/services/storage/drizzle-storage.ts +0 -581
  41. package/src/services/storage/index.ts +0 -15
  42. package/src/services/storage/lancedb-vector-storage.ts +0 -494
  43. package/src/services/storage/memory-storage.ts +0 -268
  44. package/src/services/storage/separated-storage.ts +0 -467
  45. package/src/services/storage/vector-storage.ts +0 -13
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @sylphx/flow
2
2
 
3
+ ## 1.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 2272596: Enhanced agent system prompts with Minimal Effective Prompt principles:
8
+
9
+ - **Workflow Standards**: Added continuous atomic commits, semver discipline (minor-first), TypeScript release workflow with changeset + CI, and proactive pre-commit cleanup
10
+ - **Research-First Mindset**: Enforced research before implementation to prevent outdated approaches
11
+ - **Silent Mode Fix**: Prevented agents from creating report files to compensate for not speaking
12
+ - **Proactive Cleanup**: Added mandatory pre-commit hygiene - refactor, remove unused code, delete outdated docs, fix tech debt
13
+ - **MEP Refactor**: Refactored all prompts (coder, orchestrator, reviewer, writer, core, code-standards, silent) using Minimal Effective Prompt principles - trust LLM, WHAT+WHEN not HOW+WHY, condition→action format, ~40% token reduction
14
+
15
+ Prime directive: Never accumulate misleading artifacts. Research is mandatory. Tests and benchmarks required (.test.ts, .bench.ts).
16
+
3
17
  ## 1.1.1
4
18
 
5
19
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sylphx/flow",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "AI-powered development workflow automation with autonomous loop mode and smart configuration",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,21 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Hook command - Dynamic content loading for Claude Code hooks
3
+ * Hook command - OS notification for Claude Code startup
4
4
  *
5
- * Purpose: Load rules and output styles dynamically via session hooks
6
- * instead of installing them as static files
5
+ * Purpose: Send OS-level notifications when Claude Code starts
7
6
  *
8
7
  * DESIGN RATIONALE:
9
- * - Single source of truth: assets/ directory
10
- * - Dynamic loading: No static file maintenance
11
- * - Flexible: Easy to extend for different hook types and targets
12
- * - Consistent: Follows sysinfo command pattern
8
+ * - Simple notification: Just notify user when Claude Code is ready
9
+ * - Cross-platform: Supports macOS, Linux, and Windows
10
+ * - Non-intrusive: Fails silently if notification system not available
13
11
  */
14
12
 
15
13
  import { exec } from 'node:child_process';
16
- import fsSync from 'node:fs';
17
14
  import os from 'node:os';
18
- import path from 'node:path';
19
15
  import { promisify } from 'node:util';
20
16
  import { Command } from 'commander';
21
17
  import { cli } from '../utils/cli-output.js';
@@ -25,7 +21,7 @@ const execAsync = promisify(exec);
25
21
  /**
26
22
  * Hook types supported
27
23
  */
28
- type HookType = 'session' | 'message' | 'notification';
24
+ type HookType = 'notification';
29
25
 
30
26
  /**
31
27
  * Target platforms supported
@@ -37,7 +33,7 @@ type TargetPlatform = 'claude-code';
37
33
  */
38
34
  export const hookCommand = new Command('hook')
39
35
  .description('Load dynamic system information for Claude Code hooks')
40
- .requiredOption('--type <type>', 'Hook type (session, message)')
36
+ .requiredOption('--type <type>', 'Hook type (notification)')
41
37
  .option('--target <target>', 'Target platform (claude-code)', 'claude-code')
42
38
  .option('--verbose', 'Show verbose output', false)
43
39
  .action(async (options) => {
@@ -46,10 +42,8 @@ export const hookCommand = new Command('hook')
46
42
  const target = options.target as TargetPlatform;
47
43
 
48
44
  // Validate hook type
49
- if (!['session', 'message', 'notification'].includes(hookType)) {
50
- throw new Error(
51
- `Invalid hook type: ${hookType}. Must be 'session', 'message', or 'notification'`
52
- );
45
+ if (hookType !== 'notification') {
46
+ throw new Error(`Invalid hook type: ${hookType}. Must be 'notification'`);
53
47
  }
54
48
 
55
49
  // Validate target
@@ -83,17 +77,9 @@ export const hookCommand = new Command('hook')
83
77
  */
84
78
  async function loadHookContent(
85
79
  hookType: HookType,
86
- target: TargetPlatform,
80
+ _target: TargetPlatform,
87
81
  verbose: boolean = false
88
82
  ): Promise<string> {
89
- if (hookType === 'session') {
90
- return await loadSessionContent(target, verbose);
91
- }
92
-
93
- if (hookType === 'message') {
94
- return await loadMessageContent(target, verbose);
95
- }
96
-
97
83
  if (hookType === 'notification') {
98
84
  return await sendNotification(verbose);
99
85
  }
@@ -101,212 +87,6 @@ async function loadHookContent(
101
87
  return '';
102
88
  }
103
89
 
104
- /**
105
- * Load content for session start hook
106
- * Includes: system info only (rules and output styles are static files)
107
- */
108
- async function loadSessionContent(_target: TargetPlatform, verbose: boolean): Promise<string> {
109
- // Load system info for session
110
- if (verbose) {
111
- cli.info('Loading system info...');
112
- }
113
- return await getSystemInfo('session');
114
- }
115
-
116
- /**
117
- * Load content for message hook
118
- * Includes: system status
119
- */
120
- async function loadMessageContent(_target: TargetPlatform, verbose: boolean): Promise<string> {
121
- if (verbose) {
122
- cli.info('Loading system status...');
123
- }
124
- return await getSystemInfo('message');
125
- }
126
-
127
- /**
128
- * Get system information
129
- */
130
- async function getSystemInfo(hookType: 'session' | 'message'): Promise<string> {
131
- const currentTime = new Date().toISOString();
132
- const tempDir = os.tmpdir();
133
-
134
- // Get memory information
135
- const totalMem = os.totalmem();
136
- const freeMem = os.freemem();
137
- const usedMem = totalMem - freeMem;
138
- const memoryUsage = ((usedMem / totalMem) * 100).toFixed(1);
139
-
140
- // Get CPU information
141
- const cpus = os.cpus();
142
- const cpuCores = cpus.length;
143
-
144
- // Get CPU usage (using load average for fast detection)
145
- const loadAvg = os.loadavg();
146
- const cpuUsagePercent = Math.round((loadAvg[0] / cpuCores) * 100);
147
-
148
- // Get platform information
149
- const platform = os.platform();
150
- const arch = os.arch();
151
-
152
- if (hookType === 'session') {
153
- // Session info includes project information
154
- const projectInfo = await detectProjectInfo();
155
-
156
- return `## Session Information
157
-
158
- **Platform:** ${platform} (${arch})
159
- **Working Directory:** ${process.cwd()}
160
- **Temp Directory:** ${tempDir}
161
- **CPU:** ${cpuCores} cores
162
- **Total Memory:** ${formatBytes(totalMem)}
163
-
164
- ## Project Information
165
-
166
- **Project Type:** ${projectInfo.type}
167
- **Package Manager:** ${projectInfo.packageManager}${
168
- projectInfo.name && projectInfo.name !== 'unnamed'
169
- ? `\n**Project:** ${projectInfo.name} (${projectInfo.version})`
170
- : ''
171
- }`;
172
- }
173
-
174
- // Message info - just current status
175
- return `## System Status
176
-
177
- **Current Time:** ${new Date(currentTime).toLocaleString()}
178
- **CPU:** ${cpuUsagePercent}%
179
- **Memory:** ${memoryUsage}% used (${formatBytes(freeMem)} free)`;
180
- }
181
-
182
- /**
183
- * Detect project information
184
- */
185
- async function detectProjectInfo() {
186
- const cwd = process.cwd();
187
- const packageJsonPath = path.join(cwd, 'package.json');
188
-
189
- // Check if package.json exists
190
- if (!fsSync.existsSync(packageJsonPath)) {
191
- return {
192
- type: 'unknown',
193
- packageManager: 'none',
194
- description: 'No package.json found',
195
- };
196
- }
197
-
198
- try {
199
- // Read package.json
200
- const packageJson = JSON.parse(fsSync.readFileSync(packageJsonPath, 'utf8'));
201
-
202
- // Detect project type based on dependencies and scripts
203
- const projectType = detectProjectType(packageJson);
204
-
205
- // Detect package manager based on package.json field, then lock files
206
- const packageManager = detectPackageManager(cwd, packageJson);
207
-
208
- return {
209
- type: projectType,
210
- packageManager: packageManager,
211
- name: packageJson.name || 'unnamed',
212
- version: packageJson.version || '0.0.0',
213
- description: packageJson.description || '',
214
- };
215
- } catch (_error) {
216
- return {
217
- type: 'js/ts',
218
- packageManager: 'unknown',
219
- description: 'Invalid package.json',
220
- };
221
- }
222
- }
223
-
224
- /**
225
- * Detect project type from package.json
226
- */
227
- function detectProjectType(packageJson: Record<string, unknown>): string {
228
- // Check for TypeScript
229
- const hasTypescript =
230
- packageJson.devDependencies?.typescript ||
231
- packageJson.dependencies?.typescript ||
232
- packageJson.devDependencies?.['@types/node'] ||
233
- packageJson.scripts?.build?.includes('tsc') ||
234
- packageJson.scripts?.dev?.includes('ts-node');
235
-
236
- if (hasTypescript) {
237
- return 'typescript';
238
- }
239
-
240
- // Check for React
241
- const hasReact =
242
- packageJson.dependencies?.react ||
243
- packageJson.devDependencies?.react ||
244
- packageJson.scripts?.dev?.includes('vite') ||
245
- packageJson.scripts?.build?.includes('vite');
246
-
247
- if (hasReact) {
248
- return 'react';
249
- }
250
-
251
- // Check for Next.js
252
- const hasNext =
253
- packageJson.dependencies?.next ||
254
- packageJson.devDependencies?.next ||
255
- packageJson.scripts?.dev === 'next dev' ||
256
- packageJson.scripts?.build === 'next build';
257
-
258
- if (hasNext) {
259
- return 'next.js';
260
- }
261
-
262
- // Default to JavaScript
263
- return 'javascript';
264
- }
265
-
266
- /**
267
- * Detect package manager from lock files
268
- */
269
- function detectPackageManager(cwd: string, packageJson?: any): string {
270
- // First, check package.json for explicit packageManager field (most accurate)
271
- if (packageJson?.packageManager) {
272
- const packageManagerField = packageJson.packageManager;
273
- // Extract manager name from "bun@1.3.1" format
274
- const managerName = packageManagerField.split('@')[0];
275
- if (['npm', 'yarn', 'pnpm', 'bun'].includes(managerName)) {
276
- return managerName;
277
- }
278
- }
279
-
280
- // Fallback: Check for lock files in order of preference
281
- const lockFiles = [
282
- { file: 'pnpm-lock.yaml', manager: 'pnpm' },
283
- { file: 'yarn.lock', manager: 'yarn' },
284
- { file: 'package-lock.json', manager: 'npm' },
285
- { file: 'bun.lockb', manager: 'bun' },
286
- ];
287
-
288
- for (const { file, manager } of lockFiles) {
289
- if (fsSync.existsSync(path.join(cwd, file))) {
290
- return manager;
291
- }
292
- }
293
-
294
- return 'npm'; // Default to npm
295
- }
296
-
297
- /**
298
- * Format bytes to human-readable string
299
- */
300
- function formatBytes(bytes: number): string {
301
- const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
302
- if (bytes === 0) {
303
- return '0 Bytes';
304
- }
305
-
306
- const i = Math.floor(Math.log(bytes) / Math.log(1024));
307
- return `${Math.round((bytes / 1024 ** i) * 100) / 100} ${sizes[i]}`;
308
- }
309
-
310
90
  /**
311
91
  * Send OS-level notification
312
92
  */
@@ -2,4 +2,3 @@
2
2
 
3
3
  export { useEnv, useEnvVar } from './useEnv.js';
4
4
  export { useIsCI, useIsDebug, useRuntimeConfig } from './useRuntimeConfig.js';
5
- export { useTargetConfig, useTargetConfigById } from './useTargetConfig.js';
@@ -1,5 +1,4 @@
1
1
  import type { MCPServerConfigUnion } from '../types.js';
2
- import { envSecurity, securitySchemas } from '../utils/security.js';
3
2
 
4
3
  /**
5
4
  * Central MCP server registry for Sylphx Flow
@@ -44,83 +43,6 @@ export interface MCPServerDefinition {
44
43
  * This replaces all hardcoded server lists throughout the codebase
45
44
  */
46
45
  export const MCP_SERVER_REGISTRY: Record<string, MCPServerDefinition> = {
47
- 'sylphx-flow': {
48
- id: 'sylphx-flow',
49
- name: 'sylphx-flow',
50
- description: 'Sylphx Flow MCP server for agent coordination and memory management',
51
- config: {
52
- type: 'stdio' as const,
53
- command: 'sylphx-flow',
54
- args: ['mcp', 'start'],
55
- env: {
56
- OPENAI_API_KEY: '',
57
- OPENAI_BASE_URL: 'https://api.openai.com/v1',
58
- EMBEDDING_MODEL: 'text-embedding-3-small',
59
- },
60
- },
61
- envVars: {
62
- OPENAI_API_KEY: {
63
- description: 'OpenAI API key for vector search embeddings',
64
- required: false,
65
- secret: true,
66
- },
67
- OPENAI_BASE_URL: {
68
- description: 'Base URL for OpenAI-compatible embedding API',
69
- required: false,
70
- default: 'https://api.openai.com/v1',
71
- },
72
- EMBEDDING_MODEL: {
73
- description: 'Embedding model to use for vector search',
74
- required: false,
75
- default: 'text-embedding-3-small',
76
- dependsOn: ['OPENAI_API_KEY', 'OPENAI_BASE_URL'],
77
- fetchChoices: async () => {
78
- // Validate environment variables
79
- const validatedBaseUrl = envSecurity.getEnvVar(
80
- 'OPENAI_BASE_URL',
81
- 'https://api.openai.com/v1'
82
- );
83
- const validatedApiKey = envSecurity.getEnvVar('OPENAI_API_KEY');
84
-
85
- if (!validatedApiKey) {
86
- throw new Error('OPENAI_API_KEY is required to fetch embedding models');
87
- }
88
-
89
- // Additional validation for API key format
90
- try {
91
- securitySchemas.apiKey.parse(validatedApiKey);
92
- } catch (_error) {
93
- throw new Error('Invalid OPENAI_API_KEY format');
94
- }
95
-
96
- const response = await fetch(`${validatedBaseUrl}/models`, {
97
- headers: { Authorization: `Bearer ${validatedApiKey}` },
98
- timeout: 10000, // Add timeout to prevent hanging
99
- });
100
-
101
- if (!response.ok) {
102
- throw new Error(`Failed to fetch models: ${response.statusText}`);
103
- }
104
-
105
- const data = await response.json();
106
- const embeddingModels = data.data
107
- .filter((m: { id: string }) => m.id.includes('embedding'))
108
- .map((m: { id: string }) => m.id)
109
- .sort();
110
-
111
- if (embeddingModels.length === 0) {
112
- throw new Error('No embedding models found');
113
- }
114
-
115
- return embeddingModels;
116
- },
117
- },
118
- },
119
- category: 'core',
120
- defaultInInit: true,
121
- required: true,
122
- },
123
-
124
46
  'gpt-image': {
125
47
  id: 'gpt-image',
126
48
  name: 'gpt-image-1-mcp',
@@ -219,6 +141,41 @@ export const MCP_SERVER_REGISTRY: Record<string, MCPServerDefinition> = {
219
141
  category: 'external',
220
142
  defaultInInit: true,
221
143
  },
144
+
145
+ coderag: {
146
+ id: 'coderag',
147
+ name: 'coderag',
148
+ description: 'CodeRAG - Lightning-fast hybrid code search (TF-IDF + Vector) for RAG',
149
+ config: {
150
+ type: 'stdio' as const,
151
+ command: 'npx',
152
+ args: ['-y', '@sylphx/coderag-mcp'],
153
+ env: {
154
+ OPENAI_API_KEY: '',
155
+ CODEBASE_ROOT: '',
156
+ INDEX_PATH: '.coderag',
157
+ },
158
+ },
159
+ envVars: {
160
+ OPENAI_API_KEY: {
161
+ description: 'OpenAI API key for embeddings (vector search)',
162
+ required: false,
163
+ secret: true,
164
+ },
165
+ CODEBASE_ROOT: {
166
+ description: 'Root directory of codebase to index',
167
+ required: false,
168
+ default: '.',
169
+ },
170
+ INDEX_PATH: {
171
+ description: 'Path to store index files',
172
+ required: false,
173
+ default: '.coderag',
174
+ },
175
+ },
176
+ category: 'core',
177
+ defaultInInit: true,
178
+ },
222
179
  };
223
180
 
224
181
  /**
@@ -46,39 +46,6 @@ export interface IStorage<T = unknown> {
46
46
  healthCheck(): Promise<{ healthy: boolean; error?: string }>;
47
47
  }
48
48
 
49
- // Search service interface
50
- export interface ISearchService {
51
- initialize(): Promise<void>;
52
- searchCodebase(query: string, options?: SearchOptions): Promise<SearchResult[]>;
53
- searchKnowledge(query: string, options?: SearchOptions): Promise<SearchResult[]>;
54
- getStatus(): Promise<SearchServiceStatus>;
55
- }
56
-
57
- // Search options
58
- export interface SearchOptions {
59
- limit?: number;
60
- offset?: number;
61
- filters?: Record<string, unknown>;
62
- sortBy?: string;
63
- sortOrder?: 'asc' | 'desc';
64
- }
65
-
66
- // Search result
67
- export interface SearchResult {
68
- id: string;
69
- content: string;
70
- score: number;
71
- metadata: Record<string, unknown>;
72
- }
73
-
74
- // Search service status
75
- export interface SearchServiceStatus {
76
- indexed: number;
77
- total: number;
78
- lastIndexed: string;
79
- healthy: boolean;
80
- }
81
-
82
49
  // Target manager interface
83
50
  export interface ITargetManager {
84
51
  getTarget(id: string): Target | null;
@@ -3,6 +3,4 @@
3
3
  * Unified exports for all domain modules
4
4
  */
5
5
 
6
- export * from './codebase/index.js';
7
- export * from './knowledge/index.js';
8
6
  export * from './utilities/index.js';
package/src/index.ts CHANGED
@@ -8,9 +8,7 @@ import { readFileSync } from 'node:fs';
8
8
  import { dirname, join } from 'node:path';
9
9
  import { fileURLToPath } from 'node:url';
10
10
  import { Command } from 'commander';
11
- import { codebaseCommand } from './commands/codebase-command.js';
12
11
  import { hookCommand } from './commands/hook-command.js';
13
- import { knowledgeCommand } from './commands/knowledge-command.js';
14
12
  import {
15
13
  flowCommand,
16
14
  statusCommand,
@@ -95,8 +93,6 @@ export function createCLI(): Command {
95
93
  program.addCommand(statusCommand);
96
94
  program.addCommand(doctorCommand);
97
95
  program.addCommand(upgradeCommand);
98
- program.addCommand(codebaseCommand);
99
- program.addCommand(knowledgeCommand);
100
96
  program.addCommand(hookCommand);
101
97
 
102
98
  return program;
@@ -293,22 +293,6 @@ export const createMCPService = (deps: MCPServiceDeps): MCPService => {
293
293
  ? await resolveConfig(server.config.command)
294
294
  : undefined;
295
295
  resolvedArgs = server.config.args ? await resolveConfig(server.config.args) : [];
296
-
297
- // Apply target-specific flags for sylphx-flow server
298
- if (serverId === 'sylphx-flow' && Array.isArray(resolvedArgs)) {
299
- const targetConfig = deps.target.mcpServerConfig;
300
- if (targetConfig) {
301
- if (targetConfig.disableTime) {
302
- resolvedArgs.push('--disable-time');
303
- }
304
- if (targetConfig.disableKnowledge) {
305
- resolvedArgs.push('--disable-knowledge');
306
- }
307
- if (targetConfig.disableCodebase) {
308
- resolvedArgs.push('--disable-codebase');
309
- }
310
- }
311
- }
312
296
  }
313
297
 
314
298
  // Update the config with resolved values (only for CLI servers)
@@ -22,12 +22,6 @@ export const claudeCodeTarget: Target = {
22
22
  isImplemented: true,
23
23
  isDefault: false,
24
24
 
25
- mcpServerConfig: {
26
- disableTime: true,
27
- disableKnowledge: false,
28
- disableCodebase: true,
29
- },
30
-
31
25
  config: {
32
26
  agentDir: '.claude/agents',
33
27
  agentExtension: '.md',
@@ -424,10 +418,10 @@ Please begin your response with a comprehensive summary of all the instructions
424
418
  throw new Error(`Failed to write settings: ${writeResult.error.message}`);
425
419
  }
426
420
 
427
- // Return 3 hooks configured (SessionStart + UserPromptSubmit + Notification)
421
+ // Return 1 hook configured (Notification only)
428
422
  return {
429
- count: 3,
430
- message: 'Configured session, message, and notification hooks',
423
+ count: 1,
424
+ message: 'Configured notification hook',
431
425
  };
432
426
  },
433
427
 
@@ -31,7 +31,6 @@ export interface ClaudeCodeSettings {
31
31
  }
32
32
 
33
33
  export interface HookConfig {
34
- sessionCommand?: string;
35
34
  notificationCommand?: string;
36
35
  }
37
36
 
@@ -41,17 +40,15 @@ export interface HookConfig {
41
40
  */
42
41
  export const generateHookCommands = async (targetId: string): Promise<HookConfig> => {
43
42
  return {
44
- sessionCommand: `sylphx-flow hook --type session --target ${targetId}`,
45
43
  notificationCommand: `sylphx-flow hook --type notification --target ${targetId}`,
46
44
  };
47
45
  };
48
46
 
49
47
  /**
50
48
  * Default hook commands (fallback)
51
- * Simplified to only include session and notification hooks
49
+ * Simplified to only include notification hook
52
50
  */
53
51
  export const DEFAULT_HOOKS: HookConfig = {
54
- sessionCommand: 'sylphx-flow hook --type session --target claude-code',
55
52
  notificationCommand: 'sylphx-flow hook --type notification --target claude-code',
56
53
  };
57
54
 
@@ -74,20 +71,9 @@ export const parseSettings = (content: string): Result<ClaudeCodeSettings, Confi
74
71
  export const buildHookConfiguration = (
75
72
  config: HookConfig = DEFAULT_HOOKS
76
73
  ): ClaudeCodeSettings['hooks'] => {
77
- const sessionCommand = config.sessionCommand || DEFAULT_HOOKS.sessionCommand!;
78
74
  const notificationCommand = config.notificationCommand || DEFAULT_HOOKS.notificationCommand!;
79
75
 
80
76
  return {
81
- SessionStart: [
82
- {
83
- hooks: [
84
- {
85
- type: 'command',
86
- command: sessionCommand,
87
- },
88
- ],
89
- },
90
- ],
91
77
  Notification: [
92
78
  {
93
79
  matcher: '',
@@ -140,7 +126,7 @@ export const serializeSettings = (settings: ClaudeCodeSettings): string => {
140
126
  * Get success message (pure)
141
127
  */
142
128
  export const getSuccessMessage = (): string => {
143
- return 'Claude Code hooks configured: SessionStart (static info) + UserPromptSubmit (dynamic info)';
129
+ return 'Claude Code hook configured: Notification';
144
130
  };
145
131
 
146
132
  /**
@@ -173,12 +159,8 @@ export const processSettings = (
173
159
  * Validate hook configuration (pure)
174
160
  */
175
161
  export const validateHookConfig = (config: HookConfig): Result<HookConfig, ConfigError> => {
176
- if (config.sessionCommand !== undefined && config.sessionCommand.trim() === '') {
177
- return failure(configError('Session command cannot be empty'));
178
- }
179
-
180
- if (config.messageCommand !== undefined && config.messageCommand.trim() === '') {
181
- return failure(configError('Message command cannot be empty'));
162
+ if (config.notificationCommand !== undefined && config.notificationCommand.trim() === '') {
163
+ return failure(configError('Notification command cannot be empty'));
182
164
  }
183
165
 
184
166
  return success(config);
@@ -23,12 +23,6 @@ export const opencodeTarget: Target = {
23
23
  isImplemented: true,
24
24
  isDefault: true,
25
25
 
26
- mcpServerConfig: {
27
- disableTime: false,
28
- disableKnowledge: false,
29
- disableCodebase: false,
30
- },
31
-
32
26
  config: {
33
27
  agentDir: '.opencode/agent',
34
28
  agentExtension: '.md',