@orkastery/cli 0.5.0 → 0.5.3

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 (131) hide show
  1. package/adapters/claude-code/README.md +11 -2
  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/onboarding.md +3 -2
  5. package/adapters/claude-code/commands/ork.md +9 -0
  6. package/adapters/codex/skills/ork/SKILL.md +18 -3
  7. package/adapters/hermes/README.md +1 -0
  8. package/adapters/hermes/bin/ork-network-status.sh +10 -0
  9. package/adapters/hermes/hermes.plugin.json +1 -0
  10. package/adapters/hermes/hitl-ingress/__init__.py +2 -2
  11. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +6 -5
  12. package/adapters/openclaw/README.md +35 -4
  13. package/adapters/openclaw/dist/hitl-ingress.js +2 -2
  14. package/adapters/openclaw/dist/index.js +47 -12
  15. package/adapters/openclaw/openclaw.plugin.json +5 -1
  16. package/adapters/openclaw/package.json +2 -2
  17. package/adapters/openclaw/src/hitl-ingress.ts +2 -2
  18. package/adapters/openclaw/src/index.ts +50 -12
  19. package/assets/orkmind_bridge.py +117 -9
  20. package/dist/adapters/claude-bg.js +59 -11
  21. package/dist/adapters/codex.js +4 -3
  22. package/dist/agents-md.js +1 -0
  23. package/dist/auditrun.js +6 -2
  24. package/dist/board.js +16 -14
  25. package/dist/branch-de-estado.js +66 -10
  26. package/dist/busca-semantica.js +52 -12
  27. package/dist/canarios-rm057.js +149 -0
  28. package/dist/canarios.js +2 -0
  29. package/dist/ci.js +8 -1
  30. package/dist/claim-lint.js +3 -1
  31. package/dist/claims.js +39 -1
  32. package/dist/company-brain-context.js +158 -22
  33. package/dist/docs.js +110 -3
  34. package/dist/doctor-pulse-cron.js +194 -0
  35. package/dist/doctor-rede.js +149 -0
  36. package/dist/doctor.js +294 -37
  37. package/dist/entrega-pr.js +27 -8
  38. package/dist/esgotamentos.js +181 -0
  39. package/dist/experiencia.js +12 -2
  40. package/dist/fabrica-estado.js +35 -9
  41. package/dist/fabrica-publicar.js +6 -0
  42. package/dist/fechamento.js +20 -66
  43. package/dist/fix.js +3 -3
  44. package/dist/forja.js +31 -7
  45. package/dist/gates.js +5 -1
  46. package/dist/hitl-contract.js +59 -4
  47. package/dist/hitl-curto.js +11 -6
  48. package/dist/hitl-gates.js +5 -0
  49. package/dist/hitl-lote.js +5 -2
  50. package/dist/hitl-resumo.js +33 -1
  51. package/dist/hitl-tempo-parado.js +201 -0
  52. package/dist/hitl-texto-livre.js +5 -5
  53. package/dist/horario.js +27 -0
  54. package/dist/hosts.js +59 -13
  55. package/dist/impedimento.js +205 -0
  56. package/dist/index.js +433 -88
  57. package/dist/indice-vetorial.js +87 -10
  58. package/dist/indice.js +3 -1
  59. package/dist/init.js +28 -5
  60. package/dist/integracoes-locais.js +4 -0
  61. package/dist/intelligence-graph-cli.js +267 -30
  62. package/dist/intelligence-graph-contexto.js +215 -0
  63. package/dist/intelligence-graph-contract.js +71 -12
  64. package/dist/intelligence-graph-extract-md.js +41 -23
  65. package/dist/intelligence-graph-extract-ts.js +181 -11
  66. package/dist/intelligence-graph-extract.js +186 -9
  67. package/dist/intelligence-graph-index.js +205 -24
  68. package/dist/intelligence-graph-parsers.js +6 -4
  69. package/dist/intelligence-graph-repo.js +10 -0
  70. package/dist/leases.js +680 -87
  71. package/dist/ledger-stats.js +15 -1
  72. package/dist/ledger.js +12 -0
  73. package/dist/licoes.js +6 -4
  74. package/dist/liveness.js +2 -1
  75. package/dist/maestro-runtime.js +7 -1
  76. package/dist/manifest.js +44 -1
  77. package/dist/master-nota.js +14 -5
  78. package/dist/master.js +129 -12
  79. package/dist/mcp-artifacts.js +36 -3
  80. package/dist/mcp-git.js +80 -15
  81. package/dist/mcp-grafo-worker.js +93 -0
  82. package/dist/mcp-grafo.js +279 -0
  83. package/dist/mcp-install.js +2 -1
  84. package/dist/mcp-server.js +23 -1
  85. package/dist/mcp-ship.js +2 -0
  86. package/dist/mcp-verify.js +3 -1
  87. package/dist/memoria.js +48 -6
  88. package/dist/network-roadmap.js +195 -20
  89. package/dist/ocupacao.js +17 -5
  90. package/dist/onboarding.js +9 -4
  91. package/dist/orkmind.js +90 -5
  92. package/dist/orquestracao.js +14 -11
  93. package/dist/parado-no-condutor.js +1089 -0
  94. package/dist/phase.js +68 -15
  95. package/dist/policies.js +79 -3
  96. package/dist/portfolio.js +4 -1
  97. package/dist/projeto-alvo.js +5 -1
  98. package/dist/prompts.js +36 -1
  99. package/dist/prova-ativacao.js +414 -0
  100. package/dist/pulse-delivery.js +60 -7
  101. package/dist/pulse.js +99 -3
  102. package/dist/ratelimit.js +20 -4
  103. package/dist/recall.js +3 -1
  104. package/dist/rede-adesao.js +399 -0
  105. package/dist/rede-forja.js +289 -0
  106. package/dist/rede-projetos.js +239 -0
  107. package/dist/rede-status.js +336 -0
  108. package/dist/rede.js +980 -0
  109. package/dist/retry.js +69 -2
  110. package/dist/roadmap-status.js +162 -7
  111. package/dist/runtime-context.js +5 -1
  112. package/dist/runtime-profiles.js +22 -1
  113. package/dist/saida-segura.js +58 -0
  114. package/dist/session-watcher-claude.js +113 -23
  115. package/dist/sessoes-contas.js +187 -0
  116. package/dist/sessoes-inventario.js +6 -12
  117. package/dist/sessoes.js +87 -3
  118. package/dist/ship.js +110 -20
  119. package/dist/thread.js +212 -14
  120. package/dist/util.js +71 -4
  121. package/dist/verify.js +2 -2
  122. package/dist/worktree.js +34 -8
  123. package/eval/casos/onboarding.json +1 -1
  124. package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
  125. package/package.json +7 -3
  126. package/references/definition-of-done.md +1 -1
  127. package/skills/README.md +1 -1
  128. package/skills/core/onboarding/SKILL.md +3 -2
  129. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  130. package/skills/phases/master-metrics/SKILL.md +8 -3
  131. package/skills/phases/ship-release/SKILL.md +6 -3
@@ -16,7 +16,9 @@ exports.registrarEntregasPorPr = registrarEntregasPorPr;
16
16
  * remota (ancestralidade conferida contra a ponta que o `ls-remote` devolve) e o check do CI no
17
17
  * head do PR. Sem CI verde, nao registra: merge sem prova independente nao e entrega.
18
18
  */
19
+ const branch_de_estado_1 = require("./branch-de-estado");
19
20
  const ci_1 = require("./ci");
21
+ const docs_1 = require("./docs");
20
22
  const fabrica_publicar_1 = require("./fabrica-publicar");
21
23
  const ledger_1 = require("./ledger");
22
24
  const modos_1 = require("./modos");
@@ -49,7 +51,7 @@ function avancarParaShip(raiz, threadId) {
49
51
  (0, thread_1.gravarThread)(raiz, atualizada);
50
52
  }
51
53
  function resultado(thread, acao, motivo, extra = {}) {
52
- return { thread, acao, motivo, mergeSha: null, headSha: null, ci: null, ...extra };
54
+ return { thread, acao, motivo, mergeSha: null, headSha: null, ci: null, docsPendentes: [], ...extra };
53
55
  }
54
56
  /**
55
57
  * `ork ship registrar-pr <thread>`: grava o `ship_done` da entrega feita por PR. Idempotente:
@@ -57,22 +59,26 @@ function resultado(thread, acao, motivo, extra = {}) {
57
59
  */
58
60
  function registrarEntregaPorPr(carregado, threadId, opcoes = {}) {
59
61
  const raiz = carregado.raiz;
60
- const remoto = opcoes.remoto ?? 'origin';
62
+ // RM-047: o `--remoto` vem da linha de comando; so nome de remoto chega ao git, e depois do `--`.
63
+ const remoto = (0, branch_de_estado_1.exigirRemoto)(opcoes.remoto ?? 'origin', 'ship');
61
64
  const base = carregado.manifesto.worktree.base_branch;
62
65
  const thread = (0, thread_1.lerThread)(raiz, threadId);
63
66
  if (thread.status === 'fechada')
64
67
  return resultado(threadId, 'ja-registrada', 'thread ja fechada');
65
68
  if (opcoes.buscar !== false)
66
- (0, util_1.exec)('git', ['fetch', '-q', remoto, `+refs/heads/${base}:refs/remotes/${remoto}/${base}`], raiz);
67
- const merge = mergeDaEntrega(raiz, threadId, remoto, base);
68
- if (!merge)
69
+ (0, util_1.exec)('git', ['fetch', '-q', '--', remoto, `+refs/heads/${base}:refs/remotes/${remoto}/${base}`], raiz);
70
+ const encontrado = mergeDaEntrega(raiz, threadId, remoto, base);
71
+ if (!encontrado)
69
72
  return resultado(threadId, 'sem-merge', `nenhum merge ship(${threadId}) em ${remoto}/${base}`);
73
+ // RM-044 (A3): o condutor roda o registrar-pr logo depois do merge; e aqui que ele fica sabendo da pagina que
74
+ // vai deixar o push da base vermelho, lida da base remota que o fetch acabou de trazer.
75
+ const merge = { ...encontrado, docsPendentes: (0, docs_1.docsPendentesDoMerge)(raiz, threadId, `refs/remotes/${remoto}/${base}`) };
70
76
  const dir = (0, thread_1.dirThread)(raiz, threadId);
71
77
  const jaTem = (0, ledger_1.lerLedger)(dir).some((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.shipConcluido && e.mergeSha === merge.mergeSha);
72
78
  if (jaTem)
73
79
  return resultado(threadId, 'ja-registrada', 'esta entrega ja tem ship_done', merge);
74
80
  // A ponta do remoto AGORA, e o merge dentro dela: e o que torna o push provado, nao presumido.
75
- const remotoAgora = (0, util_1.exec)('git', ['ls-remote', remoto, `refs/heads/${base}`], raiz);
81
+ const remotoAgora = (0, util_1.exec)('git', ['ls-remote', '--', remoto, `refs/heads/${base}`], raiz);
76
82
  const ponta = remotoAgora.ok ? remotoAgora.stdout.split('\t')[0].trim() : '';
77
83
  if (!ponta || !(0, util_1.exec)('git', ['merge-base', '--is-ancestor', merge.mergeSha, ponta], raiz).ok) {
78
84
  return resultado(threadId, 'recusada', `o merge ${merge.mergeSha.slice(0, 7)} nao esta na ponta de ${remoto}/${base}`, merge);
@@ -81,11 +87,18 @@ function registrarEntregaPorPr(carregado, threadId, opcoes = {}) {
81
87
  if (ci.required && !ci.ok) {
82
88
  return resultado(threadId, 'recusada', `sem CI verde no head do PR: ${ci.detail}`, { ...merge, ci });
83
89
  }
90
+ // RM-037 (fatia 3, defeito 6): o ensaio confere tudo e para aqui, sem ledger, fase nem fabrica.
91
+ if (opcoes.dryRun) {
92
+ return resultado(threadId, 'registraria', `ensaio: registraria ship_done pelo merge ${merge.mergeSha.slice(0, 7)} do PR (nada gravado)`, { ...merge, ci });
93
+ }
84
94
  (0, ledger_1.registrar)(dir, threadId, ledger_1.TIPOS_DE_EVENTO.shipConcluido, {
85
95
  de: thread.base?.branch ?? null,
86
96
  para: base,
87
97
  shaDe: merge.headSha,
88
98
  mergeSha: merge.mergeSha,
99
+ // RM-037 (fatia 5, A1): a ponta que o ls-remote provou vai em campo proprio; o recibo do Maestro confere o push
100
+ // contra ela quando a base andou depois do merge.
101
+ pontaDaBase: ponta,
89
102
  jaIncorporado: true,
90
103
  remoto,
91
104
  shaRemoto: ponta,
@@ -174,6 +187,9 @@ function registrarEntregaExternaPorPr(carregado, threadId, opcoes) {
174
187
  if (ci && !ci.ok) {
175
188
  return resultado(threadId, 'recusada', `sem CI verde no head do PR: ${ci.detail}`, { mergeSha, headSha, ci });
176
189
  }
190
+ if (opcoes.dryRun) {
191
+ return resultado(threadId, 'registraria', `ensaio: registraria ship_done pelo merge ${mergeSha.slice(0, 7)} do PR #${n} de ${repo} (nada gravado)`, { mergeSha, headSha, ci });
192
+ }
177
193
  (0, ledger_1.registrar)(dir, threadId, ledger_1.TIPOS_DE_EVENTO.shipConcluido, {
178
194
  de: thread.base?.branch ?? null,
179
195
  para: `${repo}:${base}`,
@@ -182,6 +198,9 @@ function registrarEntregaExternaPorPr(carregado, threadId, opcoes) {
182
198
  url: pr.html_url ?? `https://github.com/${repo}/pull/${n}`,
183
199
  shaDe: headSha,
184
200
  mergeSha,
201
+ // RM-037 (fatia 5, A1; aviso da rodada 1 do CHECK): a ponta conferida vai em campo proprio, como no PR local; a
202
+ // comparacao aceita `ahead`, e o recibo do Maestro confere o push contra ela.
203
+ pontaDaBase: ponta,
185
204
  jaIncorporado: true,
186
205
  remoto: `github:${repo}`,
187
206
  shaRemoto: ponta,
@@ -200,9 +219,9 @@ function registrarEntregaExternaPorPr(carregado, threadId, opcoes) {
200
219
  }
201
220
  /** `ork ship registrar-pr --todas`: toda thread aberta que ja tem merge `ship(<thread>)` na base. */
202
221
  function registrarEntregasPorPr(carregado, opcoes = {}) {
203
- const remoto = opcoes.remoto ?? 'origin';
222
+ const remoto = (0, branch_de_estado_1.exigirRemoto)(opcoes.remoto ?? 'origin', 'ship');
204
223
  const base = carregado.manifesto.worktree.base_branch;
205
- (0, util_1.exec)('git', ['fetch', '-q', remoto, `+refs/heads/${base}:refs/remotes/${remoto}/${base}`], carregado.raiz);
224
+ (0, util_1.exec)('git', ['fetch', '-q', '--', remoto, `+refs/heads/${base}:refs/remotes/${remoto}/${base}`], carregado.raiz);
206
225
  const r = (0, thread_1.listarIds)(carregado.raiz)
207
226
  .filter((id) => (0, thread_1.lerThread)(carregado.raiz, id).status !== 'fechada')
208
227
  .filter((id) => mergeDaEntrega(carregado.raiz, id, remoto, base) !== null)
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ /**
3
+ * RM-040 (B7): `ork accounts esgotamentos`, a medida da metrica do item.
4
+ *
5
+ * A metrica da RM-040 e "zero despacho numa conta que outro projeto do mesmo usuario ja viu
6
+ * esgotada, dentro do prazo dela". Este relatorio so le: as marcas do registro compartilhado
7
+ * (`~/.orkastery/private/contas.json`) e os `phase_dispatch` com perfil dos ledgers de cada projeto
8
+ * registrado nesta maquina (`~/.orkastery/projetos.json`). Conta o despacho que caiu na conta de
9
+ * uma marca, dentro da janela dela, vindo de projeto diferente do que marcou.
10
+ *
11
+ * A saida nunca leva diretorio de conta: a conta vira um id opaco (sha256 da chave, 12 hex), o
12
+ * projeto sai pelo nome registrado e o perfil, pelo id.
13
+ *
14
+ * Limite declarado: o registro so guarda as marcas vivas. Uso bem sucedido, login reconferido e
15
+ * prazo vencido apagam a marca na gravacao seguinte; por isso o numero e um piso, e a leitura vale
16
+ * enquanto a marca existe.
17
+ */
18
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ var desc = Object.getOwnPropertyDescriptor(m, k);
21
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
22
+ desc = { enumerable: true, get: function() { return m[k]; } };
23
+ }
24
+ Object.defineProperty(o, k2, desc);
25
+ }) : (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ o[k2] = m[k];
28
+ }));
29
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
30
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
31
+ }) : function(o, v) {
32
+ o["default"] = v;
33
+ });
34
+ var __importStar = (this && this.__importStar) || (function () {
35
+ var ownKeys = function(o) {
36
+ ownKeys = Object.getOwnPropertyNames || function (o) {
37
+ var ar = [];
38
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
39
+ return ar;
40
+ };
41
+ return ownKeys(o);
42
+ };
43
+ return function (mod) {
44
+ if (mod && mod.__esModule) return mod;
45
+ var result = {};
46
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
47
+ __setModuleDefault(result, mod);
48
+ return result;
49
+ };
50
+ })();
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ exports.NAO_REGISTRADO = exports.LIMITE_DO_RELATORIO = exports.CONTRATO_ESGOTAMENTOS = void 0;
53
+ exports.contaOpaca = contaOpaca;
54
+ exports.fimDaJanela = fimDaJanela;
55
+ exports.relatorioDeEsgotamentos = relatorioDeEsgotamentos;
56
+ exports.textoDosEsgotamentos = textoDosEsgotamentos;
57
+ const node_crypto_1 = require("node:crypto");
58
+ const fs = __importStar(require("node:fs"));
59
+ const horario_1 = require("./horario");
60
+ const ledger_1 = require("./ledger");
61
+ const ledger_stats_1 = require("./ledger-stats");
62
+ const projeto_alvo_1 = require("./projeto-alvo");
63
+ const runtime_profiles_1 = require("./runtime-profiles");
64
+ const thread_1 = require("./thread");
65
+ const util_1 = require("./util");
66
+ exports.CONTRATO_ESGOTAMENTOS = 'ork.esgotamentos/v1';
67
+ exports.LIMITE_DO_RELATORIO = 'o registro guarda so as marcas vivas (uso bem sucedido, login reconferido e prazo vencido ' +
68
+ 'apagam a marca): o total e um piso, valido enquanto a marca existe';
69
+ exports.NAO_REGISTRADO = 'nao registrado';
70
+ function contaOpaca(chave) {
71
+ return (0, node_crypto_1.createHash)('sha256').update(chave).digest('hex').slice(0, 12);
72
+ }
73
+ function caminhoReal(p) {
74
+ try {
75
+ return fs.realpathSync(p);
76
+ }
77
+ catch {
78
+ return p;
79
+ }
80
+ }
81
+ /** Fim da janela da marca: o prazo para cota esgotada; sem prazo (login, credencial paga), aberta. */
82
+ function fimDaJanela(m) {
83
+ if (m.estado !== 'esgotado')
84
+ return Number.POSITIVE_INFINITY;
85
+ const ate = m.esgotadoAte === null ? NaN : Date.parse(m.esgotadoAte);
86
+ return Number.isFinite(ate) ? ate : Number.NEGATIVE_INFINITY;
87
+ }
88
+ function relatorioDeEsgotamentos(opcoes = {}) {
89
+ const agoraMs = opcoes.agoraMs ?? Date.now();
90
+ const desdeMs = (0, ledger_stats_1.parsePeriodo)(opcoes.desde ?? '7d', agoraMs);
91
+ if (desdeMs >= agoraMs)
92
+ throw Error('ledger.period.order');
93
+ // Um projeto por raiz real: o registro pode trazer a mesma copia por dois caminhos.
94
+ const vistos = new Set();
95
+ const projetos = (0, projeto_alvo_1.listarProjetos)().filter((p) => {
96
+ const real = caminhoReal(p.raiz);
97
+ if (vistos.has(real))
98
+ return false;
99
+ vistos.add(real);
100
+ return true;
101
+ }).map((p) => ({ ...p, real: caminhoReal(p.raiz) }));
102
+ const nomeDaRaiz = (raiz) => projetos.find((p) => p.real === caminhoReal(raiz))?.nome ?? exports.NAO_REGISTRADO;
103
+ const contas = (0, runtime_profiles_1.lerContasCompartilhadas)();
104
+ const marcas = contas.map((c) => ({ c, real: caminhoReal(c.projeto), inicio: Date.parse(c.em), fim: fimDaJanela(c) }));
105
+ const despachos = [];
106
+ const lidos = [];
107
+ for (const p of projetos) {
108
+ let comPerfil = 0;
109
+ let ids = [];
110
+ try {
111
+ ids = p.presente ? (0, thread_1.listarIds)(p.raiz) : [];
112
+ }
113
+ catch {
114
+ ids = [];
115
+ }
116
+ for (const id of ids) {
117
+ let eventos = [];
118
+ try {
119
+ eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(p.raiz, id));
120
+ }
121
+ catch {
122
+ continue;
123
+ }
124
+ for (const e of eventos) {
125
+ if (e.tipo !== 'phase_dispatch' || e.perfil === undefined || e.perfil === null)
126
+ continue;
127
+ const t = Date.parse(String(e.ts));
128
+ if (!Number.isFinite(t) || t < desdeMs || t >= agoraMs)
129
+ continue;
130
+ let perfil, chave;
131
+ try {
132
+ perfil = (0, runtime_profiles_1.validarPerfilDeDespacho)(e.perfil);
133
+ chave = (0, runtime_profiles_1.chaveDaConta)(perfil);
134
+ }
135
+ catch {
136
+ continue;
137
+ }
138
+ comPerfil++;
139
+ const marca = marcas.find((m) => m.c.chave === chave && m.real !== p.real && t >= m.inicio && t < m.fim);
140
+ if (!marca)
141
+ continue;
142
+ despachos.push({ em: new Date(t).toISOString(), projeto: p.nome, thread: String(e.thread ?? id),
143
+ fase: typeof e.fase === 'string' ? e.fase : null, runtime: perfil.runtime, perfil: perfil.id,
144
+ conta: contaOpaca(chave), marcadaPor: nomeDaRaiz(marca.c.projeto) });
145
+ }
146
+ }
147
+ lidos.push({ nome: p.nome, presente: p.presente, despachosComPerfil: comPerfil });
148
+ }
149
+ despachos.sort((a, b) => a.em.localeCompare(b.em));
150
+ return {
151
+ contrato: exports.CONTRATO_ESGOTAMENTOS,
152
+ periodo: { desde: new Date(desdeMs).toISOString(), ate: new Date(agoraMs).toISOString(), intervalo: '[desde,ate)' },
153
+ marcas: contas.map((c) => ({ conta: contaOpaca(c.chave), runtime: c.chave.slice(0, c.chave.indexOf(':')), estado: c.estado,
154
+ motivo: c.motivo, em: c.em, esgotadoAte: c.esgotadoAte, projeto: nomeDaRaiz(c.projeto) })),
155
+ projetos: lidos,
156
+ despachos,
157
+ total: despachos.length,
158
+ limite: exports.LIMITE_DO_RELATORIO,
159
+ };
160
+ }
161
+ /** Texto para o terminal, com o horario do dono e o fuso uma vez no fim. */
162
+ function textoDosEsgotamentos(r) {
163
+ const linhas = [
164
+ `Esgotamentos de conta ${(0, horario_1.formatarDataHora)(r.periodo.desde)} ate ${(0, horario_1.formatarDataHora)(r.periodo.ate)} ${r.periodo.intervalo}`,
165
+ ` marcas vivas no registro: ${r.marcas.length}`,
166
+ ];
167
+ for (const m of r.marcas) {
168
+ const ate = m.estado === 'esgotado' ? `ate ${(0, horario_1.formatarDataHora)(m.esgotadoAte)}` : 'sem prazo';
169
+ linhas.push(` conta ${m.conta} ${m.runtime} ${m.estado} desde ${(0, horario_1.formatarDataHora)(m.em)}, ${ate} visto em ${m.projeto} (${m.motivo})`);
170
+ }
171
+ linhas.push(` projetos lidos: ${r.projetos.length === 0 ? 'nenhum registrado'
172
+ : r.projetos.map((p) => `${p.nome} (${p.presente ? `${p.despachosComPerfil} despacho(s) com perfil` : 'fora do disco'})`).join(', ')}`);
173
+ linhas.push(` despachos em conta marcada por outro projeto: ${r.total}`);
174
+ if (r.despachos.length > 0) {
175
+ linhas.push((0, util_1.tabela)(['QUANDO', 'PROJETO', 'THREAD', 'FASE', 'PERFIL', 'CONTA', 'MARCADA POR'], r.despachos.map((d) => [(0, horario_1.formatarDataHora)(d.em), d.projeto, d.thread, d.fase ?? '-', d.perfil, d.conta, d.marcadaPor]))
176
+ .split('\n').map((l) => ` ${l}`).join('\n'));
177
+ }
178
+ linhas.push(` limite: ${r.limite}`);
179
+ linhas.push((0, horario_1.legendaDoFuso)());
180
+ return linhas.join('\n');
181
+ }
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IDIOMA_PADRAO = void 0;
3
4
  exports.normalizarIdioma = normalizarIdioma;
4
5
  exports.validarPreferencias = validarPreferencias;
5
6
  exports.idiomaDoSistema = idiomaDoSistema;
@@ -44,6 +45,11 @@ function validarPreferencias(valor) {
44
45
  }
45
46
  return resultado;
46
47
  }
48
+ /**
49
+ * Ensaio de 03/10 (R2): sem idioma escolhido, vale a língua da CLI. Antes era en-US, e uma máquina com
50
+ * LANG=C.UTF-8 (contêiner, CI, servidor) recebia a experiência em inglês de uma CLI que fala português.
51
+ */
52
+ exports.IDIOMA_PADRAO = 'pt-BR';
47
53
  /** C, POSIX e und (raiz do ICU) dizem que o sistema não escolheu idioma: vale o padrão. */
48
54
  const SEM_IDIOMA = new Set(['c', 'posix', 'und']);
49
55
  function idiomaEscolhido(valor) {
@@ -52,11 +58,15 @@ function idiomaEscolhido(valor) {
52
58
  }
53
59
  function idiomaDoSistema(env = process.env, doIntl = () => Intl.DateTimeFormat().resolvedOptions().locale) {
54
60
  const locale = env.LC_ALL || env.LC_MESSAGES || env.LANG;
55
- return idiomaEscolhido(locale?.split(/[.@]/)[0].replace(/_/g, '-')) ?? idiomaEscolhido(doIntl()) ?? 'en-US';
61
+ if (locale) {
62
+ // Com C ou POSIX explícito, o Intl do Node cai no en-US do ICU: ele não diz a escolha de ninguém.
63
+ return idiomaEscolhido(locale.split(/[.@]/)[0].replace(/_/g, '-')) ?? exports.IDIOMA_PADRAO;
64
+ }
65
+ return idiomaEscolhido(doIntl()) ?? exports.IDIOMA_PADRAO;
56
66
  }
57
67
  function resolverExperiencia(owner = {}, sistema = { language: idiomaDoSistema(), timezone: (0, horario_1.fusoDoSistema)() }) {
58
68
  const p = validarPreferencias(owner);
59
- const language = p.language ?? normalizarIdioma(sistema.language) ?? 'en-US';
69
+ const language = p.language ?? normalizarIdioma(sistema.language) ?? exports.IDIOMA_PADRAO;
60
70
  return {
61
71
  language, timezone: p.timezone ?? (0, horario_1.normalizarFuso)(sistema.timezone) ?? 'UTC',
62
72
  depth: p.depth ?? 'curta', experience: p.experience ?? true,
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.PULSACAO_MS = exports.DIR_DA_FABRICA = exports.BRANCH_DA_FABRICA = exports.CONTRATO_MAQUINA = void 0;
36
+ exports.LIMIAR_SEM_BATIDA_MS = exports.PULSACAO_MS = exports.DIR_DA_FABRICA = exports.BRANCH_DA_FABRICA = exports.CONTRATO_MAQUINA = void 0;
37
37
  exports.despachoDaThread = despachoDaThread;
38
38
  exports.runtimeDaThread = runtimeDaThread;
39
39
  exports.arquivoDaMaquina = arquivoDaMaquina;
@@ -76,10 +76,12 @@ const horario_1 = require("./horario");
76
76
  const ledger_1 = require("./ledger");
77
77
  const modos_1 = require("./modos");
78
78
  const orquestracao_1 = require("./orquestracao");
79
+ const parado_no_condutor_1 = require("./parado-no-condutor");
79
80
  const roadmap_reservas_1 = require("./roadmap-reservas");
80
81
  const thread_1 = require("./thread");
81
82
  const util_1 = require("./util");
82
83
  const versao_1 = require("./versao");
84
+ const saida_segura_1 = require("./saida-segura");
83
85
  exports.CONTRATO_MAQUINA = 'ork.fabrica-maquina/v1';
84
86
  exports.BRANCH_DA_FABRICA = 'ork/fabrica-estado';
85
87
  /** O diretorio dos retratos na branch; a leitura sem clone (RM-054) le o mesmo. */
@@ -90,6 +92,12 @@ const PREFIXO = 'fabrica';
90
92
  const TENTATIVAS = 5;
91
93
  /** Retrato igual ao ultimo publicado so volta ao remoto depois disto: e o sinal de vida da maquina. */
92
94
  exports.PULSACAO_MS = 60 * 60 * 1000;
95
+ /**
96
+ * Maquina sem retrato novo ha mais disto esta sem batida: o mesmo limiar da rede (RM-053, `SEM_BATIDA_MS`).
97
+ * RM-037 (fatia 4): mora aqui, junto da pulsacao, porque o status do roadmap tambem o le; o panorama da
98
+ * rede o reexporta.
99
+ */
100
+ exports.LIMIAR_SEM_BATIDA_MS = 3 * 60 * 60 * 1000;
93
101
  const ARQUIVO_DA_MARCA = 'fabrica-publicada.json';
94
102
  const ARQUIVO_DO_LOG = 'fabrica.log';
95
103
  /** O trio do ultimo `phase_dispatch` do ledger da thread; tudo `null` quando nao ha despacho legivel. */
@@ -155,9 +163,20 @@ function retratoDaMaquina(carregado, opcoes = {}) {
155
163
  const entregas = entregasNaBase(raiz, carregado.manifesto.worktree.base_branch, remoto);
156
164
  const itemDaThread = new Map((0, roadmap_reservas_1.reservasLocais)(raiz, remoto).filter((r) => r.thread).map((r) => [r.thread, r.item]));
157
165
  const threads = itens.map(({ thread: t, raiz: raizDoPerfil }) => {
158
- const pausa = linhas.get(t.id)?.pausas[0];
159
166
  const entregue = entregas.get(t.id) ?? null;
160
- const esperaVoce = !entregue && linhas.get(t.id)?.precisaDeHumano === true;
167
+ // RM-037 (fatia 4): o fim de turno sem pergunta e do condutor, e as outras maquinas nao o leem como espera
168
+ // do dono. Sai so a pausa que o observador abriu nele; outra pausa da thread continua contando.
169
+ let espera = null;
170
+ try {
171
+ espera = (0, parado_no_condutor_1.esperaDoCondutor)(t, (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raizDoPerfil, t.id)), quando);
172
+ }
173
+ catch {
174
+ espera = null;
175
+ }
176
+ const pausas = (linhas.get(t.id)?.pausas ?? []).filter((p) => !(espera && p.motivo === 'human.pending' && p.fonte === 'ledger' &&
177
+ p.fase === (espera.fase ?? t.faseAtual)));
178
+ const pausa = pausas[0];
179
+ const esperaVoce = !entregue && pausas.some((p) => p.sessaoViva !== true);
161
180
  return {
162
181
  id: t.id, nome: curto(t.nome, 100), modo: (0, modos_1.tagDoModo)(t.modo), fase: t.faseAtual, status: t.status,
163
182
  roadmap: t.roadmap ?? itemDaThread.get(t.id) ?? null, branch: t.base?.branch ?? null,
@@ -216,7 +235,8 @@ function gravarMarca(raiz, marca) {
216
235
  */
217
236
  function publicarMaquina(carregado, opcoes = {}) {
218
237
  const raiz = carregado.raiz;
219
- const remoto = opcoes.remoto ?? carregado.manifesto.fabrica.remoto;
238
+ // RM-047: antes do retrato e da marca, para o remoto invalido recusar mesmo sem mudanca a enviar.
239
+ const remoto = (0, branch_de_estado_1.exigirRemoto)(opcoes.remoto ?? carregado.manifesto.fabrica.remoto, PREFIXO);
220
240
  const estado = retratoDaMaquina(carregado, { ...opcoes, remoto });
221
241
  const assinatura = assinaturaDoRetrato(estado);
222
242
  const marca = lerMarca(raiz);
@@ -256,7 +276,7 @@ function publicarMaquina(carregado, opcoes = {}) {
256
276
  /** `ork fabrica sair`: tira o retrato desta maquina da branch. `null` quando nao havia retrato. */
257
277
  function removerMaquina(carregado, opcoes = {}) {
258
278
  const raiz = carregado.raiz;
259
- const remoto = opcoes.remoto ?? carregado.manifesto.fabrica.remoto;
279
+ const remoto = (0, branch_de_estado_1.exigirRemoto)(opcoes.remoto ?? carregado.manifesto.fabrica.remoto, PREFIXO);
260
280
  const maquina = (0, roadmap_reservas_1.quemSouEu)(raiz, { maquina: opcoes.maquina }).maquina;
261
281
  for (let tentativa = 1; tentativa <= TENTATIVAS; tentativa++) {
262
282
  const { ponta, atualizado } = (0, branch_de_estado_1.buscarBranch)(raiz, remoto, exports.BRANCH_DA_FABRICA, PREFIXO, 30000);
@@ -313,8 +333,13 @@ function blocoDaMaquina(m, eu) {
313
333
  t.id, t.modo, t.fase, runtimeDaThread(t), t.roadmap ?? '-', t.esperaVoce ? `sim: ${curto(t.pergunta ?? 'veredito', 40)}` : '-',
314
334
  ]))];
315
335
  }
316
- /** `ork fabrica`: todas as maquinas. */
317
- function textoDaFabrica(p, eu) {
336
+ /**
337
+ * `ork fabrica`: todas as maquinas. RM-053 (fatia 2): o painel vem do remoto, onde outras pessoas
338
+ * escrevem; cada valor dele (o `por`, o `projeto`, a pergunta) chega a tela numa linha so, sem nada
339
+ * que o terminal execute.
340
+ */
341
+ function textoDaFabrica(painel, eu) {
342
+ const p = (0, saida_segura_1.valoresEmUmaLinha)(painel);
318
343
  const linhas = [];
319
344
  if (!p.atualizado)
320
345
  linhas.push('AVISO: sem leitura nova do remoto; esta e a ultima copia lida nesta maquina.', '');
@@ -327,8 +352,9 @@ function textoDaFabrica(p, eu) {
327
352
  linhas.push((0, horario_1.legendaDoFuso)());
328
353
  return linhas.join('\n');
329
354
  }
330
- /** A secao de `ork board` com as outras maquinas. */
331
- function textoDasOutrasMaquinas(p, eu) {
355
+ /** A secao de `ork board` com as outras maquinas, saneada como o `ork fabrica`. */
356
+ function textoDasOutrasMaquinas(painel, eu) {
357
+ const p = (0, saida_segura_1.valoresEmUmaLinha)(painel);
332
358
  const outras = p.maquinas.filter((m) => m.maquina !== eu);
333
359
  const origem = p.atualizado ? 'lido agora' : 'ultima copia local';
334
360
  if (outras.length === 0)
@@ -39,18 +39,24 @@ exports.publicarEmSegundoPlano = publicarEmSegundoPlano;
39
39
  *
40
40
  * Modulo a parte, com o minimo de dependencias, porque quem chama (despacho de fase, entrega,
41
41
  * thread nova) nao pode esperar rede nem arrastar o retrato inteiro para dentro de si.
42
+ *
43
+ * RM-053 (D9): o mesmo evento tambem dispara o retrato desta maquina na rede da pessoa, pela
44
+ * `rede-adesao` (tao leve quanto este modulo): so membro, no maximo uma vez a cada 14 minutos.
42
45
  */
43
46
  const node_child_process_1 = require("node:child_process");
44
47
  const fs = __importStar(require("node:fs"));
45
48
  const path = __importStar(require("node:path"));
46
49
  const maquina_1 = require("./maquina");
47
50
  const manifest_1 = require("./manifest");
51
+ const rede_adesao_1 = require("./rede-adesao");
48
52
  /**
49
53
  * Publica sem segurar quem chamou (thread nova, despacho de fase, entrega). So com a fabrica
50
54
  * compartilhada nesta maquina (`ork fabrica entrar`) ou no projeto; `ORK_FABRICA_PUBLICAR=0`
51
55
  * desliga (testes e `ork eval`).
52
56
  */
53
57
  function publicarEmSegundoPlano(raiz) {
58
+ // A rede decide por si (adesao, teto e ambiente); o retorno continua sendo o da fabrica.
59
+ (0, rede_adesao_1.publicarRedeEmSegundoPlano)({ diretorio: raiz });
54
60
  if (process.env.ORK_FABRICA_PUBLICAR === '0')
55
61
  return false;
56
62
  let carregado;
@@ -1,37 +1,4 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.liberarAoFechar = liberarAoFechar;
37
4
  /**
@@ -43,61 +10,48 @@ exports.liberarAoFechar = liberarAoFechar;
43
10
  * derruba. Cada parte roda isolada (achado A1 do CHECK 1): erro de E/S numa nao impede a outra, e o
44
11
  * que nao saiu agora sai na poda do proximo pedido de regiao ou no `ork roadmap reservas --soltar-orfas`.
45
12
  */
46
- const fs = __importStar(require("node:fs"));
47
- const path = __importStar(require("node:path"));
48
- const estado_thread_1 = require("./estado-thread");
49
13
  const ledger_1 = require("./ledger");
50
14
  const leases_1 = require("./leases");
51
15
  const roadmap_reservas_1 = require("./roadmap-reservas");
16
+ const sessoes_1 = require("./sessoes");
52
17
  const thread_1 = require("./thread");
53
18
  function liberarAoFechar(raiz, threadId) {
54
- const saida = { leases: [], fila: [], reservas: [], falhas: [] };
19
+ const saida = { leases: [], fila: [], reservas: [], sessoes: [], falhas: [] };
55
20
  const falhou = (parte, e) => saida.falhas.push(`${parte}: ${e?.message ?? String(e)}`);
56
- // Os leases de regiao sao por checkout: o de quem fecha, a raiz do projeto e, quando a thread tem
57
- // worktree, os pegos de la (sugestao 6 do CHECK 2: fechar da worktree tambem solta os da raiz).
58
- const real = (p) => { try {
59
- return fs.realpathSync(p);
60
- }
61
- catch {
62
- return path.resolve(p);
63
- } };
64
- const candidatos = [raiz];
21
+ // RM-036 (D6): os leases de regiao moram todos no estado canonico, chamado de qualquer checkout, e a
22
+ // soltura de la ja alcanca o legado que a versao anterior gravou nas worktrees. Uma soltura basta.
65
23
  try {
66
- candidatos.push((0, estado_thread_1.raizDoEstado)(raiz));
24
+ const solto = (0, leases_1.soltarThreadFechada)(raiz, threadId, 'fechamento');
25
+ saida.leases.push(...solto.leases);
26
+ saida.fila.push(...solto.fila);
67
27
  }
68
28
  catch (e) {
69
- falhou('raiz', e);
29
+ falhou(`leases em ${raiz}`, e);
70
30
  }
71
31
  try {
72
- const wt = (0, thread_1.lerThread)(raiz, threadId).worktree;
73
- if (wt && fs.existsSync(wt))
74
- candidatos.push(wt);
32
+ saida.reservas = (0, roadmap_reservas_1.soltarReservaDaThread)(raiz, threadId);
75
33
  }
76
34
  catch (e) {
77
- falhou('thread', e);
78
- }
79
- const checkouts = candidatos.filter((c, i) => candidatos.findIndex((x) => real(x) === real(c)) === i);
80
- for (const checkout of checkouts) {
81
- try {
82
- const solto = (0, leases_1.soltarThreadFechada)(checkout, threadId, 'fechamento');
83
- saida.leases.push(...solto.leases);
84
- saida.fila.push(...solto.fila);
85
- }
86
- catch (e) {
87
- falhou(`leases em ${checkout}`, e);
88
- }
35
+ falhou('reserva', e);
89
36
  }
37
+ // RM-056 (ao fechar): a sessao fantasma presa a thread fechada seguia no inventario e no doctor ate
38
+ // alguem rodar `ork sessions limpar-fantasmas` (624f65db e d38ae1d4, 03/10). So consulta o runtime
39
+ // quando o ledger tem sessao sem fim; nunca para nem remove nada no runtime, e sessao viva fica.
90
40
  try {
91
- saida.reservas = (0, roadmap_reservas_1.soltarReservaDaThread)(raiz, threadId);
41
+ if ((0, sessoes_1.sessoesSemFim)(raiz, threadId).length > 0) {
42
+ const r = (0, sessoes_1.limparFantasmas)(raiz, { thread: threadId, origem: 'fechamento' });
43
+ saida.sessoes = r.itens.filter((i) => i.acao === 'solto');
44
+ }
92
45
  }
93
46
  catch (e) {
94
- falhou('reserva', e);
47
+ falhou('sessoes', e);
95
48
  }
96
49
  // Sugestao 2 do CHECK 2: a falha tambem vai ao ledger da thread, de melhor esforco.
97
50
  if (saida.falhas.length > 0) {
98
51
  try {
99
52
  (0, ledger_1.registrarSeExiste)((0, thread_1.dirThread)(raiz, threadId), threadId, ledger_1.TIPOS_DE_EVENTO.solturaFalhou, { falhas: saida.falhas,
100
- correcao: 'a poda do proximo pedido de regiao solta o que ficou; reserva: ork roadmap reservas --soltar-orfas' });
53
+ correcao: 'a poda do proximo pedido de regiao solta o que ficou; reserva: ork roadmap reservas --soltar-orfas; ' +
54
+ 'sessao fantasma: ork sessions limpar-fantasmas' });
101
55
  }
102
56
  catch { /* o ledger que nao grava ja esta nas falhas */ }
103
57
  }
package/dist/fix.js CHANGED
@@ -150,7 +150,7 @@ function derivarCorrecoes(thread, rodada, resultado, idsUsados) {
150
150
  }
151
151
  for (const cmd of resultado.regressoes) {
152
152
  nascer('verify.regression', `comando ${cmd.nome}`, `REGRESSAO: "${cmd.comando}" passava na baseline gravada antes do GO (commit ` +
153
- `${resultado.baseline?.commit.slice(0, 8) ?? 'desconhecido'}) e falha agora. Este defeito ` +
153
+ `${resultado.baseline ? (0, util_1.shaCurto)(resultado.baseline.commit) : 'desconhecido'}) e falha agora. Este defeito ` +
154
154
  'e desta thread, nao divida pre-existente. Corrija ate o comando voltar a passar.', [cmd.comando], `codigo ${cmd.code}:\n${cmd.resumo}`);
155
155
  }
156
156
  for (const cmd of resultado.falhasSemBaseline) {
@@ -339,7 +339,7 @@ function reverificarSobConducao(carregado, threadId, opcoes) {
339
339
  veredito = 'PASSOU';
340
340
  razao =
341
341
  `${vereditos.length} correcao(oes) aprovada(s) por comando reexecutado no HEAD real` +
342
- (verify ? `, com o verify completo verde no commit ${verify.commit.slice(0, 8)}` : '');
342
+ (verify ? `, com o verify completo verde no commit ${(0, util_1.shaCurto)(verify.commit)}` : '');
343
343
  }
344
344
  else if (rodadas >= limite) {
345
345
  veredito = 'BLOQUEADO';
@@ -459,7 +459,7 @@ function textoDoReverify(r) {
459
459
  }
460
460
  if (r.verify) {
461
461
  linhas.push('');
462
- linhas.push(`Verify completo no HEAD ${r.verify.commit.slice(0, 8)}: ${r.verify.ok ? 'verde' : `reprovado (${r.verify.motivos.join(', ')})`}`);
462
+ linhas.push(`Verify completo no HEAD ${(0, util_1.shaCurto)(r.verify.commit)}: ${r.verify.ok ? 'verde' : `reprovado (${r.verify.motivos.join(', ')})`}`);
463
463
  }
464
464
  linhas.push('');
465
465
  linhas.push(`Veredito final: ${r.veredito}`);