sedd 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +140 -2
  2. package/commands/sedd.board.md +67 -0
  3. package/commands/sedd.clarify.md +86 -21
  4. package/commands/sedd.specify.md +27 -1
  5. package/dist/cli/board.d.ts +9 -0
  6. package/dist/cli/board.d.ts.map +1 -0
  7. package/dist/cli/board.js +211 -0
  8. package/dist/cli/board.js.map +1 -0
  9. package/dist/cli/clarify.d.ts +5 -1
  10. package/dist/cli/clarify.d.ts.map +1 -1
  11. package/dist/cli/clarify.js +52 -8
  12. package/dist/cli/clarify.js.map +1 -1
  13. package/dist/cli/index.js +31 -0
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/cli/setup-github.d.ts +5 -0
  16. package/dist/cli/setup-github.d.ts.map +1 -0
  17. package/dist/cli/setup-github.js +437 -0
  18. package/dist/cli/setup-github.js.map +1 -0
  19. package/dist/cli/specify.d.ts +1 -0
  20. package/dist/cli/specify.d.ts.map +1 -1
  21. package/dist/cli/specify.js +97 -9
  22. package/dist/cli/specify.js.map +1 -1
  23. package/dist/cli/status.d.ts.map +1 -1
  24. package/dist/cli/status.js +31 -0
  25. package/dist/cli/status.js.map +1 -1
  26. package/dist/cli/tasks.d.ts.map +1 -1
  27. package/dist/cli/tasks.js +102 -1
  28. package/dist/cli/tasks.js.map +1 -1
  29. package/dist/cli/update.d.ts.map +1 -1
  30. package/dist/cli/update.js +21 -0
  31. package/dist/cli/update.js.map +1 -1
  32. package/dist/core/board-manager.d.ts +65 -0
  33. package/dist/core/board-manager.d.ts.map +1 -0
  34. package/dist/core/board-manager.js +326 -0
  35. package/dist/core/board-manager.js.map +1 -0
  36. package/dist/index.d.ts +3 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +2 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/types/index.d.ts +117 -0
  41. package/dist/types/index.d.ts.map +1 -1
  42. package/dist/types/index.js +11 -0
  43. package/dist/types/index.js.map +1 -1
  44. package/dist/utils/github.d.ts +99 -0
  45. package/dist/utils/github.d.ts.map +1 -0
  46. package/dist/utils/github.js +488 -0
  47. package/dist/utils/github.js.map +1 -0
  48. package/package.json +61 -61
package/README.md CHANGED
@@ -179,9 +179,22 @@ Criar migration de follow-up? [Y/n]
179
179
  |---------|-----------|
180
180
  | `sedd init` | Inicializar SEDD no projeto |
181
181
  | `sedd specify <id> <name>` | Criar nova feature spec |
182
+ | `sedd specify <id> <name> --from-issue <url>` | Criar feature a partir de GitHub issue (baixa imagens) |
182
183
  | `sedd clarify` | Criar migration com decisões |
184
+ | `sedd clarify --from-issue <url>` | Pre-popular migration com dados de GitHub issue (baixa imagens) |
183
185
  | `sedd status` | Ver status atual |
186
+ | `sedd check` | Verificar estrutura e pre-requisitos |
187
+ | `sedd tasks <json>` | Adicionar tasks a migration atual |
188
+ | `sedd complete <task-id>` | Marcar task como concluida |
189
+ | `sedd estimate` | Estimar esforco da feature atual |
190
+ | `sedd validate` | Validar implementacao contra expectativa |
191
+ | `sedd board` | Kanban board no terminal |
184
192
  | `sedd update` | Atualizar templates e migrar features existentes |
193
+ | `sedd migrate` | Migrar specs legados para nova estrutura |
194
+ | `sedd github setup` | Configurar integracao com GitHub Projects |
195
+ | `sedd github status` | Ver status da integracao GitHub |
196
+ | `sedd github sync` | Forcar sync bidirecional com GitHub |
197
+ | `sedd github refresh` | Re-ler colunas do projeto GitHub |
185
198
 
186
199
  ## Slash Commands (AI)
187
200
 
@@ -194,6 +207,9 @@ Criar migration de follow-up? [Y/n]
194
207
  | `/sedd.dashboard` | Ver status atual de migrations e tasks |
195
208
  | `/sedd.estimate` | Estimar prazo e complexidade antes de começar |
196
209
  | `/sedd.validate` | Validar implementação contra expectativa |
210
+ | `/sedd.board` | Ver kanban board da feature |
211
+ | `/sedd.tasks` | Gerar tasks para migration |
212
+ | `/sedd.migrate` | Migrar specs legados |
197
213
 
198
214
  ---
199
215
 
@@ -318,12 +334,16 @@ Gaps: 1 encontrado
318
334
  .sedd/001-user-auth/
319
335
  ├── spec.md # Especificação + Expectativa
320
336
  ├── _meta.json # Metadados + expectation estruturada
337
+ ├── assets/ # Imagens baixadas de GitHub issues
338
+ │ ├── image-001.png
339
+ │ └── image-002.jpg
321
340
 
322
341
  ├── 001_timestamp/ # Migration 1
323
342
  │ ├── clarify.md # Discussão + DEVE/NÃO DEVE
324
343
  │ ├── decisions.md # Decisões
325
344
  │ ├── tasks.md # Tasks T001-XXX
326
- └── acceptance.md # Critérios positivos e negativos
345
+ ├── acceptance.md # Critérios positivos e negativos
346
+ │ └── assets/ # Imagens de --from-issue no clarify
327
347
 
328
348
  └── progress.md # Progresso + checkpoints + desvios
329
349
  ```
@@ -365,6 +385,114 @@ Pending tasks:
365
385
 
366
386
  ---
367
387
 
388
+ ## GitHub Integration
389
+
390
+ SEDD integra com GitHub Projects V2 para sincronizar tasks como issues e gerenciar status via kanban board.
391
+
392
+ ### Passo a passo
393
+
394
+ **1. Instalar GitHub CLI**
395
+
396
+ ```bash
397
+ # Windows
398
+ winget install GitHub.cli
399
+
400
+ # Mac
401
+ brew install gh
402
+
403
+ # Linux
404
+ sudo apt install gh
405
+ ```
406
+
407
+ **2. Autenticar**
408
+
409
+ ```bash
410
+ gh auth login
411
+ ```
412
+
413
+ Selecione as opcoes:
414
+ - `GitHub.com`
415
+ - `HTTPS`
416
+ - `Login with a web browser`
417
+
418
+ O terminal vai mostrar um codigo (ex: `XXXX-XXXX`). Copie o codigo no terminal e cole no navegador quando solicitado.
419
+
420
+ Verifique:
421
+ ```bash
422
+ gh auth status
423
+ ```
424
+
425
+ **3. Adicionar scope de projetos**
426
+
427
+ ```bash
428
+ gh auth refresh -s project
429
+ ```
430
+
431
+ O terminal vai mostrar outro codigo. Mesmo processo: copie no terminal e cole no navegador.
432
+
433
+ **4. Ter um GitHub Project**
434
+
435
+ Va em github.com > seu repo > Projects > New Project > Board.
436
+ Crie colunas como: Todo, In Progress, Done.
437
+
438
+ **5. Configurar SEDD**
439
+
440
+ ```bash
441
+ sedd github setup
442
+ ```
443
+
444
+ O setup interativo vai:
445
+ - Detectar seu repositorio
446
+ - Listar suas organizacoes e conta pessoal
447
+ - Permitir escolher o owner dos projetos
448
+ - Listar projetos disponiveis
449
+ - Mapear colunas do board
450
+
451
+ ### Comandos GitHub
452
+
453
+ | Comando | Descricao |
454
+ |---------|-----------|
455
+ | `sedd github setup` | Configuracao interativa |
456
+ | `sedd github status` | Ver config e testar conexao |
457
+ | `sedd github sync` | Forcar sync bidirecional |
458
+ | `sedd github refresh` | Re-ler colunas se mudaram no GitHub |
459
+ | `sedd board` | Kanban board no terminal |
460
+
461
+ ### Funcionalidades
462
+
463
+ - Use `--from-issue <url>` no `sedd specify` ou `sedd clarify` para criar features/migrations a partir de GitHub issues
464
+ - Imagens da issue sao baixadas automaticamente para `assets/` e os links reescritos para paths relativos, permitindo que a AI veja o conteudo visual
465
+ - Use `sedd board` para visualizar o kanban no terminal
466
+ - Multi-org: escolha entre suas organizacoes e conta pessoal durante o setup
467
+
468
+ ### From Issue com Download de Imagens
469
+
470
+ Ao usar `--from-issue`, o SEDD automaticamente:
471
+
472
+ 1. Busca titulo, body e labels da issue
473
+ 2. Detecta imagens no body (`.png`, `.jpg`, `.gif`, `.webp`, `.svg` e `github.com/user-attachments`)
474
+ 3. Baixa cada imagem para `assets/` dentro do diretorio da feature/migration
475
+ 4. Reescreve os links markdown para paths relativos (`./assets/image-001.png`)
476
+
477
+ ```bash
478
+ sedd specify 042 from-issue --from-issue https://github.com/org/repo/issues/42
479
+
480
+ ✓ Issue #42: Add dark mode toggle
481
+ ✓ Downloaded 3 images to assets/
482
+ ```
483
+
484
+ Resultado no `spec.md`:
485
+ ```markdown
486
+ ![screenshot](./assets/image-001.png)
487
+ ![mockup](./assets/image-002.png)
488
+ ```
489
+
490
+ Isso permite que a AI veja o conteudo visual das imagens via Read tool, em vez de apenas a URL como texto.
491
+
492
+ Se o download de alguma imagem falhar, o link original e mantido.
493
+
494
+ ---
495
+
368
496
  ## Configuração
369
497
 
370
498
  `sedd.config.json`:
@@ -373,7 +501,17 @@ Pending tasks:
373
501
  {
374
502
  "specsDir": ".sedd",
375
503
  "branchPattern": "{{id}}-{{name}}",
376
- "scriptRunner": "auto"
504
+ "scriptRunner": "auto",
505
+ "github": {
506
+ "engine": "both",
507
+ "owner": "user",
508
+ "repo": "my-project",
509
+ "project": {
510
+ "projectNumber": 3,
511
+ "projectId": "PVT_...",
512
+ "title": "My Kanban"
513
+ }
514
+ }
377
515
  }
378
516
  ```
379
517
 
@@ -0,0 +1,67 @@
1
+ # /sedd.board — View Kanban Board
2
+
3
+ ## Purpose
4
+ Display the kanban board for the current feature, showing task status across columns (Todo, In Progress, Done). Provides WIP limit warnings and suggests the next task to work on.
5
+
6
+ ## When to Use
7
+ - To visualize the current state of tasks in a feature migration
8
+ - To check WIP limits and flow health
9
+ - To see suggestions for what to work on next
10
+ - To sync task status with GitHub Projects
11
+
12
+ ## Pre-flight Checks
13
+ 1. Must be in a SEDD project (`.sedd/` directory exists)
14
+ 2. Must have at least one feature with tasks
15
+ 3. For GitHub sync: `sedd.config.json` must have `github.engine` set to `github` or `both`
16
+
17
+ ## Commands
18
+
19
+ ### View current feature board
20
+ ```bash
21
+ sedd board
22
+ ```
23
+
24
+ ### View all feature boards
25
+ ```bash
26
+ sedd board --all
27
+ ```
28
+
29
+ ### JSON output (for programmatic use)
30
+ ```bash
31
+ sedd board --json
32
+ ```
33
+
34
+ ### Move a task to a different column
35
+ ```bash
36
+ sedd board --move T001-001 "In Progress"
37
+ sedd board --move T001-002 "Done"
38
+ ```
39
+
40
+ ### Sync board with GitHub
41
+ ```bash
42
+ sedd board --sync
43
+ ```
44
+
45
+ ## Board Layout
46
+ ```
47
+ Kanban: 001-my-feature (Migration 003)
48
+
49
+ Todo [2/5] In Progress [1/3] Done [4]
50
+ ───────────── ───────────── ─────────
51
+ T003-004 Setup DB T003-002 Auth API T003-001 Init
52
+ T003-005 Tests T003-003 Schema
53
+
54
+ WIP: OK
55
+ Next: T003-004 "Setup DB" (Next in queue)
56
+ ```
57
+
58
+ ## Workflow
59
+ 1. Run `/sedd.board` to see current status
60
+ 2. When starting a task: `sedd board --move T001-001 "In Progress"`
61
+ 3. When completing a task: `sedd complete T001-001` (auto-moves to Done)
62
+ 4. If using GitHub: `sedd board --sync` to push changes to the project board
63
+
64
+ ## Notes
65
+ - Works in local mode (no GitHub) by reading tasks.md directly
66
+ - WIP limits are optional, configured via `sedd github setup`
67
+ - Suggestions use a Lean algorithm: prioritize finishing in-progress work, then pick the next task in queue
@@ -51,26 +51,67 @@ User runs `/sedd.clarify`
51
51
  - Every migration has tasks.md (generated at the end)
52
52
  - Tasks reference this migration ID
53
53
 
54
+ ⚠️ **ANNOTATE EVERYTHING - TUDO VIRA TASK**
55
+ - Cada ponto do usuario → anotar como fonte de task
56
+ - Cada sugestao da AI aceita → anotar como fonte de task
57
+ - Cada decisao tomada → anotar implicacoes como fontes de task
58
+ - Cada edge case levantado → anotar como fonte de task
59
+ - Formato: **[TASK_SOURCE:{tipo}]** antes de cada ponto anotado
60
+ - Tipos: user-req, ai-suggestion, decision, edge-case, constraint
61
+
54
62
  ## Workflow
55
63
 
56
- ### Step 1: Capture Expected Outcome (FIRST - MANDATORY)
64
+ ### Step 1: Load Context PRIMEIRO
57
65
 
58
- **ANTES DE QUALQUER COISA**, pergunte ao usuário:
66
+ Read from feature root:
67
+ - spec.md (especialmente `## Expectation` e user stories)
68
+ - interfaces.ts (entidades)
69
+ - _meta.json (expectation do specify)
70
+ - Previous migrations (if any)
59
71
 
60
- ```
61
- 🎯 Qual é sua EXPECTATIVA para esta clarificação?
72
+ ### Step 1.5: Suggest Expectations (PROACTIVE)
62
73
 
63
- O que você espera ter funcionando ao final desta migration?
64
- (Isso será usado para validar se as tasks cobrem seu objetivo)
65
- ```
74
+ Com base no contexto carregado, AI DEVE:
75
+
76
+ 1. Apresentar a expectativa original da spec:
77
+ > "Expectativa original (da spec): {quote}"
78
+
79
+ 2. SUGERIR expectativas adicionais para esta migration baseado em:
80
+ - User stories nao cobertas por migrations anteriores
81
+ - Edge cases identificados nas interfaces
82
+ - Dependencias entre entidades
83
+ - Potenciais problemas de performance/seguranca
84
+ - Gaps entre a expectativa original e o que ja foi implementado
85
+
86
+ 3. Apresentar assim:
87
+ ```
88
+ Com base na spec e no que ja temos, sugiro para esta migration:
89
+
90
+ DEVE:
91
+ - [sugestao 1 baseada na spec]
92
+ - [sugestao 2 baseada em edge case]
93
+ - [sugestao 3 baseada em dependencia]
94
+
95
+ NAO DEVE:
96
+ - [restricao identificada]
97
+
98
+ Potenciais que identifiquei:
99
+ - [concern 1]
100
+ - [concern 2]
101
+
102
+ Quer acrescentar algo? Quer que eu veja outro potencial?
103
+ ```
104
+
105
+ 4. Aguardar usuario confirmar, ajustar, ou adicionar
106
+ 5. SO ENTAO consolidar expectativa final (summary + must + mustNot)
66
107
 
67
108
  Save in `clarify.md` under `## Expected Outcome` section (NO TOPO).
68
109
 
69
- **NÃO PROSSIGA** sem a expectativa do usuário.
110
+ **NÃO PROSSIGA** sem a expectativa do usuário confirmada.
70
111
 
71
- ### Step 1.5: Detail MUST and MUST NOT (STRUCTURED EXPECTATION)
112
+ ### Step 2: Detail MUST and MUST NOT (STRUCTURED EXPECTATION)
72
113
 
73
- Após capturar o resumo da expectativa, detalhar com regras claras:
114
+ Após consolidar as expectativas (originais + sugeridas + usuario), detalhar com regras claras:
74
115
 
75
116
  ```
76
117
  Agora vamos detalhar sua expectativa:
@@ -111,13 +152,6 @@ Save in `clarify.md` under `## Expectation Details`:
111
152
  }
112
153
  ```
113
154
 
114
- ### Step 2: Load Context
115
-
116
- Read from feature root:
117
- - spec.md (especialmente a seção Expectation original)
118
- - interfaces.ts
119
- - Previous migrations (if any)
120
-
121
155
  ### Step 3: Create New Migration Folder
122
156
 
123
157
  Generate new migration folder:
@@ -199,9 +233,10 @@ When user provides information (not a command):
199
233
  "O sistema precisa suportar múltiplos tenants, cada um com suas próprias configurações..."
200
234
 
201
235
  **Key Points Extracted:**
202
- - Multi-tenant architecture required
203
- - Per-tenant configuration
204
- - Isolation between tenants
236
+ - **[TASK_SOURCE:user-req]** Multi-tenant architecture required
237
+ - **[TASK_SOURCE:user-req]** Per-tenant configuration
238
+ - **[TASK_SOURCE:ai-suggestion]** Isolation strategy needs definition
239
+ - **[TASK_SOURCE:edge-case]** Cross-tenant data leaks prevention
205
240
 
206
241
  ---
207
242
  ```
@@ -274,7 +309,14 @@ Proceed to Step 6 (Generate Tasks).
274
309
 
275
310
  ### Step 6: Generate tasks.md (After All Q&A Complete)
276
311
 
277
- Based on all decisions, create tasks:
312
+ Ao gerar tasks, VARRER clarify.md por TODOS os `[TASK_SOURCE:*]` tags:
313
+ - Cada tag com tipo `user-req` → task obrigatoria
314
+ - Cada tag com tipo `ai-suggestion` (aceita) → task obrigatoria
315
+ - Cada tag com tipo `decision` → task para implementar decisao
316
+ - Cada tag com tipo `edge-case` → task de validacao/protecao
317
+ - Cada tag com tipo `constraint` → task de teste negativo
318
+
319
+ Based on all decisions and TASK_SOURCE tags, create tasks:
278
320
 
279
321
  ```markdown
280
322
  # Tasks - Migration 001
@@ -593,6 +635,9 @@ For automated workflows, use the SEDD CLI:
593
635
  # Create new migration (creates clarify.md, tasks.md, decisions.md)
594
636
  sedd clarify
595
637
 
638
+ # Create migration pre-populated from a GitHub issue
639
+ sedd clarify --from-issue https://github.com/owner/repo/issues/42
640
+
596
641
  # Add tasks to current migration
597
642
  sedd tasks '[{"story":"US1","description":"Task description"}]'
598
643
 
@@ -603,4 +648,24 @@ sedd complete T001-001
603
648
  sedd status
604
649
  ```
605
650
 
651
+ **Options:**
652
+ - `--from-issue <url>` - Pre-populate clarify.md with context from a GitHub issue
653
+
654
+ ### --from-issue Flow
655
+
656
+ When `--from-issue` is provided:
657
+
658
+ 1. Fetches issue title and body from GitHub
659
+ 2. **Downloads images** from the issue body to `{migration}/assets/` and rewrites links to relative paths (e.g. `./assets/image-001.png`), so the AI can see the visual content via Read tool
660
+ 3. Pre-populates `clarify.md` with:
661
+ - `## Context (from GitHub Issue #N)` containing the issue body (with local image paths)
662
+ - `## Expected Outcome` set to the issue title
663
+ 4. Links migration to the issue in `.github-sync.json`
664
+ 5. Comments on the issue: "SEDD migration {id} started from this issue"
665
+
666
+ Supported image formats: `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.svg`, and any `github.com/user-attachments` URL.
667
+ If a download fails, the original URL link is kept.
668
+
669
+ **Requires:** `gh` CLI installed and authenticated. GitHub integration (`sedd github setup`) needed for board/comment features.
670
+
606
671
  Scripts also available in `.sedd/scripts/powershell/` and `.sedd/scripts/bash/`.
@@ -20,7 +20,11 @@ User runs `/sedd.specify "feature description"` or `/sedd.specify` (interactive)
20
20
 
21
21
  3. **Check for existing feature branch**
22
22
  - If on feature branch (###-name): use existing feature
23
- - If not: create new feature
23
+ - If on master/main or outra branch nao-feature:
24
+ 1. Determinar proximo feature ID (buscar maior ###- nas branches + 1)
25
+ 2. Criar branch `{id}-{nome}` com `git checkout -b {id}-{nome}`
26
+ 3. Confirmar: "Criei a branch {id}-{nome} e ja estou nela"
27
+ 4. SO ENTAO prosseguir com criacao da estrutura
24
28
 
25
29
  ## Configuration
26
30
 
@@ -189,6 +193,9 @@ sedd specify 024 dark-mode-toggle -d "Add dark mode support"
189
193
  # Create with expectation (recommended)
190
194
  sedd specify 024 dark-mode-toggle -d "Add dark mode support" -e "User can toggle dark mode"
191
195
 
196
+ # Create from GitHub issue (reads title, body, labels)
197
+ sedd specify 042 from-issue --from-issue https://github.com/owner/repo/issues/42
198
+
192
199
  # Check structure
193
200
  sedd check
194
201
 
@@ -199,5 +206,24 @@ sedd status
199
206
  **Options:**
200
207
  - `-d, --description` - Feature description
201
208
  - `-e, --expectation` - Expected outcome (used for alignment verification)
209
+ - `--from-issue <url>` - Create feature from a GitHub issue URL
210
+
211
+ ### --from-issue Flow
212
+
213
+ When `--from-issue` is provided:
214
+
215
+ 1. Fetches issue title, body, and labels from GitHub
216
+ 2. Uses issue title as feature name (if feature-name is `from-issue` or `_`)
217
+ 3. Extracts acceptance criteria from issue body (if present)
218
+ 4. Creates branch, spec.md, interfaces.ts, _meta.json
219
+ 5. **Downloads images** from the issue body to `assets/` and rewrites links to relative paths (e.g. `./assets/image-001.png`), so the AI can see the visual content via Read tool
220
+ 6. Saves `sourceIssue` in `_meta.json` (permanent link)
221
+ 7. Moves issue to "In Progress" on the GitHub project board
222
+ 8. Comments on the issue: "SEDD feature created from this issue"
223
+
224
+ Supported image formats: `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.svg`, and any `github.com/user-attachments` URL.
225
+ If a download fails, the original URL link is kept.
226
+
227
+ **Requires:** `gh` CLI installed and authenticated. GitHub integration (`sedd github setup`) needed for board/comment features.
202
228
 
203
229
  Scripts also available in `.sedd/scripts/powershell/sedd-specify.ps1` and `.sedd/scripts/bash/sedd-specify.sh`.
@@ -0,0 +1,9 @@
1
+ interface BoardOptions {
2
+ all?: boolean;
3
+ json?: boolean;
4
+ move?: string;
5
+ sync?: boolean;
6
+ }
7
+ export declare function board(options?: BoardOptions): Promise<void>;
8
+ export {};
9
+ //# sourceMappingURL=board.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board.d.ts","sourceRoot":"","sources":["../../src/cli/board.ts"],"names":[],"mappings":"AAQA,UAAU,YAAY;IACpB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+FrE"}
@@ -0,0 +1,211 @@
1
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import chalk from 'chalk';
4
+ import inquirer from 'inquirer';
5
+ import { loadConfig } from '../types/index.js';
6
+ import { GitOperations } from '../utils/git.js';
7
+ import { BoardManager } from '../core/board-manager.js';
8
+ export async function board(options = {}) {
9
+ const cwd = process.cwd();
10
+ const config = loadConfig(cwd);
11
+ const git = new GitOperations(cwd);
12
+ const bm = new BoardManager(config, cwd);
13
+ const specsDir = join(cwd, config.specsDir);
14
+ if (!existsSync(specsDir)) {
15
+ console.log(chalk.yellow('No specs directory found. Run "sedd init" first.'));
16
+ return;
17
+ }
18
+ if (options.move) {
19
+ const args = process.argv;
20
+ const moveIdx = args.indexOf('--move');
21
+ const taskId = args[moveIdx + 1];
22
+ const targetColumn = args[moveIdx + 2];
23
+ if (!taskId || !targetColumn) {
24
+ console.log(chalk.red('Usage: sedd board --move <task-id> "<column>"'));
25
+ return;
26
+ }
27
+ const { featureDir, meta } = getFeatureContext(cwd, config, git);
28
+ if (!featureDir || !meta)
29
+ return;
30
+ const success = bm.moveTask(featureDir, meta, taskId, targetColumn);
31
+ if (!success) {
32
+ console.log(chalk.red(`Failed to move ${taskId}`));
33
+ return;
34
+ }
35
+ console.log(chalk.green(`✓ Moved ${taskId} to "${targetColumn}"`));
36
+ if (bm.isGitHubEnabled()) {
37
+ const autoSync = config.github?.autoSync || 'ask';
38
+ if (autoSync === 'off')
39
+ return;
40
+ if (autoSync === 'ask') {
41
+ const { shouldSync } = await inquirer.prompt([{
42
+ type: 'confirm',
43
+ name: 'shouldSync',
44
+ message: 'Sync this change to GitHub?',
45
+ default: true,
46
+ }]);
47
+ if (!shouldSync)
48
+ return;
49
+ }
50
+ const result = bm.syncToGitHub(featureDir, meta);
51
+ if (result.moved > 0 || result.synced > 0) {
52
+ console.log(chalk.green(`✓ Synced to GitHub`));
53
+ }
54
+ }
55
+ return;
56
+ }
57
+ if (options.sync) {
58
+ const { featureDir, meta } = getFeatureContext(cwd, config, git);
59
+ if (!featureDir || !meta)
60
+ return;
61
+ if (!bm.isGitHubEnabled()) {
62
+ console.log(chalk.yellow('GitHub sync not enabled. Run "sedd github setup" first.'));
63
+ return;
64
+ }
65
+ console.log(chalk.cyan('Syncing board with GitHub...'));
66
+ const result = bm.syncToGitHub(featureDir, meta);
67
+ console.log(chalk.green(`✓ Synced: ${result.synced} | Created: ${result.created} | Moved: ${result.moved}`));
68
+ if (result.errors.length > 0) {
69
+ result.errors.forEach(e => console.log(chalk.yellow(` ⚠ ${e}`)));
70
+ }
71
+ return;
72
+ }
73
+ if (options.all) {
74
+ showAllBoards(cwd, config, bm, options.json);
75
+ }
76
+ else {
77
+ const { featureDir, meta } = getFeatureContext(cwd, config, git);
78
+ if (!featureDir || !meta)
79
+ return;
80
+ const boardStatus = bm.getBoard(featureDir, meta);
81
+ if (!boardStatus) {
82
+ console.log(chalk.yellow('No active migration with tasks. Run "sedd clarify" then "sedd tasks" first.'));
83
+ return;
84
+ }
85
+ if (options.json) {
86
+ console.log(JSON.stringify(boardStatus, null, 2));
87
+ return;
88
+ }
89
+ renderBoard(boardStatus, bm, config);
90
+ }
91
+ }
92
+ function getFeatureContext(cwd, config, git) {
93
+ const specsDir = join(cwd, config.specsDir);
94
+ let currentFeature = null;
95
+ if (git.hasGit()) {
96
+ const branch = git.getCurrentBranch();
97
+ if (git.isFeatureBranch(branch)) {
98
+ const featureDir = join(specsDir, branch);
99
+ if (existsSync(featureDir)) {
100
+ currentFeature = branch;
101
+ }
102
+ }
103
+ }
104
+ if (!currentFeature) {
105
+ const features = readdirSync(specsDir, { withFileTypes: true })
106
+ .filter(d => d.isDirectory() && /^\d{3}-/.test(d.name))
107
+ .map(d => d.name)
108
+ .sort()
109
+ .reverse();
110
+ if (features.length > 0) {
111
+ currentFeature = features[0];
112
+ }
113
+ }
114
+ if (!currentFeature) {
115
+ console.log(chalk.yellow('No features found.'));
116
+ return { featureDir: null, meta: null };
117
+ }
118
+ const featureDir = join(specsDir, currentFeature);
119
+ const metaPath = join(featureDir, '_meta.json');
120
+ if (!existsSync(metaPath)) {
121
+ console.log(chalk.yellow(`No _meta.json for feature ${currentFeature}`));
122
+ return { featureDir: null, meta: null };
123
+ }
124
+ const meta = JSON.parse(readFileSync(metaPath, 'utf-8'));
125
+ return { featureDir, meta };
126
+ }
127
+ function showAllBoards(cwd, config, bm, json) {
128
+ const specsDir = join(cwd, config.specsDir);
129
+ const features = readdirSync(specsDir, { withFileTypes: true })
130
+ .filter(d => d.isDirectory() && /^\d{3}-/.test(d.name))
131
+ .map(d => d.name)
132
+ .sort();
133
+ if (features.length === 0) {
134
+ console.log(chalk.yellow('No features found.'));
135
+ return;
136
+ }
137
+ const allBoards = [];
138
+ for (const feature of features) {
139
+ const featureDir = join(specsDir, feature);
140
+ const metaPath = join(featureDir, '_meta.json');
141
+ if (!existsSync(metaPath))
142
+ continue;
143
+ const meta = JSON.parse(readFileSync(metaPath, 'utf-8'));
144
+ const boardStatus = bm.getBoard(featureDir, meta);
145
+ if (boardStatus) {
146
+ allBoards.push(boardStatus);
147
+ }
148
+ }
149
+ if (json) {
150
+ console.log(JSON.stringify(allBoards, null, 2));
151
+ return;
152
+ }
153
+ if (allBoards.length === 0) {
154
+ console.log(chalk.yellow('No active boards found.'));
155
+ return;
156
+ }
157
+ for (const boardStatus of allBoards) {
158
+ renderBoard(boardStatus, bm, config);
159
+ console.log('');
160
+ }
161
+ }
162
+ function renderBoard(boardStatus, bm, config) {
163
+ console.log(chalk.cyan.bold(`\nKanban: ${boardStatus.featureName} (Migration ${boardStatus.migrationId})\n`));
164
+ const colWidth = 22;
165
+ const headers = boardStatus.columns.map(col => {
166
+ const countStr = col.wipLimit
167
+ ? `[${col.tasks.length}/${col.wipLimit}]`
168
+ : `[${col.tasks.length}]`;
169
+ const header = `${col.name} ${countStr}`;
170
+ return header.padEnd(colWidth);
171
+ });
172
+ console.log(chalk.bold(headers.join(' ')));
173
+ const separators = boardStatus.columns.map(() => '─'.repeat(colWidth));
174
+ console.log(chalk.gray(separators.join(' ')));
175
+ const maxRows = Math.max(...boardStatus.columns.map(c => c.tasks.length));
176
+ for (let i = 0; i < maxRows; i++) {
177
+ const cells = boardStatus.columns.map(col => {
178
+ const task = col.tasks[i];
179
+ if (!task)
180
+ return ' '.repeat(colWidth);
181
+ const text = `${task.id} ${truncate(task.description, colWidth - task.id.length - 2)}`;
182
+ return text.padEnd(colWidth);
183
+ });
184
+ console.log(cells.join(' '));
185
+ }
186
+ if (maxRows === 0) {
187
+ console.log(chalk.gray(' (no tasks)'));
188
+ }
189
+ const violations = bm.checkWipLimits(boardStatus);
190
+ if (violations.length > 0) {
191
+ console.log('');
192
+ for (const v of violations) {
193
+ console.log(chalk.red(`⚠ WIP: "${v.column}" has ${v.current}/${v.limit} items`));
194
+ }
195
+ }
196
+ else {
197
+ console.log(chalk.gray('\nWIP: OK'));
198
+ }
199
+ const suggestions = bm.suggestNext(boardStatus);
200
+ if (suggestions.length > 0) {
201
+ const top = suggestions[0];
202
+ console.log(chalk.cyan(`Next: ${top.taskId} "${truncate(top.description, 40)}" (${top.reason})`));
203
+ }
204
+ }
205
+ function truncate(str, maxLen) {
206
+ const clean = str.replace(/\[[\w-]+\]\s*/g, '');
207
+ if (clean.length <= maxLen)
208
+ return clean;
209
+ return clean.substring(0, maxLen - 3) + '...';
210
+ }
211
+ //# sourceMappingURL=board.js.map