@noclaf/cli 0.6.0 → 0.8.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.
- package/README.md +22 -1
- package/dist/adapters/supabase/calendar-gateway.js +48 -0
- package/dist/adapters/supabase/calendar-gateway.js.map +1 -0
- package/dist/adapters/supabase/calendar-write-gateway.js +35 -0
- package/dist/adapters/supabase/calendar-write-gateway.js.map +1 -0
- package/dist/adapters/supabase/checklist-gateway.js +63 -0
- package/dist/adapters/supabase/checklist-gateway.js.map +1 -0
- package/dist/adapters/supabase/gateway.js +10 -0
- package/dist/adapters/supabase/gateway.js.map +1 -1
- package/dist/adapters/supabase/release-gateway.js +61 -0
- package/dist/adapters/supabase/release-gateway.js.map +1 -0
- package/dist/adapters/supabase/sprint-gateway.js +59 -0
- package/dist/adapters/supabase/sprint-gateway.js.map +1 -0
- package/dist/adapters/supabase/task-gateway.js +36 -33
- package/dist/adapters/supabase/task-gateway.js.map +1 -1
- package/dist/core/types.js +4 -6
- package/dist/core/types.js.map +1 -1
- package/dist/lib/calendar-logic.js +59 -0
- package/dist/lib/calendar-logic.js.map +1 -0
- package/dist/lib/calendar-write-logic.js +6 -0
- package/dist/lib/calendar-write-logic.js.map +1 -0
- package/dist/lib/checklist-logic.js +5 -0
- package/dist/lib/checklist-logic.js.map +1 -0
- package/dist/lib/dates.js +21 -0
- package/dist/lib/dates.js.map +1 -0
- package/dist/lib/pg-error.js +4 -0
- package/dist/lib/pg-error.js.map +1 -1
- package/dist/lib/release-logic.js +10 -0
- package/dist/lib/release-logic.js.map +1 -0
- package/dist/lib/sprint-logic.js +31 -0
- package/dist/lib/sprint-logic.js.map +1 -0
- package/dist/tools/activate-sprint.js +44 -0
- package/dist/tools/activate-sprint.js.map +1 -0
- package/dist/tools/add-checklist-item.js +44 -0
- package/dist/tools/add-checklist-item.js.map +1 -0
- package/dist/tools/add-holiday.js +41 -0
- package/dist/tools/add-holiday.js.map +1 -0
- package/dist/tools/add-home-office.js +31 -0
- package/dist/tools/add-home-office.js.map +1 -0
- package/dist/tools/add-vacation.js +39 -0
- package/dist/tools/add-vacation.js.map +1 -0
- package/dist/tools/create-release.js +46 -0
- package/dist/tools/create-release.js.map +1 -0
- package/dist/tools/create-sprint.js +66 -0
- package/dist/tools/create-sprint.js.map +1 -0
- package/dist/tools/create-task.js +26 -8
- package/dist/tools/create-task.js.map +1 -1
- package/dist/tools/end-sprint.js +37 -0
- package/dist/tools/end-sprint.js.map +1 -0
- package/dist/tools/finalize-release.js +45 -0
- package/dist/tools/finalize-release.js.map +1 -0
- package/dist/tools/get-calendar.js +40 -0
- package/dist/tools/get-calendar.js.map +1 -0
- package/dist/tools/get-sprint.js +38 -0
- package/dist/tools/get-sprint.js.map +1 -0
- package/dist/tools/get-task.js +1 -0
- package/dist/tools/get-task.js.map +1 -1
- package/dist/tools/index.js +42 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/list-releases.js +32 -0
- package/dist/tools/list-releases.js.map +1 -0
- package/dist/tools/list-sprints.js +30 -0
- package/dist/tools/list-sprints.js.map +1 -0
- package/dist/tools/list-tasks.js +18 -16
- package/dist/tools/list-tasks.js.map +1 -1
- package/dist/tools/remove-checklist-item.js +42 -0
- package/dist/tools/remove-checklist-item.js.map +1 -0
- package/dist/tools/remove-checklist.js +42 -0
- package/dist/tools/remove-checklist.js.map +1 -0
- package/dist/tools/remove-holiday.js +31 -0
- package/dist/tools/remove-holiday.js.map +1 -0
- package/dist/tools/remove-home-office.js +32 -0
- package/dist/tools/remove-home-office.js.map +1 -0
- package/dist/tools/remove-vacation.js +31 -0
- package/dist/tools/remove-vacation.js.map +1 -0
- package/dist/tools/sprint-common.js +13 -0
- package/dist/tools/sprint-common.js.map +1 -0
- package/dist/tools/update-checklist-item.js +51 -0
- package/dist/tools/update-checklist-item.js.map +1 -0
- package/dist/tools/update-release.js +58 -0
- package/dist/tools/update-release.js.map +1 -0
- package/dist/tools/update-sprint.js +56 -0
- package/dist/tools/update-sprint.js.map +1 -0
- package/dist/tools/update-task.js +46 -31
- package/dist/tools/update-task.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -92,30 +92,51 @@ Operações do MCP, com o nome **sem o prefixo** (declarado por grupo — o pref
|
|
|
92
92
|
`src/brand.ts`). Tabela gerada da fonte por `bun run gen:docs`.
|
|
93
93
|
|
|
94
94
|
<!-- TOOLS:START -->
|
|
95
|
-
<!-- gerado por `bun run gen:docs` — não edite à mão.
|
|
95
|
+
<!-- gerado por `bun run gen:docs` — não edite à mão. 44 tools. -->
|
|
96
96
|
|
|
97
97
|
### Tools de produto — prefixo `nos_`
|
|
98
98
|
|
|
99
99
|
| Operação | O que faz |
|
|
100
100
|
| --- | --- |
|
|
101
|
+
| `activate_sprint` | Reativa uma sprint: encerra qualquer outra ativa do projeto (tasks não concluídas voltam pro backlog) e reabre a escolhida com status "ativa", start_date = hoje e end_date = null (como a UI). |
|
|
101
102
|
| `add_checklist` | Cria uma checklist nomeada (com itens) numa tarefa — a checklist nativa que aparece clicável na UI, melhor que enfiar um DoD no texto da descrição. |
|
|
103
|
+
| `add_checklist_item` | Adiciona um item desmarcado ao fim de uma checklist existente. |
|
|
104
|
+
| `add_holiday` | Cria feriado no calendário do time (só admin/gerente). |
|
|
105
|
+
| `add_home_office` | Marca home office do PRÓPRIO usuário num dia (o banco pode recusar por limite mensal). |
|
|
106
|
+
| `add_vacation` | Registra férias de um usuário no calendário do time (só admin/gerente). |
|
|
102
107
|
| `attach_pr` | Anexa a URL de um pull request a uma tarefa e a coloca em review: grava `pr_url`, seta `review_state=pending` e move o status pra `code_review`. |
|
|
103
108
|
| `comment_task` | Adiciona um comentário em uma tarefa. |
|
|
109
|
+
| `create_release` | Cria uma release (status planning) no projeto. |
|
|
110
|
+
| `create_sprint` | Cria uma sprint já ATIVA. |
|
|
104
111
|
| `create_task` | Cria uma nova tarefa no projeto atual. |
|
|
105
112
|
| `end_allocation` | [ENCERRA O DIA] Bate ponto de SAÍDA do usuário e fecha qualquer task_allocation aberta. |
|
|
113
|
+
| `end_sprint` | Encerra a sprint: tasks fora de done/production saem da sprint e voltam pro backlog; done/production ficam. |
|
|
106
114
|
| `end_task_allocation` | [PARA TIMER DE TASK] Para a task_allocation ativa. |
|
|
115
|
+
| `finalize_release` | Finaliza a release: status delivered + delivered_at. |
|
|
107
116
|
| `get_active_allocation` | Retorna o estado atual de cronometragem do usuário: alocação ativa, task atual sendo cronometrada, e segmentos por task na alocação atual. |
|
|
117
|
+
| `get_calendar` | Calendário pessoal: só os dias com eventos (feriados, meus prazos, férias, home office, releases, aniversários e tempo de casa). |
|
|
108
118
|
| `get_context` | Retorna o contexto completo do projeto NOS ativo: dados do projeto, repositórios, sprint ativa, membros e usuário autenticado. |
|
|
119
|
+
| `get_sprint` | Detalha uma sprint: contagem de tasks por status e tasks vencidas (end_date < hoje e fora de done/production), com key/title/end_date. |
|
|
109
120
|
| `get_task` | Retorna detalhes completos de uma tarefa: descrição, assignees, checklist, comentários, histórico recente, repositórios vinculados e labels. |
|
|
110
121
|
| `list_my_allocations` | Lista alocações passadas do usuário (encerradas), ordenadas por data decrescente. |
|
|
111
122
|
| `list_projects` | Lista os projetos do NOS aos quais você tem acesso. |
|
|
123
|
+
| `list_releases` | Lista as releases do projeto (id, name, status, target_date, delivered_at). |
|
|
124
|
+
| `list_sprints` | Lista as sprints do projeto (ativa e encerradas) com status e datas, mais recentes primeiro. |
|
|
112
125
|
| `list_tasks` | Lista tarefas do projeto atual, filtradas pelos parâmetros opcionais. |
|
|
113
126
|
| `move_task` | Atalho pra mudar o status de uma tarefa (move entre colunas do Kanban). |
|
|
114
127
|
| `record_delivery` | Registra uma ENTREGA do loop de build (um ticket concluído / PR aberto) na analítica de entrega do NOS. |
|
|
128
|
+
| `remove_checklist` | Remove uma checklist inteira (os itens vão junto). |
|
|
129
|
+
| `remove_checklist_item` | Remove um item de checklist. |
|
|
130
|
+
| `remove_holiday` | Exclui feriado pelo id (só admin/gerente). |
|
|
131
|
+
| `remove_home_office` | Remove home office do PRÓPRIO usuário num dia. |
|
|
132
|
+
| `remove_vacation` | Exclui férias pelo id (só admin/gerente). |
|
|
115
133
|
| `set_project` | Define o projeto ativo da sessão (em memória, dura enquanto o servidor estiver rodando). |
|
|
116
134
|
| `set_review` | Registra o veredito de um review no ticket: seta `tasks.review_state`. |
|
|
117
135
|
| `start_allocation` | Inicia uma alocação (bate o ponto) para o usuário atual. |
|
|
118
136
|
| `start_task_allocation` | Começa a cronometrar tempo numa task específica. |
|
|
137
|
+
| `update_checklist_item` | Marca/desmarca (checked) e/ou edita o texto (text) de um item de checklist. |
|
|
138
|
+
| `update_release` | Edita uma release: name, target_date, description e/ou status (planning\|in_progress\|cancelled). |
|
|
139
|
+
| `update_sprint` | Edita nome e/ou datas de uma sprint. |
|
|
119
140
|
| `update_task` | Atualiza campos de uma tarefa existente. |
|
|
120
141
|
|
|
121
142
|
### Tools que espelham o CLI — prefixo `noclaf_`
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { FINISHED_FILTER } from '../../core/types.js';
|
|
2
|
+
/** Adaptador Supabase do `CalendarGateway` (leitura do calendário pessoal). */
|
|
3
|
+
export function calendarGateway(db) {
|
|
4
|
+
const ok = (r, what) => {
|
|
5
|
+
if (r.error)
|
|
6
|
+
throw new Error(`Erro ao ler ${what}: ${r.error.message}`);
|
|
7
|
+
return r.data ?? [];
|
|
8
|
+
};
|
|
9
|
+
const names = async (ids) => {
|
|
10
|
+
if (ids.length === 0)
|
|
11
|
+
return new Map();
|
|
12
|
+
const rows = ok(await db.from('profiles').select('id, full_name').in('id', ids), 'perfis');
|
|
13
|
+
return new Map(rows.map((p) => [p.id, p.full_name ?? 'Sem nome']));
|
|
14
|
+
};
|
|
15
|
+
return {
|
|
16
|
+
async getCalendarSources(userId, from, to) {
|
|
17
|
+
const [holidays, vacations, homeOffice, releases, people, tasks] = await Promise.all([
|
|
18
|
+
db.from('holidays').select('id, date, name, type, scope').gte('date', from).lte('date', to),
|
|
19
|
+
db.from('vacations').select('id, user_id, start_date, end_date, notes').lte('start_date', to).gte('end_date', from),
|
|
20
|
+
db.from('home_office_days').select('user_id, date').gte('date', from).lte('date', to),
|
|
21
|
+
db.from('releases').select('project_id, name, status, target_date').gte('target_date', from).lte('target_date', to),
|
|
22
|
+
db.from('profiles').select('full_name, birth_date, company_anniversary_date').eq('is_active', true),
|
|
23
|
+
db.from('tasks')
|
|
24
|
+
.select('key, title, status, end_date, task_assignees!inner(user_id), projects(name)')
|
|
25
|
+
.eq('task_assignees.user_id', userId)
|
|
26
|
+
.gte('end_date', from).lte('end_date', to)
|
|
27
|
+
.not('status', 'in', FINISHED_FILTER),
|
|
28
|
+
]);
|
|
29
|
+
const vac = ok(vacations, 'férias');
|
|
30
|
+
const ho = ok(homeOffice, 'home office');
|
|
31
|
+
const name = await names([...new Set([...vac.map((v) => v.user_id), ...ho.map((h) => h.user_id)])]);
|
|
32
|
+
return {
|
|
33
|
+
holidays: ok(holidays, 'feriados'),
|
|
34
|
+
deadlines: ok(tasks, 'prazos').map((t) => ({
|
|
35
|
+
key: t.key, title: t.title, status: t.status, end_date: t.end_date,
|
|
36
|
+
project: t.projects?.name ?? '',
|
|
37
|
+
})),
|
|
38
|
+
vacations: vac.map((v) => ({ ...v, person: name.get(v.user_id) ?? 'Sem nome' })),
|
|
39
|
+
homeOffice: ho.map((h) => ({ date: h.date, person: name.get(h.user_id) ?? 'Sem nome' })),
|
|
40
|
+
releases: ok(releases, 'releases'),
|
|
41
|
+
people: ok(people, 'perfis').map((p) => ({
|
|
42
|
+
name: p.full_name ?? 'Sem nome', birth_date: p.birth_date, company_anniversary_date: p.company_anniversary_date,
|
|
43
|
+
})),
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=calendar-gateway.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar-gateway.js","sourceRoot":"","sources":["../../../src/adapters/supabase/calendar-gateway.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Adaptador Supabase da escrita no calendário; RLS decide quem pode. */
|
|
2
|
+
export function calendarWriteGateway(db) {
|
|
3
|
+
const one = (r, what) => {
|
|
4
|
+
if (r.error || !r.data)
|
|
5
|
+
throw new Error(`Erro ao ${what}: ${r.error?.message ?? 'sem retorno'}`);
|
|
6
|
+
return r.data;
|
|
7
|
+
};
|
|
8
|
+
const many = (r, what) => {
|
|
9
|
+
if (r.error)
|
|
10
|
+
throw new Error(`Erro ao ${what}: ${r.error.message}`);
|
|
11
|
+
return r.data ?? [];
|
|
12
|
+
};
|
|
13
|
+
return {
|
|
14
|
+
async addHoliday(h) {
|
|
15
|
+
return one(await db.from('holidays').insert(h).select('id').single(), 'criar feriado');
|
|
16
|
+
},
|
|
17
|
+
async removeHoliday(id) {
|
|
18
|
+
return many(await db.from('holidays').delete().eq('id', id).select('id'), 'excluir feriado');
|
|
19
|
+
},
|
|
20
|
+
async addVacation(v) {
|
|
21
|
+
return one(await db.from('vacations').insert(v).select('id').single(), 'criar férias');
|
|
22
|
+
},
|
|
23
|
+
async removeVacation(id) {
|
|
24
|
+
return many(await db.from('vacations').delete().eq('id', id).select('id'), 'excluir férias');
|
|
25
|
+
},
|
|
26
|
+
async addHomeOffice(userId, date) {
|
|
27
|
+
return one(await db.from('home_office_days').insert({ user_id: userId, date }).select('id').single(), 'criar home office');
|
|
28
|
+
},
|
|
29
|
+
async removeHomeOffice(userId, date) {
|
|
30
|
+
const r = await db.from('home_office_days').delete().eq('user_id', userId).eq('date', date).select('id');
|
|
31
|
+
return many(r, 'excluir home office');
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=calendar-write-gateway.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar-write-gateway.js","sourceRoot":"","sources":["../../../src/adapters/supabase/calendar-write-gateway.ts"],"names":[],"mappings":"AAGA,yEAAyE;AACzE,MAAM,UAAU,oBAAoB,CAAC,EAAY;IAC/C,MAAM,GAAG,GAAG,CAAI,CAAwD,EAAE,IAAY,EAAK,EAAE;QAC3F,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,CAAC,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,CAAC,CAAC;QACjG,OAAO,CAAC,CAAC,IAAI,CAAC;IAChB,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,CAAI,CAA0D,EAAE,IAAY,EAAO,EAAE;QAChG,IAAI,CAAC,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACpE,OAAO,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IACtB,CAAC,CAAC;IACF,OAAO;QACL,KAAK,CAAC,UAAU,CAAC,CAAC;YAChB,OAAO,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC;QACzF,CAAC;QACD,KAAK,CAAC,aAAa,CAAC,EAAE;YACpB,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,iBAAiB,CAAC,CAAC;QAC/F,CAAC;QACD,KAAK,CAAC,WAAW,CAAC,CAAC;YACjB,OAAO,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC;QACzF,CAAC;QACD,KAAK,CAAC,cAAc,CAAC,EAAE;YACrB,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,gBAAgB,CAAC,CAAC;QAC/F,CAAC;QACD,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI;YAC9B,OAAO,GAAG,CACR,MAAM,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EACzF,mBAAmB,CACpB,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,gBAAgB,CAAC,MAAM,EAAE,IAAI;YACjC,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACzG,OAAO,IAAI,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC;QACxC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { nextItemOrder } from '../../lib/checklist-logic.js';
|
|
2
|
+
/** Adaptador Supabase da edição de checklists; a posse é validada via task -> projeto. */
|
|
3
|
+
export function checklistGateway(db) {
|
|
4
|
+
const fail = (what, e) => {
|
|
5
|
+
if (e)
|
|
6
|
+
throw new Error(`Erro ao ${what}: ${e.message}`);
|
|
7
|
+
};
|
|
8
|
+
const inProject = async (taskId, projectId) => {
|
|
9
|
+
const r = await db.from('tasks').select('id').eq('id', taskId).eq('project_id', projectId).maybeSingle();
|
|
10
|
+
fail('validar tarefa', r.error);
|
|
11
|
+
return !!r.data;
|
|
12
|
+
};
|
|
13
|
+
const itemTask = async (itemId, projectId) => {
|
|
14
|
+
const r = await db.from('task_checklist_items').select('task_id').eq('id', itemId).maybeSingle();
|
|
15
|
+
fail('ler item', r.error);
|
|
16
|
+
return r.data && (await inProject(r.data.task_id, projectId)) ? r.data.task_id : null;
|
|
17
|
+
};
|
|
18
|
+
const listTask = async (listId, projectId) => {
|
|
19
|
+
const r = await db.from('task_checklists').select('task_id').eq('id', listId).maybeSingle();
|
|
20
|
+
fail('ler checklist', r.error);
|
|
21
|
+
return r.data && (await inProject(r.data.task_id, projectId)) ? r.data.task_id : null;
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
async updateChecklistItem(projectId, itemId, patch) {
|
|
25
|
+
if (!(await itemTask(itemId, projectId)))
|
|
26
|
+
return null;
|
|
27
|
+
const r = await db.from('task_checklist_items').update(patch).eq('id', itemId).select('id, text, checked');
|
|
28
|
+
fail('atualizar item', r.error);
|
|
29
|
+
return r.data?.[0] ?? null;
|
|
30
|
+
},
|
|
31
|
+
async addChecklistItem(projectId, checklistId, text) {
|
|
32
|
+
const taskId = await listTask(checklistId, projectId);
|
|
33
|
+
if (!taskId)
|
|
34
|
+
return null;
|
|
35
|
+
const cur = await db.from('task_checklist_items').select('order').eq('checklist_id', checklistId);
|
|
36
|
+
fail('ler itens', cur.error);
|
|
37
|
+
const order = nextItemOrder((cur.data ?? []).map((i) => i.order));
|
|
38
|
+
const r = await db
|
|
39
|
+
.from('task_checklist_items')
|
|
40
|
+
.insert({ task_id: taskId, checklist_id: checklistId, text, checked: false, order })
|
|
41
|
+
.select('id')
|
|
42
|
+
.single();
|
|
43
|
+
fail('criar item', r.error);
|
|
44
|
+
return { id: r.data.id, order };
|
|
45
|
+
},
|
|
46
|
+
async removeChecklistItem(projectId, itemId) {
|
|
47
|
+
if (!(await itemTask(itemId, projectId)))
|
|
48
|
+
return null;
|
|
49
|
+
const r = await db.from('task_checklist_items').delete().eq('id', itemId).select('id');
|
|
50
|
+
fail('remover item', r.error);
|
|
51
|
+
return r.data ?? [];
|
|
52
|
+
},
|
|
53
|
+
async removeChecklist(projectId, checklistId) {
|
|
54
|
+
if (!(await listTask(checklistId, projectId)))
|
|
55
|
+
return null;
|
|
56
|
+
// itens saem junto: FK checklist_id ON DELETE CASCADE.
|
|
57
|
+
const r = await db.from('task_checklists').delete().eq('id', checklistId).select('id');
|
|
58
|
+
fail('remover checklist', r.error);
|
|
59
|
+
return r.data ?? [];
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=checklist-gateway.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checklist-gateway.js","sourceRoot":"","sources":["../../../src/adapters/supabase/checklist-gateway.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,11 @@ import { contextGateway } from './context-gateway.js';
|
|
|
2
2
|
import { taskGateway } from './task-gateway.js';
|
|
3
3
|
import { allocationGateway } from './allocation-gateway.js';
|
|
4
4
|
import { analyticsGateway } from './analytics-gateway.js';
|
|
5
|
+
import { sprintGateway } from './sprint-gateway.js';
|
|
6
|
+
import { calendarGateway } from './calendar-gateway.js';
|
|
7
|
+
import { calendarWriteGateway } from './calendar-write-gateway.js';
|
|
8
|
+
import { releaseGateway } from './release-gateway.js';
|
|
9
|
+
import { checklistGateway } from './checklist-gateway.js';
|
|
5
10
|
/**
|
|
6
11
|
* Adaptador Supabase da `Gateway`, composto pelos gateways de domínio. Toda query
|
|
7
12
|
* PostgREST vive nos módulos `*-gateway.ts` — este arquivo só junta as peças.
|
|
@@ -13,6 +18,11 @@ export function createSupabaseGateway(db) {
|
|
|
13
18
|
...taskGateway(db),
|
|
14
19
|
...allocationGateway(db),
|
|
15
20
|
...analyticsGateway(db),
|
|
21
|
+
...sprintGateway(db),
|
|
22
|
+
...calendarGateway(db),
|
|
23
|
+
...calendarWriteGateway(db),
|
|
24
|
+
...releaseGateway(db),
|
|
25
|
+
...checklistGateway(db),
|
|
16
26
|
};
|
|
17
27
|
}
|
|
18
28
|
//# sourceMappingURL=gateway.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway.js","sourceRoot":"","sources":["../../../src/adapters/supabase/gateway.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,EAAY;IAChD,OAAO;QACL,GAAG,cAAc,CAAC,EAAE,CAAC;QACrB,GAAG,WAAW,CAAC,EAAE,CAAC;QAClB,GAAG,iBAAiB,CAAC,EAAE,CAAC;QACxB,GAAG,gBAAgB,CAAC,EAAE,CAAC;KACxB,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"gateway.js","sourceRoot":"","sources":["../../../src/adapters/supabase/gateway.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,EAAY;IAChD,OAAO;QACL,GAAG,cAAc,CAAC,EAAE,CAAC;QACrB,GAAG,WAAW,CAAC,EAAE,CAAC;QAClB,GAAG,iBAAiB,CAAC,EAAE,CAAC;QACxB,GAAG,gBAAgB,CAAC,EAAE,CAAC;QACvB,GAAG,aAAa,CAAC,EAAE,CAAC;QACpB,GAAG,eAAe,CAAC,EAAE,CAAC;QACtB,GAAG,oBAAoB,CAAC,EAAE,CAAC;QAC3B,GAAG,cAAc,CAAC,EAAE,CAAC;QACrB,GAAG,gBAAgB,CAAC,EAAE,CAAC;KACxB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { FINISHED_FILTER } from '../../core/types.js';
|
|
2
|
+
const COLS = 'id, project_id, name, status, target_date, delivered_at';
|
|
3
|
+
/** Adaptador Supabase do `ReleaseGateway`. */
|
|
4
|
+
export function releaseGateway(db) {
|
|
5
|
+
return {
|
|
6
|
+
async listReleases(projectId, status) {
|
|
7
|
+
let q = db.from('releases').select(COLS).eq('project_id', projectId);
|
|
8
|
+
if (status)
|
|
9
|
+
q = q.eq('status', status);
|
|
10
|
+
const { data, error } = await q.order('target_date', { ascending: true });
|
|
11
|
+
if (error)
|
|
12
|
+
throw new Error(`Erro ao listar releases: ${error.message}`);
|
|
13
|
+
return data ?? [];
|
|
14
|
+
},
|
|
15
|
+
async findRelease(projectId, releaseId) {
|
|
16
|
+
const { data, error } = await db
|
|
17
|
+
.from('releases')
|
|
18
|
+
.select(COLS)
|
|
19
|
+
.eq('project_id', projectId)
|
|
20
|
+
.eq('id', releaseId)
|
|
21
|
+
.maybeSingle();
|
|
22
|
+
if (error)
|
|
23
|
+
throw new Error(`Erro ao buscar release: ${error.message}`);
|
|
24
|
+
return data ?? null;
|
|
25
|
+
},
|
|
26
|
+
async createRelease(r) {
|
|
27
|
+
const { data, error } = await db.from('releases').insert(r).select(COLS).single();
|
|
28
|
+
if (error)
|
|
29
|
+
throw new Error(`Erro ao criar release: ${error.message}`);
|
|
30
|
+
return data;
|
|
31
|
+
},
|
|
32
|
+
async updateRelease(releaseId, patch) {
|
|
33
|
+
const { data, error } = await db.from('releases').update(patch).eq('id', releaseId).select(COLS).single();
|
|
34
|
+
if (error)
|
|
35
|
+
throw new Error(`Erro ao atualizar release: ${error.message}`);
|
|
36
|
+
return data;
|
|
37
|
+
},
|
|
38
|
+
async finalizeRelease(releaseId, unlinkPending) {
|
|
39
|
+
// Desvincular é idempotente: roda antes, então retry após falha não deixa release delivered com pendentes.
|
|
40
|
+
if (unlinkPending) {
|
|
41
|
+
const { error } = await db
|
|
42
|
+
.from('tasks')
|
|
43
|
+
.update({ release_id: null, updated_at: new Date().toISOString() })
|
|
44
|
+
.eq('release_id', releaseId)
|
|
45
|
+
.not('status', 'in', FINISHED_FILTER);
|
|
46
|
+
if (error)
|
|
47
|
+
throw new Error(`Erro ao desvincular tasks pendentes: ${error.message}`);
|
|
48
|
+
}
|
|
49
|
+
const { data, error } = await db
|
|
50
|
+
.from('releases')
|
|
51
|
+
.update({ status: 'delivered', delivered_at: new Date().toISOString() })
|
|
52
|
+
.eq('id', releaseId)
|
|
53
|
+
.select(COLS)
|
|
54
|
+
.single();
|
|
55
|
+
if (error)
|
|
56
|
+
throw new Error(`Erro ao finalizar release: ${error.message}`);
|
|
57
|
+
return data;
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=release-gateway.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release-gateway.js","sourceRoot":"","sources":["../../../src/adapters/supabase/release-gateway.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const COLS = 'id, project_id, name, status, start_date, end_date';
|
|
2
|
+
/** Adaptador Supabase do `SprintGateway` (ciclo de vida de sprints). */
|
|
3
|
+
export function sprintGateway(db) {
|
|
4
|
+
return {
|
|
5
|
+
async listSprints(projectId) {
|
|
6
|
+
const { data, error } = await db
|
|
7
|
+
.from('sprints')
|
|
8
|
+
.select(COLS)
|
|
9
|
+
.eq('project_id', projectId)
|
|
10
|
+
.order('created_at', { ascending: false });
|
|
11
|
+
if (error)
|
|
12
|
+
throw new Error(`Erro ao listar sprints: ${error.message}`);
|
|
13
|
+
return data ?? [];
|
|
14
|
+
},
|
|
15
|
+
async findSprint(projectId, idOrActive) {
|
|
16
|
+
let q = db.from('sprints').select(COLS).eq('project_id', projectId);
|
|
17
|
+
q = idOrActive === 'active'
|
|
18
|
+
? q.eq('status', 'ativa').order('created_at', { ascending: false }).limit(1)
|
|
19
|
+
: q.eq('id', idOrActive);
|
|
20
|
+
const { data, error } = await q.maybeSingle();
|
|
21
|
+
if (error)
|
|
22
|
+
throw new Error(`Erro ao buscar sprint: ${error.message}`);
|
|
23
|
+
return data ?? null;
|
|
24
|
+
},
|
|
25
|
+
async listSprintTasks(sprintId) {
|
|
26
|
+
const { data, error } = await db
|
|
27
|
+
.from('tasks')
|
|
28
|
+
.select('id, key, title, status, end_date')
|
|
29
|
+
.eq('sprint_id', sprintId);
|
|
30
|
+
if (error)
|
|
31
|
+
throw new Error(`Erro ao listar tasks da sprint: ${error.message}`);
|
|
32
|
+
return data ?? [];
|
|
33
|
+
},
|
|
34
|
+
async createSprint(projectId, name, startDate, endDate) {
|
|
35
|
+
const { data, error } = await db
|
|
36
|
+
.from('sprints')
|
|
37
|
+
.insert({ project_id: projectId, name, status: 'ativa', start_date: startDate, end_date: endDate })
|
|
38
|
+
.select(COLS)
|
|
39
|
+
.single();
|
|
40
|
+
if (error)
|
|
41
|
+
throw new Error(`Erro ao criar sprint: ${error.message}`);
|
|
42
|
+
return data;
|
|
43
|
+
},
|
|
44
|
+
async updateSprint(sprintId, patch) {
|
|
45
|
+
const { data, error } = await db.from('sprints').update(patch).eq('id', sprintId).select(COLS).single();
|
|
46
|
+
if (error)
|
|
47
|
+
throw new Error(`Erro ao atualizar sprint: ${error.message}`);
|
|
48
|
+
return data;
|
|
49
|
+
},
|
|
50
|
+
async returnTasksToBacklog(taskIds) {
|
|
51
|
+
if (taskIds.length === 0)
|
|
52
|
+
return;
|
|
53
|
+
const { error } = await db.from('tasks').update({ sprint_id: null, status: 'backlog' }).in('id', taskIds);
|
|
54
|
+
if (error)
|
|
55
|
+
throw new Error(`Erro ao devolver tasks ao backlog: ${error.message}`);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=sprint-gateway.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sprint-gateway.js","sourceRoot":"","sources":["../../../src/adapters/supabase/sprint-gateway.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,7 +36,9 @@ export function formatTaskList(tasks, assigneesByTask) {
|
|
|
36
36
|
priority: t.priority,
|
|
37
37
|
type: t.type,
|
|
38
38
|
sprint_id: t.sprint_id,
|
|
39
|
+
start_date: t.start_date,
|
|
39
40
|
end_date: t.end_date,
|
|
41
|
+
release_id: t.release_id,
|
|
40
42
|
created_at: t.created_at,
|
|
41
43
|
assignees: assigneesByTask.get(t.id) ?? [],
|
|
42
44
|
}));
|
|
@@ -64,14 +66,10 @@ export function buildChecklistInsert(taskId, title, icon, order) {
|
|
|
64
66
|
export function taskGateway(db) {
|
|
65
67
|
return {
|
|
66
68
|
async listTasks(filter) {
|
|
67
|
-
const restrict = await resolveAssigneeFilter(db, filter.userId, filter.assignee);
|
|
68
69
|
const sprint = await resolveSprintFilter(db, filter.projectId, filter.sprint);
|
|
69
70
|
if (sprint.noActive)
|
|
70
71
|
return { tasks: [], note: 'Não há sprint ativa neste projeto.' };
|
|
71
|
-
|
|
72
|
-
if (restrict?.mode === 'in' && restrict.ids.length === 0)
|
|
73
|
-
return { tasks: [] };
|
|
74
|
-
const rows = await queryFilteredTasks(db, filter, restrict, sprint.filter);
|
|
72
|
+
const rows = await queryFilteredTasks(db, filter, sprint.filter);
|
|
75
73
|
if (rows.length === 0)
|
|
76
74
|
return { tasks: [] };
|
|
77
75
|
const { assigneeRows, profilesById } = await loadAssigneeProfiles(db, rows.map((t) => t.id));
|
|
@@ -192,7 +190,7 @@ export function taskGateway(db) {
|
|
|
192
190
|
const insertRes = await db
|
|
193
191
|
.from('tasks')
|
|
194
192
|
.insert(payload)
|
|
195
|
-
.select('id, key, title, status, priority, type, sprint_id, end_date, created_at')
|
|
193
|
+
.select('id, key, title, status, priority, type, sprint_id, start_date, end_date, created_at')
|
|
196
194
|
.single();
|
|
197
195
|
if (insertRes.error)
|
|
198
196
|
throw new Error(`Erro ao criar tarefa: ${insertRes.error.message}`);
|
|
@@ -210,7 +208,7 @@ export function taskGateway(db) {
|
|
|
210
208
|
async getCurrentTask(taskId, projectId) {
|
|
211
209
|
const res = await db
|
|
212
210
|
.from('tasks')
|
|
213
|
-
.select('id, title, description, status, priority, type, sprint_id, end_date, project_id')
|
|
211
|
+
.select('id, title, description, status, priority, type, sprint_id, release_id, start_date, end_date, project_id')
|
|
214
212
|
.eq('id', taskId)
|
|
215
213
|
.eq('project_id', projectId)
|
|
216
214
|
.maybeSingle();
|
|
@@ -297,7 +295,7 @@ export function taskGateway(db) {
|
|
|
297
295
|
async reloadTask(taskId) {
|
|
298
296
|
const finalRes = await db
|
|
299
297
|
.from('tasks')
|
|
300
|
-
.select('id, key, title, status, priority, type, sprint_id, end_date, updated_at')
|
|
298
|
+
.select('id, key, title, status, priority, type, sprint_id, start_date, end_date, updated_at')
|
|
301
299
|
.eq('id', taskId)
|
|
302
300
|
.single();
|
|
303
301
|
if (finalRes.error)
|
|
@@ -414,21 +412,6 @@ export function taskGateway(db) {
|
|
|
414
412
|
},
|
|
415
413
|
};
|
|
416
414
|
}
|
|
417
|
-
async function resolveAssigneeFilter(db, userId, assignee) {
|
|
418
|
-
if (!assignee)
|
|
419
|
-
return null;
|
|
420
|
-
if (assignee === 'unassigned') {
|
|
421
|
-
const sub = await db.from('task_assignees').select('task_id');
|
|
422
|
-
if (sub.error)
|
|
423
|
-
throw new Error(`Erro filtrando por assignee: ${sub.error.message}`);
|
|
424
|
-
return { mode: 'not_in', ids: (sub.data ?? []).map((r) => r.task_id) };
|
|
425
|
-
}
|
|
426
|
-
const userFilter = assignee === 'me' ? userId : assignee;
|
|
427
|
-
const sub = await db.from('task_assignees').select('task_id').eq('user_id', userFilter);
|
|
428
|
-
if (sub.error)
|
|
429
|
-
throw new Error(`Erro filtrando por assignee: ${sub.error.message}`);
|
|
430
|
-
return { mode: 'in', ids: (sub.data ?? []).map((r) => r.task_id) };
|
|
431
|
-
}
|
|
432
415
|
async function resolveSprintFilter(db, projectId, sprint) {
|
|
433
416
|
if (!sprint)
|
|
434
417
|
return { noActive: false, filter: null };
|
|
@@ -449,15 +432,33 @@ async function resolveSprintFilter(db, projectId, sprint) {
|
|
|
449
432
|
return { noActive: false, filter: { mode: 'is_null' } };
|
|
450
433
|
return { noActive: false, filter: { mode: 'eq', value: sprint } };
|
|
451
434
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
.
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
435
|
+
function applyAssigneeFilter(query, filter) {
|
|
436
|
+
const { assignee } = filter;
|
|
437
|
+
if (assignee === 'unassigned')
|
|
438
|
+
return query.is('task_assignees', null);
|
|
439
|
+
if (assignee)
|
|
440
|
+
return query.eq('task_assignees.user_id', assignee === 'me' ? filter.userId : assignee);
|
|
441
|
+
return query;
|
|
442
|
+
}
|
|
443
|
+
/** Sobreposição: end_date >= from E coalesce(start_date, end_date) <= to (sem end_date não entra). */
|
|
444
|
+
function applyOverlapFilter(query, filter) {
|
|
445
|
+
let q = query;
|
|
446
|
+
if (filter.from)
|
|
447
|
+
q = q.gte('end_date', filter.from);
|
|
448
|
+
if (filter.to) {
|
|
449
|
+
q = q.not('end_date', 'is', null);
|
|
450
|
+
q = q.or(`start_date.lte.${filter.to},and(start_date.is.null,end_date.lte.${filter.to})`);
|
|
451
|
+
}
|
|
452
|
+
return q;
|
|
453
|
+
}
|
|
454
|
+
async function queryFilteredTasks(db, filter, sprintFilter) {
|
|
455
|
+
const cols = 'id, key, title, status, priority, type, sprint_id, start_date, end_date, release_id, created_at';
|
|
456
|
+
const { assignee } = filter;
|
|
457
|
+
// Join filtrado no PostgREST: evita mandar centenas de ids na URL (.in/.not.in).
|
|
458
|
+
const embed = !assignee ? '' : assignee === 'unassigned' ? ', task_assignees!left(user_id)' : ', task_assignees!inner(user_id)';
|
|
459
|
+
let query = db.from('tasks').select(`${cols}${embed}`).eq('project_id', filter.projectId);
|
|
460
|
+
query = applyAssigneeFilter(query, filter);
|
|
461
|
+
query = applyOverlapFilter(query, filter);
|
|
461
462
|
if (sprintFilter?.mode === 'eq')
|
|
462
463
|
query = query.eq('sprint_id', sprintFilter.value);
|
|
463
464
|
else if (sprintFilter?.mode === 'is_null')
|
|
@@ -480,7 +481,9 @@ async function queryFilteredTasks(db, filter, restrictIds, sprintFilter) {
|
|
|
480
481
|
const { data, error } = await query;
|
|
481
482
|
if (error)
|
|
482
483
|
throw new Error(`Erro ao listar tarefas: ${error.message}`);
|
|
483
|
-
|
|
484
|
+
// O embed serve só de filtro: não vaza pro resultado.
|
|
485
|
+
const rows = (data ?? []);
|
|
486
|
+
return rows.map(({ task_assignees: _ta, ...row }) => row);
|
|
484
487
|
}
|
|
485
488
|
async function loadAssigneeProfiles(db, taskIds) {
|
|
486
489
|
const assigneesRes = await db.from('task_assignees').select('task_id, user_id').in('task_id', taskIds);
|