@brickhouse-tech/sync-agents 0.1.3 → 0.1.5

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Brickhouse Tech
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,11 +1,13 @@
1
1
  # sync-agents
2
2
 
3
- One set of agent rules to rule them all. `sync-agents` keeps your AI coding agent configurations in a single `.agents/` directory and syncs them to agent-specific directories (`.claude/`, `.windsurf/`) via symlinks. This ensures all agents follow the same rules, skills, and workflows without duplicating files.
3
+ One set of agent rules to rule them all. `sync-agents` keeps your AI coding agent configurations in a single `.agents/` directory and syncs them to agent-specific directories (`.claude/`, `.windsurf/`, `.cursor/`, `.github/copilot/`) via symlinks. This ensures all agents follow the same rules, skills, and workflows without duplicating files.
4
4
 
5
5
  AGENTS.md serves as an auto-generated index of everything in `.agents/` and is symlinked to CLAUDE.md for Claude compatibility.
6
6
 
7
7
  ## Installation
8
8
 
9
+ ### npm
10
+
9
11
  ```bash
10
12
  npm install @brickhouse-tech/sync-agents
11
13
  ```
@@ -16,6 +18,13 @@ or globally:
16
18
  npm install -g @brickhouse-tech/sync-agents
17
19
  ```
18
20
 
21
+ ### Standalone (no npm required)
22
+
23
+ ```bash
24
+ curl -fsSL https://raw.githubusercontent.com/brickhouse-tech/sync-agents/main/src/sh/sync-agents.sh -o /usr/local/bin/sync-agents
25
+ chmod +x /usr/local/bin/sync-agents
26
+ ```
27
+
19
28
  ## Topology
20
29
 
21
30
  `.agents/` is the source of truth. It contains all rules, skills, workflows, and state for your agents:
@@ -37,7 +46,7 @@ npm install -g @brickhouse-tech/sync-agents
37
46
  └── STATE.md
38
47
  ```
39
48
 
40
- Running `sync-agents sync` creates symlinks from `.agents/` subdirectories into `.claude/` and `.windsurf/`. Any changes to `.agents/` are automatically reflected in the target directories because they are symlinks, not copies.
49
+ Running `sync-agents sync` creates symlinks from `.agents/` subdirectories into `.claude/`, `.windsurf/`, `.cursor/`, and `.github/copilot/`. Any changes to `.agents/` are automatically reflected in the target directories because they are symlinks, not copies.
41
50
 
42
51
  AGENTS.md is also symlinked to CLAUDE.md so that Claude reads the index natively.
43
52
 
@@ -50,7 +59,10 @@ AGENTS.md is also symlinked to CLAUDE.md so that Claude reads the index natively
50
59
  | Command | Description |
51
60
  |---|---|
52
61
  | `init` | Initialize the `.agents/` directory structure with `rules/`, `skills/`, `workflows/`, `STATE.md`, and generate `AGENTS.md` |
53
- | `sync` | Create symlinks from `.agents/` into `.claude/` and `.windsurf/`, and symlink `AGENTS.md` to `CLAUDE.md` |
62
+ | `sync` | Create symlinks from `.agents/` into all target directories, and symlink `AGENTS.md` to `CLAUDE.md` |
63
+ | `watch` | Watch `.agents/` for changes and auto-regenerate `AGENTS.md` |
64
+ | `import <url>` | Import a rule/skill/workflow from a URL |
65
+ | `hook` | Install a pre-commit git hook for auto-sync |
54
66
  | `status` | Show the current sync status of all targets and symlinks |
55
67
  | `add <type> <name>` | Add a new rule, skill, or workflow from a template (type is `rule`, `skill`, or `workflow`) |
56
68
  | `index` | Regenerate `AGENTS.md` by scanning the contents of `.agents/` |
@@ -63,7 +75,7 @@ AGENTS.md is also symlinked to CLAUDE.md so that Claude reads the index natively
63
75
  | `-h`, `--help` | Show help message |
64
76
  | `-v`, `--version` | Show version |
65
77
  | `-d`, `--dir <path>` | Set project root directory (default: current directory) |
66
- | `--targets <list>` | Comma-separated list of sync targets (default: `claude,windsurf`) |
78
+ | `--targets <list>` | Comma-separated list of sync targets (default: `claude,windsurf,cursor,copilot`) |
67
79
  | `--dry-run` | Show what would be done without making changes |
68
80
  | `--force` | Overwrite existing files and symlinks |
69
81
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brickhouse-tech/sync-agents",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Simple scripts to DRY up common agent interactions across multiple LLM providers.",
5
5
  "keywords": [
6
6
  "agents",
@@ -0,0 +1,23 @@
1
+ ---
2
+ trigger: always_on
3
+ ---
4
+
5
+ # ${NAME}
6
+
7
+ ## Description
8
+
9
+ Brief description of what this skill enables.
10
+
11
+ ## Usage
12
+
13
+ When to use this skill and how to invoke it.
14
+
15
+ ## Examples
16
+
17
+ ```
18
+ Example usage or invocation here.
19
+ ```
20
+
21
+ ## Notes
22
+
23
+ Any caveats, prerequisites, or related skills.
@@ -1,42 +1,16 @@
1
-
2
1
  ---
3
2
  trigger: always_on
4
3
  ---
5
4
 
6
5
  # State
7
6
 
8
- This is the state template for sync-agents. It is used to define the state of the agent and its environment. The state markdown file itself is a human readble source for the agent to read and understand its current situation. It can be used to track the progress of the agent, identify any issues or challenges it may be facing, and provide a clear overview of its goals and objectives. The state is an important tool for the agent to use in order to make informed decisions and take appropriate actions to achieve its goals. By maintaining an up-to-date state, the agent can continuously learn and evolve, becoming more effective and efficient in its tasks.
9
-
10
- The goal is to improve the performance of the agent by providing it with a clear and structured representation of its current situation. This allows the agent to make informed decisions and take appropriate actions to achieve its goals. The state is also used to track the progress of the agent and identify any issues or areas for improvement. By maintaining an up-to-date state, the agent can continuously learn and evolve, becoming more effective and efficient in its xtasks.
11
-
12
- ## TRACKING Agent State
13
-
14
- Every state tracking will begin with a header of `### YYYYMMDDHHMMSS STATE: <STATE_NAME or OBJECTIVE` followed by a description of the state, any relevant information about the agent's performance, issues, or updates, and any actions taken or planned to address the current state. This format allows for easy tracking and monitoring of the agent's progress over time, as well as providing a clear record of the agent's history and development. By maintaining a detailed and organized state history, the agent can learn from past experiences and make informed decisions to improve its performance in the future.>
15
-
16
- The format above will be written below the `## STATE HISTORY BELOW` header in the STATE.md file. This allows for easy tracking and monitoring of the agent's progress over time, as well as providing a clear record of the agent's history and development. By maintaining a detailed and organized state history, the agent can learn from past experiences and make informed decisions to improve its performance in the future.
17
-
18
- ## Formatted Agent State
7
+ Track project progress, current objectives, and resumption context.
8
+ Update this file regularly so agents can pick up where they left off.
19
9
 
20
- The formatted agent state will be a structured representation of the agent's current situation, including its goals, objectives, performance metrics, and any relevant information about its environment. This formatted state will be used by the agent to make informed decisions and take appropriate actions to achieve its goals. By maintaining an up-to-date and well-structured formatted state, the agent can continuously learn and evolve, becoming more effective and efficient in its tasks. The formatted state will also be used to track the progress of the agent and identify any issues or areas for improvement, allowing for continuous optimization of the agent's performance.
10
+ ## Format
21
11
 
22
- Example:
12
+ ### YYYYMMDDHHMMSS STATE: <objective>
23
13
 
24
- The state is structured as follows:
25
-
26
- ```json
27
- {
28
- "agent_name": "string",
29
- "goals": ["string"],
30
- "skills": ["string"],
31
- "workflows": ["string"],
32
- "issues": ["string"],
33
- "last_updated": "timestamp"
34
- }
35
- ```
36
- to `.agents/state.json`
14
+ Description of current state, progress, blockers, and next steps.
37
15
 
38
16
  ## STATE HISTORY BELOW
39
-
40
-
41
-
42
-
@@ -0,0 +1,24 @@
1
+ ---
2
+ trigger: always_on
3
+ ---
4
+
5
+ # ${NAME}
6
+
7
+ ## Trigger
8
+
9
+ Describe when this workflow should be activated.
10
+
11
+ ## Steps
12
+
13
+ 1. Step one
14
+ 2. Step two
15
+ 3. Step three
16
+
17
+ ## Conditions
18
+
19
+ - Pre-conditions that must be met
20
+ - Any guards or checks
21
+
22
+ ## Output
23
+
24
+ What the workflow produces or changes when complete.
@@ -19,7 +19,7 @@ else
19
19
  fi
20
20
 
21
21
  # Agent target directories
22
- TARGETS=("claude" "windsurf")
22
+ TARGETS=("claude" "windsurf" "cursor" "copilot")
23
23
 
24
24
  # Colors (disabled if not a terminal)
25
25
  if [[ -t 1 ]]; then
@@ -37,6 +37,27 @@ info() { echo -e "${GREEN}[info]${RESET} $*"; }
37
37
  warn() { echo -e "${YELLOW}[warn]${RESET} $*"; }
38
38
  error() { echo -e "${RED}[error]${RESET} $*" >&2; }
39
39
 
40
+ # Resolve target directory path (copilot uses .github/copilot/ instead of .copilot/)
41
+ resolve_target_dir() {
42
+ local target="$1"
43
+ local root="$2"
44
+ if [[ "$target" == "copilot" ]]; then
45
+ echo "$root/.github/copilot"
46
+ else
47
+ echo "$root/.$target"
48
+ fi
49
+ }
50
+
51
+ # Resolve relative path from target dir back to .agents/ (accounts for depth)
52
+ resolve_agents_rel() {
53
+ local target="$1"
54
+ if [[ "$target" == "copilot" ]]; then
55
+ echo "../../$AGENTS_DIR"
56
+ else
57
+ echo "../$AGENTS_DIR"
58
+ fi
59
+ }
60
+
40
61
  usage() {
41
62
  cat <<EOF
42
63
  ${BOLD}sync-agents${RESET} v${VERSION} - One set of agent rules to rule them all.
@@ -46,17 +67,20 @@ ${BOLD}USAGE${RESET}
46
67
 
47
68
  ${BOLD}COMMANDS${RESET}
48
69
  init Initialize .agents/ directory structure and AGENTS.md
49
- sync Sync .agents/ to .claude/ and .windsurf/ via symlinks
70
+ sync Sync .agents/ to agent directories via symlinks
50
71
  status Show current sync status
51
72
  add <type> <name> Add a new rule, skill, or workflow from template
52
73
  index Regenerate AGENTS.md index from .agents/ contents
53
74
  clean Remove all synced symlinks (does not remove .agents/)
75
+ watch Watch .agents/ for changes and auto-regenerate index
76
+ import <url> Import a rule/skill/workflow from a URL
77
+ hook Install a pre-commit git hook for auto-sync
54
78
 
55
79
  ${BOLD}OPTIONS${RESET}
56
80
  -h, --help Show this help message
57
81
  -v, --version Show version
58
82
  -d, --dir <path> Set project root directory (default: current directory)
59
- --targets <list> Comma-separated targets to sync (default: claude,windsurf)
83
+ --targets <list> Comma-separated targets (overrides .agents/config)
60
84
  --dry-run Show what would be done without making changes
61
85
  --force Overwrite existing files/symlinks
62
86
 
@@ -174,6 +198,19 @@ STATE_EOF
174
198
  warn "$AGENTS_DIR/STATE.md already exists, skipping"
175
199
  fi
176
200
 
201
+ # Create default config if it doesn't exist
202
+ if [[ ! -f "$PROJECT_ROOT/$AGENTS_DIR/config" ]]; then
203
+ cat > "$PROJECT_ROOT/$AGENTS_DIR/config" <<CONFIG_EOF
204
+ # sync-agents configuration
205
+ # Comma-separated list of sync targets (available: claude, windsurf, cursor, copilot)
206
+ # Override per-command with: sync-agents sync --targets claude,cursor
207
+ targets = claude,windsurf,cursor,copilot
208
+ CONFIG_EOF
209
+ info "Created $AGENTS_DIR/config"
210
+ else
211
+ warn "$AGENTS_DIR/config already exists, skipping"
212
+ fi
213
+
177
214
  # Generate AGENTS.md if it doesn't exist
178
215
  if [[ ! -f "$PROJECT_ROOT/$AGENTS_MD" ]]; then
179
216
  generate_agents_md
@@ -214,8 +251,19 @@ cmd_add() {
214
251
  exit 1
215
252
  fi
216
253
 
217
- # Use RULE_TEMPLATE for all types, substituting name
218
- if [[ -f "$TEMPLATES_DIR/RULE_TEMPLATE.md" ]]; then
254
+ # Use type-specific template (RULE_TEMPLATE, SKILL_TEMPLATE, WORKFLOW_TEMPLATE)
255
+ local template_name
256
+ case "$type" in
257
+ rules) template_name="RULE_TEMPLATE.md" ;;
258
+ skills) template_name="SKILL_TEMPLATE.md" ;;
259
+ workflows) template_name="WORKFLOW_TEMPLATE.md" ;;
260
+ *) template_name="RULE_TEMPLATE.md" ;;
261
+ esac
262
+
263
+ if [[ -f "$TEMPLATES_DIR/$template_name" ]]; then
264
+ sed "s/\${NAME}/$name/g" "$TEMPLATES_DIR/$template_name" > "$filepath"
265
+ elif [[ -f "$TEMPLATES_DIR/RULE_TEMPLATE.md" ]]; then
266
+ # Fallback to rule template if type-specific template missing
219
267
  sed "s/\${NAME}/$name/g" "$TEMPLATES_DIR/RULE_TEMPLATE.md" > "$filepath"
220
268
  else
221
269
  cat > "$filepath" <<TMPL_EOF
@@ -244,16 +292,16 @@ cmd_sync() {
244
292
  info "Syncing $AGENTS_DIR/ to agent directories..."
245
293
 
246
294
  for target in "${ACTIVE_TARGETS[@]}"; do
247
- local target_dir="$PROJECT_ROOT/.$target"
248
- info "Syncing to .${target}/"
295
+ local target_dir
296
+ target_dir="$(resolve_target_dir "$target" "$PROJECT_ROOT")"
297
+ local agents_rel
298
+ agents_rel="$(resolve_agents_rel "$target")"
299
+ info "Syncing to ${target_dir#"$PROJECT_ROOT"/}/"
249
300
 
250
301
  # Sync subdirectories: rules, skills, workflows
251
302
  for subdir in rules skills workflows; do
252
303
  if [[ -d "$agents_abs/$subdir" ]]; then
253
- # Both .agents/ and .<target>/ live at PROJECT_ROOT, so the relative
254
- # path from .<target>/<subdir> back to .agents/<subdir> is always one
255
- # level up: ../.agents/<subdir>
256
- local source_rel="../$AGENTS_DIR/$subdir"
304
+ local source_rel="$agents_rel/$subdir"
257
305
  create_symlink "$source_rel" "$target_dir/$subdir" "$DRY_RUN"
258
306
  fi
259
307
  done
@@ -303,9 +351,11 @@ cmd_status() {
303
351
 
304
352
  # Check each target
305
353
  for target in "${TARGETS[@]}"; do
306
- local target_dir="$PROJECT_ROOT/.$target"
354
+ local target_dir
355
+ target_dir="$(resolve_target_dir "$target" "$PROJECT_ROOT")"
356
+ local display_dir="${target_dir#"$PROJECT_ROOT"/}"
307
357
  if [[ -d "$target_dir" ]] || [[ -L "$target_dir/rules" ]]; then
308
- echo -e "${CYAN}.$target/${RESET}"
358
+ echo -e "${CYAN}${display_dir}/${RESET}"
309
359
  for subdir in rules skills workflows; do
310
360
  if [[ -L "$target_dir/$subdir" ]]; then
311
361
  local link_target
@@ -318,7 +368,7 @@ cmd_status() {
318
368
  fi
319
369
  done
320
370
  else
321
- echo -e "${RED}[not synced]${RESET} .$target/"
371
+ echo -e "${RED}[not synced]${RESET} ${display_dir}/"
322
372
  fi
323
373
  done
324
374
  }
@@ -329,22 +379,141 @@ cmd_index() {
329
379
  info "Regenerated $AGENTS_MD"
330
380
  }
331
381
 
382
+ cmd_watch() {
383
+ ensure_agents_dir
384
+
385
+ local watch_dir="$PROJECT_ROOT/$AGENTS_DIR"
386
+
387
+ if command -v fswatch >/dev/null 2>&1; then
388
+ info "Watching $AGENTS_DIR/ for changes... (Ctrl+C to stop)"
389
+ cmd_index
390
+ fswatch -o "$watch_dir" | while read -r _; do
391
+ info "Change detected, regenerating index..."
392
+ cmd_index
393
+ done
394
+ elif command -v inotifywait >/dev/null 2>&1; then
395
+ info "Watching $AGENTS_DIR/ for changes... (Ctrl+C to stop)"
396
+ cmd_index
397
+ inotifywait -m -r -e modify,create,delete,move --format '%w%f' "$watch_dir" | while read -r _; do
398
+ info "Change detected, regenerating index..."
399
+ cmd_index
400
+ done
401
+ else
402
+ error "Neither fswatch (macOS) nor inotifywait (Linux) found."
403
+ error "Install with: brew install fswatch OR apt install inotify-tools"
404
+ exit 1
405
+ fi
406
+ }
407
+
408
+ cmd_import() {
409
+ local url="${1:-}"
410
+ if [[ -z "$url" ]]; then
411
+ error "Usage: sync-agents import <url>"
412
+ exit 1
413
+ fi
414
+
415
+ ensure_agents_dir
416
+
417
+ local filename
418
+ filename="$(basename "$url")"
419
+ if [[ "$filename" != *.md ]]; then
420
+ filename="${filename}.md"
421
+ fi
422
+
423
+ # Auto-detect type from URL path
424
+ local type=""
425
+ case "$url" in
426
+ */rules/*) type="rules" ;;
427
+ */skills/*) type="skills" ;;
428
+ */workflows/*) type="workflows" ;;
429
+ esac
430
+
431
+ if [[ -z "$type" ]]; then
432
+ echo "Could not detect type from URL. Choose:"
433
+ echo " 1) rule"
434
+ echo " 2) skill"
435
+ echo " 3) workflow"
436
+ read -rp "Selection (1-3): " choice
437
+ case "$choice" in
438
+ 1) type="rules" ;;
439
+ 2) type="skills" ;;
440
+ 3) type="workflows" ;;
441
+ *) error "Invalid selection"; exit 1 ;;
442
+ esac
443
+ fi
444
+
445
+ mkdir -p "$PROJECT_ROOT/$AGENTS_DIR/$type"
446
+ local dest="$PROJECT_ROOT/$AGENTS_DIR/$type/$filename"
447
+
448
+ info "Importing $url → $AGENTS_DIR/$type/$filename"
449
+
450
+ if ! curl -fsSL "$url" -o "$dest"; then
451
+ error "Failed to download: $url"
452
+ exit 1
453
+ fi
454
+
455
+ info "Imported successfully."
456
+ cmd_index
457
+ }
458
+
459
+ cmd_hook() {
460
+ if [[ ! -d "$PROJECT_ROOT/.git" ]]; then
461
+ error "Not a git repository (no .git/ found)."
462
+ exit 1
463
+ fi
464
+
465
+ local hook_dir="$PROJECT_ROOT/.git/hooks"
466
+ local hook_file="$hook_dir/pre-commit"
467
+ mkdir -p "$hook_dir"
468
+
469
+ local marker="sync-agents start"
470
+
471
+ if [[ -f "$hook_file" ]] && grep -q "$marker" "$hook_file"; then
472
+ info "Git hook already installed in $hook_file"
473
+ return 0
474
+ fi
475
+
476
+ local hook_block
477
+ hook_block="$(cat <<'HOOK'
478
+
479
+ # --- sync-agents start ---
480
+ if command -v sync-agents >/dev/null 2>&1; then
481
+ sync-agents sync 2>/dev/null
482
+ sync-agents index 2>/dev/null
483
+ git add AGENTS.md CLAUDE.md .claude/ .windsurf/ .cursor/ .github/copilot/ 2>/dev/null || true
484
+ fi
485
+ # --- sync-agents end ---
486
+ HOOK
487
+ )"
488
+
489
+ if [[ -f "$hook_file" ]]; then
490
+ echo "$hook_block" >> "$hook_file"
491
+ info "Appended sync-agents hook to existing $hook_file"
492
+ else
493
+ printf '#!/bin/sh\n%s\n' "$hook_block" > "$hook_file"
494
+ chmod +x "$hook_file"
495
+ info "Created git hook: $hook_file"
496
+ fi
497
+ }
498
+
332
499
  cmd_clean() {
333
500
  info "Removing synced symlinks..."
334
501
 
335
502
  for target in "${ACTIVE_TARGETS[@]}"; do
336
- local target_dir="$PROJECT_ROOT/.$target"
503
+ local target_dir
504
+ target_dir="$(resolve_target_dir "$target" "$PROJECT_ROOT")"
505
+ local display_dir="${target_dir#"$PROJECT_ROOT"/}"
337
506
  for subdir in rules skills workflows; do
338
507
  if [[ -L "$target_dir/$subdir" ]]; then
339
508
  rm "$target_dir/$subdir"
340
- info "Removed: .$target/$subdir"
509
+ info "Removed: ${display_dir}/$subdir"
341
510
  fi
342
511
  done
343
512
 
344
513
  # Remove target dir if empty
345
514
  if [[ -d "$target_dir" ]] && [[ -z "$(ls -A "$target_dir" 2>/dev/null)" ]]; then
346
515
  rmdir "$target_dir"
347
- info "Removed empty directory: .$target/"
516
+ info "Removed empty directory: ${display_dir}/"
348
517
  fi
349
518
  done
350
519
 
@@ -535,11 +704,22 @@ main() {
535
704
  PROJECT_ROOT="$(find_project_root)"
536
705
  fi
537
706
 
538
- # Resolve active targets
707
+ # Resolve active targets (priority: --targets flag > .agents/config > built-in defaults)
539
708
  if [[ -n "$custom_targets" ]]; then
540
709
  IFS=',' read -ra ACTIVE_TARGETS <<< "$custom_targets"
541
710
  else
542
- ACTIVE_TARGETS=("${TARGETS[@]}")
711
+ local config_file="$PROJECT_ROOT/$AGENTS_DIR/config"
712
+ if [[ -f "$config_file" ]]; then
713
+ local config_targets
714
+ config_targets="$(sed -n 's/^targets *= *//p' "$config_file" | tr -d ' ')"
715
+ if [[ -n "$config_targets" ]]; then
716
+ IFS=',' read -ra ACTIVE_TARGETS <<< "$config_targets"
717
+ else
718
+ ACTIVE_TARGETS=("${TARGETS[@]}")
719
+ fi
720
+ else
721
+ ACTIVE_TARGETS=("${TARGETS[@]}")
722
+ fi
543
723
  fi
544
724
 
545
725
  # Dispatch command
@@ -562,6 +742,15 @@ main() {
562
742
  clean)
563
743
  cmd_clean
564
744
  ;;
745
+ watch)
746
+ cmd_watch
747
+ ;;
748
+ import)
749
+ cmd_import "$@"
750
+ ;;
751
+ hook)
752
+ cmd_hook
753
+ ;;
565
754
  "")
566
755
  usage
567
756
  exit 0