@orkastery/cli 0.5.3 → 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 (212) hide show
  1. package/adapters/claude-code/README.md +158 -0
  2. package/adapters/claude-code/mods/autoridade.json +56 -0
  3. package/adapters/claude-code/mods/ork-clima/.claude-plugin/plugin.json +14 -0
  4. package/adapters/claude-code/mods/ork-clima/hooks/contas.ts +283 -0
  5. package/adapters/claude-code/mods/ork-clima/hooks/hooks.json +3 -0
  6. package/adapters/claude-code/mods/ork-clima/hooks/previsao.ts +393 -0
  7. package/adapters/claude-code/mods/ork-clima/hooks/register.ts +205 -0
  8. package/adapters/claude-code/mods/ork-clima/orkastery-mod.json +5 -0
  9. package/adapters/claude-code/mods/ork-clima/types/index.d.ts +80 -0
  10. package/adapters/claude-code/mods/ork-freio/.claude-plugin/plugin.json +14 -0
  11. package/adapters/claude-code/mods/ork-freio/hooks/carga.ts +160 -0
  12. package/adapters/claude-code/mods/ork-freio/hooks/conferencia.ts +309 -0
  13. package/adapters/claude-code/mods/ork-freio/hooks/hooks.json +3 -0
  14. package/adapters/claude-code/mods/ork-freio/hooks/lote.ts +270 -0
  15. package/adapters/claude-code/mods/ork-freio/hooks/register.ts +285 -0
  16. package/adapters/claude-code/mods/ork-freio/orkastery-mod.json +5 -0
  17. package/adapters/claude-code/mods/ork-freio/types/index.d.ts +127 -0
  18. package/adapters/claude-code/mods/ork-mesa/.claude-plugin/plugin.json +14 -0
  19. package/adapters/claude-code/mods/ork-mesa/hooks/cartoes.tsx +246 -0
  20. package/adapters/claude-code/mods/ork-mesa/hooks/decidir.ts +110 -0
  21. package/adapters/claude-code/mods/ork-mesa/hooks/fila.ts +253 -0
  22. package/adapters/claude-code/mods/ork-mesa/hooks/hooks.json +3 -0
  23. package/adapters/claude-code/mods/ork-mesa/hooks/obvia.ts +98 -0
  24. package/adapters/claude-code/mods/ork-mesa/hooks/register.tsx +493 -0
  25. package/adapters/claude-code/mods/ork-mesa/orkastery-mod.json +5 -0
  26. package/adapters/claude-code/mods/ork-mesa/types/index.d.ts +131 -0
  27. package/adapters/claude-code/mods/ork-pista/.claude-plugin/plugin.json +14 -0
  28. package/adapters/claude-code/mods/ork-pista/hooks/acoes.ts +71 -0
  29. package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +117 -0
  30. package/adapters/claude-code/mods/ork-pista/hooks/hooks.json +3 -0
  31. package/adapters/claude-code/mods/ork-pista/hooks/pista.tsx +356 -0
  32. package/adapters/claude-code/mods/ork-pista/hooks/register.tsx +439 -0
  33. package/adapters/claude-code/mods/ork-pista/orkastery-mod.json +5 -0
  34. package/adapters/claude-code/mods/ork-pista/types/index.d.ts +85 -0
  35. package/adapters/claude-code/mods/ork-ponte/.claude-plugin/plugin.json +13 -0
  36. package/adapters/claude-code/mods/ork-ponte/hooks/faixa.tsx +57 -0
  37. package/adapters/claude-code/mods/ork-ponte/hooks/guarda.ts +410 -0
  38. package/adapters/claude-code/mods/ork-ponte/hooks/hooks.json +3 -0
  39. package/adapters/claude-code/mods/ork-ponte/hooks/mostrado.ts +55 -0
  40. package/adapters/claude-code/mods/ork-ponte/hooks/nucleo.ts +157 -0
  41. package/adapters/claude-code/mods/ork-ponte/hooks/papel.ts +42 -0
  42. package/adapters/claude-code/mods/ork-ponte/hooks/register.ts +331 -0
  43. package/adapters/claude-code/mods/ork-ponte/hooks/vigia.ts +76 -0
  44. package/adapters/claude-code/mods/ork-ponte/orkastery-mod.json +5 -0
  45. package/adapters/claude-code/mods/ork-ponte/types/index.d.ts +178 -0
  46. package/adapters/claude-code/mods/ork-portao/.claude-plugin/plugin.json +14 -0
  47. package/adapters/claude-code/mods/ork-portao/hooks/hooks.json +3 -0
  48. package/adapters/claude-code/mods/ork-portao/hooks/lease.ts +201 -0
  49. package/adapters/claude-code/mods/ork-portao/hooks/plano.ts +304 -0
  50. package/adapters/claude-code/mods/ork-portao/hooks/register.ts +339 -0
  51. package/adapters/claude-code/mods/ork-portao/hooks/verify.ts +152 -0
  52. package/adapters/claude-code/mods/ork-portao/orkastery-mod.json +5 -0
  53. package/adapters/claude-code/mods/ork-portao/types/index.d.ts +60 -0
  54. package/adapters/claude-code/mods/ork-radar/.claude-plugin/plugin.json +14 -0
  55. package/adapters/claude-code/mods/ork-radar/hooks/colisao.ts +420 -0
  56. package/adapters/claude-code/mods/ork-radar/hooks/hooks.json +3 -0
  57. package/adapters/claude-code/mods/ork-radar/hooks/mapa.tsx +322 -0
  58. package/adapters/claude-code/mods/ork-radar/hooks/register.tsx +470 -0
  59. package/adapters/claude-code/mods/ork-radar/orkastery-mod.json +5 -0
  60. package/adapters/claude-code/mods/ork-radar/types/index.d.ts +72 -0
  61. package/adapters/claude-code/mods/ork-sentinela/.claude-plugin/plugin.json +14 -0
  62. package/adapters/claude-code/mods/ork-sentinela/hooks/alertas.ts +85 -0
  63. package/adapters/claude-code/mods/ork-sentinela/hooks/despacho.ts +156 -0
  64. package/adapters/claude-code/mods/ork-sentinela/hooks/hooks.json +3 -0
  65. package/adapters/claude-code/mods/ork-sentinela/hooks/register.ts +511 -0
  66. package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +186 -0
  67. package/adapters/claude-code/mods/ork-sentinela/orkastery-mod.json +5 -0
  68. package/adapters/claude-code/mods/ork-sentinela/types/index.d.ts +65 -0
  69. package/adapters/claude-code/mods/ork-torre/.claude-plugin/plugin.json +14 -0
  70. package/adapters/claude-code/mods/ork-torre/hooks/agenda.ts +60 -0
  71. package/adapters/claude-code/mods/ork-torre/hooks/detalhe.tsx +236 -0
  72. package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +42 -0
  73. package/adapters/claude-code/mods/ork-torre/hooks/hooks.json +3 -0
  74. package/adapters/claude-code/mods/ork-torre/hooks/painel.tsx +344 -0
  75. package/adapters/claude-code/mods/ork-torre/hooks/rede.ts +97 -0
  76. package/adapters/claude-code/mods/ork-torre/hooks/register.tsx +437 -0
  77. package/adapters/claude-code/mods/ork-torre/orkastery-mod.json +5 -0
  78. package/adapters/claude-code/mods/ork-torre/types/index.d.ts +108 -0
  79. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +1 -1
  80. package/adapters/openclaw/README.md +2 -1
  81. package/adapters/openclaw/openclaw.plugin.json +1 -1
  82. package/adapters/openclaw/package.json +1 -1
  83. package/assets/docs-en/markdownlint-cli2.jsonc +22 -0
  84. package/assets/docs-en/padroes/documentacao-de-produto.md +135 -0
  85. package/assets/docs-en/padroes/roadmap-de-produto.md +100 -0
  86. package/assets/docs-en/produto/README.md +14 -0
  87. package/assets/docs-en/produto/_modelo-feature.md +62 -0
  88. package/assets/docs-en/roadmap/README.md +14 -0
  89. package/assets/docs-en/roadmap/_modelo-item.md +75 -0
  90. package/dist/adapters/claude-bg.js +77 -13
  91. package/dist/adapters/codex.js +10 -1
  92. package/dist/agents-md.js +24 -15
  93. package/dist/auditrun.js +17 -2
  94. package/dist/board.js +4 -3
  95. package/dist/branch-de-estado.js +23 -1
  96. package/dist/catalogo.js +33 -0
  97. package/dist/ci.js +13 -7
  98. package/dist/claims-conferir.js +342 -0
  99. package/dist/claims.js +3 -1
  100. package/dist/company-brain-client.js +36 -1
  101. package/dist/company-brain-journal.js +2 -1
  102. package/dist/company-brain-migration.js +36 -1
  103. package/dist/conducao-sentinela.js +388 -0
  104. package/dist/conducao-texto.js +12 -18
  105. package/dist/conducao.js +122 -30
  106. package/dist/conhecimento.js +490 -0
  107. package/dist/docs.js +22 -8
  108. package/dist/doctor-pulse-cron.js +182 -27
  109. package/dist/doctor-rede.js +18 -17
  110. package/dist/doctor.js +115 -111
  111. package/dist/entrega-pr.js +22 -21
  112. package/dist/escopo-escrita.js +10 -1
  113. package/dist/estado-thread.js +23 -1
  114. package/dist/experiencia-instalacao.js +45 -25
  115. package/dist/fabrica-batida.js +310 -0
  116. package/dist/fabrica-estado.js +38 -8
  117. package/dist/fabrica-publicar.js +3 -1
  118. package/dist/fila-pesada.js +444 -0
  119. package/dist/fix.js +3 -2
  120. package/dist/forja.js +1 -1
  121. package/dist/gates.js +3 -28
  122. package/dist/handoff.js +10 -6
  123. package/dist/hitl-local-receipt.js +2 -0
  124. package/dist/hitl-resumo.js +29 -3
  125. package/dist/hitl-tempo-parado.js +4 -4
  126. package/dist/hitl.js +29 -33
  127. package/dist/horario.js +14 -7
  128. package/dist/hosts.js +52 -1
  129. package/dist/impedimento.js +108 -14
  130. package/dist/index.js +623 -521
  131. package/dist/indice.js +7 -1
  132. package/dist/init.js +43 -47
  133. package/dist/instabilidade.js +144 -0
  134. package/dist/integracoes-locais.js +2 -0
  135. package/dist/intelligence-graph-cli.js +92 -21
  136. package/dist/intelligence-graph-contexto.js +56 -17
  137. package/dist/intelligence-graph-contract.js +2 -1
  138. package/dist/intelligence-graph-extract-md.js +56 -4
  139. package/dist/intelligence-graph-extract-ts.js +71 -3
  140. package/dist/intelligence-graph-query.js +66 -19
  141. package/dist/ledger.js +15 -1
  142. package/dist/liveness.js +6 -3
  143. package/dist/locale-ajuda.js +761 -0
  144. package/dist/locale-gerados.js +160 -0
  145. package/dist/locale-master.js +99 -0
  146. package/dist/locale-onboarding.js +92 -0
  147. package/dist/locale-phase.js +151 -0
  148. package/dist/locale-pulse.js +211 -0
  149. package/dist/locale-retry.js +385 -0
  150. package/dist/locale-roadmap.js +102 -0
  151. package/dist/locale-ship.js +494 -0
  152. package/dist/locale-thread.js +277 -0
  153. package/dist/locale-verify.js +125 -0
  154. package/dist/locale.js +714 -0
  155. package/dist/manifest.js +129 -3
  156. package/dist/maquina.js +23 -4
  157. package/dist/master-digest.js +6 -1
  158. package/dist/master-nota.js +4 -6
  159. package/dist/master.js +21 -24
  160. package/dist/mcp-artifacts.js +11 -2
  161. package/dist/mcp-git.js +23 -6
  162. package/dist/mcp-grafo.js +7 -4
  163. package/dist/mcp-server.js +8 -2
  164. package/dist/mcp-ship.js +3 -1
  165. package/dist/mcp-verify.js +6 -1
  166. package/dist/modos.js +3 -6
  167. package/dist/network-roadmap.js +5 -2
  168. package/dist/noctum-arco.js +911 -0
  169. package/dist/noctum-capacidade.js +141 -0
  170. package/dist/noctum-envelope.js +810 -0
  171. package/dist/noctum-execucao.js +304 -0
  172. package/dist/noctum-fila.js +280 -0
  173. package/dist/ocupacao.js +29 -2
  174. package/dist/onboarding.js +40 -21
  175. package/dist/orkmind.js +9 -2
  176. package/dist/orquestracao.js +13 -12
  177. package/dist/parado-no-condutor.js +34 -9
  178. package/dist/phase.js +94 -39
  179. package/dist/policies.js +4 -4
  180. package/dist/portfolio.js +4 -2
  181. package/dist/postura-local.js +234 -0
  182. package/dist/preflight.js +11 -10
  183. package/dist/procedencia.js +225 -0
  184. package/dist/projeto-alvo.js +127 -4
  185. package/dist/prompts.js +6 -2
  186. package/dist/pulse-delivery.js +13 -2
  187. package/dist/pulse.js +52 -19
  188. package/dist/ratelimit.js +4 -2
  189. package/dist/redacao-saida.js +63 -0
  190. package/dist/rede-status.js +3 -2
  191. package/dist/retry.js +232 -148
  192. package/dist/roadmap-reservas.js +20 -3
  193. package/dist/roadmap-status.js +129 -33
  194. package/dist/runtime-context.js +181 -3
  195. package/dist/runtimes.js +2 -1
  196. package/dist/session-events.js +7 -3
  197. package/dist/session-watcher-claude.js +7 -1
  198. package/dist/session-watcher.js +185 -33
  199. package/dist/sessoes-contas.js +1 -1
  200. package/dist/ship-publicar.js +800 -0
  201. package/dist/ship.js +84 -81
  202. package/dist/steal.js +77 -0
  203. package/dist/thread-close.js +3 -2
  204. package/dist/thread.js +153 -82
  205. package/dist/util.js +8 -1
  206. package/dist/verify.js +141 -52
  207. package/dist/vida-da-thread.js +254 -0
  208. package/dist/worktree-local.js +165 -0
  209. package/dist/worktree.js +20 -0
  210. package/dist/yaml.js +27 -8
  211. package/package.json +1 -1
  212. package/schemas/code-artifact-graph.v1.schema.json +2 -1
package/dist/thread.js CHANGED
@@ -39,6 +39,7 @@ var __importStar = (this && this.__importStar) || (function () {
39
39
  };
40
40
  })();
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.TETO_DO_PEDIDO = exports.ARQUIVO_DO_PEDIDO = void 0;
42
43
  exports.dirThreads = dirThreads;
43
44
  exports.dirThread = dirThread;
44
45
  exports.caminhoThread = caminhoThread;
@@ -57,6 +58,8 @@ exports.avisoDeThreadSemWorktree = avisoDeThreadSemWorktree;
57
58
  exports.avisoDeWorktreeQueFalharia = avisoDeWorktreeQueFalharia;
58
59
  exports.avisoDeChaveSemCommit = avisoDeChaveSemCommit;
59
60
  exports.avisoDaWorktree = avisoDaWorktree;
61
+ exports.prepararPedido = prepararPedido;
62
+ exports.pedidoDaThread = pedidoDaThread;
60
63
  exports.novaThread = novaThread;
61
64
  exports.exigirVarianteCompativel = exigirVarianteCompativel;
62
65
  exports.blocoDaThread = blocoDaThread;
@@ -67,12 +70,14 @@ exports.resumoDaThread = resumoDaThread;
67
70
  exports.threadsDaListagem = threadsDaListagem;
68
71
  exports.tabelaDeThreads = tabelaDeThreads;
69
72
  exports.exigirFase = exigirFase;
73
+ const worktree_local_1 = require("./worktree-local");
70
74
  const fs = __importStar(require("node:fs"));
71
75
  const path = __importStar(require("node:path"));
72
76
  const ciclos_1 = require("./ciclos");
73
77
  const modos_1 = require("./modos");
74
78
  const manifest_1 = require("./manifest");
75
79
  const slug_1 = require("./slug");
80
+ const node_crypto_1 = require("node:crypto");
76
81
  const types_1 = require("./types");
77
82
  const util_1 = require("./util");
78
83
  const ledger_1 = require("./ledger");
@@ -81,6 +86,7 @@ const creation_operation_store_1 = require("./creation-operation-store");
81
86
  const horario_1 = require("./horario");
82
87
  const maquina_1 = require("./maquina");
83
88
  const conducao_texto_1 = require("./conducao-texto");
89
+ const locale_1 = require("./locale");
84
90
  /** Diretorio de threads do projeto. */
85
91
  function dirThreads(raiz) {
86
92
  return path.join((0, manifest_1.dirEstado)((0, estado_thread_1.raizDoEstado)(raiz)), 'threads');
@@ -108,7 +114,7 @@ function listarIds(raiz) {
108
114
  function lerThread(raiz, id) {
109
115
  const caminho = caminhoThread(raiz, id);
110
116
  if (!fs.existsSync(caminho)) {
111
- throw new Error(`thread "${id}" nao encontrada em ${dirThreads(raiz)}`);
117
+ throw new locale_1.ErroDoCatalogo((m) => m.thread.naoEncontrada(id, dirThreads(raiz)));
112
118
  }
113
119
  return (0, util_1.lerJson)(caminho);
114
120
  }
@@ -133,11 +139,7 @@ function carimbarBase(raiz) {
133
139
  function avisoDeThreadSemBase(thread, gravada) {
134
140
  if (thread.base.commit !== util_1.COMMIT_DESCONHECIDO)
135
141
  return null;
136
- return gravada
137
- ? `Aviso: o repositório ainda não tem commit, e a thread ${thread.id} nasceu sem base: o ship não tem de onde partir. ` +
138
- `Faça o primeiro commit, feche esta com ork thread close ${thread.id} --motivo engano --por <quem> ` +
139
- '--justificativa "aberta antes do primeiro commit" e abra outra.'
140
- : 'Aviso: o repositório ainda não tem commit, e a thread nasceria sem base: faça o primeiro commit antes de abrir a primeira thread.';
142
+ return (0, locale_1.msg)().thread.semBase(thread.id, gravada);
141
143
  }
142
144
  /** Resolve um id livre a partir do assunto normalizado (`<abbrev>-<assunto>`). */
143
145
  function idDisponivel(raiz, abbrev, assunto) {
@@ -196,6 +198,8 @@ function worktreePrevista(carregado, id, slug, opcoes = {}) {
196
198
  */
197
199
  function criarWorktree(carregado, id, slug, opcoes = {}) {
198
200
  const { raiz, manifesto } = carregado;
201
+ // RM-047 (P3): worktree.dir do manifesto fora da raiz só cria checkout com a confirmação desta máquina.
202
+ (0, worktree_local_1.exigirPastaDasWorktrees)(raiz, manifesto);
199
203
  const { dir, branch } = alvoDaWorktree(carregado, id, slug, opcoes);
200
204
  if (fs.existsSync(dir)) {
201
205
  throw new Error(`worktree ja existe em ${dir}`);
@@ -232,13 +236,12 @@ function criarWorktree(carregado, id, slug, opcoes = {}) {
232
236
  function pedidoDeWorktree(flags, porThread) {
233
237
  const worktree = flags.worktree === false ? undefined : flags.worktree;
234
238
  if (typeof worktree === 'string' && !worktree.trim())
235
- throw new Error('uso: --worktree pede auto ou um diretório que já existe');
236
- if (typeof flags.semWorktree === 'string') {
237
- throw new Error(`uso: --sem-worktree não leva valor (recebeu "${flags.semWorktree}")`);
238
- }
239
+ throw new Error((0, locale_1.msg)().thread.worktreeVazia);
240
+ if (typeof flags.semWorktree === 'string')
241
+ throw new Error((0, locale_1.msg)().thread.semWorktreeComValor(flags.semWorktree));
239
242
  const semWorktree = flags.semWorktree === true;
240
243
  if (semWorktree && worktree !== undefined)
241
- throw new Error('uso: --worktree e --sem-worktree se excluem; use um dos dois');
244
+ throw new Error((0, locale_1.msg)().thread.worktreeESemWorktree);
242
245
  if (semWorktree)
243
246
  return { criar: false, dir: null, origem: 'sem-worktree' };
244
247
  if (worktree === true || worktree === 'auto')
@@ -254,13 +257,12 @@ function pedidoDeWorktree(flags, porThread) {
254
257
  function linhaDaWorktree(por, gravada, variante) {
255
258
  if (!por || (gravada && por !== 'chave'))
256
259
  return null;
257
- const verbo = gravada ? 'criada' : 'seria criada';
258
- if (por === 'chave') {
259
- return ` worktree: ${verbo} pela chave worktree.por_thread do orkastery.yaml; para criar sem ela, use --sem-worktree`;
260
- }
260
+ const m = (0, locale_1.msg)().thread;
261
+ if (por === 'chave')
262
+ return m.worktreeChave(gravada);
261
263
  if (por === 'flag')
262
- return ` worktree: ${verbo} pelo --worktree auto`;
263
- return ` worktree: ${verbo} pelo ciclo ${variante ?? 'da thread'}, que exige worktree isolada`;
264
+ return m.worktreeFlag(gravada);
265
+ return m.worktreeCiclo(gravada, variante ?? null);
264
266
  }
265
267
  /**
266
268
  * P4 do ensaio da 0.5.0: o que acontece no SHIP com a thread criada por `--sem-worktree`. O `ork ship` entrega a
@@ -271,49 +273,27 @@ function linhaDaWorktree(por, gravada, variante) {
271
273
  function avisoDeThreadSemWorktree(thread, manifesto, gravada = true) {
272
274
  const base = manifesto.worktree.base_branch;
273
275
  const branch = thread.base.branch;
274
- const inicio = gravada
275
- ? `Aviso: thread ${thread.id} sem worktree (--sem-worktree): ela trabalha na raiz do projeto`
276
- : `Aviso: sem worktree (--sem-worktree), a thread ${thread.id} trabalharia na raiz do projeto`;
277
- const ensure = `Antes do GO, ork worktree ensure ${thread.id} cria a worktree e a branch da thread`;
278
- if (thread.base.commit === util_1.COMMIT_DESCONHECIDO) {
279
- // Sem commit, nem o `ork worktree ensure` tem de onde partir: o caminho e o do aviso de thread sem base.
280
- return `${inicio}, num repositório ainda sem commit, fora de qualquer branch, e o ork ship não tem branch de origem ` +
281
- 'para entregar. Faça o primeiro commit e siga o aviso de thread sem base.';
282
- }
283
- if (branch === 'HEAD') {
284
- return `${inicio}, com o HEAD destacado, fora de qualquer branch, e o ork ship não tem branch de origem para entregar. ${ensure}.`;
285
- }
286
- if (branch !== base) {
287
- return `${inicio}, na branch ${branch}, e o ork ship entrega essa branch como estiver, com o que mais entrar nela; ` +
288
- `com --para ${branch}, a entrega vira push direto, que a policy push_direto_na_base confere. ${ensure}.`;
289
- }
276
+ const aviso = (c) => (0, locale_1.msg)().thread.avisoSemWorktree(thread.id, gravada, c);
277
+ // Sem commit, nem o `ork worktree ensure` tem de onde partir: o caminho e o do aviso de thread sem base.
278
+ if (thread.base.commit === util_1.COMMIT_DESCONHECIDO)
279
+ return aviso({ caso: 'sem-commit' });
280
+ if (branch === 'HEAD')
281
+ return aviso({ caso: 'head' });
282
+ if (branch !== base)
283
+ return aviso({ caso: 'outra', branch });
290
284
  const policy = manifesto.policies?.push_direto_na_base;
291
- const efeito = policy === 'block'
292
- ? 'o ork ship barra a entrega por push_direto_na_base (block): não há branch de thread para mergear'
293
- : policy === undefined || policy === 'off'
294
- ? 'o ork ship empurra a base direto, sem branch de thread (push_direto_na_base desligada)'
295
- : `o ork ship avisa push_direto_na_base (${policy}) e empurra a base direto, sem branch de thread`;
296
- return `${inicio}, na branch base ${base}, e ${efeito}. ${ensure}; depois do GO, os commits já estão na base e o ship não os separa.`;
285
+ return aviso({ caso: 'base', base, policy: policy === undefined ? undefined : String(policy) });
297
286
  }
298
287
  /**
299
288
  * P4 do ensaio da 0.5.0 (CHECK): no `--dry-run`, por que a criacao de verdade recusaria a worktree, em vez de preve-la.
300
289
  * O ciclo que exige worktree nao aceita `--sem-worktree`, entao a saida so e sugerida para a chave e a flag.
301
290
  */
302
291
  function avisoDeWorktreeQueFalharia(f) {
303
- const semWorktree = f.por === 'ciclo' ? '' : ' ou crie com --sem-worktree';
304
- if (f.motivo === 'pasta-existe') {
305
- return `Aviso: a pasta ${f.dir} já existe, e a criação de verdade recusaria a worktree da thread: tire a pasta${semWorktree}.`;
306
- }
307
- if (f.motivo === 'branch-existe') {
308
- return `Aviso: a branch ${f.branch} já existe, e a criação de verdade recusaria a worktree da thread: tire a branch${semWorktree}.`;
309
- }
310
- return 'Aviso: o repositório ainda não tem commit, e a criação de verdade recusaria a worktree da thread no git worktree add: ' +
311
- 'faça o primeiro commit antes.';
292
+ return (0, locale_1.msg)().thread.worktreeFalharia(f.motivo, f.dir, f.branch, f.por === 'ciclo');
312
293
  }
313
294
  /** P4 do ensaio da 0.5.0: a worktree que a chave pede nao tem de onde partir num repositorio sem commit. */
314
295
  function avisoDeChaveSemCommit(gravada) {
315
- return 'Aviso: worktree.por_thread pede a worktree da thread, mas o repositório ainda não tem commit: ' +
316
- `a thread ${gravada ? 'nasceu' : 'nasceria'} na raiz do projeto, sem worktree.`;
296
+ return (0, locale_1.msg)().thread.chaveSemCommit(gravada);
317
297
  }
318
298
  /** P4: o aviso de worktree do `ork thread new`, para o stderr, ou `null` quando nao ha o que avisar. */
319
299
  function avisoDaWorktree(origem, resultado, manifesto) {
@@ -323,6 +303,86 @@ function avisoDaWorktree(origem, resultado, manifesto) {
323
303
  return avisoDeChaveSemCommit(resultado.gravada);
324
304
  return null;
325
305
  }
306
+ /** RM-059 (T6.0): o arquivo do pedido guardado, na pasta da thread. */
307
+ exports.ARQUIVO_DO_PEDIDO = 'pedido.md';
308
+ /**
309
+ * O prompt da fase vai inteiro como UM argumento do `claude --bg`, e o Linux recusa argumento acima de
310
+ * 128 KiB (MAX_ARG_STRLEN); o pedido fica com a metade, para o template caber junto.
311
+ */
312
+ exports.TETO_DO_PEDIDO = 64 * 1024;
313
+ /** O pedido como ele vai ser guardado: sem espaco nas pontas, nao vazio e dentro do teto. */
314
+ function prepararPedido(bruto) {
315
+ const texto = bruto.trim();
316
+ if (!texto)
317
+ throw new locale_1.ErroDoCatalogo((m) => m.thread.pedidoVazio);
318
+ const bytes = Buffer.byteLength(texto, 'utf8');
319
+ if (bytes > exports.TETO_DO_PEDIDO)
320
+ throw new locale_1.ErroDoCatalogo((m) => m.thread.pedidoGrande(bytes, exports.TETO_DO_PEDIDO));
321
+ return { texto, meta: { arquivo: exports.ARQUIVO_DO_PEDIDO, sha256: (0, node_crypto_1.createHash)('sha256').update(texto, 'utf8').digest('hex'), bytes } };
322
+ }
323
+ /**
324
+ * RM-059 (T6.0): o pedido guardado na criacao da thread, conferido contra o sha256 gravado; `null` na
325
+ * thread criada sem pedido. Arquivo que falta ou que nao bate com o sha256 (editado fora do nucleo) e
326
+ * erro tipado: o render nunca usa um pedido sem a prova de que e o da criacao.
327
+ */
328
+ function pedidoDaThread(raiz, thread) {
329
+ const meta = thread.pedido;
330
+ if (!meta)
331
+ return null;
332
+ const restaurar = 'passe --pedido no render ou restaure o arquivo';
333
+ // O nome do arquivo e fixo: um thread.json editado nao aponta o render para outro arquivo do projeto.
334
+ if (meta.arquivo !== exports.ARQUIVO_DO_PEDIDO || !/^[a-f0-9]{64}$/.test(String(meta.sha256))) {
335
+ throw new Error(`thread.pedido.divergente: o pedido da thread ${thread.id} no thread.json nao e o que a criacao grava; ${restaurar}`);
336
+ }
337
+ const arquivo = path.join(dirThread(raiz, thread.id), exports.ARQUIVO_DO_PEDIDO);
338
+ let fd;
339
+ try {
340
+ fd = fs.openSync(arquivo, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
341
+ }
342
+ catch (e) {
343
+ if (e.code === 'ENOENT')
344
+ throw new Error(`thread.pedido.ausente: a thread ${thread.id} guardou o pedido em ${meta.arquivo} e ele sumiu; ${restaurar}`);
345
+ throw new Error(`thread.pedido.divergente: ${meta.arquivo} da thread ${thread.id} nao abre como arquivo comum; ${restaurar}`);
346
+ }
347
+ try {
348
+ const st = fs.fstatSync(fd);
349
+ if (!st.isFile() || st.size > exports.TETO_DO_PEDIDO)
350
+ throw new Error(`thread.pedido.divergente: ${meta.arquivo} da thread ${thread.id} nao e o arquivo guardado; ${restaurar}`);
351
+ const bytes = fs.readFileSync(fd);
352
+ const sha256 = (0, node_crypto_1.createHash)('sha256').update(bytes).digest('hex');
353
+ if (sha256 !== meta.sha256) {
354
+ throw new Error(`thread.pedido.divergente: ${meta.arquivo} da thread ${thread.id} nao bate com o sha256 gravado na criacao ` +
355
+ `(${(0, util_1.shaCurto)(meta.sha256)}): foi editado fora do nucleo; ${restaurar}`);
356
+ }
357
+ return { texto: bytes.toString('utf8'), sha256 };
358
+ }
359
+ finally {
360
+ fs.closeSync(fd);
361
+ }
362
+ }
363
+ /**
364
+ * Grava o pedido sem meio-termo: escreve num temporario com fsync e o liga ao nome final, que nao pode existir
365
+ * (o `link` recusa sobrescrever). Uma falha no meio nao deixa `pedido.md` pela metade.
366
+ */
367
+ function gravarPedido(dir, texto) {
368
+ fs.mkdirSync(dir, { recursive: true });
369
+ const alvo = path.join(dir, exports.ARQUIVO_DO_PEDIDO);
370
+ const temporario = path.join(dir, `.${exports.ARQUIVO_DO_PEDIDO}.${process.pid}.${Date.now()}.tmp`);
371
+ const fd = fs.openSync(temporario, 'wx', 0o600);
372
+ try {
373
+ try {
374
+ fs.writeFileSync(fd, texto, 'utf8');
375
+ fs.fsyncSync(fd);
376
+ }
377
+ finally {
378
+ fs.closeSync(fd);
379
+ }
380
+ fs.linkSync(temporario, alvo);
381
+ }
382
+ finally {
383
+ fs.rmSync(temporario, { force: true });
384
+ }
385
+ }
326
386
  /** Cria a thread: valida modo contra o manifesto, gera o slug e carimba a base. */
327
387
  function novaThread(carregado, opcoes) {
328
388
  if (opcoes.dryRun)
@@ -342,21 +402,23 @@ function exigirVarianteCompativel(variante, def) {
342
402
  return;
343
403
  const [unico, ...resto] = def.blocos;
344
404
  if (unico && resto.length === 0 && unico.fases.length < types_1.FASES.length) {
345
- throw new Error(`o ciclo ${variante} redesenha os blocos e o modo ${def.tag} tem um bloco so ` +
346
- `(${unico.fases.join('-')}): crie a thread sem --ciclo ou escolha um modo de ciclo completo`);
405
+ throw new locale_1.ErroDoCatalogo((m) => m.thread.varianteIncompativel(variante, def.tag, unico.fases.join('-')));
347
406
  }
348
407
  }
349
408
  function criarThreadSerializada(carregado, opcoes) {
350
409
  const { raiz, manifesto } = carregado;
351
410
  const permitidos = manifesto.conduction.allowed_modes;
352
411
  if (!permitidos.includes(opcoes.modo)) {
353
- throw new Error(`modo ${modos_1.MODOS[opcoes.modo].tag} fora de conduction.allowed_modes ` +
354
- `(permitidos: ${permitidos.map((m) => modos_1.MODOS[m].tag).join(', ')})`);
412
+ const tag = modos_1.MODOS[opcoes.modo].tag, lista = permitidos.map((p) => modos_1.MODOS[p].tag).join(', ');
413
+ throw new locale_1.ErroDoCatalogo((m) => m.thread.modoNaoPermitido(tag, lista));
355
414
  }
356
415
  const assuntoBruto = (0, slug_1.normalizarAssunto)(opcoes.assunto ?? opcoes.nome);
357
416
  if (!assuntoBruto) {
358
- throw new Error(`nome "${opcoes.nome}" nao produz assunto valido (esperado [a-z0-9])`);
417
+ const nome = opcoes.nome;
418
+ throw new locale_1.ErroDoCatalogo((m) => m.thread.nomeSemAssunto(nome));
359
419
  }
420
+ // RM-059 (T6.0): o pedido e conferido antes de qualquer gravacao, tambem no ensaio.
421
+ const pedido = opcoes.pedido !== undefined ? prepararPedido(opcoes.pedido) : null;
360
422
  const abbrev = manifesto.project.abbrev;
361
423
  const def = (0, modos_1.definicaoDoModo)(opcoes.modo);
362
424
  const variante = opcoes.variante ?? null;
@@ -368,17 +430,18 @@ function criarThreadSerializada(carregado, opcoes) {
368
430
  if (variante) {
369
431
  const dv = (0, ciclos_1.definicaoDaVariante)(variante);
370
432
  if (dv.exigeBranch && !opcoes.branch) {
371
- throw new Error(`o ciclo ${variante} parte de uma branch que ja existe: informe --branch <branch>`);
433
+ throw new locale_1.ErroDoCatalogo((m) => m.thread.cicloExigeBranch(variante));
372
434
  }
373
- if (opcoes.branch) {
374
- const existe = (0, util_1.exec)('git', ['rev-parse', '--verify', `refs/heads/${opcoes.branch}`], raiz);
435
+ const branch = opcoes.branch;
436
+ if (branch) {
437
+ const existe = (0, util_1.exec)('git', ['rev-parse', '--verify', `refs/heads/${branch}`], raiz);
375
438
  if (!existe.ok) {
376
- throw new Error(`branch "${opcoes.branch}" nao existe neste repositorio`);
439
+ throw new locale_1.ErroDoCatalogo((m) => m.thread.branchInexistente(branch));
377
440
  }
378
441
  }
379
442
  }
380
443
  else if (opcoes.branch) {
381
- throw new Error('--branch so vale com --ciclo merge-branch');
444
+ throw new locale_1.ErroDoCatalogo((m) => m.thread.branchSemCiclo);
382
445
  }
383
446
  // `greenfield`, `merge-branch` e `feature-xl-faseada` exigem worktree isolada: sao os
384
447
  // ciclos que escrevem codigo em paralelo com outras threads.
@@ -419,7 +482,7 @@ function criarThreadSerializada(carregado, opcoes) {
419
482
  const slug = opcoes.slug ?? (0, slug_1.montarSlug)(abbrev, assunto, blocos[0].slugFases);
420
483
  // O override `--slug` do builder tambem passa pela regex canonica.
421
484
  if (!(0, slug_1.slugValido)(slug)) {
422
- throw new Error(`slug invalido: "${slug}" (regex canonica: ${slug_1.REGEX_SLUG.source})`);
485
+ throw new locale_1.ErroDoCatalogo((m) => m.thread.slugInvalido(slug, slug_1.REGEX_SLUG.source));
423
486
  }
424
487
  const thread = {
425
488
  ...(origin ? { creationOrigin: origin } : {}),
@@ -442,6 +505,7 @@ function criarThreadSerializada(carregado, opcoes) {
442
505
  sessoes: [],
443
506
  ...(opcoes.exigeRuntimeDiferente === true ? { exigeRuntimeDiferente: true } : {}),
444
507
  ...(opcoes.doneWhen && opcoes.doneWhen.length > 0 ? { doneWhen: opcoes.doneWhen } : {}),
508
+ ...(pedido ? { pedido: pedido.meta } : {}),
445
509
  decisoes: [],
446
510
  claims: [],
447
511
  leases: [],
@@ -478,8 +542,9 @@ function criarThreadSerializada(carregado, opcoes) {
478
542
  const ocupadaPelaChave = pelaChave && !exigeWorktree && prevista &&
479
543
  (prevista.falha === 'pasta-existe' || prevista.falha === 'branch-existe') ? prevista : null;
480
544
  if (ocupadaPelaChave) {
481
- const qual = ocupadaPelaChave.falha === 'pasta-existe' ? `a pasta ${ocupadaPelaChave.dir}` : `a branch ${ocupadaPelaChave.branch}`;
482
- throw new Error(`${qual} já existe, e a chave worktree.por_thread pede a worktree da thread: tire-a ou crie com --sem-worktree`);
545
+ const pasta = ocupadaPelaChave.falha === 'pasta-existe';
546
+ const alvo = pasta ? ocupadaPelaChave.dir : ocupadaPelaChave.branch;
547
+ throw new locale_1.ErroDoCatalogo((m) => m.thread.ocupadaPelaChave(pasta, alvo));
483
548
  }
484
549
  let worktreeCriada = null;
485
550
  if (worktreePor) {
@@ -493,6 +558,10 @@ function criarThreadSerializada(carregado, opcoes) {
493
558
  commit: commitDaBranch.ok ? commitDaBranch.stdout.trim() : thread.base.commit,
494
559
  };
495
560
  }
561
+ // RM-059 (T6.0): o pedido vai ao lado do thread.json, so com permissao do dono, como ele, e antes dele: o
562
+ // thread.json nunca aponta para um pedido que nao foi gravado.
563
+ if (pedido)
564
+ gravarPedido(dirThread(raiz, id), pedido.texto);
496
565
  gravarThread(raiz, thread);
497
566
  (0, ledger_1.registrar)(dirThread(raiz, id), id, ledger_1.TIPOS_DE_EVENTO.threadCriada, {
498
567
  ...(origin ? { creationOrigin: origin } : {}),
@@ -510,6 +579,7 @@ function criarThreadSerializada(carregado, opcoes) {
510
579
  branchDeOrigem: opcoes.branch ?? null,
511
580
  maquina: thread.maquina,
512
581
  ...(thread.roadmap ? { roadmap: thread.roadmap } : {}),
582
+ ...(pedido ? { pedido: pedido.meta } : {}),
513
583
  });
514
584
  if (worktreeCriada) {
515
585
  (0, ledger_1.registrar)(dirThread(raiz, id), id, ledger_1.TIPOS_DE_EVENTO.worktreeCriada, {
@@ -552,38 +622,39 @@ function canalDaSessao(s) {
552
622
  }
553
623
  function resumoDaThread(thread, conducao) {
554
624
  const def = (0, modos_1.definicaoDoModo)(thread.modo);
625
+ const m = (0, locale_1.msg)().thread, r = m.rotulos;
626
+ // RM-061 (F2a): o rotulo vem do catalogo, na largura do locale; o valor gravado (nome, criterio) sai como esta.
627
+ const campo = (rotulo, valor) => ` ${rotulo.padEnd(m.largura)} ${valor}`;
555
628
  const linhas = [];
556
- linhas.push(` id ${thread.id}`);
557
- linhas.push(` slug ${thread.slug}`);
558
- linhas.push(` nome ${thread.nome}`);
559
- linhas.push(` modo ${def.tag} (${pausasDaThread(thread)} pausas humanas previstas)`);
560
- linhas.push(` ciclo ${thread.variante ?? 'padrao do modo'}`);
561
- linhas.push(` fase ${thread.faseAtual}`);
562
- linhas.push(` status ${thread.status}`);
563
- linhas.push(` base ${thread.base.branch} @ ${(0, util_1.shaCurto)(thread.base.commit)}`);
564
- linhas.push(` worktree ${thread.worktree ?? '(raiz do projeto)'}`);
629
+ linhas.push(campo(r.id, thread.id));
630
+ linhas.push(campo(r.slug, thread.slug));
631
+ linhas.push(campo(r.nome, thread.nome));
632
+ linhas.push(campo(r.modo, m.modo(def.tag, pausasDaThread(thread))));
633
+ linhas.push(campo(r.ciclo, thread.variante ?? m.cicloPadrao));
634
+ linhas.push(campo(r.fase, thread.faseAtual));
635
+ linhas.push(campo(r.status, m.status(thread.status)));
636
+ linhas.push(campo(r.base, `${thread.base.branch} @ ${(0, util_1.shaCurto)(thread.base.commit)}`));
637
+ linhas.push(campo(r.worktree, thread.worktree ?? m.raizDoProjeto));
565
638
  // I-36 (T17): quem passa a leitura da conducao ve a linha unica; sem ela o resumo fica como era.
566
639
  if (conducao !== undefined)
567
- linhas.push(` conducao ${conducao ? (0, conducao_texto_1.linhaDeConducao)(conducao) : 'ninguem conduz agora'}`);
640
+ linhas.push(campo(r.conducao, conducao ? (0, conducao_texto_1.linhaDeConducao)(conducao) : m.ninguemConduz));
568
641
  // I-43 (D4, viga a): a exigencia so aparece quando existe, para nao poluir o resumo
569
642
  // das threads que nao a declararam.
570
- if (thread.exigeRuntimeDiferente === true) {
571
- linhas.push(' validacao CHECK em runtime diferente do GO (exigido pela thread)');
572
- }
643
+ if (thread.exigeRuntimeDiferente === true)
644
+ linhas.push(m.validacao);
573
645
  // I-43 (D4, viga b): o criterio aparece COM o comando. Mostrar so o criterio seria
574
646
  // reproduzir a prosa do envelope numa tela nova.
575
647
  if (thread.doneWhen && thread.doneWhen.length > 0) {
576
- linhas.push(` pronto quando (${thread.doneWhen.length} criterio(s) executaveis)`);
648
+ linhas.push(m.prontoQuando(thread.doneWhen.length));
577
649
  for (const d of thread.doneWhen)
578
650
  linhas.push(` ${d.criterio}\n $ ${d.comando}`);
579
651
  }
580
652
  if (thread.score) {
581
- linhas.push(` score ${thread.score.valor}/5 por ${thread.score.avaliadoPor} ` +
582
- `(${thread.score.regime}) em ${(0, horario_1.formatarDataHoraRotulada)(thread.score.avaliadoEm)}`);
653
+ linhas.push(campo(r.score, m.score(thread.score.valor, thread.score.avaliadoPor, thread.score.regime, (0, horario_1.formatarDataHoraRotulada)(thread.score.avaliadoEm))));
583
654
  }
584
- linhas.push(' blocos previstos');
655
+ linhas.push(m.blocosPrevistos);
585
656
  for (const b of thread.blocos) {
586
- const marca = b.pausa ? `pausa prevista: ${b.pausaSobre}` : 'sem pausa humana prevista';
657
+ const marca = b.pausa ? m.pausaPrevista(m.pausaSobre(b.pausaSobre)) : m.semPausa;
587
658
  linhas.push(` ${b.slugFases.padEnd(6)} ${b.fases.join('-').padEnd(18)} ${marca}`);
588
659
  }
589
660
  return linhas.join('\n');
@@ -639,7 +710,7 @@ function tabelaDeThreads(raiz, opcoes = {}) {
639
710
  function exigirFase(thread, bruto) {
640
711
  const fase = bruto.toUpperCase();
641
712
  if (!thread.fases.includes(fase)) {
642
- throw new Error(`fase invalida: "${bruto}" (esperado uma de ${thread.fases.join(', ')})`);
713
+ throw new Error((0, locale_1.msg)().phase.faseInvalida(bruto, thread.fases.join(', ')));
643
714
  }
644
715
  return fase;
645
716
  }
package/dist/util.js CHANGED
@@ -197,7 +197,14 @@ function lerJsonl(caminho) {
197
197
  /** Anexa um registro ao armazem JSONL, criando o diretorio que faltar. */
198
198
  function anexarJsonl(caminho, valor) {
199
199
  fs.mkdirSync(path.dirname(caminho), { recursive: true });
200
- fs.appendFileSync(caminho, JSON.stringify(valor) + '\n', 'utf8');
200
+ // RM-047: O_NOFOLLOW; um armazém versionado como link (claims, board) não leva o append para fora da raiz.
201
+ const fd = fs.openSync(caminho, fs.constants.O_WRONLY | fs.constants.O_APPEND | fs.constants.O_CREAT | fs.constants.O_NOFOLLOW, 0o644);
202
+ try {
203
+ fs.writeFileSync(fd, JSON.stringify(valor) + '\n', 'utf8');
204
+ }
205
+ finally {
206
+ fs.closeSync(fd);
207
+ }
201
208
  }
202
209
  /** Proximo id sequencial de um armazem (`C1`, `C2`, ... / `F1`, `F2`, ...). */
203
210
  function proximoIdSequencial(ids, prefixo) {