@sylphx/flow 1.0.1 → 1.0.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.
- package/CHANGELOG.md +12 -0
- package/package.json +10 -9
- package/src/commands/codebase-command.ts +168 -0
- package/src/commands/flow-command.ts +1137 -0
- package/src/commands/flow-orchestrator.ts +296 -0
- package/src/commands/hook-command.ts +444 -0
- package/src/commands/init-command.ts +92 -0
- package/src/commands/init-core.ts +322 -0
- package/src/commands/knowledge-command.ts +161 -0
- package/src/commands/run-command.ts +120 -0
- package/src/components/benchmark-monitor.tsx +331 -0
- package/src/components/reindex-progress.tsx +261 -0
- package/src/composables/functional/index.ts +14 -0
- package/src/composables/functional/useEnvironment.ts +171 -0
- package/src/composables/functional/useFileSystem.ts +139 -0
- package/src/composables/index.ts +5 -0
- package/src/composables/useEnv.ts +13 -0
- package/src/composables/useRuntimeConfig.ts +27 -0
- package/src/composables/useTargetConfig.ts +45 -0
- package/src/config/ai-config.ts +376 -0
- package/src/config/constants.ts +35 -0
- package/src/config/index.ts +27 -0
- package/src/config/rules.ts +43 -0
- package/src/config/servers.ts +371 -0
- package/src/config/targets.ts +126 -0
- package/src/core/agent-loader.ts +141 -0
- package/src/core/agent-manager.ts +174 -0
- package/src/core/ai-sdk.ts +603 -0
- package/src/core/app-factory.ts +381 -0
- package/src/core/builtin-agents.ts +9 -0
- package/src/core/command-system.ts +550 -0
- package/src/core/config-system.ts +550 -0
- package/src/core/connection-pool.ts +390 -0
- package/src/core/di-container.ts +155 -0
- package/src/core/error-handling.ts +519 -0
- package/src/core/formatting/bytes.test.ts +115 -0
- package/src/core/formatting/bytes.ts +64 -0
- package/src/core/functional/async.ts +313 -0
- package/src/core/functional/either.ts +109 -0
- package/src/core/functional/error-handler.ts +135 -0
- package/src/core/functional/error-types.ts +311 -0
- package/src/core/functional/index.ts +19 -0
- package/src/core/functional/option.ts +142 -0
- package/src/core/functional/pipe.ts +189 -0
- package/src/core/functional/result.ts +204 -0
- package/src/core/functional/validation.ts +138 -0
- package/src/core/headless-display.ts +96 -0
- package/src/core/index.ts +6 -0
- package/src/core/installers/file-installer.ts +303 -0
- package/src/core/installers/mcp-installer.ts +213 -0
- package/src/core/interfaces/index.ts +22 -0
- package/src/core/interfaces/repository.interface.ts +91 -0
- package/src/core/interfaces/service.interface.ts +133 -0
- package/src/core/interfaces.ts +129 -0
- package/src/core/loop-controller.ts +200 -0
- package/src/core/result.ts +351 -0
- package/src/core/rule-loader.ts +147 -0
- package/src/core/rule-manager.ts +240 -0
- package/src/core/service-config.ts +252 -0
- package/src/core/session-service.ts +121 -0
- package/src/core/state-detector.ts +389 -0
- package/src/core/storage-factory.ts +115 -0
- package/src/core/stream-handler.ts +288 -0
- package/src/core/target-manager.ts +161 -0
- package/src/core/type-utils.ts +427 -0
- package/src/core/unified-storage.ts +456 -0
- package/src/core/upgrade-manager.ts +300 -0
- package/src/core/validation/limit.test.ts +155 -0
- package/src/core/validation/limit.ts +46 -0
- package/src/core/validation/query.test.ts +44 -0
- package/src/core/validation/query.ts +20 -0
- package/src/db/auto-migrate.ts +322 -0
- package/src/db/base-database-client.ts +144 -0
- package/src/db/cache-db.ts +218 -0
- package/src/db/cache-schema.ts +75 -0
- package/src/db/database.ts +70 -0
- package/src/db/index.ts +252 -0
- package/src/db/memory-db.ts +153 -0
- package/src/db/memory-schema.ts +29 -0
- package/src/db/schema.ts +289 -0
- package/src/db/session-repository.ts +733 -0
- package/src/domains/codebase/index.ts +5 -0
- package/src/domains/codebase/tools.ts +139 -0
- package/src/domains/index.ts +8 -0
- package/src/domains/knowledge/index.ts +10 -0
- package/src/domains/knowledge/resources.ts +537 -0
- package/src/domains/knowledge/tools.ts +174 -0
- package/src/domains/utilities/index.ts +6 -0
- package/src/domains/utilities/time/index.ts +5 -0
- package/src/domains/utilities/time/tools.ts +291 -0
- package/src/index.ts +211 -0
- package/src/services/agent-service.ts +273 -0
- package/src/services/claude-config-service.ts +252 -0
- package/src/services/config-service.ts +258 -0
- package/src/services/evaluation-service.ts +271 -0
- package/src/services/functional/evaluation-logic.ts +296 -0
- package/src/services/functional/file-processor.ts +273 -0
- package/src/services/functional/index.ts +12 -0
- package/src/services/index.ts +13 -0
- package/src/services/mcp-service.ts +432 -0
- package/src/services/memory.service.ts +476 -0
- package/src/services/search/base-indexer.ts +156 -0
- package/src/services/search/codebase-indexer-types.ts +38 -0
- package/src/services/search/codebase-indexer.ts +647 -0
- package/src/services/search/embeddings-provider.ts +455 -0
- package/src/services/search/embeddings.ts +316 -0
- package/src/services/search/functional-indexer.ts +323 -0
- package/src/services/search/index.ts +27 -0
- package/src/services/search/indexer.ts +380 -0
- package/src/services/search/knowledge-indexer.ts +422 -0
- package/src/services/search/semantic-search.ts +244 -0
- package/src/services/search/tfidf.ts +559 -0
- package/src/services/search/unified-search-service.ts +888 -0
- package/src/services/smart-config-service.ts +385 -0
- package/src/services/storage/cache-storage.ts +487 -0
- package/src/services/storage/drizzle-storage.ts +581 -0
- package/src/services/storage/index.ts +15 -0
- package/src/services/storage/lancedb-vector-storage.ts +494 -0
- package/src/services/storage/memory-storage.ts +268 -0
- package/src/services/storage/separated-storage.ts +467 -0
- package/src/services/storage/vector-storage.ts +13 -0
- package/src/shared/agents/index.ts +63 -0
- package/src/shared/files/index.ts +99 -0
- package/src/shared/index.ts +32 -0
- package/src/shared/logging/index.ts +24 -0
- package/src/shared/processing/index.ts +153 -0
- package/src/shared/types/index.ts +25 -0
- package/src/targets/claude-code.ts +574 -0
- package/src/targets/functional/claude-code-logic.ts +185 -0
- package/src/targets/functional/index.ts +6 -0
- package/src/targets/opencode.ts +529 -0
- package/src/types/agent.types.ts +32 -0
- package/src/types/api/batch.ts +108 -0
- package/src/types/api/errors.ts +118 -0
- package/src/types/api/index.ts +55 -0
- package/src/types/api/requests.ts +76 -0
- package/src/types/api/responses.ts +180 -0
- package/src/types/api/websockets.ts +85 -0
- package/src/types/api.types.ts +9 -0
- package/src/types/benchmark.ts +49 -0
- package/src/types/cli.types.ts +87 -0
- package/src/types/common.types.ts +35 -0
- package/src/types/database.types.ts +510 -0
- package/src/types/mcp-config.types.ts +448 -0
- package/src/types/mcp.types.ts +69 -0
- package/src/types/memory-types.ts +63 -0
- package/src/types/provider.types.ts +28 -0
- package/src/types/rule.types.ts +24 -0
- package/src/types/session.types.ts +214 -0
- package/src/types/target-config.types.ts +295 -0
- package/src/types/target.types.ts +140 -0
- package/src/types/todo.types.ts +25 -0
- package/src/types.ts +40 -0
- package/src/utils/advanced-tokenizer.ts +191 -0
- package/src/utils/agent-enhancer.ts +114 -0
- package/src/utils/ai-model-fetcher.ts +19 -0
- package/src/utils/async-file-operations.ts +516 -0
- package/src/utils/audio-player.ts +345 -0
- package/src/utils/cli-output.ts +266 -0
- package/src/utils/codebase-helpers.ts +211 -0
- package/src/utils/console-ui.ts +79 -0
- package/src/utils/database-errors.ts +140 -0
- package/src/utils/debug-logger.ts +49 -0
- package/src/utils/error-handler.ts +53 -0
- package/src/utils/file-operations.ts +310 -0
- package/src/utils/file-scanner.ts +259 -0
- package/src/utils/functional/array.ts +355 -0
- package/src/utils/functional/index.ts +15 -0
- package/src/utils/functional/object.ts +279 -0
- package/src/utils/functional/string.ts +281 -0
- package/src/utils/functional.ts +543 -0
- package/src/utils/help.ts +20 -0
- package/src/utils/immutable-cache.ts +106 -0
- package/src/utils/index.ts +78 -0
- package/src/utils/jsonc.ts +158 -0
- package/src/utils/logger.ts +396 -0
- package/src/utils/mcp-config.ts +249 -0
- package/src/utils/memory-tui.ts +414 -0
- package/src/utils/models-dev.ts +91 -0
- package/src/utils/notifications.ts +169 -0
- package/src/utils/object-utils.ts +51 -0
- package/src/utils/parallel-operations.ts +487 -0
- package/src/utils/paths.ts +143 -0
- package/src/utils/process-manager.ts +155 -0
- package/src/utils/prompts.ts +120 -0
- package/src/utils/search-tool-builder.ts +214 -0
- package/src/utils/secret-utils.ts +179 -0
- package/src/utils/security.ts +537 -0
- package/src/utils/session-manager.ts +168 -0
- package/src/utils/session-title.ts +87 -0
- package/src/utils/settings.ts +182 -0
- package/src/utils/simplified-errors.ts +410 -0
- package/src/utils/sync-utils.ts +159 -0
- package/src/utils/target-config.ts +570 -0
- package/src/utils/target-utils.ts +394 -0
- package/src/utils/template-engine.ts +94 -0
- package/src/utils/test-audio.ts +71 -0
- package/src/utils/todo-context.ts +46 -0
- package/src/utils/token-counter.ts +288 -0
- package/dist/index.d.ts +0 -10
- package/dist/index.js +0 -59554
- package/dist/lancedb.linux-x64-gnu-b7f0jgsz.node +0 -0
- package/dist/lancedb.linux-x64-musl-tgcv22rx.node +0 -0
- package/dist/shared/chunk-25dwp0dp.js +0 -89
- package/dist/shared/chunk-3pjb6063.js +0 -208
- package/dist/shared/chunk-4d6ydpw7.js +0 -2854
- package/dist/shared/chunk-4wjcadjk.js +0 -225
- package/dist/shared/chunk-5j4w74t6.js +0 -30
- package/dist/shared/chunk-5j8m3dh3.js +0 -58
- package/dist/shared/chunk-5thh3qem.js +0 -91
- package/dist/shared/chunk-6g9xy73m.js +0 -252
- package/dist/shared/chunk-7eq34c42.js +0 -23
- package/dist/shared/chunk-c2gwgx3r.js +0 -115
- package/dist/shared/chunk-cjd3mk4c.js +0 -1320
- package/dist/shared/chunk-g5cv6703.js +0 -368
- package/dist/shared/chunk-hpkhykhq.js +0 -574
- package/dist/shared/chunk-m2322pdk.js +0 -122
- package/dist/shared/chunk-nd5fdvaq.js +0 -26
- package/dist/shared/chunk-pgd3m6zf.js +0 -108
- package/dist/shared/chunk-qk8n91hw.js +0 -494
- package/dist/shared/chunk-rkkn8szp.js +0 -16855
- package/dist/shared/chunk-t16rfxh0.js +0 -61
- package/dist/shared/chunk-t4fbfa5v.js +0 -19
- package/dist/shared/chunk-t77h86w6.js +0 -276
- package/dist/shared/chunk-v0ez4aef.js +0 -71
- package/dist/shared/chunk-v29j2r3s.js +0 -32051
- package/dist/shared/chunk-vfbc6ew5.js +0 -765
- package/dist/shared/chunk-vmeqwm1c.js +0 -204
- package/dist/shared/chunk-x66eh37x.js +0 -137
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core initialization logic - extracted for reuse without UI coupling
|
|
3
|
+
* Used by both flow command (integrated) and legacy init command (standalone)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import ora from 'ora';
|
|
8
|
+
import { targetManager } from '../core/target-manager.js';
|
|
9
|
+
import { CLIError } from '../utils/error-handler.js';
|
|
10
|
+
import { projectSettings } from '../utils/settings.js';
|
|
11
|
+
import { validateTarget } from '../utils/target-config.js';
|
|
12
|
+
import { ConfigService } from '../services/config-service.js';
|
|
13
|
+
|
|
14
|
+
export interface InitOptions {
|
|
15
|
+
target?: string;
|
|
16
|
+
verbose?: boolean;
|
|
17
|
+
dryRun?: boolean;
|
|
18
|
+
clear?: boolean;
|
|
19
|
+
mcp?: boolean;
|
|
20
|
+
agents?: boolean;
|
|
21
|
+
rules?: boolean;
|
|
22
|
+
outputStyles?: boolean;
|
|
23
|
+
slashCommands?: boolean;
|
|
24
|
+
hooks?: boolean;
|
|
25
|
+
quiet?: boolean; // Suppress all output for programmatic use
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ComponentInstallResult {
|
|
29
|
+
targetId: string;
|
|
30
|
+
targetName: string;
|
|
31
|
+
installed: {
|
|
32
|
+
mcp?: number;
|
|
33
|
+
agents?: number;
|
|
34
|
+
outputStyles?: number;
|
|
35
|
+
rules?: number;
|
|
36
|
+
slashCommands?: number;
|
|
37
|
+
hooks?: number;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Select and validate target - PURE LOGIC, no UI
|
|
43
|
+
* @returns targetId
|
|
44
|
+
*/
|
|
45
|
+
export async function selectAndValidateTarget(options: InitOptions): Promise<string> {
|
|
46
|
+
let targetId = options.target;
|
|
47
|
+
|
|
48
|
+
// Target selection (with UI prompt if needed)
|
|
49
|
+
if (!targetId) {
|
|
50
|
+
targetId = await targetManager.promptForTargetSelection();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Validate target
|
|
54
|
+
if (targetId) {
|
|
55
|
+
try {
|
|
56
|
+
validateTarget(targetId);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
if (error instanceof Error) {
|
|
59
|
+
throw new CLIError(error.message, 'UNSUPPORTED_TARGET');
|
|
60
|
+
}
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!targetId) {
|
|
66
|
+
throw new Error('Target ID not set');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return targetId;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Preview what will be installed in dry run mode
|
|
74
|
+
*/
|
|
75
|
+
export async function previewDryRun(targetId: string, options: InitOptions): Promise<void> {
|
|
76
|
+
const targetOption = targetManager.getTarget(targetId);
|
|
77
|
+
if (targetOption._tag === 'None') {
|
|
78
|
+
throw new Error(`Target not found: ${targetId}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const target = targetOption.value;
|
|
82
|
+
|
|
83
|
+
if (options.mcp !== false && target.setupMCP) {
|
|
84
|
+
console.log(chalk.cyan.bold('MCP Tools:'));
|
|
85
|
+
console.log(chalk.dim(' ✓ MCP servers will be configured'));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (options.agents !== false && target.setupAgents) {
|
|
89
|
+
console.log(chalk.cyan.bold('\nAgents:'));
|
|
90
|
+
console.log(chalk.dim(' ✓ Development agents will be installed'));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (options.outputStyles !== false && target.setupOutputStyles) {
|
|
94
|
+
console.log(chalk.cyan.bold('\nOutput Styles:'));
|
|
95
|
+
console.log(chalk.dim(' ✓ Output styles will be installed'));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (options.rules !== false && target.setupRules) {
|
|
99
|
+
console.log(chalk.cyan.bold('\nRules:'));
|
|
100
|
+
console.log(chalk.dim(' ✓ Custom rules will be installed'));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (options.slashCommands !== false && target.setupSlashCommands) {
|
|
104
|
+
console.log(chalk.cyan.bold('\nSlash Commands:'));
|
|
105
|
+
console.log(chalk.dim(' ✓ Slash commands will be installed'));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (options.hooks !== false && target.setupHooks) {
|
|
109
|
+
console.log(chalk.cyan.bold('\nHooks:'));
|
|
110
|
+
console.log(chalk.dim(' ✓ Hooks will be configured'));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Install all components - CORE LOGIC with minimal UI
|
|
116
|
+
*/
|
|
117
|
+
export async function installComponents(
|
|
118
|
+
targetId: string,
|
|
119
|
+
options: InitOptions
|
|
120
|
+
): Promise<ComponentInstallResult> {
|
|
121
|
+
const targetOption = targetManager.getTarget(targetId);
|
|
122
|
+
if (targetOption._tag === 'None') {
|
|
123
|
+
throw new Error(`Target not found: ${targetId}`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const target = targetOption.value;
|
|
127
|
+
const quiet = options.quiet || false;
|
|
128
|
+
const result: ComponentInstallResult = {
|
|
129
|
+
targetId,
|
|
130
|
+
targetName: target.name,
|
|
131
|
+
installed: {},
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Setup MCP servers if target supports it and MCP is enabled
|
|
135
|
+
// Note: No spinner here because MCP setup is interactive (user prompts)
|
|
136
|
+
if (target.setupMCP && options.mcp !== false) {
|
|
137
|
+
try {
|
|
138
|
+
const mcpResult = await target.setupMCP(process.cwd(), options);
|
|
139
|
+
result.installed.mcp = mcpResult.count;
|
|
140
|
+
|
|
141
|
+
if (!quiet) {
|
|
142
|
+
if (mcpResult.count > 0) {
|
|
143
|
+
console.log(
|
|
144
|
+
chalk.green(
|
|
145
|
+
`✔ Installed ${chalk.cyan(mcpResult.count)} MCP server${mcpResult.count !== 1 ? 's' : ''}`
|
|
146
|
+
)
|
|
147
|
+
);
|
|
148
|
+
} else {
|
|
149
|
+
console.log(chalk.dim('ℹ No MCP servers selected'));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
} catch (error) {
|
|
153
|
+
// If user cancels MCP setup (Ctrl+C), continue with other components
|
|
154
|
+
if (error instanceof Error && error.name === 'ExitPromptError') {
|
|
155
|
+
if (!quiet) {
|
|
156
|
+
console.log(chalk.yellow('\n⚠️ MCP setup cancelled, continuing with other components\n'));
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
if (!quiet) {
|
|
160
|
+
console.error(chalk.red('✖ Failed to setup MCP servers'));
|
|
161
|
+
}
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Install agents if target supports it and agents are not skipped
|
|
168
|
+
if (target.setupAgents && options.agents !== false) {
|
|
169
|
+
const agentSpinner = quiet ? null : ora({ text: 'Installing agents', color: 'cyan' }).start();
|
|
170
|
+
try {
|
|
171
|
+
const agentResult = await target.setupAgents(process.cwd(), { ...options, quiet: true });
|
|
172
|
+
result.installed.agents = agentResult.count;
|
|
173
|
+
|
|
174
|
+
if (agentSpinner) {
|
|
175
|
+
agentSpinner.succeed(
|
|
176
|
+
chalk.green(`Installed ${chalk.cyan(agentResult.count)} agent${agentResult.count !== 1 ? 's' : ''}`)
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
} catch (error) {
|
|
180
|
+
if (agentSpinner) {
|
|
181
|
+
agentSpinner.fail(chalk.red('Failed to install agents'));
|
|
182
|
+
}
|
|
183
|
+
throw error;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Install output styles if target supports it and output styles are not skipped
|
|
188
|
+
if (target.setupOutputStyles && options.outputStyles !== false) {
|
|
189
|
+
const stylesSpinner = quiet ? null : ora({ text: 'Installing output styles', color: 'cyan' }).start();
|
|
190
|
+
try {
|
|
191
|
+
const stylesResult = await target.setupOutputStyles(process.cwd(), { ...options, quiet: true });
|
|
192
|
+
result.installed.outputStyles = stylesResult.count;
|
|
193
|
+
|
|
194
|
+
if (stylesSpinner) {
|
|
195
|
+
if (stylesResult.count > 0) {
|
|
196
|
+
stylesSpinner.succeed(
|
|
197
|
+
chalk.green(
|
|
198
|
+
`Installed ${chalk.cyan(stylesResult.count)} output style${stylesResult.count !== 1 ? 's' : ''}`
|
|
199
|
+
)
|
|
200
|
+
);
|
|
201
|
+
} else if (stylesResult.message) {
|
|
202
|
+
stylesSpinner.info(chalk.dim(stylesResult.message));
|
|
203
|
+
} else {
|
|
204
|
+
stylesSpinner.info(chalk.dim('No output styles to install'));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
} catch (error) {
|
|
208
|
+
if (stylesSpinner) {
|
|
209
|
+
stylesSpinner.fail(chalk.red('Failed to install output styles'));
|
|
210
|
+
}
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Install rules if target supports it and rules are not skipped
|
|
216
|
+
if (target.setupRules && options.rules !== false) {
|
|
217
|
+
const rulesSpinner = quiet ? null : ora({ text: 'Installing rules', color: 'cyan' }).start();
|
|
218
|
+
try {
|
|
219
|
+
const rulesResult = await target.setupRules(process.cwd(), { ...options, quiet: true });
|
|
220
|
+
result.installed.rules = rulesResult.count;
|
|
221
|
+
|
|
222
|
+
if (rulesSpinner) {
|
|
223
|
+
if (rulesResult.count > 0) {
|
|
224
|
+
rulesSpinner.succeed(
|
|
225
|
+
chalk.green(
|
|
226
|
+
`Installed ${chalk.cyan(rulesResult.count)} rule${rulesResult.count !== 1 ? 's' : ''}`
|
|
227
|
+
)
|
|
228
|
+
);
|
|
229
|
+
} else if (rulesResult.message) {
|
|
230
|
+
rulesSpinner.info(chalk.dim(rulesResult.message));
|
|
231
|
+
} else {
|
|
232
|
+
rulesSpinner.info(chalk.dim('No rules to install'));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
} catch (error) {
|
|
236
|
+
if (rulesSpinner) {
|
|
237
|
+
rulesSpinner.fail(chalk.red('Failed to install rules'));
|
|
238
|
+
}
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Install slash commands if target supports it and slash commands are not skipped
|
|
244
|
+
if (target.setupSlashCommands && options.slashCommands !== false) {
|
|
245
|
+
const commandsSpinner = quiet ? null : ora({
|
|
246
|
+
text: 'Installing slash commands',
|
|
247
|
+
color: 'cyan',
|
|
248
|
+
}).start();
|
|
249
|
+
try {
|
|
250
|
+
const commandsResult = await target.setupSlashCommands(process.cwd(), { ...options, quiet: true });
|
|
251
|
+
result.installed.slashCommands = commandsResult.count;
|
|
252
|
+
|
|
253
|
+
if (commandsSpinner) {
|
|
254
|
+
if (commandsResult.count > 0) {
|
|
255
|
+
commandsSpinner.succeed(
|
|
256
|
+
chalk.green(
|
|
257
|
+
`Installed ${chalk.cyan(commandsResult.count)} slash command${commandsResult.count !== 1 ? 's' : ''}`
|
|
258
|
+
)
|
|
259
|
+
);
|
|
260
|
+
} else if (commandsResult.message) {
|
|
261
|
+
commandsSpinner.info(chalk.dim(commandsResult.message));
|
|
262
|
+
} else {
|
|
263
|
+
commandsSpinner.info(chalk.dim('No slash commands to install'));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
} catch (error) {
|
|
267
|
+
if (commandsSpinner) {
|
|
268
|
+
commandsSpinner.fail(chalk.red('Failed to install slash commands'));
|
|
269
|
+
}
|
|
270
|
+
throw error;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Setup hooks if target supports it and hooks are not skipped
|
|
275
|
+
if (target.setupHooks && options.hooks !== false) {
|
|
276
|
+
const hooksSpinner = quiet ? null : ora({ text: 'Setting up hooks', color: 'cyan' }).start();
|
|
277
|
+
try {
|
|
278
|
+
const hooksResult = await target.setupHooks(process.cwd(), { ...options, quiet: true });
|
|
279
|
+
result.installed.hooks = hooksResult.count;
|
|
280
|
+
|
|
281
|
+
if (hooksSpinner) {
|
|
282
|
+
if (hooksResult.count > 0) {
|
|
283
|
+
const message = hooksResult.message
|
|
284
|
+
? `Configured ${chalk.cyan(hooksResult.count)} hook${hooksResult.count !== 1 ? 's' : ''} - ${hooksResult.message}`
|
|
285
|
+
: `Configured ${chalk.cyan(hooksResult.count)} hook${hooksResult.count !== 1 ? 's' : ''}`;
|
|
286
|
+
hooksSpinner.succeed(chalk.green(message));
|
|
287
|
+
} else {
|
|
288
|
+
hooksSpinner.info(chalk.dim(hooksResult.message || 'No hooks to configure'));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
} catch (error) {
|
|
292
|
+
// Don't fail entire setup if hooks fail
|
|
293
|
+
if (hooksSpinner) {
|
|
294
|
+
hooksSpinner.warn(chalk.yellow('Could not setup hooks'));
|
|
295
|
+
console.warn(chalk.dim(` ${error instanceof Error ? error.message : String(error)}`));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Save the selected target as project default
|
|
301
|
+
try {
|
|
302
|
+
await projectSettings.setDefaultTarget(targetId);
|
|
303
|
+
|
|
304
|
+
// Save to new ConfigService for proper layered configuration
|
|
305
|
+
await ConfigService.saveProjectSettings({
|
|
306
|
+
target: targetId,
|
|
307
|
+
version: '1.0.0',
|
|
308
|
+
lastUpdated: new Date().toISOString(),
|
|
309
|
+
});
|
|
310
|
+
} catch (error) {
|
|
311
|
+
// Don't fail the entire setup if we can't save settings
|
|
312
|
+
if (!quiet) {
|
|
313
|
+
console.warn(
|
|
314
|
+
chalk.yellow(
|
|
315
|
+
`⚠ Warning: Could not save default target: ${error instanceof Error ? error.message : String(error)}`
|
|
316
|
+
)
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return result;
|
|
322
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge CLI commands
|
|
3
|
+
* Knowledge base search and management functionality
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
import { getKnowledgeContent } from '../domains/knowledge/resources.js';
|
|
8
|
+
import { getSearchService } from '../services/search/unified-search-service.js';
|
|
9
|
+
import { CLIError } from '../utils/error-handler.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Knowledge search command
|
|
13
|
+
*/
|
|
14
|
+
export const knowledgeSearchCommand = new Command('search')
|
|
15
|
+
.description('Search knowledge base, documentation, and guides')
|
|
16
|
+
.argument('<query>', 'Search query - use natural language, technology names, or topic keywords')
|
|
17
|
+
.option('-l, --limit <number>', 'Maximum number of results to return', '10')
|
|
18
|
+
.option('--include-content', 'Include full content in results', true)
|
|
19
|
+
.action(async (query, options) => {
|
|
20
|
+
try {
|
|
21
|
+
console.log(`📚 Searching knowledge base for: "${query}"`);
|
|
22
|
+
|
|
23
|
+
const searchService = getSearchService();
|
|
24
|
+
await searchService.initialize();
|
|
25
|
+
|
|
26
|
+
const result = await searchService.searchKnowledge(query, {
|
|
27
|
+
limit: Number.parseInt(options.limit, 10) || 10,
|
|
28
|
+
include_content: options.includeContent !== false,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const output = searchService.formatResultsForCLI(result.results, query, result.totalIndexed);
|
|
32
|
+
console.log(output);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw new CLIError(`Knowledge search failed: ${(error as Error).message}`);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Knowledge get command
|
|
40
|
+
*/
|
|
41
|
+
export const knowledgeGetCommand = new Command('get')
|
|
42
|
+
.description('Get specific knowledge document by URI')
|
|
43
|
+
.argument('<uri>', 'Knowledge URI to access (e.g., "knowledge://stacks/react-app")')
|
|
44
|
+
.action(async (uri) => {
|
|
45
|
+
try {
|
|
46
|
+
const content = await getKnowledgeContent(uri);
|
|
47
|
+
console.log(content);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
const errorMessage = `Knowledge get failed: ${(error as Error).message}`;
|
|
50
|
+
|
|
51
|
+
// Show available URIs
|
|
52
|
+
const searchService = getSearchService();
|
|
53
|
+
const availableURIs = await searchService.getAvailableKnowledgeURIs();
|
|
54
|
+
if (availableURIs.length > 0) {
|
|
55
|
+
console.log('\n**Available knowledge URIs:**');
|
|
56
|
+
for (const uri of availableURIs) {
|
|
57
|
+
console.log(`• ${uri}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
throw new CLIError(errorMessage);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Knowledge list command
|
|
66
|
+
*/
|
|
67
|
+
export const knowledgeListCommand = new Command('list')
|
|
68
|
+
.description('List all available knowledge resources')
|
|
69
|
+
.option('--category <type>', 'Filter by category (stacks, guides, universal, data)')
|
|
70
|
+
.action(async (options) => {
|
|
71
|
+
try {
|
|
72
|
+
const searchService = getSearchService();
|
|
73
|
+
await searchService.initialize();
|
|
74
|
+
const availableURIs = await searchService.getAvailableKnowledgeURIs();
|
|
75
|
+
|
|
76
|
+
if (availableURIs.length === 0) {
|
|
77
|
+
console.log('📭 No knowledge documents available');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let filteredURIs = availableURIs;
|
|
82
|
+
if (options.category) {
|
|
83
|
+
filteredURIs = availableURIs.filter((uri) => uri.includes(`/${options.category}/`));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log(`📚 Available Knowledge Resources (${filteredURIs.length} documents):\n`);
|
|
87
|
+
|
|
88
|
+
// Group by category
|
|
89
|
+
const grouped = filteredURIs.reduce(
|
|
90
|
+
(acc, uri) => {
|
|
91
|
+
const category = uri.split('/')[2] || 'unknown';
|
|
92
|
+
if (!acc[category]) {
|
|
93
|
+
acc[category] = [];
|
|
94
|
+
}
|
|
95
|
+
acc[category].push(uri);
|
|
96
|
+
return acc;
|
|
97
|
+
},
|
|
98
|
+
{} as Record<string, string[]>
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
for (const [category, uris] of Object.entries(grouped)) {
|
|
102
|
+
console.log(`### ${category.charAt(0).toUpperCase() + category.slice(1)}`);
|
|
103
|
+
for (const uri of uris) {
|
|
104
|
+
const name = uri.split('/').pop() || 'Unknown';
|
|
105
|
+
console.log(`• ${name} - ${uri}`);
|
|
106
|
+
}
|
|
107
|
+
console.log('');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log('**Usage:**');
|
|
111
|
+
console.log('• sylphx knowledge search <query> - Search knowledge base');
|
|
112
|
+
console.log('• sylphx knowledge get <uri> - Get specific document');
|
|
113
|
+
} catch (error) {
|
|
114
|
+
throw new CLIError(`Knowledge status failed: ${(error as Error).message}`);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Knowledge status command
|
|
120
|
+
*/
|
|
121
|
+
export const knowledgeStatusCommand = new Command('status')
|
|
122
|
+
.description('Get knowledge base system status')
|
|
123
|
+
.action(async () => {
|
|
124
|
+
try {
|
|
125
|
+
console.log('\n### 📚 Knowledge Base Status\n');
|
|
126
|
+
|
|
127
|
+
const searchService = getSearchService();
|
|
128
|
+
await searchService.initialize();
|
|
129
|
+
const status = await searchService.getStatus();
|
|
130
|
+
|
|
131
|
+
if (status.knowledge.indexed) {
|
|
132
|
+
console.log('**Status:** ✓ Ready');
|
|
133
|
+
console.log(`**Documents:** ${status.knowledge.documentCount} files`);
|
|
134
|
+
} else if (status.knowledge.isIndexing) {
|
|
135
|
+
console.log(`**Status:** 🔄 Building index (${status.knowledge.progress || 0}%)`);
|
|
136
|
+
console.log('**Note:** Please wait a moment and try again');
|
|
137
|
+
} else {
|
|
138
|
+
console.log('**Status:** ⚠️ Not initialized');
|
|
139
|
+
console.log('**Note:** Will auto-index on first search');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
console.log('\n**Available Commands:**');
|
|
143
|
+
console.log('• sylphx knowledge search <query> - Search knowledge base');
|
|
144
|
+
console.log('• sylphx knowledge get <uri> - Get specific document');
|
|
145
|
+
} catch (error) {
|
|
146
|
+
throw new CLIError(`Knowledge list failed: ${(error as Error).message}`);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Main knowledge command
|
|
152
|
+
*/
|
|
153
|
+
export const knowledgeCommand = new Command('knowledge').description(
|
|
154
|
+
'Knowledge base search and management commands'
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// Add subcommands
|
|
158
|
+
knowledgeCommand.addCommand(knowledgeSearchCommand);
|
|
159
|
+
knowledgeCommand.addCommand(knowledgeGetCommand);
|
|
160
|
+
knowledgeCommand.addCommand(knowledgeListCommand);
|
|
161
|
+
knowledgeCommand.addCommand(knowledgeStatusCommand);
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { targetManager } from '../core/target-manager.js';
|
|
5
|
+
import { CLIError } from '../utils/error-handler.js';
|
|
6
|
+
import { getAgentsDir } from '../utils/paths.js';
|
|
7
|
+
|
|
8
|
+
export async function loadAgentContent(agentName: string, agentFilePath?: string): Promise<string> {
|
|
9
|
+
const { enhanceAgentContent } = await import('../utils/agent-enhancer.js');
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
// If specific file path provided, load from there
|
|
13
|
+
if (agentFilePath) {
|
|
14
|
+
const content = await fs.readFile(path.resolve(agentFilePath), 'utf-8');
|
|
15
|
+
return content;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// First try to load from .claude/agents/ directory (processed agents with rules and styles)
|
|
19
|
+
const claudeAgentPath = path.join(process.cwd(), '.claude', 'agents', `${agentName}.md`);
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const content = await fs.readFile(claudeAgentPath, 'utf-8');
|
|
23
|
+
return content;
|
|
24
|
+
} catch (_error) {
|
|
25
|
+
// Try to load from local agents/ directory (user-defined agents)
|
|
26
|
+
const localAgentPath = path.join(process.cwd(), 'agents', `${agentName}.md`);
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const content = await fs.readFile(localAgentPath, 'utf-8');
|
|
30
|
+
// Enhance user-defined agents with rules and styles
|
|
31
|
+
return await enhanceAgentContent(content);
|
|
32
|
+
} catch (_error2) {
|
|
33
|
+
// Try to load from the package's agents directory
|
|
34
|
+
const packageAgentsDir = getAgentsDir();
|
|
35
|
+
const packageAgentPath = path.join(packageAgentsDir, `${agentName}.md`);
|
|
36
|
+
|
|
37
|
+
const content = await fs.readFile(packageAgentPath, 'utf-8');
|
|
38
|
+
// Enhance package agents with rules and styles
|
|
39
|
+
return await enhanceAgentContent(content);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} catch (_error) {
|
|
43
|
+
throw new CLIError(
|
|
44
|
+
`Agent '${agentName}' not found${agentFilePath ? ` at ${agentFilePath}` : ''}`,
|
|
45
|
+
'AGENT_NOT_FOUND'
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function extractAgentInstructions(agentContent: string): string {
|
|
51
|
+
// Extract content after YAML front matter
|
|
52
|
+
const yamlFrontMatterRegex = /^---\s*\n[\s\S]*?\n---\s*\n/;
|
|
53
|
+
const match = agentContent.match(yamlFrontMatterRegex);
|
|
54
|
+
|
|
55
|
+
if (match) {
|
|
56
|
+
return agentContent.substring(match[0].length).trim();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// If no front matter, return the full content
|
|
60
|
+
return agentContent.trim();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function executeTargetCommand(
|
|
64
|
+
targetId: string,
|
|
65
|
+
systemPrompt: string,
|
|
66
|
+
userPrompt: string,
|
|
67
|
+
options: RunCommandOptions
|
|
68
|
+
): Promise<void> {
|
|
69
|
+
// Get the target object
|
|
70
|
+
const targetOption = targetManager.getTarget(targetId);
|
|
71
|
+
|
|
72
|
+
if (targetOption._tag === 'None') {
|
|
73
|
+
throw new CLIError(`Target not found: ${targetId}`, 'TARGET_NOT_FOUND');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const target = targetOption.value;
|
|
77
|
+
|
|
78
|
+
// Check if the target is implemented
|
|
79
|
+
if (!target.isImplemented) {
|
|
80
|
+
throw new CLIError(
|
|
81
|
+
`Target '${targetId}' is not implemented. Supported targets: ${getExecutableTargets().join(', ')}`,
|
|
82
|
+
'TARGET_NOT_IMPLEMENTED'
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Check if the target supports command execution
|
|
87
|
+
if (!target.executeCommand) {
|
|
88
|
+
throw new CLIError(
|
|
89
|
+
`Target '${targetId}' does not support command execution. Supported targets: ${getExecutableTargets().join(', ')}`,
|
|
90
|
+
'EXECUTION_NOT_SUPPORTED'
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Use the target's executeCommand method
|
|
95
|
+
return target.executeCommand(systemPrompt, userPrompt, options);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get list of targets that support command execution
|
|
100
|
+
*/
|
|
101
|
+
function getExecutableTargets(): string[] {
|
|
102
|
+
return targetManager.getImplementedTargetIDs().filter((targetId) => {
|
|
103
|
+
const targetOption = targetManager.getTarget(targetId);
|
|
104
|
+
if (targetOption._tag === 'None') {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
return targetOption.value.executeCommand !== undefined;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* LEGACY: run command has been integrated into the flow command.
|
|
113
|
+
* Use `flow [prompt]` instead of standalone `run` command.
|
|
114
|
+
*
|
|
115
|
+
* This file now only exports utility functions:
|
|
116
|
+
* - loadAgentContent()
|
|
117
|
+
* - extractAgentInstructions()
|
|
118
|
+
*
|
|
119
|
+
* These are used internally by the flow command.
|
|
120
|
+
*/
|