@nio-cli/cli 0.1.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.
Files changed (196) hide show
  1. package/README.md +280 -0
  2. package/dist/adapters/supabase/allocation-gateway.js +236 -0
  3. package/dist/adapters/supabase/allocation-gateway.js.map +1 -0
  4. package/dist/adapters/supabase/analytics-gateway.js +18 -0
  5. package/dist/adapters/supabase/analytics-gateway.js.map +1 -0
  6. package/dist/adapters/supabase/client.js +96 -0
  7. package/dist/adapters/supabase/client.js.map +1 -0
  8. package/dist/adapters/supabase/context-gateway.js +23 -0
  9. package/dist/adapters/supabase/context-gateway.js.map +1 -0
  10. package/dist/adapters/supabase/gateway.js +18 -0
  11. package/dist/adapters/supabase/gateway.js.map +1 -0
  12. package/dist/adapters/supabase/task-gateway.js +450 -0
  13. package/dist/adapters/supabase/task-gateway.js.map +1 -0
  14. package/dist/auth.js +118 -0
  15. package/dist/auth.js.map +1 -0
  16. package/dist/brand.js +91 -0
  17. package/dist/brand.js.map +1 -0
  18. package/dist/cli/commands/auth.js +128 -0
  19. package/dist/cli/commands/auth.js.map +1 -0
  20. package/dist/cli/commands/clean.js +120 -0
  21. package/dist/cli/commands/clean.js.map +1 -0
  22. package/dist/cli/commands/completion.js +114 -0
  23. package/dist/cli/commands/completion.js.map +1 -0
  24. package/dist/cli/commands/exec.js +59 -0
  25. package/dist/cli/commands/exec.js.map +1 -0
  26. package/dist/cli/commands/init/auth-step.js +49 -0
  27. package/dist/cli/commands/init/auth-step.js.map +1 -0
  28. package/dist/cli/commands/init/clients-step.js +76 -0
  29. package/dist/cli/commands/init/clients-step.js.map +1 -0
  30. package/dist/cli/commands/init/context-step.js +71 -0
  31. package/dist/cli/commands/init/context-step.js.map +1 -0
  32. package/dist/cli/commands/init/index.js +76 -0
  33. package/dist/cli/commands/init/index.js.map +1 -0
  34. package/dist/cli/commands/init/project-step.js +105 -0
  35. package/dist/cli/commands/init/project-step.js.map +1 -0
  36. package/dist/cli/commands/init/provision-step.js +103 -0
  37. package/dist/cli/commands/init/provision-step.js.map +1 -0
  38. package/dist/cli/commands/plan.js +45 -0
  39. package/dist/cli/commands/plan.js.map +1 -0
  40. package/dist/cli/commands/skills.js +23 -0
  41. package/dist/cli/commands/skills.js.map +1 -0
  42. package/dist/cli/commands/sync.js +296 -0
  43. package/dist/cli/commands/sync.js.map +1 -0
  44. package/dist/cli/commands/validate-plan.js +42 -0
  45. package/dist/cli/commands/validate-plan.js.map +1 -0
  46. package/dist/cli/copy/auth.json +6 -0
  47. package/dist/cli/copy/flows.json +6 -0
  48. package/dist/cli/copy/init.json +19 -0
  49. package/dist/cli/copy/sync.json +3 -0
  50. package/dist/cli/copy.js +23 -0
  51. package/dist/cli/copy.js.map +1 -0
  52. package/dist/cli/flows/clients.js +130 -0
  53. package/dist/cli/flows/clients.js.map +1 -0
  54. package/dist/cli/flows/completion.js +63 -0
  55. package/dist/cli/flows/completion.js.map +1 -0
  56. package/dist/cli/flows/dependencies.js +114 -0
  57. package/dist/cli/flows/dependencies.js.map +1 -0
  58. package/dist/cli/flows/sections.js +85 -0
  59. package/dist/cli/flows/sections.js.map +1 -0
  60. package/dist/cli/flows/user-config.js +37 -0
  61. package/dist/cli/flows/user-config.js.map +1 -0
  62. package/dist/cli/ui/render.js +237 -0
  63. package/dist/cli/ui/render.js.map +1 -0
  64. package/dist/cli/ui/report.js +117 -0
  65. package/dist/cli/ui/report.js.map +1 -0
  66. package/dist/cli.js +36 -0
  67. package/dist/cli.js.map +1 -0
  68. package/dist/config.js +280 -0
  69. package/dist/config.js.map +1 -0
  70. package/dist/constants.js +9 -0
  71. package/dist/constants.js.map +1 -0
  72. package/dist/core/ports.js +2 -0
  73. package/dist/core/ports.js.map +1 -0
  74. package/dist/core/types.js +7 -0
  75. package/dist/core/types.js.map +1 -0
  76. package/dist/database.types.js +11 -0
  77. package/dist/database.types.js.map +1 -0
  78. package/dist/lib/active-project.js +28 -0
  79. package/dist/lib/active-project.js.map +1 -0
  80. package/dist/lib/autopull.js +13 -0
  81. package/dist/lib/autopull.js.map +1 -0
  82. package/dist/lib/client-configs.js +191 -0
  83. package/dist/lib/client-configs.js.map +1 -0
  84. package/dist/lib/client-install.js +40 -0
  85. package/dist/lib/client-install.js.map +1 -0
  86. package/dist/lib/colors.js +93 -0
  87. package/dist/lib/colors.js.map +1 -0
  88. package/dist/lib/cowork-extension.js +143 -0
  89. package/dist/lib/cowork-extension.js.map +1 -0
  90. package/dist/lib/dependencies.js +145 -0
  91. package/dist/lib/dependencies.js.map +1 -0
  92. package/dist/lib/dependency-install.js +163 -0
  93. package/dist/lib/dependency-install.js.map +1 -0
  94. package/dist/lib/duration.js +5 -0
  95. package/dist/lib/duration.js.map +1 -0
  96. package/dist/lib/exec-delegate.js +167 -0
  97. package/dist/lib/exec-delegate.js.map +1 -0
  98. package/dist/lib/exec-engines.js +72 -0
  99. package/dist/lib/exec-engines.js.map +1 -0
  100. package/dist/lib/file-merge.js +33 -0
  101. package/dist/lib/file-merge.js.map +1 -0
  102. package/dist/lib/harness.js +90 -0
  103. package/dist/lib/harness.js.map +1 -0
  104. package/dist/lib/hooks.js +217 -0
  105. package/dist/lib/hooks.js.map +1 -0
  106. package/dist/lib/patterns.js +61 -0
  107. package/dist/lib/patterns.js.map +1 -0
  108. package/dist/lib/plan-delegate.js +106 -0
  109. package/dist/lib/plan-delegate.js.map +1 -0
  110. package/dist/lib/project-context.js +151 -0
  111. package/dist/lib/project-context.js.map +1 -0
  112. package/dist/lib/prompts.js +69 -0
  113. package/dist/lib/prompts.js.map +1 -0
  114. package/dist/lib/provision-apply.js +220 -0
  115. package/dist/lib/provision-apply.js.map +1 -0
  116. package/dist/lib/provision-collect.js +47 -0
  117. package/dist/lib/provision-collect.js.map +1 -0
  118. package/dist/lib/provision.js +45 -0
  119. package/dist/lib/provision.js.map +1 -0
  120. package/dist/lib/require-config.js +32 -0
  121. package/dist/lib/require-config.js.map +1 -0
  122. package/dist/lib/rules.js +99 -0
  123. package/dist/lib/rules.js.map +1 -0
  124. package/dist/lib/sections.js +89 -0
  125. package/dist/lib/sections.js.map +1 -0
  126. package/dist/lib/skill-serve.js +129 -0
  127. package/dist/lib/skill-serve.js.map +1 -0
  128. package/dist/lib/skills-cache.js +99 -0
  129. package/dist/lib/skills-cache.js.map +1 -0
  130. package/dist/lib/skills.js +236 -0
  131. package/dist/lib/skills.js.map +1 -0
  132. package/dist/lib/targets.js +151 -0
  133. package/dist/lib/targets.js.map +1 -0
  134. package/dist/lib/task-history.js +15 -0
  135. package/dist/lib/task-history.js.map +1 -0
  136. package/dist/lib/telemetry.js +51 -0
  137. package/dist/lib/telemetry.js.map +1 -0
  138. package/dist/lib/tool-result.js +12 -0
  139. package/dist/lib/tool-result.js.map +1 -0
  140. package/dist/lib/validate-plan-delegate.js +107 -0
  141. package/dist/lib/validate-plan-delegate.js.map +1 -0
  142. package/dist/lib/version-check.js +89 -0
  143. package/dist/lib/version-check.js.map +1 -0
  144. package/dist/matrix-logo.js +122 -0
  145. package/dist/matrix-logo.js.map +1 -0
  146. package/dist/mcp-server.js +189 -0
  147. package/dist/mcp-server.js.map +1 -0
  148. package/dist/session-factory.js +19 -0
  149. package/dist/session-factory.js.map +1 -0
  150. package/dist/spinner.js +12 -0
  151. package/dist/spinner.js.map +1 -0
  152. package/dist/tools/comment-task.js +72 -0
  153. package/dist/tools/comment-task.js.map +1 -0
  154. package/dist/tools/create-task.js +129 -0
  155. package/dist/tools/create-task.js.map +1 -0
  156. package/dist/tools/delegate-exec.js +63 -0
  157. package/dist/tools/delegate-exec.js.map +1 -0
  158. package/dist/tools/end-allocation.js +38 -0
  159. package/dist/tools/end-allocation.js.map +1 -0
  160. package/dist/tools/end-task-allocation.js +37 -0
  161. package/dist/tools/end-task-allocation.js.map +1 -0
  162. package/dist/tools/exec-status.js +43 -0
  163. package/dist/tools/exec-status.js.map +1 -0
  164. package/dist/tools/get-active-allocation.js +69 -0
  165. package/dist/tools/get-active-allocation.js.map +1 -0
  166. package/dist/tools/get-context.js +48 -0
  167. package/dist/tools/get-context.js.map +1 -0
  168. package/dist/tools/get-task.js +137 -0
  169. package/dist/tools/get-task.js.map +1 -0
  170. package/dist/tools/index.js +44 -0
  171. package/dist/tools/index.js.map +1 -0
  172. package/dist/tools/list-my-allocations.js +71 -0
  173. package/dist/tools/list-my-allocations.js.map +1 -0
  174. package/dist/tools/list-projects.js +38 -0
  175. package/dist/tools/list-projects.js.map +1 -0
  176. package/dist/tools/list-tasks.js +93 -0
  177. package/dist/tools/list-tasks.js.map +1 -0
  178. package/dist/tools/move-task.js +82 -0
  179. package/dist/tools/move-task.js.map +1 -0
  180. package/dist/tools/plan.js +56 -0
  181. package/dist/tools/plan.js.map +1 -0
  182. package/dist/tools/record-delivery.js +71 -0
  183. package/dist/tools/record-delivery.js.map +1 -0
  184. package/dist/tools/set-project.js +52 -0
  185. package/dist/tools/set-project.js.map +1 -0
  186. package/dist/tools/start-allocation.js +32 -0
  187. package/dist/tools/start-allocation.js.map +1 -0
  188. package/dist/tools/start-task-allocation.js +75 -0
  189. package/dist/tools/start-task-allocation.js.map +1 -0
  190. package/dist/tools/update-task.js +139 -0
  191. package/dist/tools/update-task.js.map +1 -0
  192. package/dist/tools/validate-plan.js +58 -0
  193. package/dist/tools/validate-plan.js.map +1 -0
  194. package/dist/version.js +16 -0
  195. package/dist/version.js.map +1 -0
  196. package/package.json +64 -0
package/README.md ADDED
@@ -0,0 +1,280 @@
1
+ <p align="center">
2
+ <img src="https://avatars.githubusercontent.com/u/241520827?s=48&v=4" alt="nio" width="80" height="80" />
3
+ </p>
4
+
5
+ <h1 align="center">nio-cli</h1>
6
+
7
+ MCP server + CLI pra controlar o **NIO** (Nucleo Operacional de Inteligência) a partir do Claude Code, Codex CLI e GitHub Copilot.
8
+
9
+ ## O que faz
10
+
11
+ Permite ao assistente de IA:
12
+
13
+ - Ler contexto do projeto (membros, sprint ativa, repositórios vinculados)
14
+ - Listar, criar, atualizar, mover entre colunas e comentar tarefas
15
+ - Bater ponto e cronometrar tempo em tarefas específicas
16
+
17
+ ## Instalação (mac / linux / windows)
18
+
19
+ Precisa apenas de **Node.js 20+**. Instala como pacote global:
20
+
21
+ ```bash
22
+ npm i -g @nio-cli/cli
23
+ ```
24
+
25
+ Pronto. Os comandos `nio` (CLI) e `nio-cli` (servidor MCP) ficam disponíveis no PATH em qualquer SO.
26
+
27
+ ## Configurar em qualquer repo
28
+
29
+ Na raiz do repositório:
30
+
31
+ ```bash
32
+ nio init
33
+ ```
34
+
35
+ Esse único comando faz tudo:
36
+
37
+ 1. Pede o seu **PAT** do NOS se você ainda não está autenticado (fluxo de geração em migração — ver `docs/specs/auth/0002-cli-native-login.md`).
38
+ 2. Lista os projetos do NOS e você escolhe um (ou cola o UUID).
39
+ 3. (Opcional) Escolhe o repositório vinculado.
40
+ 4. Escreve `nio.json` na raiz **e o adiciona ao `.gitignore`** (binding local, não versionado).
41
+ 5. Mostra o contexto carregado pra você validar.
42
+ 6. Pergunta quais clientes MCP configurar — global ou por-repo.
43
+
44
+ Reinicie o cliente de IA depois pra carregar as tools.
45
+
46
+ ## Comandos do CLI
47
+
48
+ Operações do CLI, **sem o binário na frente** (declarado no cabeçalho da tabela). Tabela
49
+ gerada da fonte por `bun run gen:docs`.
50
+
51
+ <!-- COMMANDS:START -->
52
+ <!-- gerado por `bun run gen:docs` — não edite à mão. binário `nio`, 13 comandos. -->
53
+
54
+ | Comando | Descrição |
55
+ | --- | --- |
56
+ | `clean-legacy` | Remove commands/skills legados (substituídos) de ~/.claude e ~/.codex |
57
+ | `completion [shell]` | Imprime o script de autocomplete (bash\|zsh\|fish). |
58
+ | `exec` | Delega a implementação a um agente headless num worktree e aguarda. |
59
+ | `exec-status <jobId>` | Estado de um job de execução (`nio exec`), em JSON |
60
+ | `init` | Cria nio.json no diretório atual vinculando a um projeto do NOS |
61
+ | `login [pat]` | Salva o token de acesso pessoal (PAT) localmente |
62
+ | `logout` | Remove credenciais locais |
63
+ | `plan` | Roda o engine pensante sobre o projeto e escreve/refina o plan.md da raiz. |
64
+ | `skills` | Skills, commands e agents do nio (lidos do repo aberto via cache) |
65
+ | `skills status` | Lista os docs do repo de skills (cache local ~/.nio/skills) |
66
+ | `sync` | Instala/atualiza skills, commands e agents nos clientes configurados, a partir do bundle (idempotente); checa atualização do pacote |
67
+ | `validate-plan` | Lê o plan.md da raiz e roda o engine pensante para julgar se o plano precisa de uma spec antes de implementar. |
68
+ | `whoami` | Mostra o usuário autenticado |
69
+ <!-- COMMANDS:END -->
70
+
71
+ ### Autocomplete (tab)
72
+
73
+ O `nio init` **oferece** ativar, e o `nio sync` **valida** e prompta se faltar. Pra
74
+ ativar à mão, adicione ao rc do seu shell:
75
+
76
+ ```bash
77
+ # zsh (~/.zshrc)
78
+ eval "$(nio completion zsh)"
79
+ # bash (~/.bashrc)
80
+ eval "$(nio completion bash)"
81
+ # fish (~/.config/fish/config.fish)
82
+ nio completion fish | source
83
+ ```
84
+
85
+ Recarregue o shell e `nio <tab>` passa a sugerir comandos, subcomandos e flags.
86
+
87
+ ## Tools disponíveis
88
+
89
+ Operações do MCP, com o nome **sem o prefixo** (declarado por grupo — o prefixo vem de
90
+ `src/brand.ts`). Tabela gerada da fonte por `bun run gen:docs`.
91
+
92
+ <!-- TOOLS:START -->
93
+ <!-- gerado por `bun run gen:docs` — não edite à mão. 20 tools. -->
94
+
95
+ ### Tools de produto — prefixo `nos_`
96
+
97
+ | Operação | O que faz |
98
+ | --- | --- |
99
+ | `comment_task` | Adiciona um comentário em uma tarefa. |
100
+ | `create_task` | Cria uma nova tarefa no projeto atual. |
101
+ | `end_allocation` | [ENCERRA O DIA] Bate ponto de SAÍDA do usuário e fecha qualquer task_allocation aberta. |
102
+ | `end_task_allocation` | [PARA TIMER DE TASK] Para a task_allocation ativa. |
103
+ | `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. |
104
+ | `get_context` | Retorna o contexto completo do projeto NOS ativo: dados do projeto, repositórios, sprint ativa, membros e usuário autenticado. |
105
+ | `get_task` | Retorna detalhes completos de uma tarefa: descrição, assignees, checklist, comentários, histórico recente, repositórios vinculados e labels. |
106
+ | `list_my_allocations` | Lista alocações passadas do usuário (encerradas), ordenadas por data decrescente. |
107
+ | `list_projects` | Lista os projetos do NOS aos quais você tem acesso. |
108
+ | `list_tasks` | Lista tarefas do projeto atual, filtradas pelos parâmetros opcionais. |
109
+ | `move_task` | Atalho pra mudar o status de uma tarefa (move entre colunas do Kanban). |
110
+ | `record_delivery` | Registra uma ENTREGA do loop de build (um ticket concluído / PR aberto) na analítica de entrega do NOS. |
111
+ | `set_project` | Define o projeto ativo da sessão (em memória, dura enquanto o servidor estiver rodando). |
112
+ | `start_allocation` | Inicia uma alocação (bate o ponto) para o usuário atual. |
113
+ | `start_task_allocation` | Começa a cronometrar tempo numa task específica. |
114
+ | `update_task` | Atualiza campos de uma tarefa existente. |
115
+
116
+ ### Tools que espelham o CLI — prefixo `nio_`
117
+
118
+ | Operação | O que faz |
119
+ | --- | --- |
120
+ | `delegate_exec` | Delega a IMPLEMENTAÇÃO a um agente de execução novo (codex ou claude local, na assinatura — sem API) num worktree já criado pelo /implement. |
121
+ | `exec_status` | Estado de uma execução delegada (`nio_delegate_exec`): running \| done \| failed, com o resumo do agente, os arquivos alterados e os checks determinísticos (tamanho, lint, build, testes). |
122
+ | `plan` | Roda o engine PENSANTE (claude ou codex local, na assinatura — sem API) sobre a raiz do projeto e escreve/refina o `plan.md` de rascunho pré-SDD. |
123
+ | `validate_plan` | Lê o `plan.md` da raiz do projeto e roda o engine PENSANTE (claude ou codex local, na assinatura — sem API) para julgar se o plano é complexo o bastante para virar uma spec SDD antes de implementar. |
124
+ <!-- TOOLS:END -->
125
+
126
+ > **Escopo do projeto.** As tools de tarefa/alocação resolvem o projeto nesta ordem:
127
+ > argumento `project_id` da chamada → projeto ativo da sessão (`set_project`) → default
128
+ > opcional do binding de repo (`nio.json`/`NIO_PROJECT_ID`).
129
+ >
130
+ > O projeto ativo é **por sessão**: vive só em memória, no processo do servidor MCP, e
131
+ > não é gravado em disco — ao reiniciar volta ao default. No Cowork, onde não há binding
132
+ > de repo, é sempre assim que se escolhe o projeto: `list_projects` → `set_project`.
133
+ > (Como um processo do Claude Desktop pode ser compartilhado entre conversas, passe
134
+ > `project_id` direto na chamada quando quiser garantir o escopo de uma conversa.)
135
+
136
+ ## Skills, commands e dependências
137
+
138
+ Além das tools, o nio entrega skills/commands/agents/hooks pros clientes. O conteúdo
139
+ vive num **repo aberto** — [`hugoreiis12-png/NIO-SKILLS-`](https://github.com/hugoreiis12-png/NIO-SKILLS-) —
140
+ e **não** é um pacote npm. O CLI baixa o repo (zipball do GitHub, sem precisar de `git`)
141
+ pra um cache local em **`~/.nio/skills`** e lê de lá. `nio sync` **atualiza o cache**
142
+ (pull da branch) toda vez, então as skills evoluem sem republicar o CLI; e **auto-detecta**
143
+ quais clientes têm o nio configurado, provisionando pra cada um conforme a seleção de
144
+ perfil/área do `nio.json`.
145
+
146
+ Overrides por ambiente:
147
+
148
+ | Variável | Efeito |
149
+ | --------------------- | ------------------------------------------------------------------ |
150
+ | `NIO_SKILLS_DIR` | Aponta pra um checkout local do repo (dev) — vence tudo |
151
+ | `NIO_SKILLS_REPO` | Outro `owner/repo` (default `hugoreiis12-png/NIO-SKILLS-`) |
152
+ | `NOCLAF_SKILLS_REF` | Outra branch/tag (default `main`) |
153
+
154
+ Cada cliente recebe no formato que entende:
155
+
156
+ | Cliente | Onde | Formato |
157
+ | --------------- | ----------------------------- | ----------------------------------------------------------------------- |
158
+ | Claude Code | `~/.claude/{commands,skills,agents}` | arquivos nativos — slash-commands e skills |
159
+ | Codex CLI | `~/.codex/` | **dual-write**: cada command/skill vira uma **skill** (`skills/<id>/SKILL.md`, auto-selecionada) **e** um **custom prompt** (`prompts/<id>.md`, no menu `/prompts:<id>`) |
160
+ | Cowork/Desktop | — | via **MCP prompts** + resources, servidos ao vivo (ignora `~/.claude`) |
161
+
162
+ > Configurar o Codex grava `NOCLAF_CLIENT=codex` no `config.toml`, o que faz o servidor
163
+ > provisionar pra `~/.codex` e filtrar os docs pelo surface `codex`. Reinicie o cliente
164
+ > depois do sync pra carregar skills/prompts novos.
165
+
166
+ > **Como aparecem no Cowork/Claude Desktop.** Lá as skills chegam como **prompts MCP**,
167
+ > que o app expõe como **slash-commands** no menu de conectores/"+" (ex.: digite `/` e
168
+ > procure os itens do nio) — são **invocados manualmente**, não carregados sozinhos
169
+ > como Agent Skills que o modelo detecta e usa por conta própria. Se não aparecerem:
170
+ > feche o app de vez (Cmd+Q) e reabra, e confirme que o conector nio está conectado
171
+ > (deve listar as tools `nos_*`). O processo do Cowork lê o mesmo cache `~/.nio/skills`
172
+ > — se o `nio sync` populou, o conteúdo está lá.
173
+
174
+ ### Visibilidade por cliente
175
+
176
+ Um doc pode ser restrito a clientes específicos via frontmatter:
177
+
178
+ ```yaml
179
+ clients: claude-code, cowork # vazio/ausente = todos os clientes
180
+ ```
181
+
182
+ Valores: `claude-code`, `codex`, `cowork`. O MCP filtra por esse campo, então um skill
183
+ marcado `cowork` não é provisionado pro `~/.claude`, e um `claude-code` não aparece como
184
+ prompt no Cowork.
185
+
186
+ ### Dependências externas
187
+
188
+ Commands/skills podem depender de libs externas, declaradas como arquivos em
189
+ `dependencies/` no repo de skills (a presença do arquivo é a declaração). No fim do
190
+ `init`/`sync`, a CLI lista cada uma e:
191
+
192
+ - **instalador estruturado** (`npm:`, `skills:` = `npx skills add`, `git:`) → oferece
193
+ rodar com `[y/N]` (comando montado a partir do campo validado, **sem shell**);
194
+ - **`manual:`** (plugin de marketplace, passos no cliente, UI) → imprime os passos por
195
+ cliente, com os comandos destacados. Ex.: o Ponytail é instalado por `/plugin` no Claude
196
+ Code e `codex plugin …` + `/hooks` no Codex — a CLI não automatiza, só orienta.
197
+
198
+ A string `install:` (se houver) é **só exibição** — nunca é executada.
199
+
200
+ A CLI **detecta o que já está instalado** e mostra um selo verde `✓ instalada` (sem
201
+ repetir descrição/passos): `npm` via `npm ls -g`, `git` pelo dir de destino, `skills`
202
+ por marcador/probe. Pra deps `manual:` (plugins), declare `detect:` no frontmatter com
203
+ um ou mais globs — suporta `~`, `*` e `**`, e segue symlinks (ok com dotfiles). Ex.: o
204
+ Ponytail usa `detect: ~/.claude/plugins/**/ponytail`.
205
+
206
+ ### Checagem de cliente
207
+
208
+ Ao escolher um cliente no `init`, a CLI verifica se ele está de fato instalado na
209
+ máquina. Se não estiver:
210
+
211
+ - **CLIs** (Claude Code, Codex) → mostra e oferece rodar o instalador:
212
+ `npm i -g @anthropic-ai/claude-code` · `npm i -g @openai/codex`;
213
+ - **apps** (Claude Desktop/Cowork, VS Code) → mostra o link de download
214
+ (ex.: https://claude.ai/download) — reabra o app depois de instalar.
215
+
216
+ ## Claude Desktop / Cowork
217
+
218
+ Selecione **Cowork** na lista de clientes do `nio init` (ou rode de novo). Com o app
219
+ instalado e você já logado (`nio login`), a CLI **ativa o conector direto** — escreve
220
+ o `nio` no `claude_desktop_config.json` usando caminhos absolutos (`node` +
221
+ `dist/mcp-server.js`) e `NOCLAF_CLIENT=cowork`. Reinicie o Claude Desktop pra carregar.
222
+ O `nio sync` reafirma esse config (atualiza os paths se o node/pacote mudou de lugar).
223
+
224
+ Não há projeto pra configurar: o Cowork não tem `nio.json` (sem working dir/repo),
225
+ então o projeto é **escolhido por sessão** — peça pro assistente rodar `nos_list_projects`
226
+ e depois `nos_set_project` com o id desejado.
227
+
228
+ ### Fallback: extensão `.mcpb`
229
+
230
+ Se o app estiver instalado mas a escrita direta falhar, ou você não tiver login salvo, a
231
+ CLI cai pro **fallback manual**: gera uma extensão `~/Downloads/nio-cli-<versão>.mcpb`
232
+ e mostra os passos:
233
+
234
+ **Configurações → Extensões → Configurações avançadas → seção "Extension Developer" →
235
+ "Install Extension…"** → selecione o `.mcpb` → preencha **só o PAT**.
236
+
237
+ Pela extensão a config não vem do `nio login`/`nio.json`, e sim do `user_config`,
238
+ injetado como variável de ambiente:
239
+
240
+ | Variável | Origem (`user_config`) | Sensível |
241
+ | ------------ | ---------------------- | -------- |
242
+ | `NOCLAF_PAT` | PAT (`noc_…`) | ✅ sim |
243
+
244
+ > **Override de default (avançado, opcional).** Fora do Cowork, em CLIs de código, você
245
+ > ainda pode definir `NIO_PROJECT_ID`/`NOCLAF_REPOSITORY_ID` no env do cliente MCP pra
246
+ > fixar um projeto default — equivalente ao `nio.json`. O projeto da sessão
247
+ > (`nos_set_project`) e o `project_id` por chamada sempre têm precedência sobre esse default.
248
+
249
+ ## Atualizando
250
+
251
+ ```bash
252
+ npm i -g @nio-cli/cli@latest
253
+ ```
254
+
255
+ O `nio sync` **checa a versão publicada** no início e, se houver uma mais nova, mostra
256
+ um aviso e **oferece atualizar ali mesmo** (roda `npm i -g @nio-cli/cli@latest` com sua
257
+ confirmação; depois é só rodar o sync de novo). Use `nio sync --yes` pra aceitar sem
258
+ prompt. A CLI também avisa em background em qualquer comando (via `update-notifier`).
259
+
260
+ ## Troubleshooting
261
+
262
+ - **`nio-cli: command not found`** — confirme o install global com `npm i -g @nio-cli/cli` e que `npm bin -g` está no PATH.
263
+ - **Tools não aparecem no Claude Code** — reinicie o Claude Code depois do `nio init`. Confira com `/mcp` dentro dele.
264
+ - **`Não autenticado`** — rode `nio init` (que já faz login inline) ou `nio login`. No Cowork, confira se o **PAT** foi preenchido na extensão.
265
+ - **`Nenhum projeto selecionado`** — escolha o projeto da sessão: `nos_list_projects` → `nos_set_project`. (Em CLI de código você também pode rodar `nio init` pra criar um `nio.json` default no repo.)
266
+ - **Skills não aparecem no Cowork** — elas chegam como **prompts MCP** (slash-commands no menu de conectores/"+"), não como skills autônomas. Feche o Claude Desktop de vez (Cmd+Q) e reabra; confirme o conector conectado (tools `nos_*` listadas).
267
+ - **`Conteúdo de skills não encontrado`** — o cache `~/.nio/skills` está vazio (fetch falhou / offline). Rode `nio sync` com rede, ou defina `NIO_SKILLS_DIR` pra um checkout local. Confirme também que o repo de skills está público.
268
+ - **`ENOENT … mkdir` ao provisionar (dotfiles)** — um symlink em `~/.claude` aponta pra um alvo inexistente. As versões atuais materializam o alvo automaticamente; se persistir, cheque o link.
269
+ - **Sobraram comandos antigos** (`new-spec`, `apply-bug`, `init-sdd` como command…) — rode `nio clean-legacy` (use `--dry-run` pra revisar antes) pra removê-los de `~/.claude` e `~/.codex`.
270
+
271
+ ## Convenções
272
+
273
+ - **Idioma**: UI/CLI em pt-BR. Código (variáveis, funções, tipos) em inglês.
274
+ - **Backups**: qualquer escrita em arquivo de config existente gera `.bak.<timestamp>` ao lado.
275
+ - **stdout reservado pro JSON-RPC** no MCP server — logs vão pra stderr.
276
+
277
+ ## Versão
278
+
279
+ v0.1.x — feature complete pra v1. Próximos passos: testes automatizados,
280
+ suporte a múltiplos perfis de usuário.
@@ -0,0 +1,236 @@
1
+ /** Adaptador Supabase do `AllocationGateway` (ponto do dia + timers de task). */
2
+ export function allocationGateway(db) {
3
+ return {
4
+ async startAllocation(userId) {
5
+ const activeRes = await db
6
+ .from('allocations')
7
+ .select('id, start_time')
8
+ .eq('user_id', userId)
9
+ .is('end_time', null)
10
+ .maybeSingle();
11
+ if (activeRes.error)
12
+ throw new Error(`Erro ao buscar alocação ativa: ${activeRes.error.message}`);
13
+ if (activeRes.data)
14
+ return { allocation: activeRes.data, alreadyActive: true };
15
+ const insertRes = await db
16
+ .from('allocations')
17
+ .insert({ user_id: userId })
18
+ .select('id, start_time')
19
+ .single();
20
+ if (insertRes.error)
21
+ throw new Error(`Erro ao iniciar alocação: ${insertRes.error.message}`);
22
+ return { allocation: insertRes.data, alreadyActive: false };
23
+ },
24
+ async endAllocation(userId) {
25
+ const activeRes = await db
26
+ .from('allocations')
27
+ .select('id, start_time')
28
+ .eq('user_id', userId)
29
+ .is('end_time', null)
30
+ .maybeSingle();
31
+ if (activeRes.error)
32
+ throw new Error(`Erro ao buscar alocação ativa: ${activeRes.error.message}`);
33
+ if (!activeRes.data)
34
+ return null;
35
+ const allocationId = activeRes.data.id;
36
+ const now = new Date().toISOString();
37
+ // Fecha task_allocations abertas dessa allocation em paralelo com o close da allocation.
38
+ const [taskCloseRes, allocCloseRes] = await Promise.all([
39
+ db
40
+ .from('task_allocations')
41
+ .update({ end_time: now })
42
+ .eq('allocation_id', allocationId)
43
+ .is('end_time', null)
44
+ .select('id'),
45
+ db
46
+ .from('allocations')
47
+ .update({ end_time: now })
48
+ .eq('id', allocationId)
49
+ .select('id, start_time, end_time')
50
+ .single(),
51
+ ]);
52
+ if (taskCloseRes.error)
53
+ throw new Error(`Erro ao fechar task_allocations: ${taskCloseRes.error.message}`);
54
+ if (allocCloseRes.error)
55
+ throw new Error(`Erro ao encerrar alocação: ${allocCloseRes.error.message}`);
56
+ return { closed: allocCloseRes.data, closedTaskAllocations: (taskCloseRes.data ?? []).length };
57
+ },
58
+ async endTaskAllocation(userId) {
59
+ const activeRes = await db
60
+ .from('task_allocations')
61
+ .select('id, task_id, start_time')
62
+ .eq('user_id', userId)
63
+ .is('end_time', null)
64
+ .maybeSingle();
65
+ if (activeRes.error)
66
+ throw new Error(`Erro ao buscar task_allocation ativa: ${activeRes.error.message}`);
67
+ if (!activeRes.data)
68
+ return null;
69
+ const active = activeRes.data;
70
+ const now = new Date().toISOString();
71
+ const closeRes = await db
72
+ .from('task_allocations')
73
+ .update({ end_time: now })
74
+ .eq('id', active.id)
75
+ .select('id, start_time, end_time')
76
+ .single();
77
+ if (closeRes.error)
78
+ throw new Error(`Erro ao parar task_allocation: ${closeRes.error.message}`);
79
+ // Info da task é best-effort (não falha o close se a task sumiu).
80
+ const taskRes = await db
81
+ .from('tasks')
82
+ .select('id, key, title')
83
+ .eq('id', active.task_id)
84
+ .maybeSingle();
85
+ const task = taskRes.data ?? { id: active.task_id, key: null, title: null };
86
+ return { closed: closeRes.data, task };
87
+ },
88
+ async listMyAllocations(userId, opts) {
89
+ let query = db
90
+ .from('allocations')
91
+ .select('id, start_time, end_time, auto_closed')
92
+ .eq('user_id', userId)
93
+ .not('end_time', 'is', null);
94
+ if (opts.from)
95
+ query = query.gte('start_time', `${opts.from.slice(0, 10)}T00:00:00Z`);
96
+ if (opts.to)
97
+ query = query.lte('start_time', `${opts.to.slice(0, 10)}T23:59:59Z`);
98
+ query = query
99
+ .order('start_time', { ascending: false })
100
+ .range(opts.offset, opts.offset + opts.limit - 1);
101
+ const { data, error } = await query;
102
+ if (error)
103
+ throw new Error(`Erro ao listar alocações: ${error.message}`);
104
+ const allocations = data ?? [];
105
+ if (allocations.length === 0)
106
+ return { allocations: [], segments: [] };
107
+ const segRes = await db
108
+ .from('task_allocations')
109
+ .select('allocation_id, start_time, end_time')
110
+ .in('allocation_id', allocations.map((a) => a.id));
111
+ if (segRes.error)
112
+ throw new Error(`Erro ao buscar segmentos: ${segRes.error.message}`);
113
+ return { allocations, segments: segRes.data ?? [] };
114
+ },
115
+ async getActiveAllocation(userId) {
116
+ const allocRes = await db
117
+ .from('allocations')
118
+ .select('id, start_time')
119
+ .eq('user_id', userId)
120
+ .is('end_time', null)
121
+ .maybeSingle();
122
+ if (allocRes.error)
123
+ throw new Error(`Erro ao buscar alocação ativa: ${allocRes.error.message}`);
124
+ if (!allocRes.data)
125
+ return null;
126
+ const allocation = allocRes.data;
127
+ const segmentsRes = await db
128
+ .from('task_allocations')
129
+ .select('id, task_id, start_time, end_time, is_overtime')
130
+ .eq('allocation_id', allocation.id)
131
+ .order('start_time', { ascending: true });
132
+ if (segmentsRes.error)
133
+ throw new Error(`Erro ao buscar segmentos: ${segmentsRes.error.message}`);
134
+ const segments = segmentsRes.data ?? [];
135
+ const { tasksById, projectsById } = await loadTaskAndProjectRefs(db, Array.from(new Set(segments.map((s) => s.task_id))));
136
+ return { allocation, segments, tasksById, projectsById };
137
+ },
138
+ async startTaskAllocation(taskId, projectId, userId, isOvertime) {
139
+ const taskRes = await db
140
+ .from('tasks')
141
+ .select('id, key, title, project_id')
142
+ .eq('id', taskId)
143
+ .eq('project_id', projectId)
144
+ .maybeSingle();
145
+ if (taskRes.error)
146
+ throw new Error(`Erro ao buscar tarefa: ${taskRes.error.message}`);
147
+ if (!taskRes.data)
148
+ return null;
149
+ const task = taskRes.data;
150
+ const now = new Date().toISOString();
151
+ const alloc = await ensureActiveAllocation(db, userId);
152
+ const previousClosed = await closePreviousTaskAllocation(db, userId, now);
153
+ const insertRes = await db
154
+ .from('task_allocations')
155
+ .insert({ allocation_id: alloc.allocationId, task_id: taskId, user_id: userId, start_time: now, is_overtime: isOvertime })
156
+ .select('id, start_time, is_overtime')
157
+ .single();
158
+ if (insertRes.error)
159
+ throw new Error(`Erro ao iniciar task_allocation: ${insertRes.error.message}`);
160
+ return {
161
+ taskAllocation: insertRes.data,
162
+ task: { id: task.id, key: task.key, title: task.title },
163
+ previousClosed,
164
+ allocationWasCreated: alloc.wasCreated,
165
+ };
166
+ },
167
+ };
168
+ }
169
+ async function loadTaskAndProjectRefs(db, taskIds) {
170
+ const tasksById = new Map();
171
+ const projectsById = new Map();
172
+ if (taskIds.length === 0)
173
+ return { tasksById, projectsById };
174
+ const tasksRes = await db.from('tasks').select('id, key, title, project_id').in('id', taskIds);
175
+ if (tasksRes.error)
176
+ throw new Error(`Erro ao buscar tarefas: ${tasksRes.error.message}`);
177
+ for (const t of tasksRes.data ?? []) {
178
+ tasksById.set(t.id, { key: t.key, title: t.title, project_id: t.project_id });
179
+ }
180
+ const projectIds = Array.from(new Set((tasksRes.data ?? []).map((t) => t.project_id)));
181
+ if (projectIds.length > 0) {
182
+ const projectsRes = await db.from('projects').select('id, name').in('id', projectIds);
183
+ if (projectsRes.error)
184
+ throw new Error(`Erro ao buscar projetos: ${projectsRes.error.message}`);
185
+ for (const p of projectsRes.data ?? [])
186
+ projectsById.set(p.id, p.name);
187
+ }
188
+ return { tasksById, projectsById };
189
+ }
190
+ /** Reaproveita a allocation (ponto) ativa do usuário ou cria uma. */
191
+ async function ensureActiveAllocation(db, userId) {
192
+ const activeAllocRes = await db
193
+ .from('allocations')
194
+ .select('id')
195
+ .eq('user_id', userId)
196
+ .is('end_time', null)
197
+ .maybeSingle();
198
+ if (activeAllocRes.error)
199
+ throw new Error(`Erro ao buscar alocação ativa: ${activeAllocRes.error.message}`);
200
+ if (activeAllocRes.data)
201
+ return { allocationId: activeAllocRes.data.id, wasCreated: false };
202
+ const newAlloc = await db.from('allocations').insert({ user_id: userId }).select('id').single();
203
+ if (newAlloc.error)
204
+ throw new Error(`Erro ao iniciar alocação: ${newAlloc.error.message}`);
205
+ return { allocationId: newAlloc.data.id, wasCreated: true };
206
+ }
207
+ /** Fecha a task_allocation ativa anterior do usuário, se houver. */
208
+ async function closePreviousTaskAllocation(db, userId, now) {
209
+ const activeRes = await db
210
+ .from('task_allocations')
211
+ .select('id, task_id, start_time')
212
+ .eq('user_id', userId)
213
+ .is('end_time', null)
214
+ .maybeSingle();
215
+ if (activeRes.error)
216
+ throw new Error(`Erro ao buscar task_allocation ativa: ${activeRes.error.message}`);
217
+ if (!activeRes.data)
218
+ return null;
219
+ const prev = activeRes.data;
220
+ const closeRes = await db
221
+ .from('task_allocations')
222
+ .update({ end_time: now })
223
+ .eq('id', prev.id)
224
+ .select('id, start_time, end_time')
225
+ .single();
226
+ if (closeRes.error)
227
+ throw new Error(`Erro ao fechar task_allocation anterior: ${closeRes.error.message}`);
228
+ // Key da task anterior é best-effort (retorno informativo).
229
+ const prevTask = await db.from('tasks').select('id, key').eq('id', prev.task_id).maybeSingle();
230
+ return {
231
+ prev: { id: prev.id, task_id: prev.task_id },
232
+ closed: { start_time: closeRes.data.start_time, end_time: closeRes.data.end_time },
233
+ prevTaskKey: prevTask.data?.key ?? null,
234
+ };
235
+ }
236
+ //# sourceMappingURL=allocation-gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allocation-gateway.js","sourceRoot":"","sources":["../../../src/adapters/supabase/allocation-gateway.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { track as trackUsage } from '../../lib/telemetry.js';
2
+ /** Adaptador Supabase do `AnalyticsGateway` (entregas + telemetria de uso). */
3
+ export function analyticsGateway(db) {
4
+ return {
5
+ async recordDelivery(row) {
6
+ // `deliveries` ainda não está nos types gerados (rode `gen:types` após a migration)
7
+ // — usamos o client destipado só pra este insert.
8
+ const raw = db;
9
+ const { error } = await raw.from('deliveries').insert(row);
10
+ if (error)
11
+ throw new Error(`Erro ao registrar entrega: ${error.message}`);
12
+ },
13
+ track(event) {
14
+ trackUsage(db, event);
15
+ },
16
+ };
17
+ }
18
+ //# sourceMappingURL=analytics-gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-gateway.js","sourceRoot":"","sources":["../../../src/adapters/supabase/analytics-gateway.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,IAAI,UAAU,EAAmB,MAAM,wBAAwB,CAAC;AAE9E,+EAA+E;AAC/E,MAAM,UAAU,gBAAgB,CAAC,EAAY;IAC3C,OAAO;QACL,KAAK,CAAC,cAAc,CAAC,GAAkB;YACrC,oFAAoF;YACpF,kDAAkD;YAClD,MAAM,GAAG,GAAG,EAA+B,CAAC;YAC5C,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3D,IAAI,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5E,CAAC;QAED,KAAK,CAAC,KAAiB;YACrB,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACxB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,96 @@
1
+ import { createClient } from '@supabase/supabase-js';
2
+ import { SUPABASE_URL, SUPABASE_ANON_KEY } from '../../constants.js';
3
+ import { loadCredentials, exchangePatForJwt } from '../../auth.js';
4
+ import { brand } from '../../brand.js';
5
+ /**
6
+ * Lê o `exp` (epoch em segundos) do payload de um JWT. Retorna 0 se não der pra
7
+ * parsear — o chamador trata 0 como "sem validade conhecida" e cai no fallback.
8
+ */
9
+ function jwtExp(token) {
10
+ try {
11
+ const payload = token.split('.')[1];
12
+ if (!payload)
13
+ return 0;
14
+ const json = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'));
15
+ return typeof json.exp === 'number' ? json.exp : 0;
16
+ }
17
+ catch {
18
+ return 0;
19
+ }
20
+ }
21
+ /** Validade absoluta (epoch em s) da troca: usa o `exp` do JWT; se ilegível, deriva do `expires_in`. */
22
+ function computeExp(exchange) {
23
+ const fromJwt = jwtExp(exchange.access_token);
24
+ if (fromJwt > 0)
25
+ return fromJwt;
26
+ return Math.floor(Date.now() / 1000) + (exchange.expires_in ?? 0);
27
+ }
28
+ /**
29
+ * Carrega PAT, troca por JWT e retorna client Supabase autenticado.
30
+ *
31
+ * O JWT do mcp-token-exchange tem `exp` fixo e o client não tem refresh
32
+ * (autoRefreshToken:false). Chumbar o token num header estático fazia toda chamada
33
+ * falhar com "JWT expired" depois do exp, até reconectar o MCP (que reinicia o
34
+ * processo → nova troca). Em vez disso injetamos um JWT fresco por request via fetch
35
+ * custom, re-trocando o PAT (durável e re-trocável) de duas formas:
36
+ * - **proativa**: quando falta <300s pro exp (margem larga que absorve skew de relógio);
37
+ * - **reativa (one-shot)**: se o servidor devolver 401 (ex.: skew mandou um JWT já
38
+ * expirado), força uma troca fresca e repete a MESMA request UMA vez.
39
+ * Assim a sessão dura indefinidamente sem reconnect, mesmo com relógio dessincronizado.
40
+ *
41
+ * Throw se não há PAT salvo, ou se a troca inicial falhar.
42
+ */
43
+ export async function createAuthenticatedClient() {
44
+ const creds = await loadCredentials();
45
+ if (!creds) {
46
+ throw new Error(`Nenhum token encontrado. Rode \`${brand.name} login <PAT>\` antes.`);
47
+ }
48
+ const { pat } = creds;
49
+ const first = await exchangePatForJwt(pat);
50
+ let token = first.access_token;
51
+ let exp = computeExp(first);
52
+ // Re-troca o PAT por um JWT novo, deduplicando trocas concorrentes numa única
53
+ // promise pra não disparar N requests ao token-exchange quando várias tools
54
+ // chamam junto. Usado tanto pela checagem proativa quanto pelo retry reativo.
55
+ let refreshing = null;
56
+ function refreshOnce() {
57
+ if (!refreshing) {
58
+ refreshing = (async () => {
59
+ const fresh = await exchangePatForJwt(pat);
60
+ token = fresh.access_token;
61
+ exp = computeExp(fresh);
62
+ })().finally(() => {
63
+ refreshing = null;
64
+ });
65
+ }
66
+ return refreshing;
67
+ }
68
+ // Proativo: refresca quando falta <300s pro exp (margem larga pra absorver skew).
69
+ async function validToken() {
70
+ const now = Math.floor(Date.now() / 1000);
71
+ if (exp - 300 > now)
72
+ return token;
73
+ await refreshOnce();
74
+ return token;
75
+ }
76
+ const authFetch = async (input, init, retried = false) => {
77
+ const headers = new Headers(init?.headers);
78
+ headers.set('Authorization', `Bearer ${await validToken()}`);
79
+ const res = await fetch(input, { ...init, headers });
80
+ // Reativo (one-shot): se o servidor rejeita o token (401) — ex.: skew mandou um
81
+ // JWT já expirado — força uma troca fresca e repete a MESMA request uma vez.
82
+ if (res.status === 401 && !retried) {
83
+ await refreshOnce();
84
+ return authFetch(input, init, true);
85
+ }
86
+ return res;
87
+ };
88
+ const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
89
+ auth: { persistSession: false, autoRefreshToken: false },
90
+ // Cast: nosso wrapper não implementa `fetch.preconnect` (que o supabase-js
91
+ // nunca chama), mas o tipo `Fetch` é `typeof fetch` e exige a propriedade.
92
+ global: { fetch: authFetch },
93
+ });
94
+ return { supabase, user: first.user };
95
+ }
96
+ //# sourceMappingURL=client.js.map