@orkastery/cli 0.5.1 → 0.5.6

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 (260) hide show
  1. package/adapters/claude-code/README.md +158 -0
  2. package/adapters/claude-code/agents/ork-master.md +2 -0
  3. package/adapters/claude-code/commands/master.md +8 -0
  4. package/adapters/claude-code/commands/ork.md +9 -0
  5. package/adapters/claude-code/mods/autoridade.json +56 -0
  6. package/adapters/claude-code/mods/ork-clima/.claude-plugin/plugin.json +14 -0
  7. package/adapters/claude-code/mods/ork-clima/hooks/contas.ts +283 -0
  8. package/adapters/claude-code/mods/ork-clima/hooks/hooks.json +3 -0
  9. package/adapters/claude-code/mods/ork-clima/hooks/previsao.ts +393 -0
  10. package/adapters/claude-code/mods/ork-clima/hooks/register.ts +205 -0
  11. package/adapters/claude-code/mods/ork-clima/orkastery-mod.json +5 -0
  12. package/adapters/claude-code/mods/ork-clima/types/index.d.ts +80 -0
  13. package/adapters/claude-code/mods/ork-freio/.claude-plugin/plugin.json +14 -0
  14. package/adapters/claude-code/mods/ork-freio/hooks/carga.ts +160 -0
  15. package/adapters/claude-code/mods/ork-freio/hooks/conferencia.ts +309 -0
  16. package/adapters/claude-code/mods/ork-freio/hooks/hooks.json +3 -0
  17. package/adapters/claude-code/mods/ork-freio/hooks/lote.ts +270 -0
  18. package/adapters/claude-code/mods/ork-freio/hooks/register.ts +285 -0
  19. package/adapters/claude-code/mods/ork-freio/orkastery-mod.json +5 -0
  20. package/adapters/claude-code/mods/ork-freio/types/index.d.ts +127 -0
  21. package/adapters/claude-code/mods/ork-mesa/.claude-plugin/plugin.json +14 -0
  22. package/adapters/claude-code/mods/ork-mesa/hooks/cartoes.tsx +246 -0
  23. package/adapters/claude-code/mods/ork-mesa/hooks/decidir.ts +110 -0
  24. package/adapters/claude-code/mods/ork-mesa/hooks/fila.ts +253 -0
  25. package/adapters/claude-code/mods/ork-mesa/hooks/hooks.json +3 -0
  26. package/adapters/claude-code/mods/ork-mesa/hooks/obvia.ts +98 -0
  27. package/adapters/claude-code/mods/ork-mesa/hooks/register.tsx +493 -0
  28. package/adapters/claude-code/mods/ork-mesa/orkastery-mod.json +5 -0
  29. package/adapters/claude-code/mods/ork-mesa/types/index.d.ts +131 -0
  30. package/adapters/claude-code/mods/ork-pista/.claude-plugin/plugin.json +14 -0
  31. package/adapters/claude-code/mods/ork-pista/hooks/acoes.ts +71 -0
  32. package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +117 -0
  33. package/adapters/claude-code/mods/ork-pista/hooks/hooks.json +3 -0
  34. package/adapters/claude-code/mods/ork-pista/hooks/pista.tsx +356 -0
  35. package/adapters/claude-code/mods/ork-pista/hooks/register.tsx +439 -0
  36. package/adapters/claude-code/mods/ork-pista/orkastery-mod.json +5 -0
  37. package/adapters/claude-code/mods/ork-pista/types/index.d.ts +85 -0
  38. package/adapters/claude-code/mods/ork-ponte/.claude-plugin/plugin.json +13 -0
  39. package/adapters/claude-code/mods/ork-ponte/hooks/faixa.tsx +57 -0
  40. package/adapters/claude-code/mods/ork-ponte/hooks/guarda.ts +410 -0
  41. package/adapters/claude-code/mods/ork-ponte/hooks/hooks.json +3 -0
  42. package/adapters/claude-code/mods/ork-ponte/hooks/mostrado.ts +55 -0
  43. package/adapters/claude-code/mods/ork-ponte/hooks/nucleo.ts +157 -0
  44. package/adapters/claude-code/mods/ork-ponte/hooks/papel.ts +42 -0
  45. package/adapters/claude-code/mods/ork-ponte/hooks/register.ts +331 -0
  46. package/adapters/claude-code/mods/ork-ponte/hooks/vigia.ts +76 -0
  47. package/adapters/claude-code/mods/ork-ponte/orkastery-mod.json +5 -0
  48. package/adapters/claude-code/mods/ork-ponte/types/index.d.ts +178 -0
  49. package/adapters/claude-code/mods/ork-portao/.claude-plugin/plugin.json +14 -0
  50. package/adapters/claude-code/mods/ork-portao/hooks/hooks.json +3 -0
  51. package/adapters/claude-code/mods/ork-portao/hooks/lease.ts +201 -0
  52. package/adapters/claude-code/mods/ork-portao/hooks/plano.ts +304 -0
  53. package/adapters/claude-code/mods/ork-portao/hooks/register.ts +339 -0
  54. package/adapters/claude-code/mods/ork-portao/hooks/verify.ts +152 -0
  55. package/adapters/claude-code/mods/ork-portao/orkastery-mod.json +5 -0
  56. package/adapters/claude-code/mods/ork-portao/types/index.d.ts +60 -0
  57. package/adapters/claude-code/mods/ork-radar/.claude-plugin/plugin.json +14 -0
  58. package/adapters/claude-code/mods/ork-radar/hooks/colisao.ts +420 -0
  59. package/adapters/claude-code/mods/ork-radar/hooks/hooks.json +3 -0
  60. package/adapters/claude-code/mods/ork-radar/hooks/mapa.tsx +322 -0
  61. package/adapters/claude-code/mods/ork-radar/hooks/register.tsx +470 -0
  62. package/adapters/claude-code/mods/ork-radar/orkastery-mod.json +5 -0
  63. package/adapters/claude-code/mods/ork-radar/types/index.d.ts +72 -0
  64. package/adapters/claude-code/mods/ork-sentinela/.claude-plugin/plugin.json +14 -0
  65. package/adapters/claude-code/mods/ork-sentinela/hooks/alertas.ts +85 -0
  66. package/adapters/claude-code/mods/ork-sentinela/hooks/despacho.ts +156 -0
  67. package/adapters/claude-code/mods/ork-sentinela/hooks/hooks.json +3 -0
  68. package/adapters/claude-code/mods/ork-sentinela/hooks/register.ts +511 -0
  69. package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +186 -0
  70. package/adapters/claude-code/mods/ork-sentinela/orkastery-mod.json +5 -0
  71. package/adapters/claude-code/mods/ork-sentinela/types/index.d.ts +65 -0
  72. package/adapters/claude-code/mods/ork-torre/.claude-plugin/plugin.json +14 -0
  73. package/adapters/claude-code/mods/ork-torre/hooks/agenda.ts +60 -0
  74. package/adapters/claude-code/mods/ork-torre/hooks/detalhe.tsx +236 -0
  75. package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +42 -0
  76. package/adapters/claude-code/mods/ork-torre/hooks/hooks.json +3 -0
  77. package/adapters/claude-code/mods/ork-torre/hooks/painel.tsx +344 -0
  78. package/adapters/claude-code/mods/ork-torre/hooks/rede.ts +97 -0
  79. package/adapters/claude-code/mods/ork-torre/hooks/register.tsx +437 -0
  80. package/adapters/claude-code/mods/ork-torre/orkastery-mod.json +5 -0
  81. package/adapters/claude-code/mods/ork-torre/types/index.d.ts +108 -0
  82. package/adapters/codex/skills/ork/SKILL.md +18 -3
  83. package/adapters/hermes/README.md +1 -0
  84. package/adapters/hermes/bin/ork-network-status.sh +10 -0
  85. package/adapters/hermes/hermes.plugin.json +1 -0
  86. package/adapters/hermes/hitl-ingress/__init__.py +2 -2
  87. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +7 -6
  88. package/adapters/openclaw/README.md +26 -5
  89. package/adapters/openclaw/dist/hitl-ingress.js +2 -2
  90. package/adapters/openclaw/dist/index.js +46 -11
  91. package/adapters/openclaw/openclaw.plugin.json +5 -1
  92. package/adapters/openclaw/package.json +2 -2
  93. package/adapters/openclaw/src/hitl-ingress.ts +2 -2
  94. package/adapters/openclaw/src/index.ts +49 -11
  95. package/assets/docs-en/markdownlint-cli2.jsonc +22 -0
  96. package/assets/docs-en/padroes/documentacao-de-produto.md +135 -0
  97. package/assets/docs-en/padroes/roadmap-de-produto.md +100 -0
  98. package/assets/docs-en/produto/README.md +14 -0
  99. package/assets/docs-en/produto/_modelo-feature.md +62 -0
  100. package/assets/docs-en/roadmap/README.md +14 -0
  101. package/assets/docs-en/roadmap/_modelo-item.md +75 -0
  102. package/assets/orkmind_bridge.py +117 -9
  103. package/dist/adapters/claude-bg.js +116 -18
  104. package/dist/adapters/codex.js +14 -4
  105. package/dist/agents-md.js +24 -14
  106. package/dist/auditrun.js +22 -3
  107. package/dist/board.js +20 -17
  108. package/dist/branch-de-estado.js +88 -10
  109. package/dist/busca-semantica.js +52 -12
  110. package/dist/canarios-rm057.js +149 -0
  111. package/dist/canarios.js +2 -0
  112. package/dist/catalogo.js +33 -0
  113. package/dist/ci.js +21 -8
  114. package/dist/claims-conferir.js +342 -0
  115. package/dist/claims.js +41 -1
  116. package/dist/company-brain-client.js +36 -1
  117. package/dist/company-brain-context.js +158 -22
  118. package/dist/company-brain-journal.js +2 -1
  119. package/dist/company-brain-migration.js +36 -1
  120. package/dist/conducao-sentinela.js +388 -0
  121. package/dist/conducao-texto.js +12 -18
  122. package/dist/conducao.js +122 -30
  123. package/dist/conhecimento.js +490 -0
  124. package/dist/docs.js +70 -17
  125. package/dist/doctor-pulse-cron.js +349 -0
  126. package/dist/doctor-rede.js +150 -0
  127. package/dist/doctor.js +195 -111
  128. package/dist/entrega-pr.js +42 -29
  129. package/dist/escopo-escrita.js +10 -1
  130. package/dist/esgotamentos.js +181 -0
  131. package/dist/estado-thread.js +23 -1
  132. package/dist/experiencia-instalacao.js +45 -25
  133. package/dist/experiencia.js +12 -2
  134. package/dist/fabrica-batida.js +310 -0
  135. package/dist/fabrica-estado.js +52 -14
  136. package/dist/fabrica-publicar.js +9 -1
  137. package/dist/fechamento.js +20 -66
  138. package/dist/fila-pesada.js +444 -0
  139. package/dist/fix.js +3 -2
  140. package/dist/forja.js +31 -7
  141. package/dist/gates.js +3 -24
  142. package/dist/handoff.js +10 -6
  143. package/dist/hitl-contract.js +59 -4
  144. package/dist/hitl-curto.js +11 -6
  145. package/dist/hitl-gates.js +5 -0
  146. package/dist/hitl-local-receipt.js +2 -0
  147. package/dist/hitl-lote.js +5 -2
  148. package/dist/hitl-resumo.js +38 -3
  149. package/dist/hitl-tempo-parado.js +201 -0
  150. package/dist/hitl-texto-livre.js +5 -5
  151. package/dist/hitl.js +29 -33
  152. package/dist/horario.js +41 -7
  153. package/dist/hosts.js +104 -11
  154. package/dist/impedimento.js +299 -0
  155. package/dist/index.js +961 -542
  156. package/dist/indice-vetorial.js +87 -10
  157. package/dist/indice.js +9 -1
  158. package/dist/init.js +56 -43
  159. package/dist/instabilidade.js +144 -0
  160. package/dist/integracoes-locais.js +4 -0
  161. package/dist/intelligence-graph-cli.js +170 -16
  162. package/dist/intelligence-graph-contexto.js +254 -0
  163. package/dist/intelligence-graph-contract.js +2 -1
  164. package/dist/intelligence-graph-extract-md.js +56 -4
  165. package/dist/intelligence-graph-extract-ts.js +71 -3
  166. package/dist/intelligence-graph-parsers.js +6 -4
  167. package/dist/intelligence-graph-query.js +66 -19
  168. package/dist/leases.js +664 -87
  169. package/dist/ledger-stats.js +15 -1
  170. package/dist/ledger.js +18 -1
  171. package/dist/licoes.js +1 -0
  172. package/dist/liveness.js +6 -3
  173. package/dist/locale-ajuda.js +761 -0
  174. package/dist/locale-gerados.js +160 -0
  175. package/dist/locale-master.js +99 -0
  176. package/dist/locale-onboarding.js +92 -0
  177. package/dist/locale-phase.js +151 -0
  178. package/dist/locale-pulse.js +211 -0
  179. package/dist/locale-retry.js +385 -0
  180. package/dist/locale-roadmap.js +102 -0
  181. package/dist/locale-ship.js +494 -0
  182. package/dist/locale-thread.js +277 -0
  183. package/dist/locale-verify.js +125 -0
  184. package/dist/locale.js +714 -0
  185. package/dist/maestro-runtime.js +4 -1
  186. package/dist/manifest.js +149 -4
  187. package/dist/maquina.js +23 -4
  188. package/dist/master-digest.js +6 -1
  189. package/dist/master-nota.js +18 -11
  190. package/dist/master.js +145 -31
  191. package/dist/mcp-artifacts.js +43 -3
  192. package/dist/mcp-git.js +42 -8
  193. package/dist/mcp-grafo-worker.js +5 -3
  194. package/dist/mcp-grafo.js +55 -6
  195. package/dist/mcp-server.js +22 -3
  196. package/dist/mcp-ship.js +3 -1
  197. package/dist/mcp-verify.js +6 -1
  198. package/dist/memoria.js +48 -6
  199. package/dist/modos.js +3 -6
  200. package/dist/network-roadmap.js +196 -18
  201. package/dist/noctum-arco.js +911 -0
  202. package/dist/noctum-capacidade.js +141 -0
  203. package/dist/noctum-envelope.js +810 -0
  204. package/dist/noctum-execucao.js +304 -0
  205. package/dist/noctum-fila.js +280 -0
  206. package/dist/ocupacao.js +40 -5
  207. package/dist/onboarding.js +40 -21
  208. package/dist/orkmind.js +99 -7
  209. package/dist/orquestracao.js +24 -21
  210. package/dist/parado-no-condutor.js +219 -38
  211. package/dist/phase.js +160 -52
  212. package/dist/policies.js +56 -5
  213. package/dist/portfolio.js +8 -3
  214. package/dist/postura-local.js +234 -0
  215. package/dist/preflight.js +11 -10
  216. package/dist/procedencia.js +225 -0
  217. package/dist/projeto-alvo.js +132 -5
  218. package/dist/prompts.js +40 -1
  219. package/dist/prova-ativacao.js +75 -6
  220. package/dist/pulse-delivery.js +47 -4
  221. package/dist/pulse.js +98 -19
  222. package/dist/ratelimit.js +24 -6
  223. package/dist/recall.js +3 -1
  224. package/dist/redacao-saida.js +63 -0
  225. package/dist/rede-adesao.js +399 -0
  226. package/dist/rede-forja.js +289 -0
  227. package/dist/rede-projetos.js +239 -0
  228. package/dist/rede-status.js +337 -0
  229. package/dist/rede.js +980 -0
  230. package/dist/retry.js +291 -140
  231. package/dist/roadmap-reservas.js +20 -3
  232. package/dist/roadmap-status.js +150 -34
  233. package/dist/runtime-context.js +181 -3
  234. package/dist/runtime-profiles.js +22 -1
  235. package/dist/runtimes.js +2 -1
  236. package/dist/saida-segura.js +58 -0
  237. package/dist/session-events.js +7 -3
  238. package/dist/session-watcher-claude.js +120 -24
  239. package/dist/session-watcher.js +185 -33
  240. package/dist/sessoes-contas.js +187 -0
  241. package/dist/sessoes-inventario.js +6 -18
  242. package/dist/sessoes.js +83 -2
  243. package/dist/ship-publicar.js +800 -0
  244. package/dist/ship.js +157 -88
  245. package/dist/steal.js +77 -0
  246. package/dist/thread-close.js +3 -2
  247. package/dist/thread.js +299 -49
  248. package/dist/util.js +8 -1
  249. package/dist/verify.js +141 -52
  250. package/dist/vida-da-thread.js +254 -0
  251. package/dist/worktree-local.js +165 -0
  252. package/dist/worktree.js +25 -2
  253. package/dist/yaml.js +27 -8
  254. package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
  255. package/package.json +7 -3
  256. package/references/definition-of-done.md +1 -1
  257. package/schemas/code-artifact-graph.v1.schema.json +2 -1
  258. package/skills/README.md +1 -1
  259. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  260. package/skills/phases/master-metrics/SKILL.md +8 -3
package/dist/doctor.js CHANGED
@@ -40,6 +40,7 @@ var __importStar = (this && this.__importStar) || (function () {
40
40
  })();
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
42
  exports.TETO_DO_DONO_DO_GIT = void 0;
43
+ exports.manifestoForaDoRepositorio = manifestoForaDoRepositorio;
43
44
  exports.checarContas = checarContas;
44
45
  exports.checarChaveDeEmbedding = checarChaveDeEmbedding;
45
46
  exports.checarDonoDoGit = checarDonoDoGit;
@@ -69,6 +70,45 @@ const runtime_ambiente_1 = require("./runtime-ambiente");
69
70
  const runtime_profiles_1 = require("./runtime-profiles");
70
71
  const preflight_1 = require("./preflight");
71
72
  const setup_1 = require("./setup");
73
+ const doctor_pulse_cron_1 = require("./doctor-pulse-cron");
74
+ const postura_local_1 = require("./postura-local");
75
+ const worktree_local_1 = require("./worktree-local");
76
+ const maquina_1 = require("./maquina");
77
+ const doctor_rede_1 = require("./doctor-rede");
78
+ const locale_1 = require("./locale");
79
+ /**
80
+ * Ensaio de 03/10/2026 (RM-049): o manifesto e achado subindo a partir do diretorio atual. Um
81
+ * `orkastery.yaml` de uma pasta acima do repositorio (um `ork init` rodado por engano no HOME) era
82
+ * lido como o deste projeto, com outro nome e outra abbrev, e o doctor dizia PRONTO. Vale o manifesto
83
+ * dentro do repositorio ou na arvore principal dele (a worktree de thread le o da arvore principal).
84
+ */
85
+ function manifestoForaDoRepositorio(dirInicial, caminhoDoManifesto) {
86
+ const topo = (0, util_1.exec)('git', ['rev-parse', '--show-toplevel'], dirInicial);
87
+ if (!topo.ok)
88
+ return null;
89
+ const real = (p) => { try {
90
+ return fs.realpathSync(p);
91
+ }
92
+ catch {
93
+ return path.resolve(p);
94
+ } };
95
+ const dirDoManifesto = real(path.dirname(caminhoDoManifesto));
96
+ const dentro = (raiz) => {
97
+ const r = path.relative(real(raiz), dirDoManifesto);
98
+ return r === '' || (!r.startsWith('..') && !path.isAbsolute(r));
99
+ };
100
+ if (dentro(topo.stdout.trim()))
101
+ return null;
102
+ const comum = (0, util_1.exec)('git', ['rev-parse', '--path-format=absolute', '--git-common-dir'], dirInicial);
103
+ if (comum.ok && path.basename(comum.stdout.trim()) === '.git' && dentro(path.dirname(comum.stdout.trim())))
104
+ return null;
105
+ return {
106
+ nome: 'manifesto do repositorio',
107
+ nivel: 'warn',
108
+ detalhe: (0, locale_1.msg)().doctor.manifestoForaDoRepo(manifest_1.NOME_MANIFESTO, caminhoDoManifesto, topo.stdout.trim()),
109
+ correcao: (0, locale_1.msg)().doctor.manifestoForaDoRepoCorrecao(topo.stdout.trim()),
110
+ };
111
+ }
72
112
  /**
73
113
  * I-33 (D7): check "contas por runtime". Cada perfil ativo tem o login conferido pelo proprio
74
114
  * CLI com o env dele (`claude auth status`, `codex login status`); o doctor so le e relata, sem
@@ -80,12 +120,12 @@ function checarContas(raiz, auth = (p) => p.runtime === 'claude-bg' ? adapter.co
80
120
  perfis = (0, runtime_profiles_1.lerPerfisComContas)(raiz).perfis.filter(p => p.estado !== 'desativado');
81
121
  }
82
122
  catch (e) {
83
- return { nome: 'contas por runtime', nivel: 'fail', detalhe: `store de perfis invalido: ${e.message}`,
84
- correcao: 'o store fica em .orkastery/private/runtime-profiles.json (arquivo 0600, pasta 0700)' };
123
+ return { nome: 'contas por runtime', nivel: 'fail', detalhe: (0, locale_1.msg)().doctor.storeInvalido(e.message),
124
+ correcao: (0, locale_1.msg)().doctor.storeCorrecao };
85
125
  }
86
126
  if (perfis.length === 0)
87
127
  return { nome: 'contas por runtime', nivel: 'ok',
88
- detalhe: 'nenhum perfil configurado: cada runtime despacha pelo ambiente do processo' };
128
+ detalhe: (0, locale_1.msg)().doctor.semPerfis };
89
129
  const partes = [];
90
130
  let nivel = 'ok';
91
131
  for (const runtime of runtime_profiles_1.RUNTIMES_COM_PERFIL) {
@@ -95,8 +135,8 @@ function checarContas(raiz, auth = (p) => p.runtime === 'claude-bg' ? adapter.co
95
135
  const estados = doRuntime.map(p => {
96
136
  const a = auth((0, runtime_profiles_1.perfilDeDespacho)(p));
97
137
  return { id: p.id, pronto: a.ok && (0, runtime_profiles_1.perfilDisponivel)(p),
98
- texto: !a.ok ? (a.pago ? 'provider pago (nunca despacha)' : a.transitorio ? 'conferencia de login inconclusiva' : 'sem login')
99
- : (0, runtime_profiles_1.perfilDisponivel)(p) ? 'pronto' : `${p.estado}${p.esgotadoAte ? ` ate ${p.esgotadoAte}` : ''}` };
138
+ texto: !a.ok ? (a.pago ? (0, locale_1.msg)().doctor.contaPaga : a.transitorio ? (0, locale_1.msg)().doctor.contaInconclusiva : (0, locale_1.msg)().doctor.contaSemLogin)
139
+ : (0, runtime_profiles_1.perfilDisponivel)(p) ? (0, locale_1.msg)().doctor.contaPronta : (0, locale_1.msg)().doctor.contaFora(p.estado, p.esgotadoAte) };
100
140
  });
101
141
  const prontos = estados.filter(e => e.pronto).length;
102
142
  if (prontos === 0)
@@ -106,7 +146,7 @@ function checarContas(raiz, auth = (p) => p.runtime === 'claude-bg' ? adapter.co
106
146
  partes.push(`${runtime}: ${estados.map(e => `${e.id} ${e.texto}`).join(', ')}`);
107
147
  }
108
148
  return { nome: 'contas por runtime', nivel, detalhe: partes.join('; '),
109
- ...(nivel !== 'ok' ? { correcao: 'ork accounts check marca os perfis (sem-auth, provider-pago); ork accounts add refaz o login de assinatura pelo proprio CLI, nunca copiando credencial' } : {}) };
149
+ ...(nivel !== 'ok' ? { correcao: (0, locale_1.msg)().doctor.contasCorrecao } : {}) };
110
150
  }
111
151
  /**
112
152
  * Variaveis que REDIRECIONAM o despacho do `claude` para um provider pago.
@@ -132,27 +172,24 @@ function checarChaveDeEmbedding(carregado, env = process.env) {
132
172
  const nome = 'chave de embedding';
133
173
  const config = (0, manifest_1.configDeEmbedding)(carregado.manifesto);
134
174
  if (config.provider === 'none')
135
- return { nome, nivel: 'ok', detalhe: 'memory.embedding com provider none: busca por significado desligada' };
175
+ return { nome, nivel: 'ok', detalhe: (0, locale_1.msg)().doctor.embeddingNone };
136
176
  const variavel = config.api_key_env;
137
177
  if (runtime_ambiente_1.ENVS_DE_PROVIDER_PAGO.includes(variavel)) {
138
- return { nome, nivel: 'fail', detalhe: `memory.embedding.api_key_env declara ${variavel}, nome da lista de provider pago`,
139
- correcao: 'use uma chave dedicada ao Orkastery com nome proprio, por exemplo ORKASTERY_EMBEDDING_API_KEY' };
178
+ return { nome, nivel: 'fail', detalhe: (0, locale_1.msg)().doctor.embeddingPago(variavel), correcao: (0, locale_1.msg)().doctor.embeddingPagoCorrecao };
140
179
  }
141
180
  if (!variavel) {
142
- return { nome, nivel: 'fail', detalhe: `memory.embedding com provider ${config.provider} sem api_key_env`,
143
- correcao: 'declare em memory.embedding.api_key_env o NOME da variavel com a chave dedicada' };
181
+ return { nome, nivel: 'fail', detalhe: (0, locale_1.msg)().doctor.embeddingSemVariavel(config.provider),
182
+ correcao: (0, locale_1.msg)().doctor.embeddingSemVariavelCorrecao };
144
183
  }
145
184
  const valor = (env[variavel] ?? '').trim();
146
185
  const dsn = carregado.manifesto.memory.database_url_env ? (env[carregado.manifesto.memory.database_url_env] ?? '') : '';
147
186
  if (valor !== '' && !(0, orkmind_1.chaveDeEmbeddingAceita)(valor, dsn)) {
148
- return { nome, nivel: 'fail', detalhe: `${variavel} tem valor recusado: parece URL, DSN ou texto com espaco (valor nunca impresso)`,
149
- correcao: `confira se ${variavel} guarda a chave dedicada, e nao outra credencial` };
187
+ return { nome, nivel: 'fail', detalhe: (0, locale_1.msg)().doctor.embeddingRecusada(variavel), correcao: (0, locale_1.msg)().doctor.embeddingRecusadaCorrecao(variavel) };
150
188
  }
151
189
  if (valor !== '') {
152
- return { nome, nivel: 'ok', detalhe: `${variavel} presente no ambiente (valor nunca impresso); ${config.provider} ${config.model}` };
190
+ return { nome, nivel: 'ok', detalhe: (0, locale_1.msg)().doctor.embeddingPresente(variavel, config.provider, config.model) };
153
191
  }
154
- return { nome, nivel: 'warn', detalhe: `${variavel} ausente do ambiente: a busca por significado usa o fallback local ou cai para FTS; o regime nao muda`,
155
- correcao: `exporte ${variavel} com a chave dedicada ao Orkastery (com limite de credito no painel do provider)` };
192
+ return { nome, nivel: 'warn', detalhe: (0, locale_1.msg)().doctor.embeddingAusente(variavel), correcao: (0, locale_1.msg)().doctor.embeddingAusenteCorrecao(variavel) };
156
193
  }
157
194
  /** Acima disso a conferencia do dono do `.git` fica parcial (aviso), para o doctor nao pesar. */
158
195
  exports.TETO_DO_DONO_DO_GIT = 200_000;
@@ -218,31 +255,29 @@ function checarDonoDoGit(dirInicial, opcoes = {}) {
218
255
  }
219
256
  if (total > 0) {
220
257
  return { nome, nivel: 'fail',
221
- detalhe: `${total} entrada(s) de ${relativo(dirComum)} com outro dono (uid ${[...uids].sort((a, b) => a - b).join(', ')}; o do ` +
222
- `repositorio e ${raiz.uid}): ${estranhos.join(', ')}${total > estranhos.length ? ', ...' : ''}; o git do dono nao grava nelas, ` +
223
- `e o fetch e o commit falham${parcial ? ` (conferencia parcial: mais de ${teto} entradas)` : ''}`,
224
- correcao: `sudo chown -R ${raiz.uid}:${raiz.gid} ${noShell(dirComum)} (o ork nao roda isso sozinho)` };
258
+ detalhe: (0, locale_1.msg)().doctor.donoOutro(total, relativo(dirComum), [...uids].sort((a, b) => a - b).join(', '), raiz.uid, `${estranhos.join(', ')}${total > estranhos.length ? ', ...' : ''}`, parcial ? teto : null),
259
+ correcao: (0, locale_1.msg)().doctor.donoCorrecao(`sudo chown -R ${raiz.uid}:${raiz.gid} ${noShell(dirComum)}`) };
225
260
  }
226
261
  if (parcial) {
227
- return { nome, nivel: 'warn', detalhe: `mais de ${teto} entradas em ${relativo(dirComum)}: conferencia parcial, sem outro dono ate aqui`,
228
- correcao: `confira o resto com: find ${noShell(dirComum)} -not -uid ${raiz.uid}` };
262
+ return { nome, nivel: 'warn', detalhe: (0, locale_1.msg)().doctor.donoParcial(teto, relativo(dirComum)),
263
+ correcao: (0, locale_1.msg)().doctor.donoParcialCorrecao(`find ${noShell(dirComum)} -not -uid ${raiz.uid}`) };
229
264
  }
230
- return { nome, nivel: 'ok', detalhe: `${vistos} entradas de ${relativo(dirComum)} com o dono do repositorio (uid ${raiz.uid})` };
265
+ return { nome, nivel: 'ok', detalhe: (0, locale_1.msg)().doctor.donoOk(vistos, relativo(dirComum), raiz.uid) };
231
266
  }
232
267
  /** Checks locais; ler a entrevista não abre driver, banco, runtime ou rede. */
233
268
  function checarOnboarding(carregado) {
234
269
  const estado = (0, onboarding_1.lerOnboarding)(carregado.raiz);
235
270
  const pendentes = onboarding_1.ETAPAS_ONBOARDING.filter(e => estado.etapas[e] === null);
236
271
  const checks = [{ nome: 'onboarding', nivel: pendentes.length ? 'warn' : 'ok',
237
- detalhe: pendentes.length ? `${pendentes.length} etapa(s) pendente(s): ${pendentes.join(', ')}` : '9 etapas respondidas',
272
+ detalhe: pendentes.length ? (0, locale_1.msg)().doctor.onboardingPendente(pendentes.length, pendentes.join(', ')) : (0, locale_1.msg)().doctor.onboardingCompleto,
238
273
  ...(pendentes.length ? { correcao: 'ork onboarding' } : {}) }];
239
274
  const escolha = estado.etapas.memoria?.conteudo;
240
275
  const modo = escolha === 'sim' || escolha === true ? 'orkmind' :
241
276
  escolha === 'orkmind' || escolha === 'files' ? escolha :
242
277
  escolha && typeof escolha === 'object' && !Array.isArray(escolha) ? escolha.modo : null;
243
278
  if ((modo === 'orkmind' || modo === 'files') && modo !== carregado.manifesto.memory.mode) {
244
- checks.push({ nome: 'onboarding memoria', nivel: 'warn', detalhe: `entrevista escolheu ${modo}; manifesto declara ${carregado.manifesto.memory.mode}`,
245
- correcao: `revise memory.mode: ${modo} em orkastery.yaml; a entrevista não altera o manifesto` });
279
+ checks.push({ nome: 'onboarding memoria', nivel: 'warn', detalhe: (0, locale_1.msg)().doctor.entrevistaMemoria(modo, carregado.manifesto.memory.mode),
280
+ correcao: (0, locale_1.msg)().doctor.entrevistaMemoriaCorrecao(modo) });
246
281
  }
247
282
  // I-35: o fuso respondido na etapa maestro orienta owner.timezone, sem editar o manifesto. Com
248
283
  // `owner.timezone` na mesma resposta (gravado no manifesto pelo `onboarding set`), vale ele: no
@@ -255,8 +290,8 @@ function checarOnboarding(carregado) {
255
290
  ? (0, horario_1.normalizarFuso)(fusoDoOwner) ?? (0, horario_1.normalizarFuso)(maestro.fuso) : undefined;
256
291
  if (fusoDaEntrevista && fusoDaEntrevista !== carregado.manifesto.owner?.timezone) {
257
292
  checks.push({ nome: 'onboarding fuso', nivel: 'warn',
258
- detalhe: `entrevista informou ${fusoDaEntrevista}; manifesto declara ${carregado.manifesto.owner?.timezone ?? `${horario_1.CHAVE_DO_FUSO} ausente`}`,
259
- correcao: `revise ${horario_1.CHAVE_DO_FUSO}: "${fusoDaEntrevista}" em orkastery.yaml; a entrevista não altera o manifesto` });
293
+ detalhe: (0, locale_1.msg)().doctor.entrevistaFuso(fusoDaEntrevista, carregado.manifesto.owner?.timezone, horario_1.CHAVE_DO_FUSO),
294
+ correcao: (0, locale_1.msg)().doctor.entrevistaFusoCorrecao(horario_1.CHAVE_DO_FUSO, fusoDaEntrevista) });
260
295
  }
261
296
  return checks;
262
297
  }
@@ -294,31 +329,48 @@ function textoDosBlocos(blocos) {
294
329
  porModo.set(b.tag, [...(porModo.get(b.tag) ?? []), b.bloco]);
295
330
  return [...porModo].map(([tag, numeros]) => `${tag} ${numeros.join(', ')}`).join('; ');
296
331
  }
332
+ /**
333
+ * Ensaio de 03/10 (R1): com perfil ativo do runtime, quem confere o login e o check "contas por runtime";
334
+ * sem perfil (ou com o store ilegivel, que aquele check reprova), o despacho usa o login do `claude` do processo.
335
+ */
336
+ function temPerfilAtivo(carregado, runtime) {
337
+ if (!carregado || carregado.erros.length)
338
+ return false;
339
+ try {
340
+ return (0, runtime_profiles_1.lerPerfisComContas)(carregado.raiz).perfis.some(p => p.runtime === runtime && p.estado !== 'desativado');
341
+ }
342
+ catch {
343
+ return false;
344
+ }
345
+ }
297
346
  /**
298
347
  * Fatia 2 do ensaio da 0.5.0 (P1): o `claude` so e obrigatorio quando algum bloco de modo permitido
299
348
  * despacha por ele. Sem manifesto, com manifesto invalido ou com setup ilegivel vale o padrao (todo
300
349
  * bloco no claude-bg), e a falta reprova como antes.
301
350
  */
302
- function checarRuntimeClaude(carregado, claude, versao) {
351
+ function checarRuntimeClaude(carregado, claude, versao, auth = null) {
303
352
  const nome = 'runtime claude-bg';
304
- if (claude)
305
- return { nome, nivel: 'ok', detalhe: `${claude} (${versao ?? 'versao desconhecida'})` };
353
+ if (claude) {
354
+ const detalhe = `${claude} (${versao ?? (0, locale_1.msg)().doctor.versaoDesconhecida})`;
355
+ // Ensaio de 03/10 (R1): sem perfil de conta, o despacho usa o login do proprio `claude`; sem ele, o
356
+ // primeiro despacho falha. Conferencia inconclusiva (timeout, JSON ilegivel) nao prova falta de login.
357
+ if (auth && !auth.ok && !auth.transitorio) {
358
+ return { nome, nivel: 'warn', detalhe: (0, locale_1.msg)().doctor.claudeSemLogin(detalhe, auth.detalhe),
359
+ correcao: auth.pago ? (0, locale_1.msg)().doctor.claudeLoginPago : (0, locale_1.msg)().doctor.claudeLogin };
360
+ }
361
+ return { nome, nivel: 'ok', detalhe };
362
+ }
306
363
  const blocos = carregado && carregado.erros.length === 0 ? blocosDoRuntime(carregado, 'claude-bg') : null;
307
364
  if (blocos && blocos.principal.length === 0) {
308
365
  // CHECK, rodada 1 (S6): as fases nao precisam dele, mas o `ork audit run` despacha sempre pelo claude-bg.
309
366
  return { nome, nivel: 'warn',
310
- detalhe: 'binario `claude` fora do PATH (opcional para as fases: nenhum bloco dos modos permitidos despacha pelo claude-bg' +
311
- (blocos.fallback.length
312
- ? `; o fallback de ${blocos.fallback.length} bloco(s) cai nele e falharia: ${textoDosBlocos(blocos.fallback)}` : '') +
313
- '; o ork audit run ainda despacha por ele)',
314
- correcao: 'para despachar pelo claude-bg (e rodar ork audit run), instale o Claude Code e garanta `claude` no PATH' };
367
+ detalhe: (0, locale_1.msg)().doctor.claudeOpcional(blocos.fallback.length
368
+ ? { blocos: blocos.fallback.length, texto: textoDosBlocos(blocos.fallback) } : null),
369
+ correcao: (0, locale_1.msg)().doctor.claudeOpcionalCorrecao };
315
370
  }
316
371
  return { nome, nivel: 'fail',
317
- detalhe: 'binario `claude` fora do PATH' + (blocos
318
- ? `; ${blocos.principal.length} bloco(s) dos modos permitidos despacham por ele (${textoDosBlocos(blocos.principal)})` : ''),
319
- correcao: 'instale o Claude Code e garanta `claude` no PATH; so com o Codex, passe cada bloco para ele ' +
320
- '(ork setup <modo> --bloco N --runtime codex --model <modelo>) ou tire o modo de conduction.allowed_modes ' +
321
- '(mantenha o conduction.default_mode entre os permitidos)' };
372
+ detalhe: (0, locale_1.msg)().doctor.claudeAusente(blocos ? { blocos: blocos.principal.length, texto: textoDosBlocos(blocos.principal) } : null),
373
+ correcao: (0, locale_1.msg)().doctor.claudeAusenteCorrecao };
322
374
  }
323
375
  /**
324
376
  * O despacho pelo Codex quando o projeto o elege: por `runtime.adapter: codex`, como antes, ou, desde
@@ -331,42 +383,52 @@ function checarDespachoPeloCodex(carregado, codex, sonda) {
331
383
  const blocos = blocosDoRuntime(carregado, 'codex')?.principal ?? [];
332
384
  if (!pelaAdapter && blocos.length === 0)
333
385
  return null;
334
- const origem = [pelaAdapter ? 'runtime.adapter: codex' : '',
335
- blocos.length ? `${blocos.length} bloco(s) dos modos permitidos no codex (${textoDosBlocos(blocos)})` : '']
336
- .filter(Boolean).join(' e ');
386
+ const origem = (0, locale_1.msg)().doctor.origemDoCodex(pelaAdapter, blocos.length ? { blocos: blocos.length, texto: textoDosBlocos(blocos) } : null);
337
387
  const sandboxConfigurado = carregado.manifesto.runtime.sandbox;
338
388
  const sandboxQuebrado = sonda !== null && !sonda.ok && sandboxConfigurado !== 'danger-full-access';
389
+ // RM-047 (P1): a postura que afrouxa o sandbox so despacha com a confirmacao local desta maquina.
390
+ const posturaSemConfirmacao = (0, postura_local_1.recusaDePostura)(carregado.raiz, carregado.manifesto, 'codex') !== null;
339
391
  return {
340
392
  nome: 'despacho pelo codex',
341
- nivel: !codex ? 'fail' : sandboxQuebrado ? 'fail' : 'ok',
393
+ nivel: !codex ? 'fail' : sandboxQuebrado || posturaSemConfirmacao ? 'fail' : 'ok',
342
394
  detalhe: !codex
343
- ? `${origem}, mas o binario \`codex\` esta fora do PATH`
395
+ ? (0, locale_1.msg)().doctor.codexForaNoDespacho(origem)
344
396
  : sandboxQuebrado
345
- ? `${origem} com sandbox "${sandboxConfigurado}", mas o sandbox nao executa nesta maquina (o agente narraria sucesso sem rodar nada)`
346
- : `${origem} com sandbox "${sandboxConfigurado}"`,
397
+ ? (0, locale_1.msg)().doctor.codexSandboxQuebrado(origem, sandboxConfigurado)
398
+ : posturaSemConfirmacao
399
+ ? (0, locale_1.msg)().doctor.codexSemConfirmacao(origem, sandboxConfigurado)
400
+ : (0, locale_1.msg)().doctor.codexSandboxOk(origem, sandboxConfigurado),
347
401
  correcao: !codex
348
- ? 'instale o Codex CLI e autentique com `codex login` (assinatura, nunca API key)'
402
+ ? (0, locale_1.msg)().doctor.codexForaNoDespachoCorrecao
349
403
  : sandboxQuebrado
350
- ? 'instale o bubblewrap do sistema, ou declare runtime.sandbox: danger-full-access ciente do risco'
351
- : undefined,
404
+ ? (0, locale_1.msg)().doctor.codexSandboxQuebradoCorrecao((0, postura_local_1.comandoDeConfirmacao)('danger-full-access'))
405
+ : posturaSemConfirmacao
406
+ ? (0, locale_1.msg)().doctor.codexSemConfirmacaoCorrecao((0, postura_local_1.comandoDeConfirmacao)(sandboxConfigurado))
407
+ : undefined,
352
408
  };
353
409
  }
354
- /** Roda todos os checks a partir do diretorio informado. */
355
- function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente_1.nomesDeProviderAtivos)()) {
410
+ /**
411
+ * Roda todos os checks a partir do diretorio informado. RM-031: `analisadores` e o check do grafo
412
+ * (`checarAnalisadoresDoGrafo` do CLI do grafo), que o `index.ts` passa: fora da familia do grafo so
413
+ * ele e o worker do MCP a abrem (fronteira do KG1), e o doctor nao a importa.
414
+ */
415
+ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente_1.nomesDeProviderAtivos)(), lerCrontab = doctor_pulse_cron_1.lerCrontabDoSistema, conferirAuthDoClaude = () => adapter.conferirAuth(null), analisadores) {
356
416
  const checks = [];
357
417
  const major = versaoNode();
358
418
  checks.push({
359
419
  nome: 'node',
360
420
  nivel: major >= 20 ? 'ok' : 'fail',
361
421
  detalhe: `v${process.versions.node}`,
362
- correcao: major >= 20 ? undefined : 'instale Node 20 ou superior',
422
+ correcao: major >= 20 ? undefined : (0, locale_1.msg)().doctor.instaleNode,
363
423
  });
424
+ if (analisadores)
425
+ checks.push(analisadores());
364
426
  const git = (0, util_1.noPath)('git');
365
427
  checks.push({
366
428
  nome: 'git',
367
429
  nivel: git ? 'ok' : 'fail',
368
- detalhe: git ?? 'nao encontrado no PATH',
369
- correcao: git ? undefined : 'instale o git',
430
+ detalhe: git ?? (0, locale_1.msg)().doctor.gitAusente,
431
+ correcao: git ? undefined : (0, locale_1.msg)().doctor.instaleGit,
370
432
  });
371
433
  const repo = (0, util_1.exec)('git', ['rev-parse', '--is-inside-work-tree'], dirInicial);
372
434
  const dentroDeRepo = repo.ok && repo.stdout.trim() === 'true';
@@ -377,8 +439,8 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
377
439
  checks.push({
378
440
  nome: 'repositorio',
379
441
  nivel: dentroDeRepo ? 'ok' : 'fail',
380
- detalhe: dentroDeRepo ? `branch ${branch}${semCommit ? ' (sem commit)' : ''}` : 'fora de um repositorio git',
381
- correcao: dentroDeRepo ? undefined : 'rode o ork dentro de um repositorio git',
442
+ detalhe: dentroDeRepo ? (0, locale_1.msg)().doctor.branch(branch, semCommit) : (0, locale_1.msg)().doctor.foraDeRepo,
443
+ correcao: dentroDeRepo ? undefined : (0, locale_1.msg)().doctor.rodeDentroDeRepo,
382
444
  });
383
445
  if (dentroDeRepo) {
384
446
  const dono = checarDonoDoGit(dirInicial);
@@ -390,7 +452,7 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
390
452
  const carregado = (0, manifest_1.carregarManifesto)(dirInicial);
391
453
  const claude = adapter.disponivel();
392
454
  const v = claude ? adapter.versao() : null;
393
- checks.push(checarRuntimeClaude(carregado, claude, v));
455
+ checks.push(checarRuntimeClaude(carregado, claude, v, claude && !temPerfilAtivo(carregado, 'claude-bg') ? conferirAuthDoClaude() : null));
394
456
  // Segundo runtime homologado. Ausente e `warn`, nao `fail`: o claude-bg segue sendo o
395
457
  // padrao, e um projeto que nunca pediu codex nao pode ficar bloqueado por ele.
396
458
  const codex = codexAdapter.disponivel();
@@ -403,13 +465,13 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
403
465
  nome: 'runtime codex',
404
466
  nivel: codex ? 'ok' : 'warn',
405
467
  detalhe: codex
406
- ? `${codex} (${codexVersao ?? 'versao desconhecida'})`
468
+ ? `${codex} (${codexVersao ?? (0, locale_1.msg)().doctor.versaoDesconhecida})`
407
469
  : usaCodex
408
- ? 'binario `codex` fora do PATH (o projeto despacha por ele: veja despacho pelo codex)'
409
- : 'binario `codex` fora do PATH (opcional: claude-bg e o runtime padrao)',
470
+ ? (0, locale_1.msg)().doctor.codexAusenteUsado
471
+ : (0, locale_1.msg)().doctor.codexAusenteOpcional,
410
472
  correcao: codex
411
473
  ? undefined
412
- : 'para despachar pelo codex, instale o Codex CLI e autentique com `codex login`',
474
+ : (0, locale_1.msg)().doctor.instaleCodex,
413
475
  });
414
476
  // Pitfall MEDIDO em 06/09/2026: com o sandbox quebrado, o `codex exec` sai 0 e o agente
415
477
  // NARRA sucesso sem executar nada. A sonda e deterministica (roda `true`, sem LLM).
@@ -420,20 +482,20 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
420
482
  nome: 'sandbox do codex',
421
483
  nivel: sondaDoCodex.ok ? 'ok' : 'warn',
422
484
  detalhe: sondaDoCodex.ok
423
- ? '`codex sandbox true` executa nesta maquina'
424
- : `sonda \`codex sandbox true\` falhou: ${sondaDoCodex.detalhe}`,
485
+ ? (0, locale_1.msg)().doctor.sandboxOk
486
+ : (0, locale_1.msg)().doctor.sandboxFalhou(sondaDoCodex.detalhe),
425
487
  correcao: sondaDoCodex.ok
426
488
  ? undefined
427
- : 'instale o pacote bubblewrap do sistema (o bwrap embutido nao cria user namespace ' +
428
- 'nesta maquina) ou declare runtime.sandbox: danger-full-access ciente do risco',
489
+ : (0, locale_1.msg)().doctor.sandboxCorrecao((0, postura_local_1.comandoDeConfirmacao)('danger-full-access')),
429
490
  });
430
491
  }
431
492
  if (!carregado) {
432
493
  checks.push({
433
494
  nome: 'manifesto',
434
495
  nivel: 'fail',
435
- detalhe: `${manifest_1.NOME_MANIFESTO} nao encontrado a partir de ${dirInicial}`,
436
- correcao: 'ork init',
496
+ detalhe: (0, locale_1.msg)().doctor.manifestoAusente(manifest_1.NOME_MANIFESTO, dirInicial),
497
+ // Ensaio de 03/10/2026 (RM-049): fora de repositorio, o `ork init` recusa; a correcao diz onde roda-lo.
498
+ correcao: dentroDeRepo ? (0, locale_1.msg)().doctor.rodeInit : (0, locale_1.msg)().doctor.entreNoRepoEInit,
437
499
  });
438
500
  }
439
501
  else {
@@ -442,10 +504,15 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
442
504
  nivel: carregado.erros.length > 0 ? 'fail' : carregado.avisos.length > 0 ? 'warn' : 'ok',
443
505
  detalhe: carregado.erros.length > 0
444
506
  ? `${carregado.caminho}: ${carregado.erros.join('; ')}`
445
- : `${carregado.caminho} (${carregado.bytes} B de ${manifest_1.LIMITE_MANIFESTO_BYTES})` +
446
- (carregado.avisos.length > 0 ? `; ${carregado.avisos.join('; ')}` : ''),
447
- correcao: carregado.erros.length > 0 ? 'corrija o manifesto e rode ork doctor de novo' : undefined,
507
+ : (0, locale_1.msg)().doctor.manifestoOk(carregado.caminho, carregado.bytes, manifest_1.LIMITE_MANIFESTO_BYTES) +
508
+ (carregado.avisos.length > 0 ? `; ${carregado.avisos.map((a) => (0, locale_1.msg)().onboarding.avisoDaPreferencia(a)).join('; ')}` : ''),
509
+ correcao: carregado.erros.length > 0 ? (0, locale_1.msg)().doctor.corrijaManifesto : undefined,
448
510
  });
511
+ if (dentroDeRepo) {
512
+ const fora = manifestoForaDoRepositorio(dirInicial, carregado.caminho);
513
+ if (fora)
514
+ checks.push(fora);
515
+ }
449
516
  checks.push(...checarOnboarding(carregado));
450
517
  const abbrev = carregado.manifesto.project.abbrev;
451
518
  const checkAbbrev = (0, slug_1.validarAbbrev)(abbrev);
@@ -453,16 +520,15 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
453
520
  nome: 'abbrev do projeto',
454
521
  nivel: checkAbbrev.ok ? 'ok' : 'fail',
455
522
  detalhe: checkAbbrev.ok
456
- ? `"${abbrev}" (parte 1 do slug de sessao)`
523
+ ? (0, locale_1.msg)().doctor.abbrevOk(abbrev)
457
524
  : checkAbbrev.erro,
458
- correcao: checkAbbrev.ok ? undefined : 'defina project.abbrev com ate 3 caracteres [a-z0-9]',
525
+ correcao: checkAbbrev.ok ? undefined : (0, locale_1.msg)().doctor.abbrevCorrecao,
459
526
  });
460
527
  const cond = carregado.manifesto.conduction;
461
528
  checks.push({
462
529
  nome: 'modos de conducao',
463
530
  nivel: 'ok',
464
- detalhe: `padrao ${modos_1.MODOS[cond.default_mode].tag}; ` +
465
- `permitidos ${cond.allowed_modes.map((m) => modos_1.MODOS[m].tag).join(', ')}`,
531
+ detalhe: (0, locale_1.msg)().doctor.modos(modos_1.MODOS[cond.default_mode].tag, cond.allowed_modes.map((m) => modos_1.MODOS[m].tag).join(', ')),
466
532
  });
467
533
  // I-35: o fuso em que todo horario chega ao dono; valor invalido avisa e nao para nada.
468
534
  const fuso = (0, horario_1.fusoDoManifesto)(carregado);
@@ -470,15 +536,28 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
470
536
  nome: 'fuso do dono',
471
537
  nivel: fuso.aviso ? 'warn' : 'ok',
472
538
  detalhe: fuso.aviso ?? (fuso.origem === 'manifesto'
473
- ? `${fuso.fuso} (${horario_1.CHAVE_DO_FUSO}); horarios para pessoas em ${(0, horario_1.rotuloDoFuso)(fuso.fuso)}`
474
- : `${fuso.fuso} (fuso do sistema; ${horario_1.CHAVE_DO_FUSO} nao configurado)`),
475
- correcao: fuso.aviso ? `corrija ${horario_1.CHAVE_DO_FUSO} com um nome IANA` : undefined,
539
+ ? (0, locale_1.msg)().doctor.fusoDoManifesto(fuso.fuso, horario_1.CHAVE_DO_FUSO, (0, horario_1.rotuloDoFuso)(fuso.fuso))
540
+ : (0, locale_1.msg)().doctor.fusoDoSistema(fuso.fuso, horario_1.CHAVE_DO_FUSO)),
541
+ correcao: fuso.aviso ? (0, locale_1.msg)().doctor.fusoCorrecao(horario_1.CHAVE_DO_FUSO) : undefined,
476
542
  });
477
543
  // Quando o manifesto ou um bloco de modo permitido ELEGE o codex, a ausencia dele (ou um
478
544
  // sandbox que nao executa) deixa de ser aviso: e exatamente o que bloquearia a fase.
479
545
  const despachoPeloCodex = checarDespachoPeloCodex(carregado, codex, sondaDoCodex);
480
546
  if (despachoPeloCodex)
481
547
  checks.push(despachoPeloCodex);
548
+ // RM-047 (P5): o manifesto pede a fabrica compartilhada, mas quem liga a publicacao e a maquina.
549
+ const fabricaPedida = (0, maquina_1.avisoDaFabricaPedida)(carregado.manifesto);
550
+ if (fabricaPedida) {
551
+ checks.push({ nome: 'fabrica compartilhada', nivel: 'warn',
552
+ detalhe: (0, locale_1.msg)().doctor.fabricaPedida, correcao: (0, locale_1.msg)().doctor.fabricaPedidaCorrecao });
553
+ }
554
+ // RM-047 (P3): worktree.dir fora da raiz so cria checkout com a confirmacao local desta maquina.
555
+ const recusaDaPasta = (0, worktree_local_1.recusaDePastaDasWorktrees)(carregado.raiz, carregado.manifesto);
556
+ if (recusaDaPasta) {
557
+ checks.push({ nome: 'pasta das worktrees', nivel: 'fail',
558
+ detalhe: (0, locale_1.msg)().doctor.pastaForaDaRaiz(carregado.manifesto.worktree.dir),
559
+ correcao: (0, locale_1.msg)().doctor.pastaForaDaRaizCorrecao(worktree_local_1.COMANDO_CONFIRMAR_WORKTREE) });
560
+ }
482
561
  const politica = carregado.manifesto.runtime.provider_policy;
483
562
  const soAssinatura = politica === 'subscription-only';
484
563
  const redirecionam = ENVS_QUE_REDIRECIONAM.filter(e => nomesHerdados.includes(e));
@@ -488,21 +567,21 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
488
567
  nome: 'custo e provider herdado',
489
568
  nivel: bloqueia ? 'fail' : soAssinatura && pagas.length > 0 ? 'warn' : 'ok',
490
569
  detalhe: bloqueia
491
- ? `politica ${politica} violada: ${redirecionam.join(', ')} redireciona o despacho do claude`
570
+ ? (0, locale_1.msg)().doctor.politicaViolada(politica, redirecionam.join(', '))
492
571
  : pagas.length > 0
493
- ? `politica ${politica}; despacho segue na assinatura local, mas ha credencial paga no ambiente: ${pagas.join(', ')}`
494
- : `politica ${politica}; nenhuma variavel de provider pago ativa`,
572
+ ? (0, locale_1.msg)().doctor.politicaComPaga(politica, pagas.join(', '))
573
+ : (0, locale_1.msg)().doctor.politicaLimpa(politica),
495
574
  correcao: bloqueia
496
- ? `remova do ambiente: ${redirecionam.join(', ')} (o despacho usa a assinatura Claude local)`
575
+ ? (0, locale_1.msg)().doctor.removaDoAmbiente(redirecionam.join(', '))
497
576
  : pagas.length > 0
498
- ? `nenhuma acao obrigatoria; nunca despache fase por ${pagas.join(', ')}`
577
+ ? (0, locale_1.msg)().doctor.nuncaDespachePorPaga(pagas.join(', '))
499
578
  : undefined,
500
579
  });
501
580
  const efetivas = (0, runtime_ambiente_1.nomesDeProviderAtivos)();
502
581
  checks.push({
503
582
  nome: 'provider efetivo da fabrica',
504
583
  nivel: soAssinatura && efetivas.length ? 'warn' : 'ok',
505
- detalhe: efetivas.length ? `nomes ativos: ${efetivas.join(', ')}` : 'nenhum nome da lista de provider ativo',
584
+ detalhe: efetivas.length ? (0, locale_1.msg)().doctor.providersAtivos(efetivas.join(', ')) : (0, locale_1.msg)().doctor.nenhumProvider,
506
585
  });
507
586
  // Bloco B6: o regime de memoria e um CHECK, nao um detalhe do manifesto. Manifesto
508
587
  // que pede `orkmind` e nao consegue liga-lo vira `warn` com a correcao, nunca `fail`:
@@ -510,15 +589,15 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
510
589
  const context = (0, project_state_1.memoryState)(carregado);
511
590
  const { estado } = (0, orkmind_1.resolverRegime)(context.loaded.manifesto, null);
512
591
  checks.push({ nome: 'fonte da memoria', nivel: context.divergent ? 'warn' : 'ok',
513
- detalhe: `${context.source}${context.divergent ? ' (cópia da worktree divergente preservada)' : ''}` });
592
+ detalhe: (0, locale_1.msg)().doctor.fonteDaMemoria(context.source, context.divergent) });
514
593
  checks.push({
515
594
  nome: 'regime de memoria',
516
595
  nivel: estado.efetivo === 'orkmind' ? 'ok' : estado.pedido === 'orkmind' ? 'warn' : 'ok',
517
596
  detalhe: estado.pedido === 'orkmind' && estado.efetivo === 'files'
518
- ? `pedido orkmind, efetivo files (${estado.motivo}): ${estado.detalhe}`
597
+ ? (0, locale_1.msg)().doctor.regimeDegradado(estado.motivo, estado.detalhe)
519
598
  : estado.efetivo === 'orkmind'
520
- ? `orkmind ativo no tenant "${estado.tenant}" pela variavel ${estado.variavel}`
521
- : 'files (fallback honesto: handoff por arquivos, ponteiro path#ancora)',
599
+ ? (0, locale_1.msg)().doctor.regimeOrkmind(estado.tenant, estado.variavel)
600
+ : (0, locale_1.msg)().doctor.memoriaFiles,
522
601
  correcao: estado.pedido === 'orkmind' && estado.efetivo === 'files' ? estado.correcao : undefined,
523
602
  });
524
603
  checks.push(checarChaveDeEmbedding(context.loaded));
@@ -532,13 +611,13 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
532
611
  nome: 'fila de rate limit',
533
612
  nivel: escalados.length > 0 ? 'warn' : 'ok',
534
613
  detalhe: fila.length === 0
535
- ? 'vazia: nenhuma fase morreu por limite de uso neste projeto'
536
- : `${esperando.length} aguardando janela, ${escalados.length} escalado(s) para humano` +
537
- (esperando.length > 0 ? `; proxima janela em ${(0, horario_1.formatarDataHoraRotulada)(esperando[0].liberaEm)}` : ''),
614
+ ? (0, locale_1.msg)().doctor.filaVazia
615
+ : (0, locale_1.msg)().doctor.filaResumo(esperando.length, escalados.length) +
616
+ (esperando.length > 0 ? (0, locale_1.msg)().doctor.filaProxima((0, horario_1.formatarDataHoraRotulada)(esperando[0].liberaEm)) : ''),
538
617
  correcao: escalados.length > 0
539
- ? `pedido escalado alem do limite de retry.max_tentativas: ork retry list e ork gate request <thread>`
618
+ ? (0, locale_1.msg)().doctor.filaEscaladoCorrecao
540
619
  : esperando.length > 0
541
- ? 'ork retry resume retoma o que ja liberou'
620
+ ? (0, locale_1.msg)().doctor.filaEsperaCorrecao
542
621
  : undefined,
543
622
  });
544
623
  const dirEstadoProjeto = path.join((0, estado_thread_1.raizDoEstado)(carregado.raiz), manifest_1.DIR_ESTADO);
@@ -550,10 +629,15 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
550
629
  nome: 'estado do projeto',
551
630
  nivel: fs.existsSync(dirEstadoProjeto) ? 'ok' : 'warn',
552
631
  detalhe: fs.existsSync(dirEstadoProjeto)
553
- ? `${dirEstadoProjeto} (${qtd} thread(s))`
554
- : `${dirEstadoProjeto} ausente`,
555
- correcao: fs.existsSync(dirEstadoProjeto) ? undefined : 'ork init cria o diretorio de estado',
632
+ ? (0, locale_1.msg)().doctor.estadoOk(dirEstadoProjeto, qtd)
633
+ : (0, locale_1.msg)().doctor.estadoAusente(dirEstadoProjeto),
634
+ correcao: fs.existsSync(dirEstadoProjeto) ? undefined : (0, locale_1.msg)().doctor.estadoCorrecao,
556
635
  });
636
+ // RM-039 (B6): com o transporte do pulse configurado, a varredura tem de bater de 15 em 15
637
+ // minutos; a instalacao antiga em `0 * * * *` vira aviso com a linha nova. Nunca edita o crontab.
638
+ const cronDoPulse = (0, doctor_pulse_cron_1.checarCronDoPulse)(path.join(dirEstadoProjeto, 'monitor'), (0, estado_thread_1.raizDoEstado)(carregado.raiz), lerCrontab);
639
+ if (cronDoPulse)
640
+ checks.push(cronDoPulse);
557
641
  checks.push(checarContas(carregado.raiz));
558
642
  // I-33 (D7): umask e permissoes do estado, na mesma regra do sensor (sem bits 0o022).
559
643
  checks.push(...(0, preflight_1.sondasDeAmbiente)(carregado.raiz));
@@ -564,23 +648,23 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
564
648
  checks.push({
565
649
  nome: 'governanca de sessoes',
566
650
  nivel: inventario.ok && inventario.semThread === 0 ? 'ok' : 'warn',
567
- detalhe: `${inventario.escopo.usuario}, Claude e Codex, global com histórico: ${inventario.total} sessões; ` +
568
- `${inventario.semThread} sem thread; ${inventario.ambiguas} ambíguas; ` +
569
- `inventário ${inventario.ok ? 'válido' : 'INCOMPLETO (zero não comprovado)'}` +
570
- (ausentes.length ? `; fonte ausente: ${ausentes.join(', ')}` : ''),
571
- correcao: inventario.ok && inventario.semThread === 0 ? undefined :
572
- 'ork sessions --global --all --json; adote identidades sem vínculo com ork sessions adopt <id>',
651
+ detalhe: (0, locale_1.msg)().doctor.governanca({ usuario: inventario.escopo.usuario, total: inventario.total, semThread: inventario.semThread,
652
+ ambiguas: inventario.ambiguas, ok: inventario.ok, ausentes: ausentes.map((o) => (0, locale_1.msg)().doctor.fonteDaSessao(o)) }),
653
+ correcao: inventario.ok && inventario.semThread === 0 ? undefined : (0, locale_1.msg)().doctor.governancaCorrecao,
573
654
  });
574
655
  }
575
656
  }
657
+ // RM-053 (fatia 2): a rede da pessoa e da maquina, nao do projeto; vale de qualquer diretorio.
658
+ checks.push((0, doctor_rede_1.checarRede)());
576
659
  return checks;
577
660
  }
578
661
  /** Texto do relatorio, com o resumo "o que vale nesta maquina agora". */
579
662
  function relatorio(checks) {
580
663
  const linhas = [];
581
- linhas.push('ork doctor: o que vale nesta maquina agora');
664
+ const m = (0, locale_1.msg)().doctor;
665
+ linhas.push(m.titulo);
582
666
  linhas.push('');
583
- const largura = Math.max(...checks.map((c) => c.nome.length));
667
+ const largura = Math.max(...checks.map((c) => (0, locale_1.nomeDoCheck)(c.nome).length));
584
668
  // I-35: o Check guarda o ISO (dado de maquina, tambem lido por teste); quem imprime para o dono
585
669
  // localiza. Vale para todo check, nao so o de contas: nenhum horario chega cru ao relatorio.
586
670
  let localizou = false;
@@ -591,9 +675,9 @@ function relatorio(checks) {
591
675
  return l;
592
676
  };
593
677
  for (const c of checks) {
594
- linhas.push(` ${(0, util_1.simbolo)(c.nivel)} ${c.nome.padEnd(largura)} ${local(c.detalhe)}`);
678
+ linhas.push(` ${(0, util_1.simbolo)(c.nivel)} ${(0, locale_1.nomeDoCheck)(c.nome).padEnd(largura)} ${local(c.detalhe)}`);
595
679
  if (c.nivel !== 'ok' && c.correcao) {
596
- linhas.push(` ${' '.repeat(largura)} correcao: ${local(c.correcao)}`);
680
+ linhas.push(` ${' '.repeat(largura)} ${m.correcao}: ${local(c.correcao)}`);
597
681
  }
598
682
  }
599
683
  // O fuso sai uma vez por mensagem, antes do veredito, que segue sendo a ultima linha.
@@ -603,13 +687,13 @@ function relatorio(checks) {
603
687
  const avisos = checks.filter((c) => c.nivel === 'warn').length;
604
688
  linhas.push('');
605
689
  linhas.push(falhas > 0
606
- ? `Veredito: BLOQUEADO (${falhas} fail, ${avisos} warn). Corrija os itens acima antes de despachar fase.`
607
- : `Veredito: PRONTO (${avisos} warn). Despacho de fase liberado por \`ork phase run\`.`);
690
+ ? m.bloqueado(falhas, avisos)
691
+ : m.pronto(avisos));
608
692
  return linhas.join('\n');
609
693
  }
610
694
  /** Executa o doctor e devolve o codigo de saida (0 = pronto). */
611
- function doctor(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente_1.nomesDeProviderAtivos)()) {
612
- const checks = checar(dirInicial, nomesHerdados);
695
+ function doctor(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente_1.nomesDeProviderAtivos)(), analisadores) {
696
+ const checks = checar(dirInicial, nomesHerdados, undefined, undefined, analisadores);
613
697
  const falhas = checks.filter((c) => c.nivel === 'fail').length;
614
698
  return { texto: relatorio(checks), codigo: falhas > 0 ? 1 : 0 };
615
699
  }