claude-plugin-viban 1.1.2 → 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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viban",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "Terminal Kanban TUI for AI-human collaborative issue tracking",
5
5
  "author": {
6
6
  "name": "happy-nut"
package/README.md CHANGED
@@ -53,6 +53,7 @@ This separation keeps your workflow clean and prevents context switching.
53
53
  - python3 (macOS/Linux built-in)
54
54
  - [gum](https://github.com/charmbracelet/gum)
55
55
  - [jq](https://jqlang.github.io/jq/)
56
+ - [gh](https://cli.github.com/) (optional, for GitHub Issues sync)
56
57
 
57
58
  > **Tip:** If using Claude Code, run `/viban:setup` to install all dependencies automatically.
58
59
 
@@ -122,6 +123,7 @@ viban assign [session-id] # Assign top backlog issue
122
123
  viban review [id] # Move issue to review
123
124
  viban done <id> # Mark issue as done
124
125
  viban get <id> # Get issue details (JSON)
126
+ viban sync # Sync with external tracker
125
127
  viban help # Show help message
126
128
  ```
127
129
 
@@ -175,6 +177,60 @@ Analyzes a problem and creates a properly structured viban issue:
175
177
  - Feature requests
176
178
  - Converting free-form descriptions to structured issues
177
179
 
180
+ #### `/viban:sync` - Sync with external tracker
181
+
182
+ Two-way sync between your viban board and an external issue tracker (currently GitHub Issues):
183
+
184
+ 1. Checks sync configuration (or initializes on first run)
185
+ 2. Shows a dry-run preview of changes
186
+ 3. Asks for confirmation before syncing
187
+ 4. Reports sync results
188
+
189
+ **Use cases:**
190
+ - Importing GitHub Issues into your local board
191
+ - Keeping remote issues in sync with local status changes
192
+ - Team collaboration where some members use GitHub and others use viban
193
+
194
+ ## External Tracker Sync
195
+
196
+ viban can sync two-way with external issue trackers. Currently supported: **GitHub Issues**.
197
+
198
+ ### Quick Start
199
+
200
+ ```bash
201
+ # First time: initialize sync (auto-detects provider from git remote)
202
+ viban sync --init
203
+
204
+ # Preview what will change
205
+ viban sync --dry-run
206
+
207
+ # Run sync
208
+ viban sync
209
+ ```
210
+
211
+ > If using Claude Code, run `/viban:sync` for a guided experience with dry-run preview and confirmation.
212
+
213
+ ### How It Works
214
+
215
+ - **First sync** imports all open remote issues as backlog cards with external IDs (e.g. `github:42`)
216
+ - **Subsequent syncs** pull remote changes and push local status updates
217
+ - **New local cards** are NOT pushed unless `--push-new` is specified (local-first default)
218
+ - **Conflicts** (both sides changed) resolve to remote-wins by default
219
+
220
+ ### Status-to-Label Mapping
221
+
222
+ | viban status | GitHub label |
223
+ |-------------|-------------|
224
+ | `backlog` | *(no label)* |
225
+ | `in_progress` | `in-progress` |
226
+ | `review` | `review` |
227
+ | `done` | *(issue closed)* |
228
+
229
+ ### Requirements
230
+
231
+ - [gh CLI](https://cli.github.com/) installed and authenticated (`gh auth login`)
232
+ - Repository must have a GitHub remote
233
+
178
234
  ## Configuration
179
235
 
180
236
  ### Data Location (viban.json)
@@ -184,18 +240,14 @@ viban stores issues in `viban.json` with the following priority:
184
240
  | Priority | Location | When Used |
185
241
  |----------|----------|-----------|
186
242
  | 1 | `$VIBAN_DATA_DIR` | Explicit override via environment variable |
187
- | 2 | `.git/` (git common dir) | In a git repository (shared across worktrees) |
188
- | 3 | `.viban/` | Non-git directories (fallback) |
243
+ | 2 | `.viban/` | Default (all projects) |
189
244
 
190
- **Why Git Common Dir?**
191
- - Shared across git worktrees (parallel work sessions)
192
- - Survives branch switches
193
- - Single source of truth for the repository
245
+ **Auto-Migration:** If viban detects `viban.json` or `sync.json` in `.git/` (legacy location), it automatically moves them to `.viban/`.
194
246
 
195
- **For Non-Git Projects:**
247
+ **For Any Project:**
196
248
  ```bash
197
249
  # viban will automatically create .viban/viban.json in current directory
198
- cd /path/to/non-git-project
250
+ cd /path/to/project
199
251
  viban add "First issue" "Description" P2 feat
200
252
  # Creates: /path/to/non-git-project/.viban/viban.json
201
253
  ```
@@ -289,13 +341,22 @@ claude-plugin-viban/
289
341
  │ └── viban # Main TUI/CLI script
290
342
  ├── docs/
291
343
  │ └── CLAUDE.md # Claude Code integration guide
344
+ ├── commands/
345
+ │ └── sync.md # /viban:sync command
292
346
  ├── scripts/
293
347
  │ ├── check-deps.sh # Dependency checker
348
+ │ ├── sync.sh # Core sync engine (provider-agnostic)
349
+ │ ├── providers/
350
+ │ │ └── github.sh # GitHub Issues provider
294
351
  │ └── tui_coprocess.py # Persistent Python coprocess for TUI rendering
295
352
  ├── skills/
296
353
  │ ├── assign/SKILL.md # /viban:assign skill
297
354
  │ ├── setup/SKILL.md # /viban:setup skill
355
+ │ ├── sync/SKILL.md # /viban:sync skill
298
356
  │ └── task/SKILL.md # /viban:task skill
357
+ ├── tests/
358
+ │ ├── run_all.zsh # Test runner
359
+ │ └── test_sync.zsh # Sync engine tests
299
360
  ├── LICENSE # MIT License
300
361
  ├── package.json # NPM package config
301
362
  └── README.md # This file
package/bin/viban CHANGED
@@ -121,6 +121,8 @@ IN_TUI=false
121
121
  cleanup() {
122
122
  # Skip cleanup in subshells — EXIT trap fires in $() command substitutions
123
123
  [[ ${ZSH_SUBSHELL:-0} -gt 0 ]] && return
124
+ # Kill background sync if running
125
+ [[ -n "${_sync_pid:-}" ]] && kill "$_sync_pid" 2>/dev/null && wait "$_sync_pid" 2>/dev/null
124
126
  _stop_coproc
125
127
  printf '\033[?25h\033[0m'
126
128
  stty echo 2>/dev/null
@@ -193,24 +195,14 @@ export TERM=${TERM:-xterm-256color}
193
195
  # ============================================================
194
196
  # Priority:
195
197
  # 1. VIBAN_DATA_DIR env var (explicit override)
196
- # 2. Git common dir (shared across worktrees)
197
- # 3. Project root .viban/ directory (non-git projects)
198
+ # 2. Project root .viban/ directory
198
199
 
199
200
  VIBAN_DATA_DIR="${VIBAN_DATA_DIR:-}"
200
201
  VIBAN_IS_GIT_REPO=false
202
+ git rev-parse --git-dir &>/dev/null && VIBAN_IS_GIT_REPO=true
201
203
 
202
204
  if [[ -z "$VIBAN_DATA_DIR" ]]; then
203
- # Try git common dir first (shared across worktrees)
204
- if _git_common="$(git rev-parse --git-common-dir 2>/dev/null)"; then
205
- VIBAN_IS_GIT_REPO=true
206
- if [[ -d "$_git_common" ]]; then
207
- VIBAN_DATA_DIR="$(cd "$_git_common" && pwd)"
208
- fi
209
- fi
210
- # Fallback: project root .viban directory
211
- if [[ -z "$VIBAN_DATA_DIR" ]]; then
212
- VIBAN_DATA_DIR="${PWD}/.viban"
213
- fi
205
+ VIBAN_DATA_DIR="${PWD}/.viban"
214
206
  fi
215
207
 
216
208
  VIBAN_JSON="${VIBAN_DATA_DIR}/viban.json"
@@ -218,13 +210,16 @@ VIBAN_JSON="${VIBAN_DATA_DIR}/viban.json"
218
210
  # Ensure data directory exists
219
211
  mkdir -p "$VIBAN_DATA_DIR"
220
212
 
221
- # Auto-migrate: .viban/viban.json -> .git/ when git repo is initialized
222
- if $VIBAN_IS_GIT_REPO; then
223
- _legacy_json="${PWD}/.viban/viban.json"
224
- if [[ -f "$_legacy_json" && ! -f "$VIBAN_JSON" ]]; then
225
- mv "$_legacy_json" "$VIBAN_JSON"
226
- rmdir "${PWD}/.viban" 2>/dev/null
227
- echo "✓ Migrated viban data from .viban/ to git directory"
213
+ # Auto-migrate: .git/viban.json -> .viban/ (legacy location)
214
+ if _git_common="$(git rev-parse --git-common-dir 2>/dev/null)"; then
215
+ _git_dir="$(cd "$_git_common" && pwd)"
216
+ if [[ -f "${_git_dir}/viban.json" && ! -f "$VIBAN_JSON" ]]; then
217
+ mv "${_git_dir}/viban.json" "$VIBAN_JSON"
218
+ echo "✓ Migrated viban.json from .git/ to .viban/"
219
+ fi
220
+ if [[ -f "${_git_dir}/sync.json" && ! -f "${VIBAN_DATA_DIR}/sync.json" ]]; then
221
+ mv "${_git_dir}/sync.json" "${VIBAN_DATA_DIR}/sync.json"
222
+ echo "✓ Migrated sync.json from .git/ to .viban/"
228
223
  fi
229
224
  fi
230
225
 
@@ -1051,7 +1046,17 @@ delete_issue() {
1051
1046
  local id=$1
1052
1047
  local repo_root=$(git rev-parse --show-toplevel 2>/dev/null)
1053
1048
  local wt_dir="$VIBAN_DATA_DIR/worktrees/$id"
1049
+
1050
+ # Determine branch name: prefer issue-{num} when external_id present
1054
1051
  local branch="viban-$id"
1052
+ local _ext_id=$(get_ext_id "$id")
1053
+ if [[ -n "$_ext_id" && "$_ext_id" != "null" ]]; then
1054
+ local _issue_num="${_ext_id##*:}"
1055
+ if git -C "$repo_root" rev-parse --verify "issue-${_issue_num}" &>/dev/null 2>&1; then
1056
+ branch="issue-${_issue_num}"
1057
+ fi
1058
+ fi
1059
+
1055
1060
  if [[ -d "$wt_dir" ]]; then
1056
1061
  git -C "$repo_root" worktree remove "$wt_dir" --force 2>/dev/null
1057
1062
  git -C "$repo_root" branch -D "$branch" 2>/dev/null
@@ -1065,6 +1070,11 @@ level1_columns() {
1065
1070
  _start_coproc
1066
1071
  local col=0 card=0
1067
1072
 
1073
+ # Auto-sync state (120 iterations × 0.5s timeout = ~60s interval)
1074
+ local _sync_counter=0
1075
+ local _SYNC_INTERVAL=120
1076
+ local _sync_pid=""
1077
+
1068
1078
  # Hide cursor and disable input echo
1069
1079
  stty -echo 2>/dev/null
1070
1080
  printf '\033[?25l\033[2J\033[H'
@@ -1073,6 +1083,27 @@ level1_columns() {
1073
1083
  update_term_cache
1074
1084
 
1075
1085
  while true; do
1086
+ # Auto-sync: reap finished background sync
1087
+ if [[ -n "$_sync_pid" ]]; then
1088
+ if ! kill -0 "$_sync_pid" 2>/dev/null; then
1089
+ wait "$_sync_pid" 2>/dev/null
1090
+ _sync_pid=""
1091
+ fi
1092
+ fi
1093
+
1094
+ # Auto-sync: trigger when interval reached and sync configured
1095
+ ((_sync_counter++)) || true
1096
+ if (( _sync_counter >= _SYNC_INTERVAL )) && [[ -z "$_sync_pid" && -f "$VIBAN_DATA_DIR/sync.json" ]]; then
1097
+ _sync_counter=0
1098
+ local _sync_provider
1099
+ _sync_provider=$(jq -r '.provider // ""' "$VIBAN_DATA_DIR/sync.json" 2>/dev/null)
1100
+ if [[ -n "$_sync_provider" && "$_sync_provider" != "null" ]]; then
1101
+ VIBAN_JSON="$VIBAN_JSON" VIBAN_DATA_DIR="$VIBAN_DATA_DIR" \
1102
+ VIBAN_PROVIDER="$_sync_provider" VIBAN_SCRIPT_DIR="$VIBAN_SCRIPT_DIR" \
1103
+ bash "$VIBAN_SCRIPT_DIR/scripts/sync.sh" --auto &
1104
+ _sync_pid=$!
1105
+ fi
1106
+ fi
1076
1107
  # Cache JSON data once per frame
1077
1108
  local json_data=$(cat "$VIBAN_JSON")
1078
1109
 
@@ -1424,6 +1455,20 @@ cmd_add() {
1424
1455
  updated_at:$now
1425
1456
  }]' "$VIBAN_JSON" > "$VIBAN_JSON.tmp" && mv "$VIBAN_JSON.tmp" "$VIBAN_JSON"
1426
1457
  rm -f "$tmpjson"
1458
+
1459
+ # Auto-create remote issue if sync is configured and no ext_id provided
1460
+ if [[ -z "$ext_id" && -f "$VIBAN_DATA_DIR/sync.json" ]]; then
1461
+ local provider
1462
+ provider=$(jq -r '.provider // ""' "$VIBAN_DATA_DIR/sync.json" 2>/dev/null)
1463
+ if [[ -n "$provider" && "$provider" != "null" ]]; then
1464
+ local created_ext_id
1465
+ created_ext_id=$(VIBAN_JSON="$VIBAN_JSON" VIBAN_DATA_DIR="$VIBAN_DATA_DIR" \
1466
+ VIBAN_PROVIDER="$provider" VIBAN_SCRIPT_DIR="$VIBAN_SCRIPT_DIR" \
1467
+ bash "$VIBAN_SCRIPT_DIR/scripts/sync_create.sh" "$id" 2>/dev/null) || true
1468
+ [[ -n "$created_ext_id" ]] && ext_id="$created_ext_id"
1469
+ fi
1470
+ fi
1471
+
1427
1472
  local type_info=""
1428
1473
  [[ -n "$issue_type" ]] && type_info=" [$issue_type]"
1429
1474
  local attach_info=""
@@ -1473,7 +1518,17 @@ cmd_done() {
1473
1518
  # Cleanup worktree if exists
1474
1519
  local repo_root=$(git rev-parse --show-toplevel 2>/dev/null)
1475
1520
  local wt_dir="$VIBAN_DATA_DIR/worktrees/$1"
1521
+
1522
+ # Determine branch name: prefer issue-{num} when external_id present
1476
1523
  local branch="viban-$1"
1524
+ local _ext_id=$(get_ext_id "$1")
1525
+ if [[ -n "$_ext_id" && "$_ext_id" != "null" ]]; then
1526
+ local _issue_num="${_ext_id##*:}"
1527
+ if git -C "$repo_root" rev-parse --verify "issue-${_issue_num}" &>/dev/null 2>&1; then
1528
+ branch="issue-${_issue_num}"
1529
+ fi
1530
+ fi
1531
+
1477
1532
  if [[ -d "$wt_dir" ]]; then
1478
1533
  git -C "$repo_root" worktree remove "$wt_dir" --force 2>/dev/null
1479
1534
  git -C "$repo_root" branch -D "$branch" 2>/dev/null
package/commands/add.md CHANGED
@@ -4,78 +4,54 @@ description: "Register a problem as a viban issue"
4
4
 
5
5
  # /add - Register Issue
6
6
 
7
- Register a problem as a viban issue. Keep it lightweight — no codebase exploration, no heavy analysis.
7
+ Register a problem as a viban issue. No codebase exploration, no solutions — symptoms only.
8
8
 
9
- > **Principle**: Clarify symptoms only if vague. Don't explore code or propose solutions.
9
+ **Input**: `$ARGUMENTS`
10
10
 
11
- ## Input
11
+ ## Step 1: Clarify (only if vague)
12
12
 
13
- **User Input**: `$ARGUMENTS`
13
+ If clear enough (who/what/where), skip to Step 2. Otherwise, one AskUserQuestion:
14
+ - header: "Problem", question: "Can you describe the symptom more specifically?"
15
+ - options: context-appropriate (e.g. "Error/crash", "Feature not working", "Performance issue", "Let me describe")
14
16
 
15
- ## Step 1: Clarify (only if needed)
17
+ ## Step 2: Priority & Type
16
18
 
17
- If the user's description is **clear enough** to register (who/what/where), skip to Step 2.
19
+ Infer from description. Don't ask unless truly ambiguous.
18
20
 
19
- If **vague or ambiguous**, concretize with one AskUserQuestion:
21
+ | Priority | Condition | Type | When |
22
+ |----------|-----------|------|------|
23
+ | P0 | System down, data loss | bug | Something broken |
24
+ | P1 | Feature broken, errors | feat | New functionality |
25
+ | P2 | Performance, warnings | chore | Maintenance, config |
26
+ | P3 | Improvements, refactoring | refactor | Code restructuring |
20
27
 
21
- - header: "Problem"
22
- - question: "Can you describe the symptom more specifically?"
23
- - options based on context, e.g.:
24
- - "Error/crash on specific action"
25
- - "Feature not working as expected"
26
- - "Performance issue"
27
- - "Let me describe"
28
- - multiSelect: false
29
-
30
- Goal: get a **one-sentence symptom** clear enough for an assignee to understand.
31
-
32
- ## Step 2: Determine Priority & Type
33
-
34
- Infer from the description. Do NOT ask unless truly ambiguous.
35
-
36
- | Condition | Priority |
37
- |-----------|----------|
38
- | System down, data loss | P0 |
39
- | Feature broken, errors | P1 |
40
- | Performance, warnings | P2 |
41
- | Improvements, refactoring | P3 |
42
-
43
- | Type | When |
44
- |------|------|
45
- | bug | Something is broken |
46
- | feat | New functionality |
47
- | chore | Maintenance, config |
48
- | refactor | Code restructuring |
49
-
50
- ## Step 3: Check Workflow for Issue Numbering
28
+ ## Step 3: Issue Numbering
51
29
 
52
30
  ```bash
53
31
  [ -f ".viban/workflow.md" ] && cat ".viban/workflow.md"
54
32
  ```
55
33
 
56
- - If workflow says **Manual** issue numbering → ask user for an external ID (e.g. `PROJ-42`)
57
- - If workflow says **Auto** or no workflow exists → let viban auto-assign
58
- - If user provided a specific ID in `$ARGUMENTS` → use it regardless of workflow
34
+ - Workflow says **Manual** → ask user for external ID (e.g. `PROJ-42`)
35
+ - **Auto** or no workflow → let viban auto-assign
36
+ - ID in `$ARGUMENTS` → use it regardless
59
37
 
60
38
  ## Step 4: Register
61
39
 
62
- Write the description to a temp file, then register:
63
-
64
40
  ```bash
65
41
  cat > /tmp/viban-desc.md <<'VIBAN_EOF'
66
42
  ## Symptoms
67
- {concretized one-sentence symptom from Step 1}
68
- {additional context from user input, if any}
43
+ {one-sentence symptom}
44
+ {additional context, if any}
69
45
  VIBAN_EOF
70
46
 
71
47
  # Auto numbering (default)
72
48
  viban add "{title}" --desc-file /tmp/viban-desc.md --priority {priority} --type {type}
73
49
 
74
- # Manual numbering (when workflow specifies manual)
50
+ # Manual numbering (when workflow specifies)
75
51
  viban add "{title}" --desc-file /tmp/viban-desc.md --priority {priority} --type {type} --ext-id "{external_id}"
76
52
  ```
77
53
 
78
- **Why heredoc?** `<<'VIBAN_EOF'` prevents shell interpretation of backticks, `$`, etc.
54
+ Use `<<'VIBAN_EOF'` (quoted) to prevent shell interpretation.
79
55
 
80
56
  ## Step 5: Report
81
57
 
@@ -86,9 +62,38 @@ Issue #{id} registered
86
62
  Status: backlog
87
63
  ```
88
64
 
89
- ## Notes
65
+ ## Step 6: Suggest Plan Mode
66
+
67
+ **Skip** for trivial issues (typo, one-liner config, simple copy edit).
68
+ **Recommend** for everything else. Use AskUserQuestion:
69
+
70
+ - header: "Next step", question: "Want to start planning the solution now?"
71
+ - options:
72
+ - "Plan now (Recommended)" — Enter plan mode to analyze and design a solution
73
+ - "Later" — Just register, work on it later
74
+
75
+ **"Plan now"**: `EnterPlanMode` → after approval, save to `.viban/plans/{issue-id}.md`:
76
+
77
+ ```bash
78
+ mkdir -p .viban/plans
79
+ ```
80
+
81
+ ```markdown
82
+ # Plan: {issue title}
83
+ > Issue #{id} | {priority} | {type} | Created: {timestamp}
84
+
85
+ {full plan content}
86
+ ```
87
+
88
+ Report: `Plan saved to .viban/plans/{issue-id}.md — /viban:assign will auto-load it.`
89
+
90
+ **"Later"**: end skill.
91
+
92
+ > **Bias towards planning.** When in doubt, suggest plan mode.
93
+
94
+ ## Rules
90
95
 
91
- - **No codebase exploration**the assignee does that during `/viban:assign`
92
- - **No solution proposals**focus on symptoms only
93
- - **Check duplicates** before registering: `viban list`
94
- - **Don't over-prioritize** — P0 is system-down only
96
+ - No codebase exploration — assignee does that in `/viban:assign`
97
+ - No solution proposals — symptoms only
98
+ - Check duplicates first: `viban list`
99
+ - P0 is system-down only