@orkastery/cli 0.6.0 → 0.6.1

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 (65) hide show
  1. package/adapters/openclaw/openclaw.plugin.json +1 -1
  2. package/adapters/openclaw/package.json +1 -1
  3. package/dist/adapters/claude-bg.js +6 -6
  4. package/dist/adapters/grok-events.js +227 -0
  5. package/dist/adapters/grok-mcp-servidor.js +612 -0
  6. package/dist/adapters/grok-mcp.js +178 -0
  7. package/dist/adapters/grok.js +686 -0
  8. package/dist/agendador-cpu.js +92 -0
  9. package/dist/branch-de-estado.js +7 -2
  10. package/dist/check-agil.js +48 -20
  11. package/dist/check-paralelo.js +73 -18
  12. package/dist/conducao.js +5 -0
  13. package/dist/docs.js +9 -16
  14. package/dist/doctor-forja.js +1 -3
  15. package/dist/doctor.js +1 -1
  16. package/dist/entrega-pr.js +10 -10
  17. package/dist/fabrica-estado.js +20 -11
  18. package/dist/horario.js +4 -1
  19. package/dist/index.js +20 -10
  20. package/dist/integracoes-locais.js +2 -0
  21. package/dist/locale-accounts.js +11 -3
  22. package/dist/locale-ajuda.js +10 -6
  23. package/dist/locale-forja.js +2 -4
  24. package/dist/locale-operacao-restante.js +2 -2
  25. package/dist/locale-retry.js +40 -2
  26. package/dist/locale-ship.js +10 -2
  27. package/dist/manifest.js +6 -1
  28. package/dist/mcp-install.js +22 -12
  29. package/dist/mcp-server.js +42 -16
  30. package/dist/merge-da-entrega.js +85 -0
  31. package/dist/network-roadmap.js +18 -14
  32. package/dist/noctum-aceite.js +154 -14
  33. package/dist/noctum-cli.js +69 -12
  34. package/dist/noctum-entrega.js +55 -7
  35. package/dist/noctum-envelope.js +1 -1
  36. package/dist/noctum-execucao.js +5 -1
  37. package/dist/noctum-fechamento.js +18 -7
  38. package/dist/noctum-fila.js +6 -1
  39. package/dist/noctum-guarda.js +81 -4
  40. package/dist/noctum-maquinas.js +5 -1
  41. package/dist/noctum-modo.js +35 -7
  42. package/dist/noctum-reconciliacao.js +4 -1
  43. package/dist/noctum-rede.js +102 -0
  44. package/dist/noctum-relatorio.js +44 -10
  45. package/dist/noctum-retomada-rede.js +71 -0
  46. package/dist/noctum-vigia.js +49 -9
  47. package/dist/parado-no-condutor.js +14 -15
  48. package/dist/phase.js +43 -15
  49. package/dist/postura-local.js +7 -3
  50. package/dist/preflight.js +2 -1
  51. package/dist/ratelimit.js +1 -0
  52. package/dist/retry.js +103 -10
  53. package/dist/runtime-context.js +165 -45
  54. package/dist/runtime-escada.js +7 -1
  55. package/dist/runtime-profiles.js +27 -17
  56. package/dist/runtimes.js +42 -5
  57. package/dist/security-scan/agil.js +18 -7
  58. package/dist/security-scan/executor.js +8 -0
  59. package/dist/session-watcher-grok.js +425 -0
  60. package/dist/session-watcher.js +19 -4
  61. package/dist/sessoes-contas.js +33 -5
  62. package/dist/setup.js +11 -11
  63. package/dist/varredura-acoes.js +8 -15
  64. package/dist/verify.js +26 -10
  65. package/package.json +2 -2
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.COLUNAS_DE_PERFIS = exports.POLITICA_PADRAO = exports.ARQUIVO_CONTAS = exports.CONTRATO_CONTAS = exports.ESTADOS_DE_PERFIL = exports.RUNTIMES_COM_PERFIL = exports.VARIAVEL_DO_PERFIL = exports.ARQUIVO_PERFIS = exports.CONTRATO_PERFIS = void 0;
36
+ exports.COLUNAS_DE_PERFIS = exports.POLITICA_PADRAO = exports.ARQUIVO_CONTAS = exports.CONTRATO_CONTAS = exports.ESTADOS_DE_PERFIL = exports.RUNTIMES_COM_INVENTARIO = exports.CAMPO_DO_PERFIL = exports.RUNTIMES_COM_PERFIL = exports.VARIAVEL_DO_PERFIL = exports.ARQUIVO_PERFIS = exports.CONTRATO_PERFIS = void 0;
37
37
  exports.runtimeComPerfil = runtimeComPerfil;
38
38
  exports.validarDiretorioDePerfil = validarDiretorioDePerfil;
39
39
  exports.validarIdDePerfil = validarIdDePerfil;
@@ -81,7 +81,7 @@ exports.perfisComHorario = perfisComHorario;
81
81
  * I-33 (D3): perfis de conta por runtime, contrato `ork.runtime-profiles/v1`.
82
82
  *
83
83
  * Um perfil aponta o DIRETORIO onde o proprio CLI do runtime guarda configuracao e login
84
- * (`CLAUDE_CONFIG_DIR` no claude-bg, `CODEX_HOME` no codex). O `ork` nunca le, copia nem
84
+ * (`CLAUDE_CONFIG_DIR` no claude-bg, `CODEX_HOME` no codex, `GROK_HOME` no grok). O `ork` nunca le, copia nem
85
85
  * migra o que o CLI grava la dentro: o login e feito pelo proprio CLI com o env do perfil, e
86
86
  * o store guarda so identidade, diretorio e estado de uso. Nenhum segredo entra aqui.
87
87
  *
@@ -101,8 +101,19 @@ const locale_1 = require("./locale");
101
101
  exports.CONTRATO_PERFIS = 'ork.runtime-profiles/v1';
102
102
  exports.ARQUIVO_PERFIS = 'runtime-profiles.json';
103
103
  /** Runtimes homologados que aceitam perfil, e a variavel que cada um le. */
104
- exports.VARIAVEL_DO_PERFIL = { 'claude-bg': 'CLAUDE_CONFIG_DIR', codex: 'CODEX_HOME' };
104
+ exports.VARIAVEL_DO_PERFIL = { 'claude-bg': 'CLAUDE_CONFIG_DIR', codex: 'CODEX_HOME', grok: 'GROK_HOME' };
105
105
  exports.RUNTIMES_COM_PERFIL = Object.keys(exports.VARIAVEL_DO_PERFIL);
106
+ /** O campo do perfil que guarda o diretorio de cada runtime (o store e o despacho usam o mesmo nome). */
107
+ exports.CAMPO_DO_PERFIL = { 'claude-bg': 'configDir', codex: 'codexHome', grok: 'grokHome' };
108
+ const CAMPOS_DE_DIRETORIO = Object.values(exports.CAMPO_DO_PERFIL);
109
+ /** O diretorio padrao de cada CLI na HOME, quando o processo nao informa a variavel. */
110
+ const PASTA_PADRAO = { 'claude-bg': '.claude', codex: '.codex', grok: '.grok' };
111
+ /**
112
+ * RM-067 (F3, F4): runtimes de assinatura que o #Noctum mede e cuja conta do processo o inventario sempre consulta
113
+ * (`claude agents`, rollouts do codex). Desde a F4, o `ork sessions` e a carga do rodizio leem tambem o `grok`, pela
114
+ * pasta de sessoes que ele grava (`RUNTIMES_DAS_SESSOES` em `sessoes-contas.ts`); a medicao do #Noctum segue sem ele.
115
+ */
116
+ exports.RUNTIMES_COM_INVENTARIO = ['claude-bg', 'codex'];
106
117
  /**
107
118
  * I-33 (D13): `provider-pago` e o perfil cujo proprio CLI diz que o login e por API key,
108
119
  * `api_key_helper`, Console ou provider de nuvem, e nao pela assinatura. Nunca recebe despacho;
@@ -135,8 +146,11 @@ function validarIdDePerfil(id) {
135
146
  }
136
147
  /** Diretorio do perfil, pelo campo do seu runtime. */
137
148
  function diretorioDoPerfil(p) {
138
- const dir = p.runtime === 'claude-bg' ? p.configDir : p.codexHome;
139
- return validarDiretorioDePerfil(dir);
149
+ return validarDiretorioDePerfil(p[exports.CAMPO_DO_PERFIL[p.runtime]]);
150
+ }
151
+ /** O perfil de despacho com o diretorio no campo do seu runtime. */
152
+ function comDiretorio(id, runtime, dir) {
153
+ return { id, runtime, [exports.CAMPO_DO_PERFIL[runtime]]: dir };
140
154
  }
141
155
  /** Valida um perfil de despacho vindo do ledger, do thread.json ou do pedido da fila. */
142
156
  function validarPerfilDeDespacho(v) {
@@ -146,16 +160,13 @@ function validarPerfilDeDespacho(v) {
146
160
  const runtime = o.runtime;
147
161
  if (typeof runtime !== 'string' || !runtimeComPerfil(runtime))
148
162
  throw new locale_1.ErroDoCatalogo((m) => m.accounts.runtimeDesconhecido);
149
- const campo = runtime === 'claude-bg' ? 'configDir' : 'codexHome';
150
- const outro = runtime === 'claude-bg' ? 'codexHome' : 'configDir';
151
- if (o[outro] !== undefined || Object.keys(o).some(k => !['id', 'runtime', campo].includes(k)))
163
+ const campo = exports.CAMPO_DO_PERFIL[runtime];
164
+ if (Object.keys(o).some(k => !['id', 'runtime', campo].includes(k)))
152
165
  throw new locale_1.ErroDoCatalogo((m) => m.accounts.despachoComCampo);
153
- const id = validarIdDePerfil(o.id), dir = validarDiretorioDePerfil(o[campo]);
154
- return runtime === 'claude-bg' ? { id, runtime, configDir: dir } : { id, runtime, codexHome: dir };
166
+ return comDiretorio(validarIdDePerfil(o.id), runtime, validarDiretorioDePerfil(o[campo]));
155
167
  }
156
168
  function perfilDeDespacho(p) {
157
- return p.runtime === 'claude-bg' ? { id: p.id, runtime: p.runtime, configDir: diretorioDoPerfil(p) }
158
- : { id: p.id, runtime: p.runtime, codexHome: diretorioDoPerfil(p) };
169
+ return comDiretorio(p.id, p.runtime, diretorioDoPerfil(p));
159
170
  }
160
171
  /**
161
172
  * Diretorio implicito de quem despacha sem perfil: o do ambiente informado, ou o padrao do
@@ -163,7 +174,7 @@ function perfilDeDespacho(p) {
163
174
  */
164
175
  function diretorioImplicito(runtime, env = process.env) {
165
176
  const valor = (env[exports.VARIAVEL_DO_PERFIL[runtime]] ?? '').trim();
166
- return valor !== '' ? valor : path.join(os.homedir(), runtime === 'claude-bg' ? '.claude' : '.codex');
177
+ return valor !== '' ? valor : path.join(os.homedir(), PASTA_PADRAO[runtime]);
167
178
  }
168
179
  /** Diretorio efetivo: o do perfil registrado, ou o implicito quando a sessao nao tem perfil. */
169
180
  function diretorioEfetivo(runtime, perfil, env = process.env) {
@@ -247,8 +258,8 @@ function validarPerfil(v) {
247
258
  throw new locale_1.ErroDoCatalogo((m) => m.accounts.perfilInvalido);
248
259
  const o = v;
249
260
  const despacho = validarPerfilDeDespacho({ id: o.id, runtime: o.runtime,
250
- ...(o.configDir !== undefined ? { configDir: o.configDir } : {}), ...(o.codexHome !== undefined ? { codexHome: o.codexHome } : {}) });
251
- const permitidos = ['id', 'runtime', 'configDir', 'codexHome', 'estado', 'esgotadoAte', 'ultimaFalha', 'ultimoUso', 'criadoEm'];
261
+ ...Object.fromEntries(CAMPOS_DE_DIRETORIO.filter(c => o[c] !== undefined).map(c => [c, o[c]])) });
262
+ const permitidos = ['id', 'runtime', ...CAMPOS_DE_DIRETORIO, 'estado', 'esgotadoAte', 'ultimaFalha', 'ultimoUso', 'criadoEm'];
252
263
  if (Object.keys(o).some(k => !permitidos.includes(k)))
253
264
  throw new locale_1.ErroDoCatalogo((m) => m.accounts.campoInesperado);
254
265
  if (!exports.ESTADOS_DE_PERFIL.includes(o.estado))
@@ -539,8 +550,7 @@ function adicionarPerfil(raiz, novo, agoraIso = new Date().toISOString()) {
539
550
  throw new locale_1.ErroDoCatalogo((m) => m.accounts.runtimeSemPerfil(novo.runtime));
540
551
  const runtime = novo.runtime;
541
552
  const dir = validarDiretorioDePerfil(novo.dir);
542
- const perfil = { id: validarIdDePerfil(novo.id), runtime,
543
- ...(runtime === 'claude-bg' ? { configDir: dir } : { codexHome: dir }),
553
+ const perfil = { ...comDiretorio(validarIdDePerfil(novo.id), runtime, dir),
544
554
  estado: 'ativo', esgotadoAte: null, ultimaFalha: null, ultimoUso: null, criadoEm: agoraIso };
545
555
  return atualizarPerfis(raiz, store => {
546
556
  const existente = store.perfis.find(p => p.id === perfil.id);
package/dist/runtimes.js CHANGED
@@ -10,6 +10,10 @@
10
10
  * `claude agents --json` (homologado em 02/09/2026).
11
11
  * codex o segundo runtime: `codex exec` headless desanexado, sessao verificada no
12
12
  * rollout que o proprio Codex grava (homologado em 06/09/2026).
13
+ * grok RM-067 (F1 e F2): o Grok Build headless, `grok -p` com `streaming-json`, sessao
14
+ * verificada na pasta que o proprio runtime grava. Desde a F4, runtime de bloco e de
15
+ * fallback no `ork setup`, sempre com o modelo dado pelo dono; nunca o padrao do projeto
16
+ * (`runtime.adapter`), que segue com o claude-bg e o codex.
13
17
  *
14
18
  * Paridade sem downgrade: o contrato do claude-bg nao muda com a chegada do codex, e todo
15
19
  * runtime novo entra por aqui com o MESMO contrato de despacho (dry-run, rate limit
@@ -49,11 +53,14 @@ var __importStar = (this && this.__importStar) || (function () {
49
53
  };
50
54
  })();
51
55
  Object.defineProperty(exports, "__esModule", { value: true });
52
- exports.ORDEM_DOS_RUNTIMES = exports.RUNTIMES = exports.RUNTIME_PADRAO = void 0;
56
+ exports.RUNTIMES_SEM_COTA_TIPADA = exports.RUNTIMES_DE_BLOCO = exports.ORDEM_DOS_RUNTIMES = exports.RUNTIMES = exports.RUNTIME_PADRAO = void 0;
53
57
  exports.runtimeConhecido = runtimeConhecido;
58
+ exports.runtimeDeBloco = runtimeDeBloco;
59
+ exports.runtimeDoManifesto = runtimeDoManifesto;
54
60
  exports.resolverRuntime = resolverRuntime;
55
61
  const claudeBg = __importStar(require("./adapters/claude-bg"));
56
62
  const codex = __importStar(require("./adapters/codex"));
63
+ const grok = __importStar(require("./adapters/grok"));
57
64
  const hitl_ingress_receipt_1 = require("./hitl-ingress-receipt");
58
65
  const locale_1 = require("./locale");
59
66
  exports.RUNTIME_PADRAO = 'claude-bg';
@@ -87,18 +94,48 @@ exports.RUNTIMES = {
87
94
  montarComando: (p) => codex.montarComando(p),
88
95
  despachar: (p) => comRecibosPublicos(p, codex.despachar),
89
96
  },
97
+ grok: {
98
+ nome: grok.NOME_ADAPTER,
99
+ fonteVerificacao: grok.FONTE_VERIFICACAO,
100
+ disponivel: () => grok.disponivel(),
101
+ versao: grok.versao,
102
+ montarComando: (p) => grok.montarComando(p),
103
+ despachar: (p) => comRecibosPublicos(p, grok.despachar),
104
+ },
90
105
  };
91
- /** Os runtimes na ordem de maturidade (o padrao primeiro). */
106
+ /**
107
+ * Os runtimes que podem ser o padrao do projeto (`runtime.adapter` do manifesto), na ordem de maturidade (o padrao
108
+ * primeiro). RM-067 (F4): o grok fica fora, porque fazer dele o runtime padrao esta fora do escopo da RM-067 e ele nao tem
109
+ * modelo padrao.
110
+ */
92
111
  exports.ORDEM_DOS_RUNTIMES = ['claude-bg', 'codex'];
93
- /** O nome e de um runtime homologado? */
112
+ /**
113
+ * Os runtimes que o setup aceita como runtime ou fallback de bloco. RM-067 (F4): os do padrao e o grok, este sempre com o
114
+ * modelo dado pelo dono (o setup exige `--model` ao trocar o runtime, e a entrada de fallback e `runtime:modelo[:esforco]`).
115
+ */
116
+ exports.RUNTIMES_DE_BLOCO = [...exports.ORDEM_DOS_RUNTIMES, 'grok'];
117
+ /**
118
+ * RM-067 (F3): runtimes cuja cota esgotada ainda nao vem tipada do proprio runtime. A escada automatica nunca troca a conta
119
+ * deles: sem o sinal tipado, nada prova que o perfil esgotou. O grok sai daqui quando a F5 ler o formato estruturado.
120
+ */
121
+ exports.RUNTIMES_SEM_COTA_TIPADA = ['grok'];
122
+ /** O nome e de um runtime homologado (resolve por nome no despacho)? */
94
123
  function runtimeConhecido(nome) {
95
124
  return Object.prototype.hasOwnProperty.call(exports.RUNTIMES, nome);
96
125
  }
126
+ /** O runtime pode ser runtime de bloco ou fallback no setup? */
127
+ function runtimeDeBloco(nome) {
128
+ return exports.RUNTIMES_DE_BLOCO.includes(nome);
129
+ }
130
+ /** O runtime pode ser o `runtime.adapter` do manifesto? */
131
+ function runtimeDoManifesto(nome) {
132
+ return exports.ORDEM_DOS_RUNTIMES.includes(nome);
133
+ }
97
134
  /** Resolve o adapter pelo nome, com erro tipado quando o runtime nao existe. */
98
135
  function resolverRuntime(nome) {
99
- const adapter = exports.RUNTIMES[nome];
136
+ const adapter = runtimeConhecido(nome) ? exports.RUNTIMES[nome] : undefined;
100
137
  if (!adapter) {
101
- throw new locale_1.ErroDoCatalogo((m) => m.phase.runtimeDesconhecido(nome, exports.ORDEM_DOS_RUNTIMES.join(', ')));
138
+ throw new locale_1.ErroDoCatalogo((m) => m.phase.runtimeDesconhecido(nome, exports.RUNTIMES_DE_BLOCO.join(', ')));
102
139
  }
103
140
  return adapter;
104
141
  }
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.PRAZO_MINIMO_DO_CLASSIC_MS = exports.PRAZO_DO_BUILD_DA_IMAGEM_MS = exports.PRAZO_POR_REGRA_DO_SEMGREP_S = exports.SEMGREP_SEM_CACHE = void 0;
37
37
  exports.especificacaoDoAgile = especificacaoDoAgile;
38
+ exports.prazoDoBuildDaImagem = prazoDoBuildDaImagem;
38
39
  exports.estourouNoAgile = estourouNoAgile;
39
40
  exports.motivoSemCredencial = motivoSemCredencial;
40
41
  exports.resultadoDoTrabalhador = resultadoDoTrabalhador;
@@ -69,7 +70,6 @@ const tools_1 = require("./tools");
69
70
  const TRABALHADOR = path.join(__dirname, 'trabalhador.js');
70
71
  /** Sem prazo da rodada, o trabalhador ganha o maior prazo do catalogo para a HEAD e para a base, com folga. */
71
72
  const FOLGA_MS = 60_000;
72
- const aspas = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
73
73
  /**
74
74
  * O Semgrep baixa as regras do registro (`p/typescript`, ...) a cada rodada, e nao tem cache delas. Regra lida de arquivo
75
75
  * local ganha outro `check_id` (o prefixo do caminho), o que muda a impressao digital de todo achado: o cache de regras
@@ -131,18 +131,24 @@ function eslintDoAgile(t, prazoMs, pecas) {
131
131
  if (t.name !== 'eslint' || !t.install?.length)
132
132
  return t;
133
133
  // A4 do CHECK: o build roda antes dos trabalhadores; com teto curto, um link lento nao consome o prazo da varredura toda.
134
- const imagem = (0, imagem_de_lint_1.garantirImagemDeLint)(t, Math.min(prazoMs, exports.PRAZO_DO_BUILD_DA_IMAGEM_MS));
134
+ const imagem = (0, imagem_de_lint_1.garantirImagemDeLint)(t, prazoDoBuildDaImagem(prazoMs));
135
135
  const comImagem = 'tag' in imagem ? (0, imagem_de_lint_1.eslintComImagem)(t, imagem.tag) : null;
136
136
  if (comImagem) {
137
137
  pecas.push({ peca: 'imagem-de-lint', estado: 'agile' });
138
138
  return comImagem;
139
139
  }
140
- pecas.push({ peca: 'imagem-de-lint', estado: 'fallback', motivo: 'motivo' in imagem ? imagem.motivo : 'script do catalogo sem o npm install esperado',
140
+ // RM-074 (F4): a ultima linha do `docker build` vem do registro do npm e pode trazer login na URL; vai ao ledger redigida.
141
+ pecas.push({ peca: 'imagem-de-lint', estado: 'fallback',
142
+ motivo: 'motivo' in imagem ? motivoSemCredencial(imagem.motivo, 200) : 'script do catalogo sem o npm install esperado',
141
143
  fallback: 'eslint do catalogo, com npm install no container' });
142
144
  return t;
143
145
  }
144
146
  /** O teto do build da imagem de lint (A4 do CHECK): estourou, o `eslint` do catalogo, com a peca em fallback. */
145
147
  exports.PRAZO_DO_BUILD_DA_IMAGEM_MS = 180_000;
148
+ /** O prazo do build da imagem de lint: o que resta da ferramenta, nunca acima do teto (RM-074 F4: o caso do teto). */
149
+ function prazoDoBuildDaImagem(restanteMs) {
150
+ return Math.min(restanteMs, exports.PRAZO_DO_BUILD_DA_IMAGEM_MS);
151
+ }
146
152
  /** O prazo minimo que sobra para a ferramenta que caiu no Agile rodar pelo caminho do Classic (A5 do CHECK). */
147
153
  exports.PRAZO_MINIMO_DO_CLASSIC_MS = 30_000;
148
154
  /** Os motivos tipados de estouro que o `scanTool` grava: o prazo da HEAD e o da base. */
@@ -228,8 +234,11 @@ function catalogoDoAgile(catalogo, agile, pecas) {
228
234
  pecas.push({ peca: 'oxlint', estado: 'agile', motivo: 'primeiro passe antes do eslint, sem tirar regra dele (check.agile.oxlint)' });
229
235
  return lista;
230
236
  }
231
- /** A rodada do Agile: as mesmas regras do `runScan`, com as ferramentas em paralelo e os caches de banco. */
232
- function runScanAgil(opts) {
237
+ /**
238
+ * A rodada do Agile: as mesmas regras do `runScan`, com as ferramentas em paralelo e os caches de banco. `rodar` e o
239
+ * grupo paralelo; os testes o trocam para ler o prazo e o argv de cada trabalhador (RM-074 F4).
240
+ */
241
+ function runScanAgil(opts, rodar = check_paralelo_1.rodarEmParalelo) {
233
242
  const start = path.resolve(opts.root);
234
243
  const root = (0, run_1.git)(start, ['rev-parse', '--show-toplevel']) ?? start;
235
244
  const generatedAt = (opts.now ?? (() => new Date()))().toISOString();
@@ -306,7 +315,9 @@ function runScanAgil(opts) {
306
315
  ctx: { headTree, mainRoot, base, head, rangeCommits: count === null ? null : Number(count), deadline, ...(baseTree ? { baseTree } : {}) } };
307
316
  const arquivo = path.join(dir, `${i}.json`);
308
317
  fs.writeFileSync(arquivo, JSON.stringify(trabalho), { mode: 0o600 });
309
- return { nome: t.name, comando: `${aspas(process.execPath)} ${aspas(TRABALHADOR)} ${aspas(arquivo)}`, cwd: root };
318
+ // RM-074 (F4): o trabalhador roda pelo argv, sem string de shell; o `comando` so identifica o item.
319
+ const argv = [process.execPath, TRABALHADOR, arquivo];
320
+ return { nome: t.name, comando: argv.join(' '), argv, cwd: root };
310
321
  });
311
322
  // S-f do CHECK 2: o teto dos trabalhadores e contado depois de todos montados, com o build da imagem de lint ja feito.
312
323
  const prazo = deadline === null ? Math.max(...tools.map(t => t.timeoutMs)) * 2 + FOLGA_MS : Math.max(1000, deadline - Date.now() + FOLGA_MS);
@@ -316,7 +327,7 @@ function runScanAgil(opts) {
316
327
  const maxParalelo = Number.isInteger(teto) && teto > 0 ? teto : undefined;
317
328
  if (maxParalelo)
318
329
  pecas[0] = { ...pecas[0], motivo: `ate ${maxParalelo} ferramenta(s) ao mesmo tempo, ao lado das lanes do verify` };
319
- const processos = (0, check_paralelo_1.rodarEmParalelo)(trabalhos, process.env, maxParalelo ? { maxParalelo } : {});
330
+ const processos = rodar(trabalhos, process.env, maxParalelo ? { maxParalelo } : {});
320
331
  const excluded = new Set();
321
332
  tools.forEach((t, i) => {
322
333
  const trabalhador = resultadoDoTrabalhador(t, processos[i], trabalhos[i].prazoMs);
@@ -38,6 +38,7 @@ exports.defaultProbe = defaultProbe;
38
38
  exports.chooseExecutor = chooseExecutor;
39
39
  exports.nativeVersionOf = nativeVersionOf;
40
40
  exports.defaultsDir = defaultsDir;
41
+ exports.argumentosDeCpuDoDocker = argumentosDeCpuDoDocker;
41
42
  exports.expand = expand;
42
43
  exports.ensureImage = ensureImage;
43
44
  exports.runDocker = runDocker;
@@ -52,6 +53,7 @@ const crypto = __importStar(require("node:crypto"));
52
53
  const fs = __importStar(require("node:fs"));
53
54
  const path = __importStar(require("node:path"));
54
55
  const guard_1 = require("./guard");
56
+ const agendador_cpu_1 = require("../agendador-cpu");
55
57
  const PROBE_TIMEOUT_MS = 20000;
56
58
  /** The probe of this machine, through the PATH. Each answer is computed once per probe. */
57
59
  function defaultProbe() {
@@ -107,6 +109,11 @@ function defaultsDir() {
107
109
  exports.CONFIG_FILES = { gitleaks: 'gitleaks.toml', eslint: 'eslint.config.mjs', ruff: 'ruff.toml', 'golangci-lint': '.golangci.yml' };
108
110
  const CONTAINER = { src: '/src', out: '/out', config: '/config' };
109
111
  const MAX_BUFFER = 512 * 1024 * 1024;
112
+ /** A cota so existe no grupo Agile; sem a variavel, o Classic continua com o argv de sempre. */
113
+ function argumentosDeCpuDoDocker(ambiente = process.env) {
114
+ const limite = Number(ambiente[agendador_cpu_1.ENV_CPUS_DOCKER]);
115
+ return Number.isFinite(limite) && limite > 0 ? ['--cpus', String(limite)] : [];
116
+ }
110
117
  function expand(arg, values) {
111
118
  return arg.replace(/\{(src|out|base|config|install|stackDir)\}/g, (_, k) => values[k]);
112
119
  }
@@ -141,6 +148,7 @@ function runDocker(inv) {
141
148
  fs.chmodSync(inv.outHost, 0o777);
142
149
  const values = { src: CONTAINER.src, out: CONTAINER.out, base: inv.base, config: configCtr, install: (tool.install ?? []).join(' '), stackDir: stackDirArg(inv.stackDir) };
143
150
  const args = ['run', '--rm', '--name', name, '--pull', 'never', '--user', containerUser(),
151
+ ...argumentosDeCpuDoDocker(),
144
152
  '--cap-drop', 'ALL', '--security-opt', 'no-new-privileges',
145
153
  ...(tool.network === 'none' ? ['--network', 'none'] : []),
146
154
  '--tmpfs', '/tmp:exec,mode=1777',