-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat(cli): Add --watch flag for automatic re-packing on file changes #1466
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 11 commits
8eb05f5
ceaa2bc
0ef59b1
97f5b41
555600d
c4f35fa
a28b883
f7e61db
7b68348
8b2365c
ce3cbfe
4048975
87a7a0f
acf2c54
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,235 @@ | ||
| import path from 'node:path'; | ||
| import process from 'node:process'; | ||
| import type { ChokidarOptions, FSWatcher } from 'chokidar'; | ||
| import pc from 'picocolors'; | ||
| import { loadFileConfig, mergeConfigs } from '../../config/configLoad.js'; | ||
| import type { RepomixConfigCli, RepomixConfigFile, RepomixConfigMerged } from '../../config/configSchema.js'; | ||
| import { defaultIgnoreList } from '../../config/defaultIgnore.js'; | ||
| import { type PackResult, pack } from '../../core/packager.js'; | ||
| import { logger } from '../../shared/logger.js'; | ||
| import type { RepomixProgressCallback } from '../../shared/types.js'; | ||
| import { reportResults } from '../cliReport.js'; | ||
| import { Spinner } from '../cliSpinner.js'; | ||
| import type { CliOptions } from '../types.js'; | ||
| import { buildCliConfig } from './defaultAction.js'; | ||
| import { runMigrationAction } from './migrationAction.js'; | ||
|
|
||
| export interface WatchDeps { | ||
| watch: (paths: string | string[], options?: ChokidarOptions) => FSWatcher; | ||
| signal?: AbortSignal; | ||
| } | ||
|
|
||
| const resolveDefaultDeps = async (): Promise<WatchDeps> => { | ||
| // Lazy-load chokidar so it is only imported when --watch is actually used | ||
| const chokidar = await import('chokidar'); | ||
| return { watch: chokidar.watch }; | ||
| }; | ||
|
|
||
| const runPack = async ( | ||
| targetPaths: string[], | ||
| config: RepomixConfigMerged, | ||
| cliOptions: CliOptions, | ||
| ): Promise<PackResult> => { | ||
| const spinner = new Spinner('Packing...', cliOptions); | ||
| spinner.start(); | ||
|
|
||
| try { | ||
| const handleProgress: RepomixProgressCallback = (message) => { | ||
| spinner.update(message); | ||
| }; | ||
|
|
||
| const packResult = await pack(targetPaths, config, handleProgress); | ||
| spinner.succeed('Packing completed successfully!'); | ||
| return packResult; | ||
| } catch (error) { | ||
| spinner.fail('Error during packing'); | ||
| throw error; | ||
| } | ||
| }; | ||
|
|
||
| /** | ||
| * Builds ignore patterns for chokidar based on the packer's ignore configuration. | ||
| * This ensures watch mode ignores the same files/directories as the packer. | ||
| */ | ||
| const buildWatchIgnorePatterns = (cwd: string, config: RepomixConfigMerged): (string | RegExp)[] => { | ||
| const patterns: (string | RegExp)[] = []; | ||
|
|
||
| // Add default ignore patterns if enabled | ||
| if (config.ignore.useDefaultPatterns) { | ||
| for (const pattern of defaultIgnoreList) { | ||
| patterns.push(pattern); | ||
| } | ||
| } | ||
|
|
||
| // Add custom ignore patterns | ||
| if (config.ignore.customPatterns) { | ||
| for (const pattern of config.ignore.customPatterns) { | ||
| patterns.push(pattern); | ||
| } | ||
| } | ||
|
|
||
| // Add the output file path | ||
| if (config.output.filePath) { | ||
| patterns.push(path.resolve(cwd, config.output.filePath)); | ||
| } | ||
|
|
||
| return patterns; | ||
| }; | ||
|
|
||
| export const runWatchAction = async ( | ||
| directories: string[], | ||
| cwd: string, | ||
| cliOptions: CliOptions, | ||
| deps?: Partial<WatchDeps>, | ||
| ): Promise<void> => { | ||
| // Early-return guard: if the signal is already aborted, do no work | ||
| // Must check before any await to prevent race conditions | ||
| if (deps?.signal?.aborted) { | ||
| return; | ||
| } | ||
|
|
||
| // Only load chokidar if no watch function is provided (enables faster tests) | ||
| const resolvedDeps: WatchDeps = deps?.watch ? (deps as WatchDeps) : { ...(await resolveDefaultDeps()), ...deps }; | ||
|
|
||
| logger.trace('Watch mode: loaded CLI options:', cliOptions); | ||
|
|
||
| // Build config — same pattern as defaultAction | ||
| await runMigrationAction(cwd); | ||
|
|
||
| const fileConfig: RepomixConfigFile = await loadFileConfig(cwd, cliOptions.config ?? null, { | ||
| skipLocalConfig: cliOptions.skipLocalConfig, | ||
| }); | ||
| logger.trace('Watch mode: loaded file config:', fileConfig); | ||
|
|
||
| const cliConfig: RepomixConfigCli = buildCliConfig(cliOptions); | ||
| logger.trace('Watch mode: CLI config:', cliConfig); | ||
|
|
||
| const config: RepomixConfigMerged = mergeConfigs(cwd, fileConfig, cliConfig); | ||
| logger.trace('Watch mode: merged config:', config); | ||
|
|
||
| const targetPaths = directories.map((directory) => path.resolve(cwd, directory)); | ||
|
|
||
| // Run initial pack | ||
| const packResult = await runPack(targetPaths, config, cliOptions); | ||
| reportResults(cwd, packResult, config, cliOptions); | ||
| logger.log(pc.dim(`\nWatching ${packResult.safeFilePaths.length} files for changes... (Ctrl+C to stop)\n`)); | ||
|
|
||
| // Watch target directories instead of individual files so new files are detected | ||
| // Apply the same ignore patterns the packer uses to avoid unnecessary rebuilds | ||
| const watchIgnorePatterns = buildWatchIgnorePatterns(cwd, config); | ||
| const watcher = resolvedDeps.watch(targetPaths, { | ||
| ignoreInitial: true, | ||
| awaitWriteFinish: { stabilityThreshold: 100 }, | ||
| ignored: watchIgnorePatterns, | ||
| }); | ||
|
coderabbitai[bot] marked this conversation as resolved.
Comment on lines
+120
to
+124
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n src/cli/actions/watchAction.ts | head -200Repository: yamadashy/repomix Length of output: 8259 🏁 Script executed: cat -n src/cli/actions/watchAction.ts | sed -n '200,250p'Repository: yamadashy/repomix Length of output: 1283 🏁 Script executed: # Check if there are any existing error handlers on the watcher elsewhere
grep -n "watcher\.on" src/cli/actions/watchAction.tsRepository: yamadashy/repomix Length of output: 192 🌐 Web query:
💡 Result: In chokidar, the FSWatcher class extends Node.js EventEmitter and emits an 'error' event when significant filesystem errors occur during watching. This includes errors like EMFILE (too many open files), UNKNOWN, EPERM, EACCES (unless ignorePermissionErrors is true), and others excluding common ignorable ones like ENOENT and ENOTDIR. To handle these errors and prevent unhandled error crashes, always attach an 'error' event listener: const watcher = chokidar.watch('path/to/watch', { ignorePermissionErrors: true // Optional: suppress permission errors }); watcher.on('error', (error) => { console.error('FS Watcher error:', error); // Handle gracefully, e.g., log, retry, or close watcher // watcher.close; }); The internal _handleError method decides whether to emit the error: - Ignores ENOENT, ENOTDIR - Ignores EPERM/EACCES if ignorePermissionErrors: true - Emits 'error' event for other significant errors - Common in large directories (e.g., node_modules) causing EMFILE Without a listener, errors can crash the process with "Emitted 'error' event on FSWatcher instance". Best practice: always listen for 'error' events, especially in production or watch mode. Example from official docs: watcher.on('error', (error) => log(Watcher error: ${error})); Citations:
Add error event handler to watcher.
Suggested fix watcher.on('change', scheduleRebuild);
watcher.on('add', scheduleRebuild);
watcher.on('unlink', scheduleRebuild);
+ watcher.on('error', (error) => {
+ logger.error('Watcher failed:', error);
+ void cleanup();
+ });🤖 Prompt for AI Agents |
||
|
|
||
| // Rebuild guard — prevents concurrent packs and queues a follow-up if changes arrive mid-pack | ||
| let isRebuilding = false; | ||
| let pendingRebuild = false; | ||
| let debounceTimer: ReturnType<typeof setTimeout> | null = null; | ||
| let shuttingDown = false; | ||
|
|
||
| const scheduleRebuild = () => { | ||
| // Guard: don't schedule new work if shutdown has been initiated | ||
| if (shuttingDown) { | ||
| return; | ||
| } | ||
|
|
||
| if (debounceTimer !== null) { | ||
| clearTimeout(debounceTimer); | ||
| } | ||
| debounceTimer = setTimeout(async () => { | ||
| debounceTimer = null; | ||
|
|
||
| // Re-check shutdown in case it was initiated while timer was pending | ||
| if (shuttingDown) { | ||
| return; | ||
| } | ||
|
|
||
| if (isRebuilding) { | ||
| pendingRebuild = true; | ||
| return; | ||
| } | ||
|
|
||
| isRebuilding = true; | ||
| try { | ||
| const result = await runPack(targetPaths, config, cliOptions); | ||
| reportResults(cwd, result, config, cliOptions); | ||
| const now = new Date(); | ||
| const timestamp = now.toLocaleTimeString('en-GB', { hour12: false }); | ||
| logger.success(`Rebuilt at ${timestamp}`); | ||
| logger.log(pc.dim('Watching for changes...')); | ||
| } catch (error) { | ||
| logger.error('Watch rebuild failed:', error); | ||
| } finally { | ||
| isRebuilding = false; | ||
| // Check if shutdown has been initiated before draining pendingRebuild | ||
| if (shuttingDown) { | ||
| pendingRebuild = false; | ||
| } else if (pendingRebuild) { | ||
| pendingRebuild = false; | ||
| scheduleRebuild(); | ||
| } | ||
| } | ||
| }, 300); | ||
|
devin-ai-integration[bot] marked this conversation as resolved.
coderabbitai[bot] marked this conversation as resolved.
coderabbitai[bot] marked this conversation as resolved.
|
||
| }; | ||
|
|
||
| watcher.on('change', scheduleRebuild); | ||
| watcher.on('add', scheduleRebuild); | ||
| watcher.on('unlink', scheduleRebuild); | ||
|
|
||
| // Graceful shutdown — shared cleanup promise that both signal and SIGINT/SIGTERM paths await | ||
| let cleanupResolve: (() => void) | null = null; | ||
| let cleanupStarted = false; | ||
| let cleanupDone = false; | ||
|
|
||
| const cleanup = async () => { | ||
| // Prevent multiple cleanup calls | ||
| if (cleanupStarted) { | ||
| return; | ||
| } | ||
| cleanupStarted = true; | ||
| shuttingDown = true; | ||
|
|
||
| if (debounceTimer !== null) { | ||
| clearTimeout(debounceTimer); | ||
| } | ||
| process.removeListener('SIGINT', onSigint); | ||
| process.removeListener('SIGTERM', onSigterm); | ||
| // Close watcher before resolving so callers don't see | ||
| // runWatchAction() resolve until shutdown is truly finished | ||
| await watcher.close(); | ||
| cleanupDone = true; | ||
| cleanupResolve?.(); | ||
| }; | ||
|
|
||
| const onSigint = () => { | ||
| cleanup(); | ||
| }; | ||
| const onSigterm = () => { | ||
| cleanup(); | ||
| }; | ||
|
|
||
| if (resolvedDeps.signal) { | ||
| // Register abort listener with { once: true } to avoid duplicate calls | ||
| resolvedDeps.signal.addEventListener('abort', () => cleanup(), { once: true }); | ||
|
|
||
| // Handle race condition: signal may already be aborted before listener was registered | ||
| if (resolvedDeps.signal.aborted) { | ||
| cleanup(); | ||
| } | ||
| } else { | ||
| process.on('SIGINT', onSigint); | ||
| process.on('SIGTERM', onSigterm); | ||
| } | ||
|
Comment on lines
+248
to
+251
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When Additionally, if this function is called multiple times in a long-running process (e.g., during tests or in a wrapper), it will leak event listeners on the |
||
|
|
||
| // Keep alive — wait until cleanup is fully complete (including watcher.close()) | ||
| // Check cleanupDone first in case cleanup finished before we got here | ||
| await new Promise<void>((resolve) => { | ||
| if (cleanupDone) { | ||
| resolve(); | ||
| return; | ||
| } | ||
| cleanupResolve = resolve; | ||
| }); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -40,6 +40,9 @@ const semanticSuggestionMap: Record<string, string[]> = { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console: ['--stdout'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| terminal: ['--stdout'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pipe: ['--stdin'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| monitor: ['--watch'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| live: ['--watch'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto: ['--watch'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const run = async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -183,6 +186,9 @@ export const run = async () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option('--skill-output <path>', 'Specify skill output directory path directly (skips location prompt)') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option('-f, --force', 'Skip all confirmation prompts (currently: skill directory overwrite)') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Watch Mode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .optionsGroup('Watch Mode') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option('-w, --watch', 'Watch for file changes and automatically re-pack') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .action(commanderActionEndpoint); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Custom error handling function | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -233,6 +239,27 @@ export const runCli = async (directories: string[], cwd: string, options: CliOpt | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| options.stdout = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Validate --watch conflicts early, before log level changes can suppress error messages | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (options.watch) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (options.remote) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new RepomixError('--watch cannot be used with --remote. Watch mode only works with local directories.'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (options.stdout) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new RepomixError('--watch cannot be used with --stdout. Watch mode writes to a file.'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (options.stdin) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new RepomixError('--watch cannot be used with --stdin. Watch mode discovers files automatically.'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (options.splitOutput) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new RepomixError( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| '--watch cannot be used with --split-output. Watch mode does not yet support split output files.', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (directories.length === 1 && isExplicitRemoteUrl(directories[0])) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new RepomixError('--watch cannot be used with remote URLs. Watch mode only works with local directories.'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+242
to
+261
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reject This only guards Suggested fix // Validate --watch conflicts early, before log level changes can suppress error messages
if (options.watch) {
- if (options.remote) {
+ const positionalRemote = directories.length === 1 && isExplicitRemoteUrl(directories[0]);
+ if (options.remote || positionalRemote) {
throw new RepomixError('--watch cannot be used with --remote. Watch mode only works with local directories.');
}
if (options.stdout) {
throw new RepomixError('--watch cannot be used with --stdout. Watch mode writes to a file.');
}🤖 Prompt for AI Agents
Comment on lines
+243
to
+261
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Watch mode silently ignores --skill-generate instead of rejecting the incompatible combination The
Suggested change
Was this helpful? React with 👍 or 👎 to provide feedback.
Comment on lines
+243
to
+261
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 Missing conflict check: When a user passes
Suggested change
Was this helpful? React with 👍 or 👎 to provide feedback. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Set log level based on verbose and quiet flags | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (options.quiet) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.setLogLevel(repomixLogLevels.SILENT); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -286,6 +313,11 @@ export const runCli = async (directories: string[], cwd: string, options: CliOpt | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return await runRemoteAction(directories[0], options); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (options.watch) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { runWatchAction } = await import('./actions/watchAction.js'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return await runWatchAction(directories, cwd, options); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { runDefaultAction } = await import('./actions/defaultAction.js'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return await runDefaultAction(directories, cwd, options); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.