@orkastery/cli 0.5.1 → 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 (110) hide show
  1. package/adapters/claude-code/agents/ork-master.md +2 -0
  2. package/adapters/claude-code/commands/master.md +8 -0
  3. package/adapters/claude-code/commands/ork.md +9 -0
  4. package/adapters/codex/skills/ork/SKILL.md +18 -3
  5. package/adapters/hermes/README.md +1 -0
  6. package/adapters/hermes/bin/ork-network-status.sh +10 -0
  7. package/adapters/hermes/hermes.plugin.json +1 -0
  8. package/adapters/hermes/hitl-ingress/__init__.py +2 -2
  9. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +6 -5
  10. package/adapters/openclaw/README.md +24 -4
  11. package/adapters/openclaw/dist/hitl-ingress.js +2 -2
  12. package/adapters/openclaw/dist/index.js +46 -11
  13. package/adapters/openclaw/openclaw.plugin.json +5 -1
  14. package/adapters/openclaw/package.json +2 -2
  15. package/adapters/openclaw/src/hitl-ingress.ts +2 -2
  16. package/adapters/openclaw/src/index.ts +49 -11
  17. package/assets/orkmind_bridge.py +117 -9
  18. package/dist/adapters/claude-bg.js +39 -5
  19. package/dist/adapters/codex.js +4 -3
  20. package/dist/agents-md.js +1 -0
  21. package/dist/auditrun.js +5 -1
  22. package/dist/board.js +16 -14
  23. package/dist/branch-de-estado.js +66 -10
  24. package/dist/busca-semantica.js +52 -12
  25. package/dist/canarios-rm057.js +149 -0
  26. package/dist/canarios.js +2 -0
  27. package/dist/ci.js +8 -1
  28. package/dist/claims.js +39 -1
  29. package/dist/company-brain-context.js +158 -22
  30. package/dist/docs.js +48 -9
  31. package/dist/doctor-pulse-cron.js +194 -0
  32. package/dist/doctor-rede.js +149 -0
  33. package/dist/doctor.js +89 -9
  34. package/dist/entrega-pr.js +20 -8
  35. package/dist/esgotamentos.js +181 -0
  36. package/dist/experiencia.js +12 -2
  37. package/dist/fabrica-estado.js +14 -6
  38. package/dist/fabrica-publicar.js +6 -0
  39. package/dist/fechamento.js +20 -66
  40. package/dist/forja.js +31 -7
  41. package/dist/gates.js +5 -1
  42. package/dist/hitl-contract.js +59 -4
  43. package/dist/hitl-curto.js +11 -6
  44. package/dist/hitl-gates.js +5 -0
  45. package/dist/hitl-lote.js +5 -2
  46. package/dist/hitl-resumo.js +9 -0
  47. package/dist/hitl-tempo-parado.js +201 -0
  48. package/dist/hitl-texto-livre.js +5 -5
  49. package/dist/horario.js +27 -0
  50. package/dist/hosts.js +52 -10
  51. package/dist/impedimento.js +205 -0
  52. package/dist/index.js +391 -74
  53. package/dist/indice-vetorial.js +87 -10
  54. package/dist/indice.js +3 -1
  55. package/dist/init.js +17 -0
  56. package/dist/integracoes-locais.js +2 -0
  57. package/dist/intelligence-graph-cli.js +91 -8
  58. package/dist/intelligence-graph-contexto.js +215 -0
  59. package/dist/intelligence-graph-parsers.js +6 -4
  60. package/dist/leases.js +664 -87
  61. package/dist/ledger-stats.js +15 -1
  62. package/dist/ledger.js +3 -0
  63. package/dist/licoes.js +1 -0
  64. package/dist/maestro-runtime.js +4 -1
  65. package/dist/manifest.js +20 -1
  66. package/dist/master-nota.js +14 -5
  67. package/dist/master.js +129 -12
  68. package/dist/mcp-artifacts.js +34 -3
  69. package/dist/mcp-git.js +20 -3
  70. package/dist/mcp-grafo-worker.js +5 -3
  71. package/dist/mcp-grafo.js +50 -4
  72. package/dist/mcp-server.js +14 -1
  73. package/dist/memoria.js +48 -6
  74. package/dist/network-roadmap.js +191 -16
  75. package/dist/ocupacao.js +11 -3
  76. package/dist/orkmind.js +90 -5
  77. package/dist/orquestracao.js +12 -10
  78. package/dist/parado-no-condutor.js +188 -32
  79. package/dist/phase.js +68 -15
  80. package/dist/policies.js +52 -1
  81. package/dist/portfolio.js +4 -1
  82. package/dist/projeto-alvo.js +5 -1
  83. package/dist/prompts.js +36 -1
  84. package/dist/prova-ativacao.js +75 -6
  85. package/dist/pulse-delivery.js +34 -2
  86. package/dist/pulse.js +49 -3
  87. package/dist/ratelimit.js +20 -4
  88. package/dist/recall.js +3 -1
  89. package/dist/rede-adesao.js +399 -0
  90. package/dist/rede-forja.js +289 -0
  91. package/dist/rede-projetos.js +239 -0
  92. package/dist/rede-status.js +336 -0
  93. package/dist/rede.js +980 -0
  94. package/dist/retry.js +69 -2
  95. package/dist/roadmap-status.js +23 -3
  96. package/dist/runtime-profiles.js +22 -1
  97. package/dist/saida-segura.js +58 -0
  98. package/dist/session-watcher-claude.js +113 -23
  99. package/dist/sessoes-contas.js +187 -0
  100. package/dist/sessoes-inventario.js +6 -18
  101. package/dist/sessoes.js +83 -2
  102. package/dist/ship.js +85 -19
  103. package/dist/thread.js +192 -13
  104. package/dist/worktree.js +5 -2
  105. package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
  106. package/package.json +7 -3
  107. package/references/definition-of-done.md +1 -1
  108. package/skills/README.md +1 -1
  109. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  110. package/skills/phases/master-metrics/SKILL.md +8 -3
package/dist/orkmind.js CHANGED
@@ -54,7 +54,8 @@ var __importStar = (this && this.__importStar) || (function () {
54
54
  };
55
55
  })();
56
56
  Object.defineProperty(exports, "__esModule", { value: true });
57
- exports.DriverEmMemoria = exports.DriverCliOrkMind = exports.LIMITE_CONSULTA_MAXIMO = exports.LIMITE_CONSULTA_PADRAO = exports.CODIGOS_DE_EMBEDDING = exports.MODELO_DE_EMBEDDING = exports.EMBED_MAX_CARACTERES = exports.EMBED_MAX_TEXTOS = exports.ESQUEMA_ORKMIND = exports.DIMENSOES = exports.COLECOES_DE_GOVERNANCA = exports.COLECOES_DO_ORK = void 0;
57
+ exports.DriverEmMemoria = exports.DriverCliOrkMind = exports.LIMITE_CONSULTA_MAXIMO = exports.LIMITE_CONSULTA_PADRAO = exports.CODIGOS_DE_EMBEDDING = exports.MODELO_DE_EMBEDDING = exports.EMBED_MAX_CARACTERES = exports.EMBED_MAX_TEXTOS = exports.ESQUEMA_ORKMIND = exports.DIMENSOES = exports.COLECOES_DE_GOVERNANCA = exports.LIMITE_TIMEOUT_DO_UNIVERSO_MS = exports.TIMEOUT_DO_UNIVERSO_MS = exports.COLECOES_DO_ORK = void 0;
58
+ exports.pertenceAoUniverso = pertenceAoUniverso;
58
59
  exports.enderecoDeMemoria = enderecoDeMemoria;
59
60
  exports.lerEndereco = lerEndereco;
60
61
  exports.violacoesDeGovernanca = violacoesDeGovernanca;
@@ -82,6 +83,7 @@ const fs = __importStar(require("node:fs"));
82
83
  const node_child_process_1 = require("node:child_process");
83
84
  const node_crypto_1 = require("node:crypto");
84
85
  const node_util_1 = require("node:util");
86
+ const node_perf_hooks_1 = require("node:perf_hooks");
85
87
  /** As colecoes do OrkMind que o `ork` grava (guia: docs/guias/memoria-e-handoff.md). */
86
88
  exports.COLECOES_DO_ORK = [
87
89
  'decision',
@@ -90,6 +92,31 @@ exports.COLECOES_DO_ORK = [
90
92
  'learning',
91
93
  'roadmap',
92
94
  ];
95
+ /** Cinco leituras governadas e a contagem, num unico subprocesso. */
96
+ exports.TIMEOUT_DO_UNIVERSO_MS = 90_000;
97
+ exports.LIMITE_TIMEOUT_DO_UNIVERSO_MS = 86_400_000;
98
+ /** Configuracao direta tambem tem prazo finito: zero no spawnSync significaria sem limite. */
99
+ function prazoDoUniversoMs(prazo) {
100
+ return typeof prazo === 'number' && Number.isSafeInteger(prazo) && prazo > 0 && prazo <= exports.LIMITE_TIMEOUT_DO_UNIVERSO_MS
101
+ ? prazo : exports.TIMEOUT_DO_UNIVERSO_MS;
102
+ }
103
+ /**
104
+ * RM-038: a fronteira do universo da busca vista do `ork`: colecao do ork e o tenant como item
105
+ * de `project`, sem injection_risk e ainda ativa. Reconferida antes de qualquer embed,
106
+ * mesmo quando a ponte ou outro driver devolve uma entrada que a biblioteca deveria recusar.
107
+ */
108
+ function pertenceAoUniverso(e, tenant, agora = Date.now()) {
109
+ // A biblioteca trata datas sem fuso como UTC. Data invalida nunca vira entrada ativa.
110
+ const expira = e.expires_at == null ? null : Date.parse(/(?:Z|[+-]\d{2}:?\d{2})$/i.test(e.expires_at) ? e.expires_at : `${e.expires_at}Z`);
111
+ return exports.COLECOES_DO_ORK.includes(e.collection) && Array.isArray(e.tags.project) &&
112
+ e.tags.project.includes(tenant) && e.injection_risk !== true && (expira === null || expira > agora);
113
+ }
114
+ /** RM-038: contagem de fora da busca bem formada (tres inteiros nao negativos, nada mais). */
115
+ function foraDaBuscaValida(x) {
116
+ const campos = ['injecao', 'expiradas', 'outrasColecoes'];
117
+ return !!x && typeof x === 'object' && !Array.isArray(x) && Object.keys(x).length === campos.length &&
118
+ campos.every(k => Number.isInteger(x[k]) && Number(x[k]) >= 0);
119
+ }
93
120
  /**
94
121
  * Colecoes de governanca dura do OrkMind: entrada aqui vira REGRA do ecossistema.
95
122
  * O agente pode gravar (o B6 grava as policies do manifesto), mas nunca como `mandatory`
@@ -313,6 +340,10 @@ function entradaDoJson(bruto) {
313
340
  const o = bruto;
314
341
  if (typeof o.id !== 'string' || typeof o.content !== 'string')
315
342
  return null;
343
+ if (o.injection_risk !== undefined && typeof o.injection_risk !== 'boolean')
344
+ return null;
345
+ if (o.expires_at !== undefined && o.expires_at !== null && typeof o.expires_at !== 'string')
346
+ return null;
316
347
  const tags = {};
317
348
  if (o.tags && typeof o.tags === 'object' && !Array.isArray(o.tags)) {
318
349
  for (const [k, v] of Object.entries(o.tags)) {
@@ -340,6 +371,8 @@ function entradaDoJson(bruto) {
340
371
  author_id: typeof o.author_id === 'string' ? o.author_id : null,
341
372
  visibility: typeof o.visibility === 'string' ? o.visibility : undefined,
342
373
  protected: typeof o.protected === 'boolean' ? o.protected : undefined,
374
+ injection_risk: o.injection_risk,
375
+ expires_at: o.expires_at,
343
376
  criadaEm: typeof o.created_at === 'string' ? o.created_at : '',
344
377
  };
345
378
  }
@@ -440,7 +473,7 @@ class DriverCliOrkMind {
440
473
  code = JSON.parse(r.stdout)?.error;
441
474
  }
442
475
  catch { /* nenhum detalhe do filho */ }
443
- throw new Error(['memory.schema.absent', 'memory.legacy.provenance-collision', 'memory.prospective.marker-invalid', 'memory.native.schema-mismatch', 'memory.query.invalid', 'memory.query.window-saturated', 'memory.query.scope-violation', 'memory.health.invalid', 'memory.fts.invalid', ...exports.CODIGOS_DE_EMBEDDING].includes(code) ? code : 'memory.transport.failed');
476
+ throw new Error(['memory.schema.absent', 'memory.legacy.provenance-collision', 'memory.prospective.marker-invalid', 'memory.native.schema-mismatch', 'memory.query.invalid', 'memory.query.window-saturated', 'memory.query.scope-violation', 'memory.health.invalid', 'memory.fts.invalid', 'memory.universo.invalid', ...exports.CODIGOS_DE_EMBEDDING].includes(code) ? code : 'memory.transport.failed');
444
477
  }
445
478
  let json;
446
479
  try {
@@ -555,6 +588,31 @@ class DriverCliOrkMind {
555
588
  }
556
589
  return r.ids;
557
590
  }
591
+ /**
592
+ * RM-038: o universo da busca numa chamada. A ponte filtra o tenant na origem e confere o
593
+ * predicado; o `ork` confere de novo cada entrada e recusa a alheia, nunca a descarta.
594
+ */
595
+ universo(tenant) {
596
+ if (!textoDeConsulta(tenant, 128) || tenant.trim() === '')
597
+ throw new Error('memory.universo.invalid');
598
+ const agora = Date.now();
599
+ const inicio = node_perf_hooks_1.performance.now();
600
+ const r = this.rodar({ op: 'universo', tenant }, prazoDoUniversoMs(this.config.universoTimeoutMs));
601
+ if (!objetoDeConsulta(r) || !Array.isArray(r.entradas) || !(r.foraDaBusca === null || foraDaBuscaValida(r.foraDaBusca))) {
602
+ throw new Error('memory.transport.universo');
603
+ }
604
+ const entradas = r.entradas.map(d => {
605
+ const e = entradaDoJson(d);
606
+ if (!e)
607
+ throw new Error('memory.transport.universo');
608
+ if (!pertenceAoUniverso(e, tenant, agora))
609
+ throw new Error('memory.query.scope-violation');
610
+ return e;
611
+ });
612
+ const fora = r.foraDaBusca;
613
+ return { entradas, foraDaBusca: fora === null ? null : { injecao: fora.injecao, expiradas: fora.expiradas, outrasColecoes: fora.outrasColecoes },
614
+ latenciaMs: node_perf_hooks_1.performance.now() - inicio };
615
+ }
558
616
  submeterHandoff(pedido) {
559
617
  try {
560
618
  const r = this.rodar({ op: 'handoff', pedido });
@@ -671,6 +729,8 @@ class DriverEmMemoria {
671
729
  embedding = { primario: true, fallback: true };
672
730
  /** Pedidos de embedding recebidos, para as assercoes de custo (chamadas ao provider). */
673
731
  pedidosDeEmbedding = [];
732
+ /** RM-038: o que a governanca da biblioteca tiraria da leitura (injection_risk, expirada), por id. */
733
+ foraDaBuscaMarcadas = new Map();
674
734
  constructor(entradas = []) {
675
735
  for (const e of entradas)
676
736
  this.entradas.push(e);
@@ -750,7 +810,31 @@ class DriverEmMemoria {
750
810
  exportar(colecao) {
751
811
  if (!this.ligado)
752
812
  throw new Error('memory.transport.unavailable');
753
- return this.entradas.filter((e) => e.collection === colecao);
813
+ // Como o search_by_tags governado: o que a governanca tira nao sai pela leitura por tag.
814
+ return this.entradas.filter((e) => e.collection === colecao && !this.foraDaBuscaMarcadas.has(e.id));
815
+ }
816
+ /** So para os testes: a entrada passa a contar como tirada pela governanca da biblioteca. */
817
+ marcarForaDaBusca(id, motivo) {
818
+ this.foraDaBuscaMarcadas.set(id, motivo);
819
+ }
820
+ /** RM-038: o mesmo predicado do universo para o dublê inteiro (universo e FTS). */
821
+ naBusca(e, tenant) {
822
+ return pertenceAoUniverso(e, tenant) && !this.foraDaBuscaMarcadas.has(e.id);
823
+ }
824
+ /** RM-038: dublê da operacao `universo` da ponte, com a contagem de fora da busca. */
825
+ universo(tenant) {
826
+ if (!textoDeConsulta(tenant, 128) || tenant.trim() === '')
827
+ throw new Error('memory.universo.invalid');
828
+ if (!this.ligado)
829
+ throw new Error('memory.transport.unavailable');
830
+ const foraDaBusca = { injecao: 0, expiradas: 0, outrasColecoes: 0 };
831
+ for (const e of this.entradas.filter(x => (x.tags.project ?? []).includes(tenant))) {
832
+ if (!exports.COLECOES_DO_ORK.includes(e.collection))
833
+ foraDaBusca.outrasColecoes += 1;
834
+ else if (this.foraDaBuscaMarcadas.has(e.id))
835
+ foraDaBusca[this.foraDaBuscaMarcadas.get(e.id)] += 1;
836
+ }
837
+ return { entradas: this.entradas.filter(e => this.naBusca(e, tenant)), foraDaBusca };
754
838
  }
755
839
  consultar(consulta) {
756
840
  const q = validarConsultaDelimitada(consulta);
@@ -802,7 +886,7 @@ class DriverEmMemoria {
802
886
  this.pedidosDeEmbedding.push(p);
803
887
  return { alvo: p.alvo, modelo: p.modelo, dim: p.dim, vetores: p.textos.map(t => vetorDeDuble(t, p.dim)) };
804
888
  }
805
- /** Dublê de FTS: todas as palavras da consulta no conteudo, sem stemming, com tenant obrigatorio. */
889
+ /** Dublê de FTS: todas as palavras da consulta no conteudo, sem stemming, dentro do universo da busca. */
806
890
  buscarTexto(tenant, texto) {
807
891
  if (!textoDeConsulta(tenant, 128) || !textoDeBuscaValido(texto))
808
892
  throw new Error('memory.fts.invalid');
@@ -811,7 +895,7 @@ class DriverEmMemoria {
811
895
  const palavras = (t) => t.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase().match(/[a-z0-9]+/g) ?? [];
812
896
  const consulta = palavras(texto);
813
897
  return this.entradas
814
- .filter(e => exports.COLECOES_DO_ORK.includes(e.collection) && (e.tags.project ?? []).includes(tenant))
898
+ .filter(e => this.naBusca(e, tenant))
815
899
  .map(e => ({ id: e.id, conteudo: palavras(e.content) }))
816
900
  .filter(e => consulta.every(p => e.conteudo.includes(p)))
817
901
  .map(e => ({ id: e.id, peso: e.conteudo.filter(p => consulta.includes(p)).length }))
@@ -838,6 +922,7 @@ function configDoManifesto(manifesto) {
838
922
  variavel,
839
923
  dsn: variavel ? (process.env[variavel] ?? '') : '',
840
924
  timeoutMs: manifesto.memory.timeout_ms || 15000,
925
+ universoTimeoutMs: prazoDoUniversoMs(manifesto.memory.universo_timeout_ms),
841
926
  tenant: manifesto.memory.tenant || manifesto.project.name,
842
927
  // Lido direto do bloco: este modulo carrega sem o parser do manifesto (memory-native-schema).
843
928
  variavelDaChaveDeEmbedding: manifesto.memory.embedding?.provider === 'openrouter' ? manifesto.memory.embedding.api_key_env : '',
@@ -69,10 +69,11 @@ const adapter = __importStar(require("./adapters/claude-bg"));
69
69
  const board_1 = require("./board");
70
70
  const gates_1 = require("./gates");
71
71
  const ledger_1 = require("./ledger");
72
+ const leases_1 = require("./leases");
72
73
  const modos_1 = require("./modos");
73
74
  const ocupacao_1 = require("./ocupacao");
74
75
  const ratelimit_1 = require("./ratelimit");
75
- const hitl_1 = require("./hitl");
76
+ const impedimento_1 = require("./impedimento");
76
77
  const thread_1 = require("./thread");
77
78
  const util_1 = require("./util");
78
79
  const horario_1 = require("./horario");
@@ -188,7 +189,8 @@ function pausasAbertas(thread, eventos, estados, quando) {
188
189
  // ESCALADA do bloco B3 (limite de tentativas estourado), que pausa qualquer modo,
189
190
  // inclusive `#Auto` -- que por definicao nao tem pausa prevista no ledger.
190
191
  eventos.forEach((e, i) => {
191
- if (e.tipo !== ledger_1.TIPOS_DE_EVENTO.gateBloqueado || e.motivo !== 'human.pending')
192
+ // RM-055: o impedimento do despacho que so o dono resolve tambem e espera dele.
193
+ if (!(0, impedimento_1.ehEsperaDoDono)(e, ledger_1.TIPOS_DE_EVENTO.gateBloqueado))
192
194
  return;
193
195
  const resolvido = eventos
194
196
  .slice(i + 1)
@@ -200,12 +202,14 @@ function pausasAbertas(thread, eventos, estados, quando) {
200
202
  if (porFase.has(chave))
201
203
  return;
202
204
  const { bloco, pausaSobre } = blocoDaFase(thread, fase);
205
+ const imp = (0, impedimento_1.ehImpedimentoDoDono)(e.motivo) ? (0, impedimento_1.impedimentoDoEvento)(e) : null;
203
206
  porFase.set(chave, parada({
204
207
  natureza: 'pausa-humana',
205
- motivo: 'human.pending',
208
+ motivo: imp ? e.motivo : 'human.pending',
206
209
  fase,
207
210
  bloco,
208
- pausaSobre: pausaSobre || 'autorizacao da retomada',
211
+ pausaSobre: imp ? `rodar \`${imp.comando}\` no terminal` : pausaSobre || 'autorizacao da retomada',
212
+ ...(imp ? { impedimento: imp } : {}),
209
213
  detalhe: typeof e.detalhe === 'string' && e.detalhe !== ''
210
214
  ? e.detalhe
211
215
  : gates_1.DESCRICAO_DO_MOTIVO['human.pending'],
@@ -256,7 +260,7 @@ function impedimentosAbertos(item, eventos, raizDoProjeto, quando) {
256
260
  pausaSobre: '',
257
261
  detalhe: `na fila de ${p.nome}, atras da thread ${p.bloqueadaPor} (colide com ${p.colidiuCom})`,
258
262
  evidencia: `.orkastery/leases/fila.json (${p.tipo})`,
259
- correcao: `espere a thread ${p.bloqueadaPor} liberar (ork lease release ${p.colidiuCom} --thread ${p.bloqueadaPor}), ou reduza a regiao pedida`,
263
+ correcao: `espere a thread ${p.bloqueadaPor} liberar (ork lease release ${(0, leases_1.argumentoDeLease)(p.colidiuCom)} --thread ${(0, leases_1.argumentoDeLease)(p.bloqueadaPor)}), ou reduza a regiao pedida`,
260
264
  desdeEm: p.desdeEm,
261
265
  sessaoViva: null,
262
266
  fonte: 'fila-de-lease',
@@ -288,7 +292,7 @@ function impedimentosAbertos(item, eventos, raizDoProjeto, quando) {
288
292
  if (e.tipo !== ledger_1.TIPOS_DE_EVENTO.gateBloqueado && e.tipo !== 'phase_wait')
289
293
  return;
290
294
  const motivo = e.motivo;
291
- if (motivo === 'human.pending' || motivo === 'claims.unverifiable')
295
+ if (motivo === 'human.pending' || motivo === 'claims.unverifiable' || (0, impedimento_1.ehImpedimentoDoDono)(motivo))
292
296
  return;
293
297
  if (!(motivo in gates_1.DESCRICAO_DO_MOTIVO))
294
298
  return;
@@ -372,10 +376,8 @@ function montarMonitor(carregado, opcoes = {}) {
372
376
  }
373
377
  else if (opcoes.semRuntime !== true) {
374
378
  if (adapter.disponivel()) {
375
- estados = new Map(adapter
376
- .listarSessoes()
377
- .filter((s) => !!s.sessionId)
378
- .map((s) => [s.sessionId, (0, hitl_1.estadoBruto)(s)]));
379
+ // RM-056 (D7): todas as contas, a mesma consulta do escalonador.
380
+ estados = (0, board_1.estadosDeSessao)(carregado.raiz, carregado.manifesto.concurrency.stale_after_min);
379
381
  runtimeDetalhe = '';
380
382
  }
381
383
  else {