@orkastery/cli 0.2.0 → 0.3.0

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 (242) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +86 -65
  3. package/adapters/README.md +30 -15
  4. package/adapters/claude-code/.claude-plugin/plugin.json +11 -5
  5. package/adapters/claude-code/README.md +110 -8
  6. package/adapters/claude-code/commands/onboarding.md +21 -0
  7. package/adapters/claude-code/commands/ork.md +99 -27
  8. package/adapters/claude-code/hooks/hooks.json +6 -1
  9. package/adapters/claude-code/hooks/ork-sensor.js +66 -0
  10. package/adapters/codex/skills/ork/SKILL.md +57 -0
  11. package/adapters/hermes/README.md +163 -0
  12. package/adapters/hermes/bin/ork-abrir-thread.sh +2 -0
  13. package/adapters/hermes/bin/ork-brain.sh +4 -0
  14. package/adapters/hermes/bin/ork-hitl-answer.py +82 -0
  15. package/adapters/hermes/bin/ork-maestro.sh +6 -0
  16. package/adapters/hermes/bin/ork-master-enviar.py +84 -0
  17. package/adapters/hermes/bin/ork-objective-message.sh +17 -0
  18. package/adapters/hermes/bin/ork-objective-status.sh +12 -0
  19. package/adapters/hermes/bin/ork-pulse-enviar.py +47 -0
  20. package/adapters/hermes/hermes.plugin.json +26 -4
  21. package/adapters/hermes/hitl-ingress/__init__.py +356 -0
  22. package/adapters/hermes/hitl-ingress/plugin.yaml +4 -0
  23. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +75 -22
  24. package/adapters/openclaw/README.md +135 -26
  25. package/adapters/openclaw/bin/ork-brain.sh +4 -0
  26. package/adapters/openclaw/construir.sh +19 -0
  27. package/adapters/openclaw/dist/hitl-ingress.js +199 -0
  28. package/adapters/openclaw/dist/index.js +437 -0
  29. package/adapters/openclaw/openclaw.plugin.json +39 -134
  30. package/adapters/openclaw/package.json +26 -0
  31. package/adapters/openclaw/src/hitl-ingress.ts +180 -0
  32. package/adapters/openclaw/src/index.ts +458 -0
  33. package/adapters/openclaw/src/tipos-openclaw.d.ts +58 -0
  34. package/adapters/openclaw/tsconfig.json +15 -0
  35. package/assets/docs/markdownlint-cli2.jsonc +22 -0
  36. package/assets/docs/padroes/documentacao-de-produto.md +133 -0
  37. package/assets/docs/padroes/roadmap-de-produto.md +98 -0
  38. package/assets/docs/produto/README.md +14 -0
  39. package/assets/docs/produto/_modelo-feature.md +59 -0
  40. package/assets/docs/roadmap/README.md +14 -0
  41. package/assets/docs/roadmap/_modelo-item.md +73 -0
  42. package/assets/orkmind-native-schema.json +32 -0
  43. package/assets/orkmind_bridge.py +357 -0
  44. package/assets/orkmind_fixture.py +67 -0
  45. package/assets/orkmind_prospective.py +138 -0
  46. package/assets/reference-tariffs-i07.json +23 -0
  47. package/dist/adapters/claude-bg.js +488 -39
  48. package/dist/adapters/codex-controller-sensor.js +449 -0
  49. package/dist/adapters/codex-controller-worker.js +361 -0
  50. package/dist/adapters/codex-controller.js +252 -0
  51. package/dist/adapters/codex-events.js +205 -0
  52. package/dist/adapters/codex-question.js +26 -0
  53. package/dist/adapters/codex-runner.js +133 -0
  54. package/dist/adapters/codex.js +394 -0
  55. package/dist/agents-md.js +84 -0
  56. package/dist/auditoria.js +11 -8
  57. package/dist/auditrun.js +5 -4
  58. package/dist/board.js +173 -22
  59. package/dist/branch-de-estado.js +136 -0
  60. package/dist/canarios-hitl.js +177 -0
  61. package/dist/canarios-i43.js +543 -0
  62. package/dist/canarios-pulse.js +147 -0
  63. package/dist/canarios-sensores.js +129 -0
  64. package/dist/canarios.js +111 -2
  65. package/dist/catalogo.js +9 -0
  66. package/dist/ci.js +216 -0
  67. package/dist/ciclos.js +2 -1
  68. package/dist/claim-lint.js +64 -0
  69. package/dist/claims.js +60 -0
  70. package/dist/company-brain-capture.js +195 -0
  71. package/dist/company-brain-cli.js +123 -0
  72. package/dist/company-brain-client.js +61 -0
  73. package/dist/company-brain-contract.js +166 -0
  74. package/dist/company-brain-journal.js +192 -0
  75. package/dist/company-brain-mcp.js +33 -0
  76. package/dist/company-brain-migration.js +60 -0
  77. package/dist/company-brain-source.js +177 -0
  78. package/dist/company-brain-worker.js +18 -0
  79. package/dist/conducao-texto.js +61 -0
  80. package/dist/conducao.js +876 -0
  81. package/dist/contrato-publico.js +39 -0
  82. package/dist/creation-operation-store.js +251 -0
  83. package/dist/creation-operation.js +148 -0
  84. package/dist/decisao-autonoma.js +183 -0
  85. package/dist/delegation.js +79 -0
  86. package/dist/demo.js +120 -0
  87. package/dist/docs.js +828 -0
  88. package/dist/doctor.js +183 -24
  89. package/dist/entrega-pr.js +117 -0
  90. package/dist/escopo-escrita.js +71 -0
  91. package/dist/estado-thread.js +222 -0
  92. package/dist/evalrunner.js +12 -0
  93. package/dist/fabrica-estado.js +329 -0
  94. package/dist/fabrica-publicar.js +76 -0
  95. package/dist/fix.js +21 -0
  96. package/dist/gates.js +55 -9
  97. package/dist/handoff.js +39 -23
  98. package/dist/hitl-canais.js +333 -0
  99. package/dist/hitl-classificacao.js +131 -0
  100. package/dist/hitl-contract.js +465 -0
  101. package/dist/hitl-estado.js +136 -0
  102. package/dist/hitl-gates.js +554 -0
  103. package/dist/hitl-ingress-receipt.js +382 -0
  104. package/dist/hitl-local-atestado.js +57 -0
  105. package/dist/hitl-local-receipt.js +328 -0
  106. package/dist/hitl-local.js +143 -0
  107. package/dist/hitl-lock.js +139 -0
  108. package/dist/hitl-lote.js +223 -0
  109. package/dist/hitl-native-offer.js +97 -0
  110. package/dist/hitl-native.js +65 -0
  111. package/dist/hitl-presentation.js +209 -0
  112. package/dist/hitl-public-receipt.js +176 -0
  113. package/dist/hitl-resumo.js +209 -0
  114. package/dist/hitl-sessions.js +475 -0
  115. package/dist/hitl.js +711 -0
  116. package/dist/horario.js +269 -0
  117. package/dist/hosts.js +198 -22
  118. package/dist/index.js +1736 -93
  119. package/dist/indice.js +99 -0
  120. package/dist/init.js +28 -3
  121. package/dist/integracoes-locais.js +17 -0
  122. package/dist/leases.js +65 -21
  123. package/dist/ledger-stats.js +272 -0
  124. package/dist/ledger.js +107 -2
  125. package/dist/licoes.js +215 -0
  126. package/dist/liveness.js +218 -0
  127. package/dist/maestro-actions.js +51 -0
  128. package/dist/maestro-authority.js +152 -0
  129. package/dist/maestro-cli.js +97 -0
  130. package/dist/maestro-contract.js +55 -0
  131. package/dist/maestro-discovery.js +132 -0
  132. package/dist/maestro-runtime.js +268 -0
  133. package/dist/maestro-snapshot.js +86 -0
  134. package/dist/maestro-sources.js +224 -0
  135. package/dist/manifest.js +165 -6
  136. package/dist/maquina.js +102 -0
  137. package/dist/master-audit.js +101 -0
  138. package/dist/master-batch.js +43 -0
  139. package/dist/master-digest.js +149 -0
  140. package/dist/master-migracao.js +155 -0
  141. package/dist/master.js +361 -77
  142. package/dist/mcp-artifacts.js +234 -0
  143. package/dist/mcp-git.js +433 -0
  144. package/dist/mcp-install.js +310 -0
  145. package/dist/mcp-maestro.js +25 -0
  146. package/dist/mcp-server.js +469 -0
  147. package/dist/mcp-ship.js +436 -0
  148. package/dist/mcp-verify.js +173 -0
  149. package/dist/memoria-humana.js +207 -0
  150. package/dist/memoria.js +314 -78
  151. package/dist/memory-migration.js +279 -0
  152. package/dist/memory-prospective.js +148 -0
  153. package/dist/modos-migracao.js +191 -0
  154. package/dist/modos.js +151 -15
  155. package/dist/monitor-lock.js +110 -0
  156. package/dist/objective.js +449 -0
  157. package/dist/ocupacao.js +267 -0
  158. package/dist/onboarding.js +303 -0
  159. package/dist/orkmind.js +389 -90
  160. package/dist/orquestracao.js +96 -69
  161. package/dist/phase.js +596 -150
  162. package/dist/playbook-capabilities.js +150 -0
  163. package/dist/playbook-contracts.js +188 -0
  164. package/dist/portfolio-context.js +61 -0
  165. package/dist/portfolio.js +180 -0
  166. package/dist/preflight.js +207 -0
  167. package/dist/process-audit.js +112 -0
  168. package/dist/project-state.js +93 -0
  169. package/dist/prompts.js +25 -5
  170. package/dist/prova-minima.js +112 -0
  171. package/dist/pulse-cadencia.js +163 -0
  172. package/dist/pulse-consentimento.js +260 -0
  173. package/dist/pulse-delivery.js +323 -0
  174. package/dist/pulse-resposta.js +542 -0
  175. package/dist/pulse.js +262 -0
  176. package/dist/ratelimit.js +35 -2
  177. package/dist/recall.js +80 -3
  178. package/dist/redacao-saida.js +45 -0
  179. package/dist/redacao-url.js +66 -0
  180. package/dist/retry.js +637 -115
  181. package/dist/roadmap-reservas.js +243 -0
  182. package/dist/runtime-ambiente.js +38 -0
  183. package/dist/runtime-context.js +215 -0
  184. package/dist/runtime-profiles.js +869 -0
  185. package/dist/runtimes.js +103 -0
  186. package/dist/sandbox.js +9 -0
  187. package/dist/session-events.js +203 -0
  188. package/dist/session-watcher-claude.js +637 -0
  189. package/dist/session-watcher.js +683 -0
  190. package/dist/sessoes-adopt.js +154 -0
  191. package/dist/sessoes-inventario.js +159 -0
  192. package/dist/sessoes.js +16 -35
  193. package/dist/setup.js +691 -0
  194. package/dist/ship.js +150 -15
  195. package/dist/slug.js +1 -1
  196. package/dist/thread-close.js +115 -0
  197. package/dist/thread.js +142 -28
  198. package/dist/tokens.js +1 -1
  199. package/dist/util.js +4 -2
  200. package/dist/verify-sandbox.js +265 -0
  201. package/dist/verify.js +270 -25
  202. package/dist/versao.js +60 -0
  203. package/dist/worktree.js +31 -2
  204. package/dist/write-activation.js +291 -0
  205. package/dist/yaml.js +2 -0
  206. package/eval/casos/onboarding.json +102 -0
  207. package/eval/casos/orkastery-bootstrap.json +35 -1
  208. package/eval/casos/scope-check-capability-map.json +45 -7
  209. package/eval/casos/ship-release.json +2 -2
  210. package/eval/fixtures/b0-slug-e-modos/caso.json +35 -22
  211. package/eval/fixtures/b2-master-log/caso.json +1 -1
  212. package/eval/fixtures/fx-adapter-editado-detectado/caso.json +19 -0
  213. package/eval/fixtures/fx-auto-quiet/caso.json +11 -0
  214. package/eval/fixtures/fx-blanket-approve/caso.json +10 -0
  215. package/eval/fixtures/fx-check-runtime-cruzado/caso.json +20 -0
  216. package/eval/fixtures/fx-codex-dry/caso.json +18 -0
  217. package/eval/fixtures/fx-donewhen-executavel/caso.json +15 -0
  218. package/eval/fixtures/fx-estado-dividido/caso.json +15 -0
  219. package/eval/fixtures/fx-fase-orfa/caso.json +116 -0
  220. package/eval/fixtures/fx-happy/caso.json +6 -4
  221. package/eval/fixtures/fx-hitl-latency/caso.json +20 -0
  222. package/eval/fixtures/fx-indice-reversao/caso.json +25 -0
  223. package/eval/fixtures/fx-listagem-abertas/caso.json +16 -0
  224. package/eval/fixtures/fx-maestro-bootstrap/caso.json +21 -0
  225. package/eval/fixtures/fx-modo-aposentado-escritor/caso.json +21 -0
  226. package/eval/fixtures/fx-modo-aposentado-leitor/caso.json +16 -0
  227. package/eval/fixtures/fx-objective-oscillation/caso.json +14 -0
  228. package/eval/fixtures/fx-omnicanal/caso.json +17 -0
  229. package/eval/fixtures/fx-sensores-runtime/caso.json +17 -0
  230. package/monitor/company-brain.cjs +17 -0
  231. package/monitor/pulse-scope.cjs +45 -0
  232. package/monitor/pulse.cron +18 -0
  233. package/monitor/varredura-pulse.sh +27 -0
  234. package/package.json +25 -4
  235. package/schemas/claims.schema.json +25 -0
  236. package/schemas/company-brain.schema.json +1158 -0
  237. package/schemas/creation-operation.schema.json +365 -0
  238. package/schemas/maestro-snapshot.schema.json +2716 -0
  239. package/skills/core/onboarding/SKILL.md +50 -0
  240. package/skills/core/orkastery-bootstrap/SKILL.md +95 -65
  241. package/skills/core/thread-state/SKILL.md +3 -1
  242. package/skills/governance/scope-check-capability-map/SKILL.md +17 -7
package/dist/index.js CHANGED
@@ -1,5 +1,59 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.parseArgs = parseArgs;
38
+ exports.main = main;
39
+ const company_brain_cli_1 = require("./company-brain-cli");
40
+ const maestro_cli_1 = require("./maestro-cli");
41
+ const hitl_public_receipt_1 = require("./hitl-public-receipt");
42
+ const hitl_presentation_1 = require("./hitl-presentation");
43
+ const hitl_native_offer_1 = require("./hitl-native-offer");
44
+ const hitl_ingress_receipt_1 = require("./hitl-ingress-receipt");
45
+ const node_path_1 = require("node:path");
46
+ const project_state_1 = require("./project-state");
47
+ const hitl_sessions_1 = require("./hitl-sessions");
48
+ const write_activation_1 = require("./write-activation");
49
+ const escopo_escrita_1 = require("./escopo-escrita");
50
+ const node_os_1 = require("node:os");
51
+ const fs = __importStar(require("node:fs"));
52
+ const path = __importStar(require("node:path"));
53
+ const node_child_process_1 = require("node:child_process");
54
+ const creation_operation_1 = require("./creation-operation");
55
+ const creation_operation_store_1 = require("./creation-operation-store");
56
+ const portfolio_context_1 = require("./portfolio-context");
3
57
  /**
4
58
  * `ork`: nucleo CLI deterministico do Orkastery (bloco B0).
5
59
  *
@@ -7,45 +61,90 @@
7
61
  * mundo real e registra no ledger. Quem escreve codigo e a orquestra (Camada 3);
8
62
  * quem decide e o humano; o meio e conduzido por software.
9
63
  */
10
- Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.parseArgs = parseArgs;
12
- exports.main = main;
64
+ const thread_close_1 = require("./thread-close");
65
+ const session_events_1 = require("./session-events");
66
+ const session_watcher_1 = require("./session-watcher");
67
+ const master_migracao_1 = require("./master-migracao");
68
+ const master_batch_1 = require("./master-batch");
69
+ const master_digest_1 = require("./master-digest");
70
+ const master_audit_1 = require("./master-audit");
71
+ const process_audit_1 = require("./process-audit");
72
+ const master_1 = require("./master");
13
73
  const auditoria_1 = require("./auditoria");
14
74
  const auditrun_1 = require("./auditrun");
15
75
  const superficie_1 = require("./superficie");
16
76
  const board_1 = require("./board");
77
+ const hitl_1 = require("./hitl");
78
+ const pulse_1 = require("./pulse");
79
+ const pulse_resposta_1 = require("./pulse-resposta");
80
+ const pulse_cadencia_1 = require("./pulse-cadencia");
81
+ const decisao_autonoma_1 = require("./decisao-autonoma");
17
82
  const orquestracao_1 = require("./orquestracao");
18
83
  const divida_1 = require("./divida");
19
84
  const ciclos_1 = require("./ciclos");
20
85
  const claims_1 = require("./claims");
21
86
  const catalogo_1 = require("./catalogo");
22
87
  const doctor_1 = require("./doctor");
88
+ const preflight_1 = require("./preflight");
23
89
  const evalrunner_1 = require("./evalrunner");
24
90
  const gates_1 = require("./gates");
91
+ const hitl_gates_1 = require("./hitl-gates");
25
92
  const handoff_1 = require("./handoff");
26
93
  const hosts_1 = require("./hosts");
27
94
  const init_1 = require("./init");
95
+ const portfolio_1 = require("./portfolio");
96
+ const agents_md_1 = require("./agents-md");
28
97
  const leases_1 = require("./leases");
29
- const master_1 = require("./master");
98
+ const sessoes_inventario_1 = require("./sessoes-inventario");
99
+ const ledger_stats_1 = require("./ledger-stats");
100
+ const sessoes_adopt_1 = require("./sessoes-adopt");
101
+ const sessoes_1 = require("./sessoes");
102
+ const runtime_ambiente_1 = require("./runtime-ambiente");
103
+ const policies_1 = require("./policies");
104
+ const master_2 = require("./master");
30
105
  const manifest_1 = require("./manifest");
106
+ const horario_1 = require("./horario");
107
+ const onboarding_1 = require("./onboarding");
108
+ const init_2 = require("./init");
31
109
  const memoria_1 = require("./memoria");
110
+ const orkmind_1 = require("./orkmind");
32
111
  const recall_1 = require("./recall");
112
+ const memory_migration_1 = require("./memory-migration");
33
113
  const fix_1 = require("./fix");
34
114
  const ratelimit_1 = require("./ratelimit");
35
115
  const retry_1 = require("./retry");
116
+ const prova_minima_1 = require("./prova-minima");
117
+ const versao_1 = require("./versao");
36
118
  const modos_1 = require("./modos");
119
+ const modos_migracao_1 = require("./modos-migracao");
120
+ const setup_1 = require("./setup");
121
+ const runtime_profiles_1 = require("./runtime-profiles");
122
+ const claude_bg_1 = require("./adapters/claude-bg");
123
+ const codex_1 = require("./adapters/codex");
124
+ const conducao_1 = require("./conducao");
37
125
  const phase_1 = require("./phase");
38
126
  const prompts_1 = require("./prompts");
39
- const sessoes_1 = require("./sessoes");
127
+ const sessoes_2 = require("./sessoes");
40
128
  const util_1 = require("./util");
41
129
  const ship_1 = require("./ship");
130
+ const ci_1 = require("./ci");
42
131
  const thread_1 = require("./thread");
132
+ const docs_1 = require("./docs");
133
+ const roadmap_reservas_1 = require("./roadmap-reservas");
134
+ const fabrica_estado_1 = require("./fabrica-estado");
135
+ const fabrica_publicar_1 = require("./fabrica-publicar");
136
+ const maquina_1 = require("./maquina");
137
+ const ledger_1 = require("./ledger");
43
138
  const tokens_1 = require("./tokens");
44
139
  const types_1 = require("./types");
45
140
  const verify_1 = require("./verify");
46
141
  const worktree_1 = require("./worktree");
47
- /** A versao publicada em `@orkastery/cli`. Anda junto com o `version` do package.json. */
48
- const VERSAO = '0.2.0';
142
+ const claim_lint_1 = require("./claim-lint");
143
+ const licoes_1 = require("./licoes");
144
+ const demo_1 = require("./demo");
145
+ const entrega_pr_1 = require("./entrega-pr");
146
+ /** A versao publicada em `@orkastery/cli`, lida do package.json (`versao.ts`). */
147
+ const VERSAO = versao_1.VERSAO_DO_ORK;
49
148
  /** Parse simples de argumentos: `--chave valor`, `--chave=valor` e flags booleanas. */
50
149
  function parseArgs(argv) {
51
150
  const posicionais = [];
@@ -77,44 +176,137 @@ function parseArgs(argv) {
77
176
  function texto(v) {
78
177
  return typeof v === 'string' ? v : undefined;
79
178
  }
179
+ /**
180
+ * I-36 (D2, D6): o que o CLI declara sobre a conducao. `--canal` (sem ele, o que a borda exporta),
181
+ * `--correlacao` (conversa ou mensagem de origem) e `--esperar [minutos]` (sem valor, 30).
182
+ */
183
+ function conducaoDoCli(args) {
184
+ if (args.opcoes.canal === true)
185
+ throw new Error('uso: --canal <claude-code|hermes|openclaw|codex|mcp|cli>');
186
+ const bruto = args.opcoes.esperar;
187
+ let esperarMs;
188
+ if (bruto === true)
189
+ esperarMs = conducao_1.ESPERA_PADRAO_MS;
190
+ else if (typeof bruto === 'string') {
191
+ const minutos = Number(bruto);
192
+ if (!Number.isFinite(minutos) || minutos <= 0 || minutos > 24 * 60)
193
+ throw new Error('uso: --esperar [minutos], de 1 a 1440 (sem valor, 30)');
194
+ esperarMs = Math.round(minutos * 60_000);
195
+ }
196
+ return { canal: (0, conducao_1.canalDoProcesso)(texto(args.opcoes.canal)), correlacao: texto(args.opcoes.correlacao) ?? null, esperarMs };
197
+ }
80
198
  const AJUDA = `ork ${VERSAO}, nucleo de orquestracao do Orkastery
81
199
 
82
200
  Uso: ork <comando> [argumentos]
83
201
 
84
202
  doctor O que vale nesta maquina agora (sai != 0 se bloqueado)
85
203
  init [--force] [--name N] [--abbrev A] Gera o orkastery.yaml do repositorio
86
- modos Tabela dos 5 modos de conducao por #TAG
204
+ modos Tabela dos ${modos_1.ORDEM_DOS_MODOS.length} modos de conducao vivos por #TAG
205
+
206
+ setup Pauta da entrevista #setup: runtime/modelo/esforco
207
+ onboarding [show|set <etapa>|reset [etapa]] Pauta e respostas do projeto (9 etapas)
208
+ [--conteudo JSON] [--por Q] [--json] Valores secretos somente em ~/.hermes/.env
209
+ [--reset [etapa]] Reset seletivo ou total, idempotente
210
+ onboarding sync [--json] Publicação opcional na memória, com degradação
211
+ por bloco de cada modo (default claude-bg/opus/high; #Fast: sonnet)
212
+ setup <modo> Config atual de cada bloco do modo
213
+ setup <modo> --bloco N [--runtime R] Edita o bloco (runtimes: claude-bg, codex);
214
+ [--model M] [--effort E] [--por Q] evento setup_configured no ledger do projeto
215
+ [--fallback R:M[:E],...] ordem de fallback de runtime do bloco (I-33)
216
+ accounts list [--json] Perfis de conta por runtime, sem segredo (I-33)
217
+ accounts add <id> --runtime R --dir D Cria o perfil e roda o login do proprio CLI com o env
218
+ [--sem-login] do perfil (nunca copia credencial)
219
+ accounts remove <id> Desativa o perfil (diretorio e login ficam onde estao)
220
+ accounts check [<id>] Confere o login de cada perfil e marca o store
221
+ setup [<modo>] --reset Volta o modo (ou tudo) ao default
222
+ setup versionar Leva o setup que vale para orkastery.setup.json: por PR, vale em
223
+ todas as maquinas e passa a ser o arquivo editado (I-52)
87
224
 
88
225
  thread new <nome> --modo <MODO> Cria a thread, o slug de 3 partes e o ledger
226
+ [--exige-runtime-diferente] o CHECK precisa de runtime que o GO nao usou
227
+ [--done "<criterio> :: <comando>"] criterio de pronto EXECUTAVEL (use ;; para varios)
89
228
  [--slug S] [--assunto A] [--worktree auto|DIR] [--dry-run]
90
- thread list Threads do projeto
91
- thread status <thread-id> Estado da thread, cruzado com o runtime
229
+ [--roadmap RM-NNN] reserva o item do roadmap antes de criar (I-47)
230
+ thread list [--todas] [--json] Threads NAO fechadas do projeto (--todas inclui as fechadas)
231
+ thread close <id> --motivo orfa|engano|superada --por Q --justificativa J
232
+ thread entrega <id> --arquivo A --sha256 H --por Q
233
+ thread status <thread-id> [--json] Estado da thread, cruzado com o runtime
234
+
235
+ portfolio inspect <id> --json Entidade, origem e ciclos com lacunas explícitas
236
+ creation start --input-file F --json Criação durável com identidade do processo local
237
+ creation show|list|events [id] --json Consulta journal e recuperação
238
+ creation resume|compensate <id> --expected-version N --json
239
+ portfolio create <product|project|initiative> <id> --title T [--parent ID]
240
+ portfolio list [product|project|initiative] [--parent ID] [--json]
241
+ portfolio show <id> [--json] Catálogo prod -> proj -> init
242
+ [--constraints A;B] [--outcomes A;B] [--threads N]
243
+ [--execution-runtime R] [--validation-runtimes R1,R2]
244
+ objective ... Aposentado na I-43: as duas vigas viraram
245
+ --exige-runtime-diferente e --done de thread
92
246
 
93
247
  phase run <thread-id> <FASE> --prompt "<texto>"
94
- [--model M] [--effort E] [--dry-run] Despacha a fase como background agent
95
- (so --model assume --effort high; o par
248
+ [--runtime R] [--model M] Despacha a fase como background agent
249
+ [--effort E] [--dry-run] (runtime: CLI > setup do bloco > manifesto;
250
+ so --model assume --effort high; o trio
96
251
  efetivo vai ao ledger como fato verificavel)
252
+ [--canal C] [--correlacao ID] Canal de origem (sem ele, o que o host declara)
253
+ [--esperar [min]] Com a thread ja conduzida, espera a vez (sem: recusa na hora)
97
254
  phase list <thread-id> Historico do ledger da thread
98
255
  (mostra o modelo/esforco reais de cada fase)
256
+ ledger stats --desde 7d [--ate ISO] Telemetria economica do ledger (intervalo [desde,ate))
257
+ [--thread T] [--modo M] [--runtime R] [--json]
258
+ ledger estimate <thread-id> --sem-ia H --ia-sem-ork H --por Q --metodo M --premissas P
259
+ [--incerteza I] Registra estimativas explicitas da fase PLAN
99
260
 
100
- sessions [--all] Sessoes vivas do runtime, cruzadas com as threads
261
+ sessions [--all] [--global] [--json] Inventário Claude e Codex da conta atual
262
+ [--exigir-limpo] Sai != 0 com fonte inválida ou sessão sem thread
263
+ sessions adopt <id> [--json] Adota identidade real sem executar prompt
264
+ sessions event --tipo T --sessao ID Ingere JSON limitado no stdin; observa sem aprovar gates
265
+ sessions watch --thread T [--sessao ID] Observa somente a sessão selecionada; --once faz uma varredura
101
266
  sessions logs <sessao> [--linhas N] Logs de uma sessao
267
+ sessions supersede <thread> <UUID> --fase F --runtime R Confirma encerramento de sessão superada
268
+ sessions request <thread> <UUID> --fase F --runtime R --pergunta P Abre pedido vinculado ao prompt nativo
269
+ sessions answer <thread> <pedido> --stdin --origem telegram --canal C --por ID --mensagem REF [--conta ID] Confirma entrega autenticada
270
+ sessions reconcile <thread> <pedido> Fecha envio pendente so com thread e pedido; consulta recibo, nunca reenvia
102
271
  sessions stop <sessao> Para uma sessao
103
272
  sessions attach <sessao> Imprime o comando de attach (precisa de TTY)
273
+ pulse [--json] [--registrar] Fila unificada de atenção humana e retry de órfãs
274
+ pulse responder --resposta-stdin --origem telegram --canal C --por ID --mensagem REF [--conta ID]
275
+ Recebe o que o dono digitou no canal do resumo (P4EJ a, 1a 2c)
276
+ pulse cadencia [<tag>] [--por P] [--json] Mostra ou troca a cadencia do resumo: OrkPulseOn, OrkPulseOn-15m,
277
+ -30m, -60m ou OrkPulseOff; pergunta nova sai na hora (I-50)
278
+ sessions hitl [--json] [--so-paradas] Radar de sessoes que exigem acao humana AGORA:
279
+ [--atencao N] [--sem-logs] classifica o estado de cada sessao do runtime,
280
+ [--so-da-raiz] [--exigir-limpo] le a pergunta que a sessao trava e diz o que
281
+ destrava (pega HITL de sessao SEM thread)
104
282
 
105
283
  claims add <thread-id> <arquivo> --claim "<alegacao>" [--verificar "<comando>"] [--fase F]
106
284
  Registra alegacao verificavel da thread
107
285
  claims list <thread-id> Claims da thread e o estado de cada uma
286
+ decisao registrar <thread-id> --decidido D --porque P --como-mudar C --custo-agora A --custo-depois B
287
+ --criterio manifesto:CHAVE|ledger:REF|medicao:COMANDO --quem Q --evidencia E [--razao R] [--reverte ID]
288
+ Decisao tomada sem perguntar: chega ao dono no resumo
289
+ decisao placar <thread-id> [--json] Decididas contra perguntas por fase, reversoes e o limiar
108
290
  claims verificar <thread-id> <claim-id> --comando "<comando>"
109
291
  Anexa o comando que comprova uma claim ja feita
110
292
  claims retirar <thread-id> <claim-id> --motivo "<motivo>"
111
293
  Retira a alegacao (o historico fica no claims.jsonl)
294
+ claims ausente <thread-id> --paths A,B --motivo "<motivo>" [--commit SHA]
295
+ Ciclo sem CHECK: declara no ledger o que ficou sem prova
112
296
  verify <thread-id> [--baseline] Reexecuta claims e verify do manifesto no HEAD real
113
297
  [--so-claims] --baseline grava o estado do mundo antes do GO
298
+ [--canal C] [--esperar [min]] So executa com a conducao da thread (sai 3 se outra conduz)
299
+ ci prepare <thread-id> Exporta claims/comandos para a candidata
300
+ ci run [<thread-id>] [--bundle ARQ] Executa o CHECK no runner independente
301
+ ci status [--sha SHA] [--remoto origin] Consulta o check exato publicado no GitHub
114
302
 
115
303
  gate next <thread-id> [--proximo FASE] Gate de tokens: mesma sessao ou nova sessao
116
304
  [--ocupacao 0..1] [--fonte F] [--transcript ARQ] [--janela N] [--refazer]
117
- gate approve <thread-id> <sobre> --por Q Registra autorizacao humana no ledger
305
+ gate request <thread-id> [--motivo M] Apresenta pedido HITL correlacionado à pausa
306
+ gate answer <thread-id> <pedido> Recebe envelope do ingresso humano autenticado
307
+ --resposta-stdin --por Q --mensagem ID --origem telegram [--canal hermes|openclaw]
308
+ [--conta ID] conta homologada do canal; obrigatoria no canal openclaw
309
+ gate approve Aposentado: aprovação sem pedido é recusada
118
310
 
119
311
  retry policy [--motivo M] [--json] Politica de retry por motivo tipado de gate
120
312
  retry plan <thread-id> [--motivo M] O que o ork faria pelo ultimo gate reprovado
@@ -141,15 +333,21 @@ Uso: ork <comando> [argumentos]
141
333
  [--id ptr-N] [--todos] [--forcar] momento (retrieve_when), nunca a janela inteira
142
334
  [--sem-conteudo] [--json] (orkmind por tag, files por path#ancora)
143
335
 
336
+ brain status|inventory|get|query|receipts|sync|reconcile|apply|rollback|bind
144
337
  memory status [--json] Regime efetivo (files|orkmind), tenant e degradacao
145
338
  memory sync [<thread-id>] [--json] Publica decisoes, policies, handoff, licao e roadmap
339
+ memory inventory --escopo <threads> [--json] Inventaria fontes canonicas e tenants excluidos, sem gravar
340
+ memory migrate --operadora <thread> --escopo <threads> [--dry-run] [--json] Migra handoffs por G3, com pacote integral e readback
146
341
  memory search --tags '<json>' [--colecao C] Busca deterministica por tag (mandatory sempre volta)
147
- [--limite N] [--json]
342
+ [--thread ID] [--restrito] [--janela N] [--limite N] [--json]
148
343
 
149
344
  ship <thread-id> --para <branch> Merge --no-ff serializado por lease e push PROVADO
345
+ ship registrar-pr <thread-id>|--todas A entrega feita por PR vira ship_done: merge ship(<thread>) na base
346
+ [--remoto R] [--json] remota e CI verde no head do PR; depois, ork master --aceitar-omissao
150
347
  [--de <branch>] [--remoto origin] [--autorizar-push <quem>] [--sem-push] [--dry-run]
151
348
 
152
- board [--all] Visao unica das threads (todos os perfis com --all)
349
+ board [--all] [--sem-remoto] Visao unica das threads (todos os perfis com --all); com a
350
+ fabrica compartilhada, tambem as outras maquinas (I-51)
153
351
  board plan Escalonador: quem avanca agora, quem espera e por que
154
352
 
155
353
  orquestracao status [--all] [--json] Monitor PROATIVO de pausas e impedimentos: quem esta
@@ -161,18 +359,33 @@ Uso: ork <comando> [argumentos]
161
359
  worktree audit <thread-id> Confere a worktree no proprio git (sai != 0 se divergir)
162
360
  worktree release <thread-id> [--forcar] Remove a worktree e limpa o registro
163
361
 
362
+ activation plan|status|enable|disable Escrita escopada com aceite, hash, leases e recibo
164
363
  lease list Leases, familias e as filas (merge e colisao de regiao)
165
364
  lease acquire <nome> --thread T --motivo M Toma um lease tipado (entra na fila se colidir)
166
365
  lease release <nome> [--thread T] [--forcar]
366
+ conducao status <thread-id> [--json] Quem conduz a thread agora (canal, sessao, fase, desde)
367
+ conducao assumir <thread-id> --por Q --motivo M
368
+ Handoff: encerra a conducao atual pelo runtime e registra quem assumiu
167
369
 
370
+ master propor <id> --score N --justificativa J --por <agente>
371
+ master batch --aceitar <thread:assinatura,...> --por <humano>
372
+ master migrar --dry-run --por Q Inspeciona correções sem alterar originais
373
+ master digest <enviar|preview|responder> Digest semanal com recibos do host
168
374
  master <thread-id> --score 0-5 --justificativa "<texto>"
169
375
  [--classe C[,C]] [--resumo R] [--por Q] [--refazer]
170
376
  Fecha a thread: POSTMORTEM + MASTER log + score
171
- master --batch [--todas] Fila de review em bloco (threads entregues sem score)
377
+ master [--todas] [--json] As entregas, com o indice derivado do ledger
378
+ master --aceitar-omissao [--json] Aceita as entregues por omissao, com registro
172
379
  master classes As classes de falha fixas do POSTMORTEM
380
+ licoes [--json] O que volta no GOAL e no PLAN da proxima thread (POSTMORTEM e
381
+ MASTER) e as propostas de policy por recorrencia (I-55)
173
382
 
383
+ demo [--manter] [--dir D] A promessa em 30 s: uma afirmacao falsa reprovada e a corrigida aceita,
384
+ offline, num repositorio temporario (I-56)
174
385
  ciclos Variantes de ciclo de "ork thread new --ciclo"
175
386
  modos --do-pedido "<texto>" [--json] Le a #TAG do pedido do builder (usado pelos adaptadores)
387
+ modos migrar [--dry-run] [--por Q] Tira modo aposentado do orkastery.yaml e do setup.json
388
+ [--json] (idempotente, com backup; nao toca em historico)
176
389
 
177
390
  prompt list Templates de prompt (embutidos e os do projeto)
178
391
  prompt lint [--template ID] Reprova template quebrado antes de ele virar despacho
@@ -180,10 +393,33 @@ Uso: ork <comando> [argumentos]
180
393
  [--pedido "<texto>"] [--template ID]
181
394
  prompt render --exemplo --fase F --modo M Renderiza sem thread nenhuma, para revisar o texto
182
395
 
396
+ roadmap reservas [--json] [--remoto R] Quem esta com cada item do roadmap, lido da branch ork/roadmap-reservas
397
+ roadmap pegar <RM-NNN> [--thread T] Reserva o item para esta maquina (push atomico: o primeiro vence)
398
+ [--nota N] [--por Q] [--maquina M] maquina = --maquina, ORK_MAQUINA ou o hostname
399
+ [--forcar --motivo M] tomar a reserva de outra maquina fica registrado
400
+ roadmap soltar <RM-NNN> [--forcar --motivo M] Devolve o item
401
+ fabrica [--json] [--sem-remoto] O que cada maquina conduz, lido da branch ork/fabrica-estado (I-51)
402
+ fabrica entrar [--maquina NOME] Esta maquina entra na fabrica compartilhada deste usuario, com
403
+ este nome (~/.orkastery/maquina.json), e publica o primeiro retrato
404
+ fabrica publicar [--forcar] [--json] Grava o retrato desta maquina na branch (push atomico, sem forca);
405
+ depois de entrar, sai sozinho ao criar thread, despachar fase,
406
+ entregar e fechar, e a cada batida do pulse
407
+ fabrica sair Para de publicar daqui e tira o retrato desta maquina da branch
408
+ docs verificar [--json] Documentacao de produto e roadmap contra o codigo e o git
409
+ (padrao do dono: frontmatter, leitura, paridade; sai != 0 com erro)
410
+ docs sincronizar [--escrever] Fatos do ledger e do git para o roadmap (merge, fase) e indices;
411
+ sem --escrever so mostra; nunca muda status por passagem de tempo
412
+ docs init Cria padroes, modelos, indices e o lint de Markdown no projeto
413
+
414
+ mcp serve --project RAIZ --host HOST Servidor MCP stdio deste projeto (codex|claude-code)
415
+ mcp install --project RAIZ --host HOST Prepara MCP; aceita --dry-run, --ship-transport, --child-permissions e --owner-permissions (Codex)
416
+
183
417
  adapter list Adaptadores de host (Camada 1) e o destino de cada um
184
418
  adapter show <host> Os 3 pitfalls de instalacao do host
185
- adapter install <host> [--dir D] Instala o adaptador (hermes|openclaw|claude-code)
186
- [--dry-run] [--force]
419
+ adapter install <host> [--dir D] Instala o adaptador (claude-code|codex|hermes|openclaw)
420
+ [--dry-run] [--force] divergencia segura resolve sozinha; o resto pergunta
421
+ [--aceitar-catalogo <arquivo>] sobrescreve a copia com o catalogo, arquivo a arquivo
422
+ [--manter-copia <arquivo>] deixa a copia como esta, arquivo a arquivo
187
423
 
188
424
  eval [--skill S] [--canario C] Canarios de comportamento + corpus das skills finas
189
425
  [--so-canarios] [--so-skills] [--json] (sai != 0 em qualquer falha)
@@ -227,11 +463,11 @@ pausaSobre do bloco dizendo o que o humano decide); impedimento e a nao prevista
227
463
  DERIVADO de thread.json, ledger.jsonl e das filas em disco: o monitor le, nunca grava.
228
464
  --exigir-limpo sai != 0 enquanto houver thread parada, para virar watchdog do orquestrador.
229
465
 
230
- Fases: GOAL PLAN GO CHECK SHIP MASTER. Modos: #Look #Default #Ork #Maestro #Auto.
466
+ Fases: GOAL PLAN GO CHECK SHIP MASTER. Modos: ${modos_1.ORDEM_DOS_MODOS.map((m) => modos_1.MODOS[m].tag).join(' ')}.
231
467
  Familias de lease: main-tree, worktree-write:<thread>, path:<glob>, board:<card>, service:<porta>.
232
468
  Ciclos: greenfield, merge-branch, goal-plan, gap, feature-xl-faseada.
233
469
  Fontes de medida do gate de tokens: runtime_reported, estimated, informada, unavailable.
234
- Hosts de Camada 1: claude-code, hermes, openclaw. Canarios: fx-happy, fx-hallucination,
470
+ Hosts de Camada 1: claude-code, codex, hermes, openclaw. Canarios: fx-happy, fx-hallucination,
235
471
  fx-stale-base, fx-wiki-destroy, fx-schema-drift, fx-concurrency.
236
472
  Packs de auditoria: clean-code, reuse, architecture, data-model, ux, security-privacy, process.
237
473
  Superficie de ataque de rede (SP8..SP12, varredura deterministica): rota sem auth, endpoint de
@@ -239,6 +475,17 @@ administracao exposto, rota sem rate limit, CORS permissivo, rota sem esquema de
239
475
  Estagios do produto: nascente, crescendo, maduro (hardening gradual, visao secao 5.2).
240
476
  `;
241
477
  function comandoThread(args) {
478
+ if (args.posicionais[1] === 'close' || args.posicionais[1] === 'entrega') {
479
+ const raiz = (0, manifest_1.exigirManifesto)().raiz, id = args.posicionais[2];
480
+ if (!id)
481
+ throw new Error('informe o id da thread');
482
+ const por = texto(args.opcoes.por) ?? '';
483
+ const r = args.posicionais[1] === 'close'
484
+ ? (0, thread_close_1.fecharAdministrativamente)(raiz, id, { motivo: texto(args.opcoes.motivo) ?? '', por, justificativa: texto(args.opcoes.justificativa) ?? '' })
485
+ : (0, thread_close_1.registrarArtefato)(raiz, id, texto(args.opcoes.arquivo) ?? '', texto(args.opcoes.sha256) ?? '', por);
486
+ console.log(JSON.stringify(r, null, 2));
487
+ return 0;
488
+ }
242
489
  const sub = args.posicionais[1];
243
490
  if (sub === 'new') {
244
491
  const carregado = (0, manifest_1.exigirManifesto)();
@@ -247,10 +494,15 @@ function comandoThread(args) {
247
494
  const doAchado = texto(args.opcoes['from-finding']) ?? texto(args.opcoes['do-achado']);
248
495
  if (doAchado) {
249
496
  const brutoModoAchado = texto(args.opcoes.modo) ?? texto(args.opcoes.mode);
250
- const modoAchado = brutoModoAchado ? (0, modos_1.parseModo)(brutoModoAchado) : undefined;
251
- if (brutoModoAchado && !modoAchado) {
252
- console.error(`modo invalido: "${brutoModoAchado}". Use um de: ${Object.values(modos_1.MODOS).map((m) => m.tag).join(', ')}`);
253
- return 2;
497
+ let modoAchado;
498
+ if (brutoModoAchado !== undefined) {
499
+ try {
500
+ modoAchado = (0, modos_1.exigirModoVivo)(brutoModoAchado);
501
+ }
502
+ catch (e) {
503
+ console.error(e.message);
504
+ return 2;
505
+ }
254
506
  }
255
507
  const brutoWorktreeAchado = args.opcoes.worktree;
256
508
  const criarWorktreeAchado = brutoWorktreeAchado === true || brutoWorktreeAchado === 'auto';
@@ -314,13 +566,35 @@ function comandoThread(args) {
314
566
  return 2;
315
567
  }
316
568
  const brutoModo = texto(args.opcoes.modo) ?? texto(args.opcoes.mode);
317
- const modo = brutoModo
318
- ? (0, modos_1.parseModo)(brutoModo)
319
- : carregado.manifesto.conduction.default_mode;
320
- if (!modo) {
321
- console.error(`modo invalido: "${brutoModo}". Use um de: ${Object.values(modos_1.MODOS).map((m) => m.tag).join(', ')}`);
569
+ let modo;
570
+ try {
571
+ modo = brutoModo !== undefined
572
+ ? (0, modos_1.exigirModoVivo)(brutoModo)
573
+ : carregado.manifesto.conduction.default_mode;
574
+ }
575
+ catch (e) {
576
+ console.error(e.message);
322
577
  return 2;
323
578
  }
579
+ // I-43 (D4, viga a): a exigencia de validacao cruzada e declarada na criacao e
580
+ // fica gravada na thread, em vez de morar num envelope a parte.
581
+ const exigeRuntimeDiferente = args.opcoes['exige-runtime-diferente'] === true;
582
+ // I-43 (D4, viga b): `--done "criterio :: comando"`, com `;;` separando varios.
583
+ // O separador `::` e obrigatorio: criterio sem comando e a prosa que o envelope
584
+ // tinha, e o produto nao aceita de volta um criterio de pronto que ninguem executa.
585
+ const doneWhen = (texto(args.opcoes.done) ?? '').split(';;').map((p) => p.trim()).filter(Boolean)
586
+ .map((entrada) => {
587
+ const corte = entrada.indexOf('::');
588
+ if (corte < 0) {
589
+ throw new Error(`done.sem-comando: "${entrada}" nao traz comando. `
590
+ + 'Use --done "<criterio> :: <comando que o prova>"; criterio sem comando e prosa, nao criterio de pronto.');
591
+ }
592
+ const criterio = entrada.slice(0, corte).trim();
593
+ const comando = entrada.slice(corte + 2).trim();
594
+ if (!criterio || !comando)
595
+ throw new Error(`done.incompleto: "${entrada}" precisa de criterio E comando`);
596
+ return { criterio, comando };
597
+ });
324
598
  const dryRun = args.opcoes['dry-run'] === true;
325
599
  const brutoWorktree = args.opcoes.worktree;
326
600
  // `--worktree auto` (ou `--worktree` sozinho) cria a worktree isolada da thread;
@@ -333,19 +607,46 @@ function comandoThread(args) {
333
607
  return 2;
334
608
  }
335
609
  const brutoFatias = texto(args.opcoes.fatias);
336
- const { thread, gravada } = (0, thread_1.novaThread)(carregado, {
337
- nome,
338
- modo,
339
- slug: texto(args.opcoes.slug),
340
- assunto: texto(args.opcoes.assunto),
341
- worktree: criarWorktree ? null : (texto(brutoWorktree) ?? null),
342
- criarWorktree,
343
- dryRun,
344
- variante,
345
- branch: texto(args.opcoes.branch),
346
- fatias: brutoFatias !== undefined ? Number(brutoFatias) : undefined,
347
- });
610
+ // I-47: `--roadmap RM-NNN` reserva o item ANTES de criar a thread. A reserva e o passo
611
+ // atomico entre maquinas (o primeiro push vence); a thread e local. Se a criacao falhar,
612
+ // a reserva e devolvida; se der certo, ela passa a apontar para a thread.
613
+ const itemDoRoadmap = dryRun ? undefined : texto(args.opcoes.roadmap);
614
+ const itemReservado = itemDoRoadmap ? (0, roadmap_reservas_1.pegarItem)(carregado.raiz, itemDoRoadmap).item : undefined;
615
+ let criada;
616
+ try {
617
+ criada = (0, thread_1.novaThread)(carregado, {
618
+ nome,
619
+ modo,
620
+ slug: texto(args.opcoes.slug),
621
+ assunto: texto(args.opcoes.assunto),
622
+ worktree: criarWorktree ? null : (texto(brutoWorktree) ?? null),
623
+ criarWorktree,
624
+ dryRun,
625
+ variante,
626
+ branch: texto(args.opcoes.branch),
627
+ fatias: brutoFatias !== undefined ? Number(brutoFatias) : undefined,
628
+ exigeRuntimeDiferente,
629
+ doneWhen,
630
+ roadmap: itemReservado,
631
+ });
632
+ }
633
+ catch (e) {
634
+ if (itemDoRoadmap) {
635
+ try {
636
+ (0, roadmap_reservas_1.soltarItem)(carregado.raiz, itemDoRoadmap);
637
+ }
638
+ catch { /* fica reservado; `ork roadmap soltar` resolve */ }
639
+ }
640
+ throw e;
641
+ }
642
+ const { thread, gravada } = criada;
643
+ const reservaDoItem = itemDoRoadmap && gravada ? (0, roadmap_reservas_1.pegarItem)(carregado.raiz, itemDoRoadmap, { thread: thread.id }) : null;
644
+ // I-51 (RM-047): com a fabrica compartilhada, as outras maquinas veem a thread nova.
645
+ if (gravada)
646
+ (0, fabrica_publicar_1.publicarEmSegundoPlano)(carregado.raiz);
348
647
  console.log(gravada ? 'Thread criada.' : 'Simulacao (--dry-run), nada foi gravado.');
648
+ if (reservaDoItem)
649
+ console.log(` roadmap: ${reservaDoItem.item} reservado para esta maquina (${reservaDoItem.reserva?.maquina})`);
349
650
  console.log((0, thread_1.resumoDaThread)(thread));
350
651
  console.log('');
351
652
  console.log(` slug em 3 partes: ${(0, phase_1.descreverSlug)(thread.slug)}`);
@@ -361,7 +662,16 @@ function comandoThread(args) {
361
662
  }
362
663
  if (sub === 'list' || sub === undefined) {
363
664
  const carregado = (0, manifest_1.exigirManifesto)();
364
- console.log((0, thread_1.tabelaDeThreads)(carregado.raiz));
665
+ // I-43 (D8): `--todas` abre o que o default esconde, e `--json` passa a devolver
666
+ // JSON de verdade. Acrescentar uma flag numa tela onde `--json` era aceito e
667
+ // IGNORADO em silencio (saindo 0) seria deixar dois pesos na mesma linha.
668
+ const todas = args.opcoes.todas === true;
669
+ if (args.opcoes.json === true) {
670
+ const linhas = (0, thread_1.threadsDaListagem)(carregado.raiz, { todas });
671
+ console.log(JSON.stringify({ todas, total: linhas.length, threads: linhas }, null, 2));
672
+ return 0;
673
+ }
674
+ console.log((0, thread_1.tabelaDeThreads)(carregado.raiz, { todas }));
365
675
  return 0;
366
676
  }
367
677
  if (sub === 'status') {
@@ -372,8 +682,14 @@ function comandoThread(args) {
372
682
  return 2;
373
683
  }
374
684
  const thread = (0, thread_1.lerThread)(carregado.raiz, id);
685
+ if (args.opcoes.json === true) {
686
+ // Idem: `ork thread status <id> --json` imprimia o TEXTO e saia 0.
687
+ console.log(JSON.stringify(thread, null, 2));
688
+ return 0;
689
+ }
375
690
  console.log(`Thread ${thread.id}`);
376
- console.log((0, thread_1.resumoDaThread)(thread));
691
+ // I-36 (T17): a linha de conducao vem da leitura unica do nucleo.
692
+ console.log((0, thread_1.resumoDaThread)(thread, (0, conducao_1.conducaoDaThread)(carregado.raiz, thread.id)));
377
693
  console.log('');
378
694
  if (thread.sessoes.length === 0) {
379
695
  console.log(' nenhuma sessao despachada ainda');
@@ -382,7 +698,7 @@ function comandoThread(args) {
382
698
  console.log(' sessoes despachadas (estado real conferido em `ork sessions`)');
383
699
  for (const s of thread.sessoes) {
384
700
  console.log(` ${s.slug.padEnd(24)} ${s.fase.padEnd(6)} ${s.sessionId.slice(0, 8)} ` +
385
- `verificada no runtime: ${s.verificada ? 'sim' : 'nao'}`);
701
+ `verificada no runtime: ${s.verificada ? 'sim' : 'nao'} canal: ${(0, thread_1.canalDaSessao)(s)}`);
386
702
  }
387
703
  }
388
704
  console.log('');
@@ -392,10 +708,280 @@ function comandoThread(args) {
392
708
  console.error(`subcomando desconhecido: thread ${sub}`);
393
709
  return 2;
394
710
  }
711
+ /**
712
+ * `ork setup [modo]`: a feature #setup no nucleo.
713
+ *
714
+ * Sem argumento, imprime a pauta da entrevista (a lista topificada dos modos vivos com a
715
+ * config atual de cada bloco): e o texto que o orquestrador entrega ao owner quando a
716
+ * tag #setup chega no pedido. Com um modo, mostra/edita/reseta a config daquele modo.
717
+ * Toda edicao vira evento `setup_configured` no ledger do projeto.
718
+ */
719
+ function comandoOnboarding(args) {
720
+ const invalido = () => { throw new Error('onboarding.input.invalid: use ork onboarding [show|set <etapa>|reset [etapa]] --conteudo <JSON> [--por Q] [--json]'); };
721
+ if (Object.keys(args.opcoes).some(k => !['conteudo', 'por', 'json', 'reset'].includes(k)))
722
+ invalido();
723
+ if ('json' in args.opcoes && args.opcoes.json !== true)
724
+ invalido();
725
+ if ('por' in args.opcoes && typeof args.opcoes.por !== 'string')
726
+ invalido();
727
+ const alias = 'reset' in args.opcoes;
728
+ const sub = alias ? 'reset' : args.posicionais[1] ?? 'show';
729
+ const etapa = alias ? texto(args.opcoes.reset) : args.posicionais[2];
730
+ if (alias && args.posicionais.length !== 1)
731
+ invalido();
732
+ if (!['show', 'set', 'reset', 'sync'].includes(sub))
733
+ invalido();
734
+ if (['show', 'sync'].includes(sub) && (args.posicionais.length > 2 || 'conteudo' in args.opcoes))
735
+ invalido();
736
+ if (sub === 'set' && (!etapa || args.posicionais.length !== 3 || typeof args.opcoes.conteudo !== 'string'))
737
+ invalido();
738
+ if (sub === 'reset' && (args.posicionais.length > 3 || 'conteudo' in args.opcoes))
739
+ invalido();
740
+ if (sub === 'sync' && 'por' in args.opcoes)
741
+ throw new Error('onboarding.input.invalid: sync não aceita --por; informe autoria em set ou reset.');
742
+ const carregado = (0, manifest_1.exigirManifesto)(), raiz = carregado.raiz, por = texto(args.opcoes.por) ?? 'owner';
743
+ if (sub === 'sync') {
744
+ const r = (0, memoria_1.sincronizarOnboarding)(carregado);
745
+ console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2) : `${r.regime}${r.motivo ? ` (${r.motivo})` : ''}: ${r.detalhe}`);
746
+ return 0;
747
+ }
748
+ let estado;
749
+ if (sub === 'set') {
750
+ let conteudo;
751
+ try {
752
+ conteudo = JSON.parse(args.opcoes.conteudo);
753
+ }
754
+ catch {
755
+ return invalido();
756
+ }
757
+ estado = (0, onboarding_1.gravarEtapa)(raiz, etapa, conteudo, por);
758
+ }
759
+ else if (sub === 'reset')
760
+ estado = (0, onboarding_1.resetarOnboarding)(raiz, etapa, por);
761
+ else
762
+ estado = (0, onboarding_1.lerOnboarding)(raiz);
763
+ console.log(args.opcoes.json === true ? JSON.stringify(estado, null, 2) : (0, onboarding_1.textoDaPauta)(estado));
764
+ return 0;
765
+ }
766
+ /**
767
+ * I-33 (D8): `ork accounts list|add|remove|check`. O login e sempre do proprio CLI com o env do
768
+ * perfil (`claude auth login`, `codex login`); o `ork` so guarda identidade, diretorio e estado,
769
+ * nunca le, copia ou migra o que o CLI grava. A lista nao tem segredo porque o store nao tem.
770
+ */
771
+ /** A8: valor citado para colar no shell: aspas simples, e a aspa simples do proprio valor fechada e reaberta. */
772
+ function aspasDeShell(valor) {
773
+ return `'${valor.split("'").join(`'"'"'`)}'`;
774
+ }
775
+ /**
776
+ * I-33 (N2): o aviso da chave de troca entre perfis sai no proprio comando que a usa (`phase run`,
777
+ * `retry`, `accounts`), nao so no `ork doctor`: valor invalido nunca liga a troca em silencio.
778
+ */
779
+ function avisarChavesDePerfis(carregado) {
780
+ for (const a of carregado.avisos)
781
+ if (a.startsWith('runtime_profiles.'))
782
+ console.error(`aviso: ${a}`);
783
+ }
784
+ function comandoAccounts(args) {
785
+ const carregado = (0, manifest_1.exigirManifesto)();
786
+ avisarChavesDePerfis(carregado);
787
+ const raiz = carregado.raiz;
788
+ const sub = args.posicionais[1] ?? 'list';
789
+ const conferir = (p) => p.runtime === 'claude-bg' ? (0, claude_bg_1.conferirAuth)(p) : (0, codex_1.conferirAuth)(p);
790
+ const imprimir = () => {
791
+ const store = (0, runtime_profiles_1.lerPerfis)(raiz);
792
+ if (args.opcoes.json === true) {
793
+ console.log(JSON.stringify(store, null, 2));
794
+ return;
795
+ }
796
+ // I-49: a tabela mostra o que o despacho enxerga, com o que outra fabrica viu na mesma conta.
797
+ const visto = (0, runtime_profiles_1.lerPerfisComContas)(raiz);
798
+ console.log(visto.perfis.length === 0 ? 'Nenhum perfil configurado: cada runtime despacha pelo ambiente do processo.'
799
+ : (0, util_1.tabela)(runtime_profiles_1.COLUNAS_DE_PERFIS, (0, runtime_profiles_1.linhasDePerfis)(visto)));
800
+ // I-35: a tabela mostra horario do dono; o fuso sai uma vez, no fim da mensagem.
801
+ if ((0, runtime_profiles_1.perfisComHorario)(store))
802
+ console.log((0, horario_1.legendaDoFuso)());
803
+ };
804
+ if (sub === 'list') {
805
+ imprimir();
806
+ return 0;
807
+ }
808
+ if (sub === 'add') {
809
+ const id = args.posicionais[2], runtime = texto(args.opcoes.runtime), dirBruto = texto(args.opcoes.dir);
810
+ if (!id || !runtime || !dirBruto) {
811
+ console.error('uso: ork accounts add <id> --runtime claude-bg|codex --dir <diretorio> [--sem-login]');
812
+ return 2;
813
+ }
814
+ const dir = path.resolve(dirBruto);
815
+ let perfil;
816
+ try {
817
+ // A7: diretorio inacessivel ou de outro usuario e recusado antes de qualquer gravacao no store.
818
+ (0, runtime_profiles_1.prepararDiretorioDoPerfil)(dir);
819
+ const desativado = (0, runtime_profiles_1.lerPerfis)(raiz).perfis.some(p => p.id === id && p.estado === 'desativado');
820
+ perfil = (0, runtime_profiles_1.adicionarPerfil)(raiz, { id, runtime, dir });
821
+ if (desativado)
822
+ console.log(`Perfil ${id} reativado: mesmo id, runtime e diretorio do perfil desativado.`);
823
+ }
824
+ catch (e) {
825
+ console.error(`perfil recusado: ${e.message}`);
826
+ return 1;
827
+ }
828
+ const despacho = (0, runtime_profiles_1.perfilDeDespacho)(perfil);
829
+ const variavel = runtime_profiles_1.VARIAVEL_DO_PERFIL[perfil.runtime];
830
+ // D13: o login do claude e fixado na assinatura (`--claudeai`), nunca no Console de API.
831
+ const comando = perfil.runtime === 'claude-bg' ? ['claude', 'auth', 'login', '--claudeai'] : ['codex', 'login'];
832
+ if (args.opcoes['sem-login'] !== true && process.stdin.isTTY && process.stdout.isTTY) {
833
+ // Login interativo do proprio CLI, com o env do perfil sobre a assinatura higienizada.
834
+ const env = perfil.runtime === 'claude-bg' ? (0, claude_bg_1.ambienteDoPerfil)(despacho) : (0, codex_1.ambienteDoDespacho)(process.env, despacho);
835
+ (0, node_child_process_1.spawnSync)(comando[0], comando.slice(1), { stdio: 'inherit', env });
836
+ }
837
+ else {
838
+ console.log(`Login pendente: rode ${variavel}=${aspasDeShell(dir)} ${comando.join(' ')} e depois ork accounts check ${id}`);
839
+ }
840
+ const auth = conferir(despacho);
841
+ // A14: conferencia inconclusiva nao marca sem-auth; o preflight do proximo despacho confere de novo.
842
+ if (!auth.ok && !auth.transitorio)
843
+ (0, runtime_profiles_1.marcarFalhaDePerfil)(raiz, id, auth.pago
844
+ ? { estado: 'provider-pago', esgotadoAte: null, motivo: 'cost.violation', detalhe: auth.detalhe }
845
+ : { estado: 'sem-auth', esgotadoAte: null, motivo: 'runtime.auth-missing', detalhe: auth.detalhe });
846
+ console.log(`Perfil ${id} (${perfil.runtime}) em ${dir}: ${auth.ok ? 'login de assinatura conferido'
847
+ : auth.transitorio ? `conferencia de login inconclusiva (${auth.detalhe}); o proximo despacho confere de novo`
848
+ : auth.pago ? `provider pago (${auth.detalhe}); nunca recebe despacho` : `sem login (${auth.detalhe}); fora do rodizio`}`);
849
+ return 0;
850
+ }
851
+ if (sub === 'remove') {
852
+ const id = args.posicionais[2];
853
+ if (!id) {
854
+ console.error('uso: ork accounts remove <id>');
855
+ return 2;
856
+ }
857
+ try {
858
+ (0, runtime_profiles_1.desativarPerfil)(raiz, id);
859
+ }
860
+ catch (e) {
861
+ console.error(e.message);
862
+ return 1;
863
+ }
864
+ console.log(`Perfil ${id} desativado: o diretorio e o login do CLI ficam onde estao.`);
865
+ return 0;
866
+ }
867
+ if (sub === 'check') {
868
+ const alvo = args.posicionais[2];
869
+ const perfis = (0, runtime_profiles_1.lerPerfis)(raiz).perfis.filter(p => p.estado !== 'desativado' && (alvo === undefined || p.id === alvo));
870
+ if (alvo !== undefined && perfis.length === 0) {
871
+ console.error(`perfil ativo "${alvo}" nao existe (veja: ork accounts list)`);
872
+ return 1;
873
+ }
874
+ let falhas = 0;
875
+ for (const p of perfis) {
876
+ const auth = conferir((0, runtime_profiles_1.perfilDeDespacho)(p));
877
+ if (auth.ok && (p.estado === 'sem-auth' || p.estado === 'provider-pago'))
878
+ (0, runtime_profiles_1.reativarPerfil)(raiz, p.id);
879
+ if (!auth.ok)
880
+ falhas++;
881
+ if (!auth.ok && auth.transitorio)
882
+ (0, runtime_profiles_1.registrarConferenciaInconclusiva)(raiz, p.id, auth.detalhe);
883
+ else if (!auth.ok) {
884
+ (0, runtime_profiles_1.marcarFalhaDePerfil)(raiz, p.id, auth.pago
885
+ ? { estado: 'provider-pago', esgotadoAte: null, motivo: 'cost.violation', detalhe: auth.detalhe }
886
+ : { estado: 'sem-auth', esgotadoAte: null, motivo: 'runtime.auth-missing', detalhe: auth.detalhe });
887
+ }
888
+ console.log(`${p.id} (${p.runtime}): ${auth.ok ? 'login de assinatura conferido'
889
+ : auth.transitorio ? `conferencia de login inconclusiva, estado mantido (${auth.detalhe})`
890
+ : auth.pago ? `provider pago, nunca despacha (${auth.detalhe})` : `sem login (${auth.detalhe})`}`);
891
+ }
892
+ console.log('');
893
+ imprimir();
894
+ return falhas > 0 ? 1 : 0;
895
+ }
896
+ console.error(`subcomando desconhecido: accounts ${sub} (use list, add, remove ou check)`);
897
+ return 2;
898
+ }
899
+ function comandoSetup(args) {
900
+ const carregado = (0, manifest_1.exigirManifesto)();
901
+ const raiz = carregado.raiz;
902
+ const modoBruto = args.posicionais[1];
903
+ const por = texto(args.opcoes.por) ?? 'owner';
904
+ if (modoBruto === 'versionar') {
905
+ // I-52 (RM-047): o setup que vale agora vai para orkastery.setup.json, para entrar por PR.
906
+ const r = (0, setup_1.versionarSetup)(raiz, por);
907
+ if (args.opcoes.json === true) {
908
+ console.log(JSON.stringify({ caminho: r.caminho, setup: r.setup }, null, 2));
909
+ return 0;
910
+ }
911
+ console.log(`Setup versionado em ${r.caminho}.`);
912
+ console.log(' Leve para o repositorio por PR: dali em diante ele vale em todas as maquinas, e ork setup <modo> --bloco N passa a editar este arquivo.');
913
+ return 0;
914
+ }
915
+ if (!modoBruto) {
916
+ if (args.opcoes.reset === true) {
917
+ (0, setup_1.resetarSetup)(raiz, undefined, por);
918
+ if (args.opcoes.json === true) {
919
+ console.log(JSON.stringify((0, setup_1.lerSetup)(raiz), null, 2));
920
+ return 0;
921
+ }
922
+ console.log('Setup resetado: todos os blocos de todos os modos voltaram ao default.');
923
+ console.log((0, setup_1.textoDaEntrevista)(raiz));
924
+ return 0;
925
+ }
926
+ console.log(args.opcoes.json === true ? JSON.stringify((0, setup_1.lerSetup)(raiz), null, 2) : (0, setup_1.textoDaEntrevista)(raiz));
927
+ return 0;
928
+ }
929
+ const modo = (0, modos_1.parseModo)(modoBruto);
930
+ if (!modo) {
931
+ console.error(`modo de conducao desconhecido: "${modoBruto}" (aceitos: ${modos_1.ORDEM_DOS_MODOS.join(', ')})`);
932
+ return 2;
933
+ }
934
+ if (args.opcoes.reset === true) {
935
+ (0, setup_1.resetarSetup)(raiz, modo, por);
936
+ if (args.opcoes.json === true) {
937
+ console.log(JSON.stringify((0, setup_1.lerSetup)(raiz).modos[modo], null, 2));
938
+ return 0;
939
+ }
940
+ console.log(`Setup do modo ${modos_1.MODOS[modo].tag} resetado para o default.`);
941
+ console.log('');
942
+ console.log((0, setup_1.textoDoSetup)(raiz, modo));
943
+ return 0;
944
+ }
945
+ const bloco = texto(args.opcoes.bloco);
946
+ const runtime = texto(args.opcoes.runtime);
947
+ const model = texto(args.opcoes.model);
948
+ const effort = texto(args.opcoes.effort);
949
+ // I-33 (D6): `--fallback runtime:modelo[:esforco],...`; `--fallback ""` remove a ordem.
950
+ const fallbackBruto = args.opcoes.fallback === true ? '' : texto(args.opcoes.fallback);
951
+ const fallback = fallbackBruto === undefined ? undefined : fallbackBruto.split(',').map(s => s.trim()).filter(s => s !== '');
952
+ if (bloco === undefined && (runtime !== undefined || model !== undefined || effort !== undefined || fallback !== undefined)) {
953
+ console.error('para editar, informe o bloco: ork setup <modo> --bloco N [--runtime R] [--model M] [--effort E] [--fallback R:M,...]');
954
+ return 2;
955
+ }
956
+ if (bloco !== undefined) {
957
+ if (runtime === undefined && model === undefined && effort === undefined && fallback === undefined) {
958
+ console.error('nada para editar: informe --runtime, --model, --effort e/ou --fallback junto de --bloco');
959
+ return 2;
960
+ }
961
+ const r = (0, setup_1.editarBloco)(raiz, modo, Number(bloco), { runtime, model, effort, ...(fallback !== undefined ? { fallback } : {}) }, por);
962
+ if (!r.ok) {
963
+ console.error(`edicao recusada: ${r.erro}`);
964
+ return 1;
965
+ }
966
+ if (args.opcoes.json === true) {
967
+ console.log(JSON.stringify(r.setup.modos[modo], null, 2));
968
+ return 0;
969
+ }
970
+ console.log(`Bloco ${r.bloco} do modo ${modos_1.MODOS[modo].tag}: ` +
971
+ `${r.de?.runtime}/${r.de?.model}/${r.de?.effort} -> ${r.para?.runtime}/${r.para?.model}/${r.para?.effort}`);
972
+ console.log(` gravado em ${r.caminho}; evento setup_configured no ledger do projeto`);
973
+ console.log('');
974
+ console.log((0, setup_1.textoDoSetup)(raiz, modo));
975
+ return 0;
976
+ }
977
+ console.log(args.opcoes.json === true ? JSON.stringify((0, setup_1.lerSetup)(raiz).modos[modo], null, 2) : (0, setup_1.textoDoSetup)(raiz, modo));
978
+ return 0;
979
+ }
395
980
  function comandoPhase(args) {
396
981
  const sub = args.posicionais[1];
397
982
  const carregado = (0, manifest_1.exigirManifesto)();
398
983
  if (sub === 'run') {
984
+ avisarChavesDePerfis(carregado);
399
985
  const id = args.posicionais[2];
400
986
  const faseBruta = args.posicionais[3];
401
987
  const prompt = texto(args.opcoes.prompt);
@@ -405,21 +991,37 @@ function comandoPhase(args) {
405
991
  }
406
992
  const thread = (0, thread_1.lerThread)(carregado.raiz, id);
407
993
  const fase = (0, thread_1.exigirFase)(thread, faseBruta);
994
+ const conducao = conducaoDoCli(args);
408
995
  const r = (0, phase_1.rodarFase)(carregado, id, {
409
996
  fase,
410
997
  prompt,
998
+ runtime: texto(args.opcoes.runtime),
411
999
  model: texto(args.opcoes.model),
412
1000
  effort: texto(args.opcoes.effort),
413
1001
  dryRun: args.opcoes['dry-run'] === true,
1002
+ canal: conducao.canal,
1003
+ ...(conducao.correlacao ? { correlacao: conducao.correlacao } : {}),
1004
+ ...(conducao.esperarMs ? { esperarMs: conducao.esperarMs } : {}),
414
1005
  });
415
- if (r.dryRun) {
1006
+ // I-36 (T12, T14): pedido repetido e segundo pedido tem resposta propria, antes dos outros gates.
1007
+ if (r.idempotente && r.conducao) {
1008
+ console.log((0, conducao_1.textoDoPedidoRepetido)(id, r.conducao));
1009
+ return 0;
1010
+ }
1011
+ if (r.motivo === 'conducao.em-andamento') {
1012
+ console.log(args.opcoes.json === true && r.recusa ? JSON.stringify(r.recusa, null, 2) : r.recusa?.texto ?? r.erro);
1013
+ return 3;
1014
+ }
1015
+ if (r.dryRun && !r.bloqueado) {
416
1016
  console.log('Simulacao (--dry-run), nada foi despachado.');
417
1017
  console.log(` slug da sessao : ${r.slug}`);
418
1018
  console.log(` prompt : ${r.promptPath}`);
419
1019
  console.log(` sha256 : ${r.promptSha256}`);
420
1020
  console.log(` pausa ao fim : ${r.pausaAoFim ? 'sim' : 'nao'}`);
1021
+ console.log(` runtime : ${r.runtime}`);
421
1022
  console.log(` modelo/esforco : ${r.model}/${r.effort}`);
422
- console.log(` comando : claude --bg "<prompt>" --name ${r.slug} ...`);
1023
+ // O prompt inteiro nao cabe na tela: o argumento longo aparece mascarado.
1024
+ console.log(` comando : ${r.comando.map((c) => (c.length > 80 ? '"<prompt>"' : c)).join(' ')}`);
423
1025
  return 0;
424
1026
  }
425
1027
  if (r.bloqueado) {
@@ -432,7 +1034,8 @@ function comandoPhase(args) {
432
1034
  return 1;
433
1035
  }
434
1036
  if (!r.sessionId) {
435
- console.error(`Despacho falhou: ${r.erro}`);
1037
+ // I-35: o erro vai ao ledger com o ISO; o dono le no fuso dele, com o fuso dito uma vez.
1038
+ console.error(`Despacho falhou: ${r.erro ? (0, horario_1.localizarTextoRotulado)(r.erro) : r.erro}`);
436
1039
  console.error(` evento registrado no ledger de ${id}`);
437
1040
  return 1;
438
1041
  }
@@ -441,11 +1044,17 @@ function comandoPhase(args) {
441
1044
  console.log(` slug da sessao : ${r.slug} (${(0, phase_1.descreverSlug)(r.slug)})`);
442
1045
  console.log(` prompt : ${r.promptPath}`);
443
1046
  console.log(` sha256 : ${r.promptSha256}`);
1047
+ console.log(` runtime : ${r.runtime}`);
444
1048
  console.log(` modelo/esforco : ${r.model}/${r.effort} (gravado no ledger, veja \`ork phase list\`)`);
445
1049
  console.log(` verificada no runtime: ${r.verificada ? 'sim' : 'NAO (confira `ork sessions`)'}`);
446
1050
  console.log(` pausa ao fim do bloco: ${r.pausaAoFim ? 'sim' : 'nao (decisao autonoma no ledger)'}`);
447
1051
  console.log('');
448
- console.log(`Acompanhe: claude attach ${r.sessionId} | ork phase list ${id}`);
1052
+ if (r.runtime === 'claude-bg') {
1053
+ console.log(`Acompanhe: claude attach ${r.sessionId} | ork phase list ${id}`);
1054
+ }
1055
+ else {
1056
+ console.log(`Acompanhe: ork phase list ${id} (eventos do despacho no log da thread)`);
1057
+ }
449
1058
  return r.verificada ? 0 : 1;
450
1059
  }
451
1060
  if (sub === 'list') {
@@ -460,12 +1069,137 @@ function comandoPhase(args) {
460
1069
  console.error(`subcomando desconhecido: phase ${sub}`);
461
1070
  return 2;
462
1071
  }
1072
+ function comandoLedger(args) {
1073
+ const carregado = (0, manifest_1.exigirManifesto)();
1074
+ const sub = args.posicionais[1];
1075
+ if (sub === 'stats') {
1076
+ const desde = texto(args.opcoes.desde);
1077
+ if (!desde)
1078
+ throw Error('uso: ork ledger stats --desde 7d [--ate ISO] [--thread T] [--modo M] [--runtime R] [--json]');
1079
+ const r = (0, ledger_stats_1.coletarEstatisticas)(carregado.raiz, { desde, ate: texto(args.opcoes.ate), thread: texto(args.opcoes.thread), modo: texto(args.opcoes.modo), runtime: texto(args.opcoes.runtime) });
1080
+ console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2) : (0, ledger_stats_1.textoDasEstatisticas)(r));
1081
+ return 0;
1082
+ }
1083
+ if (sub === 'estimate') {
1084
+ const thread = args.posicionais[2], semIa = Number(texto(args.opcoes['sem-ia'])), iaSemOrk = Number(texto(args.opcoes['ia-sem-ork']));
1085
+ const por = texto(args.opcoes.por), metodo = texto(args.opcoes.metodo), premissas = texto(args.opcoes.premissas);
1086
+ if (!thread || !por || !metodo || !premissas)
1087
+ throw Error('uso: ork ledger estimate <thread-id> --sem-ia H --ia-sem-ork H --por Q --metodo M --premissas P [--incerteza I]');
1088
+ const e = (0, ledger_stats_1.registrarEstimativaPlano)(carregado.raiz, thread, { semIaHoras: semIa, iaSemOrkHoras: iaSemOrk, por, metodo, premissas, incerteza: texto(args.opcoes.incerteza) });
1089
+ console.log(args.opcoes.json === true ? JSON.stringify(e, null, 2) : `Estimativa PLAN registrada em ${thread}: sem IA ${semIa} h; IA sem Orkastery ${iaSemOrk} h.`);
1090
+ return 0;
1091
+ }
1092
+ throw Error('uso: ork ledger stats|estimate ...');
1093
+ }
1094
+ /**
1095
+ * `ork sessions hitl`: quem, entre as sessoes do runtime, espera o humano AGORA.
1096
+ *
1097
+ * Complementa o `ork monitor`, que e thread-centrico: aqui a varredura parte das SESSOES,
1098
+ * entao ela enxerga a sessao `claude --bg` que travou em HITL sem ter thread nenhuma --
1099
+ * o buraco exato do incidente de 05/09/2026 (codigo 2FA do `npm publish`).
1100
+ *
1101
+ * O `--exigir-limpo` transforma o radar em watchdog: sai != 0 enquanto houver sessao
1102
+ * esperando humano, entao um cron ou o proprio orquestrador trata "tem gente esperando"
1103
+ * como falha acionavel, sem precisar interpretar texto.
1104
+ */
1105
+ function comandoSessionsHitl(args, raiz) {
1106
+ const bruto = texto(args.opcoes.atencao);
1107
+ const atencaoMin = bruto === undefined ? undefined : Number(bruto);
1108
+ if (atencaoMin !== undefined && (!Number.isFinite(atencaoMin) || atencaoMin < 0)) {
1109
+ console.error(`--atencao espera minutos (inteiro >= 0), recebeu "${bruto}"`);
1110
+ return 2;
1111
+ }
1112
+ const radar = (0, hitl_1.varrerSessoes)({
1113
+ raiz,
1114
+ registrar: args.opcoes.registrar === true,
1115
+ escopo: texto(args.opcoes.escopo)?.split(',').map(s => s.trim()),
1116
+ registrarMaquina: args.opcoes['registrar-maquina'] === true,
1117
+ linhasLogs: texto(args.opcoes.linhas) === undefined ? undefined : Number(texto(args.opcoes.linhas)),
1118
+ soDaRaiz: args.opcoes['so-da-raiz'] === true,
1119
+ soParadas: args.opcoes['so-paradas'] === true,
1120
+ semLogs: args.opcoes['sem-logs'] === true,
1121
+ atencaoMin,
1122
+ });
1123
+ console.log(args.opcoes.json === true ? JSON.stringify(radar, null, 2) : (0, hitl_1.textoDoRadar)(radar));
1124
+ if (!radar.runtimeConsultado)
1125
+ return 1;
1126
+ if (args.opcoes['exigir-limpo'] === true)
1127
+ return radar.resumo.precisamDeHumano > 0 ? 1 : 0;
1128
+ return 0;
1129
+ }
463
1130
  function comandoSessions(args) {
464
1131
  const sub = args.posicionais[1];
465
1132
  const carregado = (0, manifest_1.carregarManifesto)();
466
1133
  const raiz = carregado?.raiz ?? process.cwd();
1134
+ if (sub === 'watch') {
1135
+ const id = texto(args.opcoes.thread);
1136
+ if (!carregado || !id) {
1137
+ console.error('uso: ork sessions watch --thread T [--sessao ID] [--once]');
1138
+ return 2;
1139
+ }
1140
+ const thread = (0, thread_1.lerThread)(raiz, id);
1141
+ const sessionId = texto(args.opcoes.sessao) ?? thread.sessoes.at(-1)?.sessionId;
1142
+ if (!sessionId || !thread.sessoes.some(s => s.sessionId === sessionId))
1143
+ throw new Error('sessão não pertence à thread');
1144
+ console.log(JSON.stringify(args.opcoes.once === true ? (0, session_watcher_1.observarSessao)(carregado, sessionId) : { pid: (0, session_watcher_1.iniciarWatcher)(raiz, sessionId) }));
1145
+ return 0;
1146
+ }
1147
+ if (sub === 'event') {
1148
+ const tipo = texto(args.opcoes.tipo), sessao = texto(args.opcoes.sessao);
1149
+ if (!carregado || !tipo || !sessao) {
1150
+ console.error('uso: ork sessions event --tipo <tipo> --sessao <id> < payload.json (máximo 16384 bytes)');
1151
+ return 2;
1152
+ }
1153
+ try {
1154
+ console.log(JSON.stringify((0, session_events_1.ingerirEvento)(raiz, sessao, tipo, (0, session_events_1.lerPayloadSensor)())));
1155
+ return 0;
1156
+ }
1157
+ catch (e) {
1158
+ console.error(`evento recusado: ${e.message}`);
1159
+ return 1;
1160
+ }
1161
+ }
467
1162
  if (sub === undefined || sub === 'list') {
468
- console.log((0, sessoes_1.tabelaDeSessoes)(raiz, args.opcoes.all === true));
1163
+ const r = (0, sessoes_inventario_1.inventariarSessoes)(raiz, { todas: args.opcoes.all === true, global: args.opcoes.global === true });
1164
+ console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2) : (0, sessoes_1.textoDoInventario)(r));
1165
+ return !r.ok || (args.opcoes['exigir-limpo'] === true && r.semThread > 0) ? 1 : 0;
1166
+ }
1167
+ if (sub === 'hitl') {
1168
+ return comandoSessionsHitl(args, carregado ? raiz : '');
1169
+ }
1170
+ if (sub === 'request') {
1171
+ const id = args.posicionais[2], sessionId = args.posicionais[3];
1172
+ const fase = texto(args.opcoes.fase), runtime = texto(args.opcoes.runtime), pergunta = texto(args.opcoes.pergunta);
1173
+ if (!id || !sessionId || !fase || !types_1.FASES.includes(fase) || !runtime)
1174
+ throw new Error('sessions request exige thread, UUID, --fase e --runtime; --pergunta só confere o conteúdo nativo');
1175
+ console.log(JSON.stringify((0, hitl_sessions_1.abrirPedidoSessao)(raiz, id, sessionId, { fase: fase, runtime, pergunta, prazo: texto(args.opcoes.prazo) })));
1176
+ return 0;
1177
+ }
1178
+ if (sub === 'answer') {
1179
+ const id = args.posicionais[2], pedido = args.posicionais[3];
1180
+ if (!id || !pedido || args.opcoes.stdin !== true)
1181
+ throw new Error('sessions answer exige thread, pedido e envelope autenticado em --stdin');
1182
+ const r = (0, hitl_gates_1.lerRespostaStdin)({ origem: texto(args.opcoes.origem), por: texto(args.opcoes.por),
1183
+ mensagem: texto(args.opcoes.mensagem), canal: texto(args.opcoes.canal), conta: texto(args.opcoes.conta) });
1184
+ console.log(JSON.stringify((0, hitl_sessions_1.responderSessao)(raiz, id, pedido, r)));
1185
+ return 0;
1186
+ }
1187
+ if (sub === 'reconcile') {
1188
+ // FX3: fecha um envio pendente so com (thread, pedido). Nao reenvia e nao re-elicita:
1189
+ // pergunta ao receptor, pelo recibo correlacionado, se ele recebeu aquele envioId.
1190
+ const id = args.posicionais[2], pedido = args.posicionais[3];
1191
+ if (!id || !pedido)
1192
+ throw new Error('sessions reconcile exige thread e pedido');
1193
+ const r = (0, hitl_sessions_1.reconciliarEnvioDeSessao)(raiz, id, pedido);
1194
+ console.log(JSON.stringify(r));
1195
+ return r.estado === 'entregue' ? 0 : 1;
1196
+ }
1197
+ if (sub === 'supersede') {
1198
+ const id = args.posicionais[2], sessionId = args.posicionais[3];
1199
+ const fase = texto(args.opcoes.fase), runtime = texto(args.opcoes.runtime);
1200
+ if (!id || !sessionId || !fase || !types_1.FASES.includes(fase) || !runtime)
1201
+ throw new Error('sessions supersede exige thread, UUID, --fase e --runtime');
1202
+ console.log(JSON.stringify((0, hitl_sessions_1.superarSessao)(raiz, id, sessionId, fase, runtime)));
469
1203
  return 0;
470
1204
  }
471
1205
  const chave = args.posicionais[2];
@@ -473,25 +1207,110 @@ function comandoSessions(args) {
473
1207
  console.error(`uso: ork sessions ${sub} <sessao>`);
474
1208
  return 2;
475
1209
  }
1210
+ if (sub === 'adopt') {
1211
+ const r = (0, sessoes_adopt_1.adotarSessao)((0, manifest_1.exigirManifesto)(), chave);
1212
+ console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2) :
1213
+ `${r.detalhe}${r.vinculo ? `: ${r.sessionId} -> ${r.vinculo.thread} (${r.vinculo.raiz})` : ''}`);
1214
+ return r.ok ? 0 : 1;
1215
+ }
476
1216
  if (sub === 'logs') {
477
1217
  const n = Number(texto(args.opcoes.linhas) ?? '60');
478
- const r = (0, sessoes_1.logsDaSessao)(chave, Number.isFinite(n) ? n : 60);
1218
+ const r = (0, sessoes_2.logsDaSessao)(chave, Number.isFinite(n) ? n : 60);
479
1219
  console.log(r.texto);
480
1220
  return r.codigo;
481
1221
  }
482
1222
  if (sub === 'stop') {
483
- const r = (0, sessoes_1.pararSessao)(chave);
1223
+ const r = (0, sessoes_2.pararSessao)(chave);
484
1224
  console.log(r.texto);
485
1225
  return r.codigo;
486
1226
  }
487
1227
  if (sub === 'attach') {
488
- const r = (0, sessoes_1.comandoDeAttach)(chave);
1228
+ const r = (0, sessoes_2.comandoDeAttach)(chave);
489
1229
  console.log(r.texto);
490
1230
  return r.codigo;
491
1231
  }
492
1232
  console.error(`subcomando desconhecido: sessions ${sub}`);
493
1233
  return 2;
494
1234
  }
1235
+ /**
1236
+ * I-41 (GO-FIX 1, B4): a decisao que a sessao toma sem perguntar ao dono vai ao ledger por aqui,
1237
+ * com o que foi decidido, o porque, como mudar, o custo de reverter, o criterio escrito, quem
1238
+ * decidiu e a evidencia. E assim que ela chega ao dono no resumo, em vez de sumir na conversa.
1239
+ */
1240
+ function comandoDecisao(args) {
1241
+ const carregado = (0, manifest_1.exigirManifesto)();
1242
+ const sub = args.posicionais[1], id = args.posicionais[2];
1243
+ if (sub === 'registrar') {
1244
+ const campo = (nome) => {
1245
+ const v = texto(args.opcoes[nome]);
1246
+ if (!v)
1247
+ throw new Error(`decisao registrar exige --${nome}`);
1248
+ return v;
1249
+ };
1250
+ if (!id)
1251
+ throw new Error('uso: ork decisao registrar <thread-id> --decidido D --porque P ...');
1252
+ const bruto = campo('criterio'), separador = bruto.indexOf(':');
1253
+ const tipo = bruto.slice(0, separador), referencia = bruto.slice(separador + 1);
1254
+ if (separador < 1 || !['manifesto', 'ledger', 'medicao'].includes(tipo) || !referencia.trim()) {
1255
+ throw new Error('decisao registrar: --criterio manifesto:CHAVE, ledger:REF ou medicao:COMANDO');
1256
+ }
1257
+ const { pedido, evento } = (0, decisao_autonoma_1.registrarDecisao)(carregado.raiz, id, {
1258
+ decidido: campo('decidido'), porque: campo('porque'), comoMudar: campo('como-mudar'),
1259
+ custoDeReverter: { agora: campo('custo-agora'), depois: campo('custo-depois') },
1260
+ criterio: { tipo, referencia }, quemDecidiu: campo('quem'), evidencia: campo('evidencia'),
1261
+ razao: texto(args.opcoes.razao), reverte: texto(args.opcoes.reverte),
1262
+ });
1263
+ const placar = (0, decisao_autonoma_1.placarDaThread)((0, ledger_1.lerLedger)((0, thread_1.dirThread)(carregado.raiz, id))).find(f => f.fase === pedido.fase);
1264
+ console.log(JSON.stringify({ ok: true, pedidoId: pedido.id, eventId: evento.eventId, fase: pedido.fase, placar }));
1265
+ return 0;
1266
+ }
1267
+ if (sub === 'placar') {
1268
+ if (!id)
1269
+ throw new Error('uso: ork decisao placar <thread-id> [--json]');
1270
+ (0, thread_1.lerThread)(carregado.raiz, id);
1271
+ const placar = (0, decisao_autonoma_1.placarDaThread)((0, ledger_1.lerLedger)((0, thread_1.dirThread)(carregado.raiz, id)));
1272
+ const taxa = (0, decisao_autonoma_1.taxaDeReversao)(placar);
1273
+ if (args.opcoes.json === true) {
1274
+ console.log(JSON.stringify({ thread: id, limiar: decisao_autonoma_1.LIMIAR_DE_DECISOES_POR_FASE, taxaDeReversao: taxa, fases: placar }, null, 2));
1275
+ return 0;
1276
+ }
1277
+ console.log((0, util_1.tabela)(['FASE', 'DECIDIDAS', 'INFORMADAS', 'PERGUNTAS', 'REVERTIDAS', 'SEM RASTRO', 'LIMIAR'], placar.map(f => [f.fase, String(f.decididas), String(f.informadas), String(f.perguntas), String(f.revertidas),
1278
+ String(f.semRastro), f.acimaDoLimiar ? `acima de ${decisao_autonoma_1.LIMIAR_DE_DECISOES_POR_FASE}: revisar` : 'ok'])));
1279
+ console.log(`\ntaxa de reversão das decisões informadas: ${taxa === null ? 'sem decisão informada ainda' : `${Math.round(taxa * 100)}%`}`);
1280
+ return 0;
1281
+ }
1282
+ throw new Error('uso: ork decisao registrar|placar <thread-id>');
1283
+ }
1284
+ /**
1285
+ * I-50 (RM-039): a tag que o dono manda no Telegram, pelo terminal. Sem tag, mostra a cadencia em
1286
+ * vigor. O `#` e opcional porque o shell trata `#` no inicio da palavra como comentario.
1287
+ */
1288
+ function comandoCadenciaDoPulse(args) {
1289
+ const carregado = (0, manifest_1.exigirManifesto)();
1290
+ if (args.posicionais.length > 3)
1291
+ throw new Error('pulse cadencia: uma tag por vez');
1292
+ const bruta = args.posicionais[2];
1293
+ const agora = new Date().toISOString();
1294
+ if (bruta !== undefined) {
1295
+ const lido = (0, pulse_resposta_1.interpretarRespostaDoPulse)(bruta.trim().startsWith('#') ? bruta : `#${bruta.trim()}`);
1296
+ if (lido.forma !== 'cadencia') {
1297
+ throw new Error(`pulse cadencia: tag desconhecida "${bruta}"; use ${Object.keys(pulse_cadencia_1.CADENCIAS).join(', ')}`);
1298
+ }
1299
+ (0, pulse_cadencia_1.gravarCadencia)(carregado.raiz, lido.tag, { por: texto(args.opcoes.por) ?? (0, node_os_1.userInfo)().username,
1300
+ canal: texto(args.opcoes.canal) ?? 'terminal', em: agora });
1301
+ }
1302
+ const vigente = (0, pulse_cadencia_1.lerCadencia)(carregado.raiz);
1303
+ if (args.opcoes.json === true) {
1304
+ console.log(JSON.stringify({ tag: vigente.tag, janelaMin: vigente.janelaMin, ancoraMin: vigente.ancoraMin,
1305
+ descricao: vigente.descricao, gravada: vigente.gravada, proximaJanela: (0, pulse_cadencia_1.inicioDaProximaJanela)(vigente, agora) }, null, 2));
1306
+ return 0;
1307
+ }
1308
+ console.log((0, pulse_cadencia_1.textoDaCadencia)(vigente, agora));
1309
+ console.log(vigente.gravada
1310
+ ? `Trocada por ${vigente.gravada.por} (${vigente.gravada.canal}) em ${(0, horario_1.formatarDataHoraRotulada)(vigente.gravada.em)}.`
1311
+ : 'Nenhuma tag gravada: vale a cadência padrão.');
1312
+ return 0;
1313
+ }
495
1314
  function comandoClaims(args) {
496
1315
  const carregado = (0, manifest_1.exigirManifesto)();
497
1316
  const sub = args.posicionais[1];
@@ -522,6 +1341,11 @@ function comandoClaims(args) {
522
1341
  console.log('');
523
1342
  console.log('AVISO: alegacao negativa sem comando de verificacao reprova em `ork verify`.');
524
1343
  }
1344
+ // I-53 (RM-037, P6): o lint avisa aqui; a suite inteira e recusada no `ci prepare`.
1345
+ for (const a of claim.lint ?? []) {
1346
+ console.log('');
1347
+ console.log(`AVISO: ${(0, claim_lint_1.linhaDoLintDeClaim)(claim.id, a)}${a.regra === 'suite-inteira' ? '. O `ci prepare` recusa esta claim.' : ''}`);
1348
+ }
525
1349
  return 0;
526
1350
  }
527
1351
  if (sub === 'verificar') {
@@ -555,6 +1379,19 @@ function comandoClaims(args) {
555
1379
  console.log(' o historico da alegacao continua no claims.jsonl e no ledger.');
556
1380
  return 0;
557
1381
  }
1382
+ if (sub === 'ausente') {
1383
+ const id = args.posicionais[2];
1384
+ const paths = (texto(args.opcoes.paths) ?? '').split(',').map((p) => p.trim()).filter(Boolean);
1385
+ const motivo = texto(args.opcoes.motivo);
1386
+ if (!id || paths.length === 0 || !motivo) {
1387
+ console.error('uso: ork claims ausente <thread-id> --paths A,B --motivo "<motivo>" [--commit SHA]');
1388
+ return 2;
1389
+ }
1390
+ (0, prova_minima_1.registrarProvaAusente)(carregado.raiz, id, { paths, motivo, commit: texto(args.opcoes.commit) });
1391
+ console.log(`Ausencia de prova registrada na thread ${id}: ${paths.join(', ')}.`);
1392
+ console.log(` motivo ${motivo}`);
1393
+ return 0;
1394
+ }
558
1395
  if (sub === 'list' || sub === undefined) {
559
1396
  const id = args.posicionais[2];
560
1397
  if (!id) {
@@ -571,11 +1408,12 @@ function comandoVerify(args) {
571
1408
  const carregado = (0, manifest_1.exigirManifesto)();
572
1409
  const id = args.posicionais[1];
573
1410
  if (!id) {
574
- console.error('uso: ork verify <thread-id> [--baseline] [--so-claims]');
1411
+ console.error('uso: ork verify <thread-id> [--baseline] [--so-claims] [--canal C] [--esperar [min]]');
575
1412
  return 2;
576
1413
  }
1414
+ const conducao = conducaoDoCli(args);
577
1415
  if (args.opcoes.baseline === true) {
578
- const b = (0, verify_1.gravarBaseline)(carregado, id);
1416
+ const b = (0, verify_1.gravarBaseline)(carregado, id, undefined, conducao);
579
1417
  console.log(`Baseline gravada para a thread ${id}.`);
580
1418
  console.log(` commit ${b.commit}`);
581
1419
  for (const c of b.comandos) {
@@ -586,13 +1424,67 @@ function comandoVerify(args) {
586
1424
  }
587
1425
  return 0;
588
1426
  }
589
- const r = (0, verify_1.verificar)(carregado, id, { soClaims: args.opcoes['so-claims'] === true });
1427
+ const r = (0, verify_1.verificar)(carregado, id, { soClaims: args.opcoes['so-claims'] === true, conducao });
590
1428
  console.log((0, verify_1.textoDoVerify)(r));
591
1429
  return r.ok ? 0 : 1;
592
1430
  }
1431
+ /**
1432
+ * `ork conducao status|assumir` (I-36, T15): quem conduz a thread agora, e o handoff explicito. O
1433
+ * status tambem libera, com prova no ledger, a conducao que ficou sem dono (T16).
1434
+ */
1435
+ function comandoConducao(args) {
1436
+ const carregado = (0, manifest_1.exigirManifesto)();
1437
+ const sub = args.posicionais[1];
1438
+ const id = args.posicionais[2];
1439
+ if (sub === 'status') {
1440
+ if (!id)
1441
+ throw new Error('uso: ork conducao status <thread-id> [--json]');
1442
+ (0, thread_1.lerThread)(carregado.raiz, id);
1443
+ (0, conducao_1.liberarSeOrfa)(carregado.raiz, id);
1444
+ const atual = (0, conducao_1.conducaoDaThread)(carregado.raiz, id);
1445
+ console.log(args.opcoes.json === true ? JSON.stringify({ thread: id, conducao: atual }, null, 2) : (0, conducao_1.textoDoStatusDaConducao)(id, atual));
1446
+ return 0;
1447
+ }
1448
+ if (sub === 'assumir') {
1449
+ const por = texto(args.opcoes.por), motivo = texto(args.opcoes.motivo);
1450
+ if (!id || !por || !motivo)
1451
+ throw new Error('uso: ork conducao assumir <thread-id> --por <quem> --motivo "<por que>" [--canal C]');
1452
+ const r = (0, conducao_1.assumirConducao)(carregado.raiz, id, { por, motivo, canal: conducaoDoCli(args).canal });
1453
+ console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2) : `${r.ok ? 'Conducao assumida.' : 'Handoff recusado.'} ${r.detalhe}`);
1454
+ return r.ok ? 0 : 3;
1455
+ }
1456
+ throw new Error('uso: ork conducao status|assumir <thread-id>');
1457
+ }
593
1458
  function comandoGate(args) {
594
1459
  const carregado = (0, manifest_1.exigirManifesto)();
595
1460
  const sub = args.posicionais[1];
1461
+ if (sub === 'context') {
1462
+ const id = args.posicionais[2], pedido = args.posicionais[3];
1463
+ if (!id || !pedido || args.posicionais.length !== 4 ||
1464
+ Object.entries(args.opcoes).some(([k, v]) => k !== 'native-offer-stdin' || v !== true))
1465
+ throw Error('uso: ork gate context <thread> <pedido> [--native-offer-stdin]');
1466
+ const view = (0, hitl_gates_1.contextoDoPedidoNativo)(carregado.raiz, id, pedido);
1467
+ const callback = args.opcoes['native-offer-stdin'] ? (0, hitl_native_offer_1.readNativeOfferStdin)() : undefined;
1468
+ console.log(JSON.stringify({ ...view, canais: (0, hitl_presentation_1.ofertaDoPedido)(view.pedido, [], callback === undefined ? undefined : { callback, raiz: carregado.raiz }),
1469
+ apresentacao: (0, hitl_presentation_1.apresentarDecisao)(view.pedido), prazoLocal: (0, hitl_presentation_1.prazoLocalDoPedido)(view.pedido) }));
1470
+ return 0;
1471
+ }
1472
+ if (sub === 'request') {
1473
+ const id = args.posicionais[2];
1474
+ if (!id)
1475
+ throw new Error('gate request exige thread');
1476
+ console.log(JSON.stringify((0, hitl_gates_1.abrirPedidoGate)(carregado.raiz, id, texto(args.opcoes.motivo))));
1477
+ return 0;
1478
+ }
1479
+ if (sub === 'answer') {
1480
+ const id = args.posicionais[2], pedido = args.posicionais[3];
1481
+ if (!id || !pedido || args.opcoes['resposta-stdin'] !== true || args.opcoes.resposta !== undefined)
1482
+ throw new Error('gate answer exige thread, pedido e --resposta-stdin');
1483
+ const r = (0, hitl_gates_1.lerRespostaStdin)({ por: texto(args.opcoes.por), mensagem: texto(args.opcoes.mensagem),
1484
+ origem: texto(args.opcoes.origem), canal: texto(args.opcoes.canal), conta: texto(args.opcoes.conta) });
1485
+ console.log(JSON.stringify((0, hitl_gates_1.responderGate)(carregado.raiz, id, pedido, r)));
1486
+ return 0;
1487
+ }
596
1488
  if (sub === 'next') {
597
1489
  const id = args.posicionais[2];
598
1490
  if (!id) {
@@ -628,7 +1520,7 @@ function comandoGate(args) {
628
1520
  console.log(`Autorizacao humana registrada no ledger da thread ${id}.`);
629
1521
  console.log(` sobre ${sobre}`);
630
1522
  console.log(` autorizado por ${por}`);
631
- console.log(` quando ${e.ts}`);
1523
+ console.log(` quando ${(0, horario_1.formatarDataHoraRotulada)(e.ts)}`);
632
1524
  return 0;
633
1525
  }
634
1526
  console.error(`subcomando desconhecido: gate ${sub}`);
@@ -694,7 +1586,7 @@ function comandoRetry(args) {
694
1586
  }
695
1587
  console.log('Sinal de rate limit reconhecido no stderr do runtime:');
696
1588
  console.log(` fonte da hora ${sinal.fonte}`);
697
- console.log(` reset em ${sinal.resetEm ?? '(o runtime nao disse a hora)'}`);
1589
+ console.log(` reset em ${sinal.resetEm ? (0, horario_1.formatarDataHoraRotulada)(sinal.resetEm) : '(o runtime nao disse a hora)'}`);
698
1590
  console.log(` trecho ${sinal.trecho}`);
699
1591
  if (sinal.resetEm === null) {
700
1592
  console.log('');
@@ -704,6 +1596,7 @@ function comandoRetry(args) {
704
1596
  return 0;
705
1597
  }
706
1598
  const carregado = (0, manifest_1.exigirManifesto)();
1599
+ avisarChavesDePerfis(carregado);
707
1600
  if (sub === 'plan' || sub === 'run') {
708
1601
  const id = args.posicionais[2];
709
1602
  if (!id) {
@@ -726,6 +1619,10 @@ function comandoRetry(args) {
726
1619
  console.log((0, retry_1.textoDoPlano)(plano));
727
1620
  return 0;
728
1621
  }
1622
+ // I-36 (D2): `--esperar` espera a conducao em andamento terminar antes de executar a retomada.
1623
+ const conducao = conducaoDoCli(args);
1624
+ if (conducao.esperarMs && args.opcoes['dry-run'] !== true)
1625
+ (0, conducao_1.esperarConducaoLivre)(carregado.raiz, id, conducao.esperarMs);
729
1626
  const r = (0, retry_1.executarRetry)(carregado, id, {
730
1627
  ...opcoes,
731
1628
  dryRun: args.opcoes['dry-run'] === true,
@@ -750,7 +1647,7 @@ function comandoRetry(args) {
750
1647
  const espera = (0, ratelimit_1.lerFilaDeRetomada)(carregado.raiz).filter((p) => p.estado === 'aguardando');
751
1648
  if (espera.length > 0) {
752
1649
  console.log('');
753
- console.log(`Proxima janela: ${espera[0].liberaEm} (${(0, ratelimit_1.faltaPara)(espera[0])}).`);
1650
+ console.log(`Proxima janela: ${(0, horario_1.formatarDataHora)(espera[0].liberaEm)} (${(0, ratelimit_1.faltaPara)(espera[0])}).`);
754
1651
  console.log('Retome com: ork retry resume');
755
1652
  }
756
1653
  return 0;
@@ -810,9 +1707,10 @@ function comandoFix(args) {
810
1707
  console.error('uso: ork fix open <thread-id> [--so-claims] [--reverify]');
811
1708
  return 2;
812
1709
  }
813
- const rodada = (0, fix_1.abrirRodada)(carregado, id, { soClaims: args.opcoes['so-claims'] === true });
1710
+ const conducao = conducaoDoCli(args);
1711
+ const rodada = (0, fix_1.abrirRodada)(carregado, id, { soClaims: args.opcoes['so-claims'] === true, conducao });
814
1712
  const reverify = args.opcoes.reverify === true && rodada.correcoes.length > 0
815
- ? (0, fix_1.reverificar)(carregado, id, { rodada: rodada.rodada })
1713
+ ? (0, fix_1.reverificar)(carregado, id, { rodada: rodada.rodada, conducao })
816
1714
  : null;
817
1715
  if (args.opcoes.json === true) {
818
1716
  console.log(JSON.stringify({ rodada, reverify }, null, 2));
@@ -864,6 +1762,7 @@ function comandoFix(args) {
864
1762
  }
865
1763
  const rodadaBruta = texto(args.opcoes.rodada);
866
1764
  const r = (0, fix_1.reverificar)(carregado, id, {
1765
+ conducao: conducaoDoCli(args),
867
1766
  rodada: rodadaBruta ? Number(rodadaBruta) : undefined,
868
1767
  parcial: args.opcoes.parcial === true,
869
1768
  });
@@ -918,6 +1817,30 @@ function comandoHandoff(args) {
918
1817
  }
919
1818
  function comandoShip(args) {
920
1819
  const carregado = (0, manifest_1.exigirManifesto)();
1820
+ if (args.posicionais[1] === 'registrar-pr') {
1821
+ // I-57 (RM-008): a entrega feita por PR vira ship_done, provada no remoto e no CI.
1822
+ const alvo = args.posicionais[2];
1823
+ const remoto = texto(args.opcoes.remoto);
1824
+ if (!alvo && args.opcoes.todas !== true) {
1825
+ console.error('uso: ork ship registrar-pr <thread-id> | --todas [--remoto R] [--json]');
1826
+ return 2;
1827
+ }
1828
+ const r = alvo ? [(0, entrega_pr_1.registrarEntregaPorPr)(carregado, alvo, { remoto })] : (0, entrega_pr_1.registrarEntregasPorPr)(carregado, { remoto });
1829
+ if (args.opcoes.json === true) {
1830
+ console.log(JSON.stringify(r, null, 2));
1831
+ return r.some((x) => x.acao === 'recusada') ? 1 : 0;
1832
+ }
1833
+ if (r.length === 0)
1834
+ console.log('Nenhuma thread aberta com merge ship(<thread>) na base.');
1835
+ for (const x of r)
1836
+ console.log(` ${x.thread.padEnd(20)} ${x.acao.padEnd(13)} ${x.motivo}`);
1837
+ const registradas = r.filter((x) => x.acao === 'registrou').length;
1838
+ if (registradas) {
1839
+ console.log('');
1840
+ console.log(`${registradas} entrega(s) registrada(s). Fechar pelo MASTER: ork master --aceitar-omissao (a nota humana sobrescreve).`);
1841
+ }
1842
+ return r.some((x) => x.acao === 'recusada') ? 1 : 0;
1843
+ }
921
1844
  const id = args.posicionais[1];
922
1845
  const para = texto(args.opcoes.para) ?? texto(args.opcoes.to);
923
1846
  if (!id || !para) {
@@ -937,6 +1860,190 @@ function comandoShip(args) {
937
1860
  console.log((0, ship_1.textoDoShip)(r));
938
1861
  return r.ok ? 0 : 1;
939
1862
  }
1863
+ function comandoPortfolio(args) {
1864
+ const root = (0, manifest_1.exigirManifesto)().raiz;
1865
+ const sub = args.posicionais[1] ?? 'list';
1866
+ if (sub === 'inspect') {
1867
+ const id = args.posicionais[2];
1868
+ if (!id) {
1869
+ console.error('uso: ork portfolio inspect <id> --json');
1870
+ return 2;
1871
+ }
1872
+ console.log(JSON.stringify((0, portfolio_context_1.inspectPortfolio)(root, id), null, 2));
1873
+ return 0;
1874
+ }
1875
+ const aliases = { product: 'product', project: 'project', initiative: 'initiative', prod: 'product', proj: 'project', init: 'initiative' };
1876
+ const split = (value, separator = ',') => value?.split(separator).map((item) => item.trim()).filter(Boolean) ?? [];
1877
+ if (sub === 'list') {
1878
+ const rawKind = args.posicionais[2];
1879
+ const kind = rawKind ? aliases[rawKind] : undefined;
1880
+ if (rawKind && !kind) {
1881
+ console.error('tipo deve ser product, project ou initiative');
1882
+ return 2;
1883
+ }
1884
+ const items = (0, portfolio_1.listEntities)(root, kind, texto(args.opcoes.parent));
1885
+ console.log(args.opcoes.json === true ? JSON.stringify({ schema: 'ork.portfolio-list/v1', updatedAt: (0, portfolio_1.readPortfolio)(root).updatedAt, items }, null, 2)
1886
+ : items.length ? items.map((item) => `${item.id}\t${item.kind}\t${item.status}\t${item.title}`).join('\n') : 'Portfólio vazio.');
1887
+ return 0;
1888
+ }
1889
+ if (sub === 'show') {
1890
+ const id = args.posicionais[2];
1891
+ if (!id) {
1892
+ console.error('uso: ork portfolio show <id>');
1893
+ return 2;
1894
+ }
1895
+ const item = (0, portfolio_1.findEntity)(root, id);
1896
+ if (!item) {
1897
+ console.error(`entidade ${id} não encontrada`);
1898
+ return 1;
1899
+ }
1900
+ console.log(args.opcoes.json === true ? JSON.stringify(item, null, 2) : `${item.id}\n${item.title}\nEstado: ${item.status}`);
1901
+ return 0;
1902
+ }
1903
+ if (sub === 'create') {
1904
+ const kind = aliases[args.posicionais[2] ?? ''];
1905
+ const id = args.posicionais[3], title = texto(args.opcoes.title), parent = texto(args.opcoes.parent);
1906
+ if (!kind || !id || !title) {
1907
+ console.error('uso: ork portfolio create <product|project|initiative> <id> --title T [--parent ID]');
1908
+ return 2;
1909
+ }
1910
+ const common = { id, title, description: texto(args.opcoes.description), ownerId: texto(args.opcoes.owner), status: texto(args.opcoes.status), acceptanceCriteria: split(texto(args.opcoes.acceptance), ';') };
1911
+ const item = kind === 'product' ? (0, portfolio_1.createProduct)(root, common)
1912
+ : kind === 'project' ? (0, portfolio_1.createProject)(root, { ...common, productId: parent ?? '', workspaceIds: split(texto(args.opcoes.workspaces)) })
1913
+ : (0, portfolio_1.createInitiative)(root, { ...common, projectId: parent ?? '', dependsOn: split(texto(args.opcoes.depends)) });
1914
+ console.log(JSON.stringify({ schema: 'ork.portfolio-created/v1', item }, null, 2));
1915
+ return 0;
1916
+ }
1917
+ console.error(`subcomando desconhecido: portfolio ${sub}`);
1918
+ return 2;
1919
+ }
1920
+ function comandoCreation(args) {
1921
+ const loaded = (0, manifest_1.exigirManifesto)();
1922
+ // CLI local opera com a autoridade do usuário do SO, assim como portfolio create.
1923
+ // Fachadas HTTP devem usar a API com principal e authorize autenticados no servidor.
1924
+ const actor = { principal: `local:uid:${(0, node_os_1.userInfo)().uid}`, authorize: () => { } };
1925
+ const sub = args.posicionais[1], id = args.posicionais[2];
1926
+ if (args.opcoes.principal !== undefined || args.opcoes.por !== undefined)
1927
+ throw new Error('creation.identity: payload não escolhe principal');
1928
+ let result;
1929
+ if (sub === 'session') {
1930
+ const portfolio = (0, portfolio_1.readPortfolio)(loaded.raiz);
1931
+ result = {
1932
+ schema: 'ork.creation-session/v1', principal: actor.principal,
1933
+ workspaceIds: [...new Set(portfolio.projects.flatMap((project) => project.workspaceIds))].sort(),
1934
+ modes: loaded.manifesto.conduction.allowed_modes,
1935
+ actions: ['create_entity', 'create_entity_with_ticket', 'open_ticket'],
1936
+ };
1937
+ }
1938
+ else if (sub === 'start') {
1939
+ const file = texto(args.opcoes['input-file']);
1940
+ if (!file) {
1941
+ console.error('uso: ork creation start --input-file F --json');
1942
+ return 2;
1943
+ }
1944
+ const content = fs.readFileSync(file, 'utf8');
1945
+ if (Buffer.byteLength(content) > 100_000)
1946
+ throw new Error('creation.input: arquivo excede limite');
1947
+ result = (0, creation_operation_1.startCreation)(loaded, actor, JSON.parse(content));
1948
+ }
1949
+ else if (sub === 'list')
1950
+ result = (0, creation_operation_store_1.listCreationOperations)(loaded.raiz, actor.principal);
1951
+ else if (!id) {
1952
+ console.error('creation exige id');
1953
+ return 2;
1954
+ }
1955
+ else if (sub === 'show' || sub === 'events') {
1956
+ const op = (0, creation_operation_store_1.readCreationOperation)(loaded.raiz, id, actor.principal);
1957
+ result = sub === 'events' ? { schema: 'ork.creation-events/v1', operationId: id, version: op.version, events: op.events } : op;
1958
+ }
1959
+ else if (sub === 'resume' || sub === 'compensate') {
1960
+ const version = Number(texto(args.opcoes['expected-version']));
1961
+ if (!Number.isSafeInteger(version) || version < 1) {
1962
+ console.error('creation exige --expected-version inteiro positivo');
1963
+ return 2;
1964
+ }
1965
+ result = sub === 'resume' ? (0, creation_operation_1.resumeCreation)(loaded, actor, id, version) : (0, creation_operation_1.compensateCreation)(loaded, actor, id, version);
1966
+ }
1967
+ else {
1968
+ console.error('subcomando creation desconhecido');
1969
+ return 2;
1970
+ }
1971
+ console.log(JSON.stringify(result, null, 2));
1972
+ return 0;
1973
+ }
1974
+ /**
1975
+ * `ork objective`: APOSENTADO na I-43 (D4).
1976
+ *
1977
+ * O Objective Envelope descrevia um gate que nao bloqueava nada, e a medida foi mais
1978
+ * dura que a suspeita do GOAL: das 137 threads do projeto, ZERO tinham
1979
+ * `creationOrigin`, e `creationOrigin` era a unica via pela qual `phase.ts` consultava
1980
+ * o envelope. O ramo nunca disparou para thread nenhuma. Havia um envelope em disco,
1981
+ * `obj-i27gatedomae`, em `awaiting_approval` desde 17/09, com tres threads de zero
1982
+ * sessoes: a unica pausa do `#Maestro` nao bloqueava o despacho das proprias threads
1983
+ * que ela criou, e aprova-la nao teria efeito.
1984
+ *
1985
+ * As DUAS VIGAS que ele guardava sairam vivas, e viraram propriedade de thread comum:
1986
+ * - validacao por runtime diferente -> `thread.exigeRuntimeDiferente` (T9);
1987
+ * - `doneWhen` executavel -> `thread.doneWhen`, que vira claim do nucleo (T10).
1988
+ *
1989
+ * A recusa e TIPADA e diz para onde ir. Sumir em silencio seria o mesmo pecado da
1990
+ * #TAG aposentada virando default: quem tem o comando num script precisa saber.
1991
+ */
1992
+ function comandoObjective(args) {
1993
+ const sub = args.posicionais[1] ?? 'list';
1994
+ console.error(`objective.aposentado: o Objective Envelope saiu do produto na I-43 (subcomando "${sub}").\n` +
1995
+ ' Ele descrevia um gate que nao bloqueava nada: das 137 threads do projeto, zero\n' +
1996
+ ' tinham creationOrigin, que era a unica via pela qual o despacho o consultava.\n' +
1997
+ ' As duas vigas que ele guardava viraram propriedade de thread comum:\n' +
1998
+ ' ork thread new "<nome>" --modo <MODO> --exige-runtime-diferente\n' +
1999
+ ' o CHECK precisa de runtime que o GO nao usou\n' +
2000
+ ' ork thread new "<nome>" --modo <MODO> --done "<criterio> :: <comando>"\n' +
2001
+ ' criterio de pronto EXECUTAVEL, que vira claim e roda no ork verify\n' +
2002
+ ' Os envelopes ja gravados continuam em .orkastery/objectives, intocados.');
2003
+ return 2;
2004
+ }
2005
+ function comandoCi(args) {
2006
+ const carregado = (0, manifest_1.exigirManifesto)();
2007
+ const sub = args.posicionais[1] ?? 'status';
2008
+ if (sub === 'prepare') {
2009
+ const thread = args.posicionais[2];
2010
+ if (!thread) {
2011
+ console.error('uso: ork ci prepare <thread-id>');
2012
+ return 2;
2013
+ }
2014
+ const arquivo = (0, ci_1.prepararBundleCi)(carregado, thread, { aoAvisar: (linha) => console.log(`AVISO: ${linha}`) });
2015
+ console.log(`Bundle de CI: ${arquivo}`);
2016
+ return 0;
2017
+ }
2018
+ if (sub === 'run') {
2019
+ const bundle = texto(args.opcoes.bundle);
2020
+ if (bundle) {
2021
+ const result = (0, ci_1.executarBundleCi)(carregado, bundle);
2022
+ console.log(JSON.stringify(result, null, 2));
2023
+ return result.ok ? 0 : 1;
2024
+ }
2025
+ const thread = args.posicionais[2];
2026
+ if (!thread) {
2027
+ console.error('uso: ork ci run <thread-id> [--json] | ork ci run --bundle <arquivo>');
2028
+ return 2;
2029
+ }
2030
+ const result = (0, ci_1.executarCi)(carregado, thread);
2031
+ console.log(args.opcoes.json === true ? JSON.stringify(result, null, 2) : `${result.status.ok ? 'CI APROVADO' : 'CI REPROVADO'}: ${result.status.detail}`);
2032
+ return result.status.ok ? 0 : 1;
2033
+ }
2034
+ if (sub === 'status') {
2035
+ const sha = texto(args.opcoes.sha) ?? args.posicionais[2] ?? (0, util_1.exec)('git', ['rev-parse', 'HEAD'], carregado.raiz).stdout.trim();
2036
+ if (!/^[0-9a-f]{40}$/.test(sha)) {
2037
+ console.error('uso: ork ci status --sha <commit> [--remoto origin]');
2038
+ return 2;
2039
+ }
2040
+ const result = (0, ci_1.consultarCi)(carregado, sha, texto(args.opcoes.remoto) ?? 'origin');
2041
+ console.log(args.opcoes.json === true ? JSON.stringify(result, null, 2) : `${result.ok ? 'CI VERDE' : 'CI NÃO LIBEROU'}: ${result.detail}`);
2042
+ return result.ok ? 0 : 1;
2043
+ }
2044
+ console.error(`subcomando desconhecido: ci ${sub}`);
2045
+ return 2;
2046
+ }
940
2047
  function comandoLease(args) {
941
2048
  const carregado = (0, manifest_1.exigirManifesto)();
942
2049
  const sub = args.posicionais[1];
@@ -956,14 +2063,14 @@ function comandoLease(args) {
956
2063
  const r = (0, leases_1.adquirirRegiao)(carregado.raiz, nome, { thread, motivo });
957
2064
  if (r.ok) {
958
2065
  console.log(`Lease ${r.nome} [${r.tipo}] adquirido pela thread ${thread}.`);
959
- console.log(` expira em ${r.lease?.expiraEm}`);
2066
+ console.log(` expira em ${(0, horario_1.formatarDataHoraRotulada)(r.lease?.expiraEm)}`);
960
2067
  if (r.tomadoDeVencido)
961
2068
  console.log(' (o lease anterior estava VENCIDO e foi tomado)');
962
2069
  return 0;
963
2070
  }
964
2071
  console.error(`Lease ${r.nome} NAO adquirido.`);
965
2072
  console.error(` motivo tipado: ${r.motivo}`);
966
- console.error(` detalhe: ${r.detalhe}`);
2073
+ console.error(` detalhe: ${(0, horario_1.localizarTextoRotulado)(r.detalhe)}`);
967
2074
  console.error(` posicao na fila: ${r.posicaoNaFila}`);
968
2075
  console.error(` correcao: ${r.correcao}`);
969
2076
  return 1;
@@ -985,14 +2092,105 @@ function comandoBoard(args) {
985
2092
  const carregado = (0, manifest_1.exigirManifesto)();
986
2093
  const sub = args.posicionais[1];
987
2094
  if (sub === 'plan' || sub === 'plano') {
988
- console.log((0, board_1.textoDoPlano)((0, board_1.planejar)(carregado)));
2095
+ const plano = (0, board_1.planejar)(carregado);
2096
+ console.log(args.opcoes.json === true ? JSON.stringify(plano, null, 2) : (0, board_1.textoDoPlano)(plano));
2097
+ return 0;
2098
+ }
2099
+ if (sub === 'reap') {
2100
+ const devolvidas = (0, board_1.devolverVagas)(carregado, { por: texto(args.opcoes.por) });
2101
+ if (args.opcoes.json === true)
2102
+ console.log(JSON.stringify(devolvidas, null, 2));
2103
+ else
2104
+ console.log((0, board_1.textoDoReap)(devolvidas));
989
2105
  return 0;
990
2106
  }
991
2107
  if (sub !== undefined && sub !== 'list') {
992
2108
  console.error(`subcomando desconhecido: board ${sub}`);
2109
+ console.error('uso: ork board [list|plan|reap] [--all] [--por <quem>] [--json]');
993
2110
  return 2;
994
2111
  }
995
- console.log((0, board_1.textoDoBoard)(carregado, args.opcoes.all === true || args.opcoes.todos === true));
2112
+ const todos = args.opcoes.all === true || args.opcoes.todos === true;
2113
+ if (args.opcoes.json === true) {
2114
+ console.log(JSON.stringify((0, board_1.threadsDeTodosOsPerfis)(carregado, todos), null, 2));
2115
+ return 0;
2116
+ }
2117
+ console.log((0, board_1.textoDoBoard)(carregado, todos));
2118
+ // I-51 (RM-047): com a fabrica compartilhada, o board mostra tambem as outras maquinas.
2119
+ if ((0, maquina_1.fabricaCompartilhada)(carregado.manifesto)) {
2120
+ const painel = (0, fabrica_estado_1.lerFabrica)(carregado.raiz, { remoto: carregado.manifesto.fabrica.remoto,
2121
+ semRemoto: args.opcoes['sem-remoto'] === true });
2122
+ console.log('');
2123
+ console.log((0, fabrica_estado_1.textoDasOutrasMaquinas)(painel, (0, maquina_1.nomeDaMaquina)()));
2124
+ }
2125
+ return 0;
2126
+ }
2127
+ /**
2128
+ * I-51 (RM-047): `ork fabrica` mostra o que cada maquina conduz; `ork fabrica publicar` grava o
2129
+ * retrato desta maquina na branch `ork/fabrica-estado`. O `--silencioso` e o da publicacao em
2130
+ * segundo plano: nada no terminal, uma linha em `.orkastery/monitor/fabrica.log`.
2131
+ */
2132
+ function comandoFabrica(args) {
2133
+ const carregado = (0, manifest_1.exigirManifesto)();
2134
+ const sub = args.posicionais[1];
2135
+ const remoto = texto(args.opcoes.remoto) ?? carregado.manifesto.fabrica.remoto;
2136
+ if (sub === 'publicar') {
2137
+ const silencioso = args.opcoes.silencioso === true;
2138
+ try {
2139
+ const r = (0, fabrica_estado_1.publicarMaquina)(carregado, { remoto, forcar: args.opcoes.forcar === true });
2140
+ if (silencioso) {
2141
+ (0, fabrica_estado_1.registrarPublicacao)(carregado.raiz, { ...r });
2142
+ return 0;
2143
+ }
2144
+ if (args.opcoes.json === true)
2145
+ console.log(JSON.stringify(r, null, 2));
2146
+ else
2147
+ console.log(r.acao === 'publicou'
2148
+ ? `Fabrica: ${r.maquina} publicou ${r.threads} thread(s) em ork/fabrica-estado (${r.commit?.slice(0, 7)}, ${r.tentativas} tentativa(s)).`
2149
+ : r.acao === 'ocupado'
2150
+ ? `Fabrica: outra publicacao desta maquina esta em andamento; tente de novo em instantes.`
2151
+ : `Fabrica: retrato de ${r.maquina} igual ao ultimo publicado; nada a enviar (use --forcar para publicar mesmo assim).`);
2152
+ if (!(0, maquina_1.fabricaCompartilhada)(carregado.manifesto) && !silencioso) {
2153
+ console.log(' esta maquina nao entrou na fabrica compartilhada: so publica quando voce pede (ork fabrica entrar liga).');
2154
+ }
2155
+ return 0;
2156
+ }
2157
+ catch (e) {
2158
+ if (silencioso) {
2159
+ (0, fabrica_estado_1.registrarPublicacao)(carregado.raiz, { acao: 'falhou', erro: e.message });
2160
+ return 1;
2161
+ }
2162
+ throw e;
2163
+ }
2164
+ }
2165
+ if (sub === 'entrar') {
2166
+ // A adesao e o nome ficam no arquivo do usuario: valem para o shell, o cron e os gateways.
2167
+ const config = (0, maquina_1.gravarConfigDaMaquina)({ nome: texto(args.opcoes.maquina) ?? (0, maquina_1.lerConfigDaMaquina)()?.nome ?? (0, maquina_1.nomeDaMaquina)(),
2168
+ fabricaCompartilhada: true });
2169
+ const r = (0, fabrica_estado_1.publicarMaquina)(carregado, { remoto, forcar: true });
2170
+ console.log(`Fabrica: esta maquina entrou como ${config.nome}; publica ao criar thread, despachar fase, entregar e fechar,`);
2171
+ console.log(` e a cada batida do pulse. Primeiro retrato: ${r.threads} thread(s) em ork/fabrica-estado (${r.commit?.slice(0, 7)}).`);
2172
+ if (process.env.ORK_MAQUINA && process.env.ORK_MAQUINA.trim() !== config.nome) {
2173
+ console.log(` AVISO: ORK_MAQUINA=${process.env.ORK_MAQUINA} neste shell vence o arquivo; alinhe os dois.`);
2174
+ }
2175
+ return 0;
2176
+ }
2177
+ if (sub === 'sair') {
2178
+ const config = (0, maquina_1.gravarConfigDaMaquina)({ fabricaCompartilhada: false });
2179
+ const r = (0, fabrica_estado_1.removerMaquina)(carregado, { remoto });
2180
+ console.log(`Fabrica: ${(0, maquina_1.nomeDaMaquina)()} saiu; nada mais e publicado daqui.` +
2181
+ (r ? ` Retrato removido de ork/fabrica-estado (${r.slice(0, 7)}).` : ' Nao havia retrato desta maquina na branch.'));
2182
+ if ((0, maquina_1.fabricaCompartilhada)(carregado.manifesto))
2183
+ console.log(' AVISO: o manifesto do projeto (ou ORK_FABRICA_COMPARTILHADA) ainda liga a fabrica aqui.');
2184
+ void config;
2185
+ return 0;
2186
+ }
2187
+ if (sub !== undefined && sub !== 'list') {
2188
+ console.error(`subcomando desconhecido: fabrica ${sub}`);
2189
+ console.error('uso: ork fabrica [--json] [--sem-remoto] | fabrica publicar [--forcar] [--json] | fabrica entrar [--maquina NOME] | fabrica sair');
2190
+ return 2;
2191
+ }
2192
+ const painel = (0, fabrica_estado_1.lerFabrica)(carregado.raiz, { remoto, semRemoto: args.opcoes['sem-remoto'] === true });
2193
+ console.log(args.opcoes.json === true ? JSON.stringify(painel, null, 2) : (0, fabrica_estado_1.textoDaFabrica)(painel, (0, maquina_1.nomeDaMaquina)()));
996
2194
  return 0;
997
2195
  }
998
2196
  /**
@@ -1105,15 +2303,95 @@ function comandoWorktree(args) {
1105
2303
  function comandoMaster(args) {
1106
2304
  const carregado = (0, manifest_1.exigirManifesto)();
1107
2305
  const primeiro = args.posicionais[1];
2306
+ if (primeiro === 'audit') {
2307
+ const r = (0, master_audit_1.auditarMaster)(carregado.raiz);
2308
+ console.log(JSON.stringify(r, null, 2));
2309
+ return r.ok ? 0 : 1;
2310
+ }
2311
+ if (primeiro === 'digest') {
2312
+ const sub = args.posicionais[2];
2313
+ if (sub === 'responder') {
2314
+ console.log(JSON.stringify((0, master_digest_1.responderLoteDigest)(carregado.raiz, texto(args.opcoes.resposta) ?? '', texto(args.opcoes.por) ?? '').map(r => ({ thread: r.thread.id, score: r.masterLog.score })), null, 2));
2315
+ return 0;
2316
+ }
2317
+ if (sub === 'preview') {
2318
+ console.log(JSON.stringify((0, master_digest_1.montarDigest)(carregado.raiz, new Date().toISOString()), null, 2));
2319
+ return 0;
2320
+ }
2321
+ if (sub !== 'enviar')
2322
+ throw new Error('uso: ork master digest <enviar|preview|responder>');
2323
+ const r = (0, master_digest_1.enviarDigest)({ raiz: carregado.raiz });
2324
+ console.log(JSON.stringify(r, null, 2));
2325
+ return r.code;
2326
+ }
2327
+ if (primeiro === 'migrar') {
2328
+ console.log(JSON.stringify((0, master_migracao_1.migrarMaster)(carregado.raiz, { dryRun: args.opcoes['dry-run'] === true, por: texto(args.opcoes.por) ?? '' }), null, 2));
2329
+ return 0;
2330
+ }
1108
2331
  if (primeiro === 'classes') {
1109
- console.log((0, master_1.tabelaDeClasses)());
2332
+ console.log((0, master_2.tabelaDeClasses)());
1110
2333
  return 0;
1111
2334
  }
1112
- if (args.opcoes.batch === true || primeiro === 'batch' || primeiro === undefined) {
1113
- console.log((0, master_1.tabelaDeBatch)(carregado.raiz, args.opcoes.todas === true));
2335
+ if (primeiro === 'ratificar' || ((args.opcoes.batch === true || primeiro === 'batch') && args.opcoes.aceitar)) {
2336
+ let selecao;
2337
+ if (primeiro === 'ratificar') {
2338
+ const partes = (texto(args.opcoes.resposta) ?? '').trim().split(/\s+/);
2339
+ const classe = (0, master_2.parseClasse)(partes[3]);
2340
+ if (partes.length !== 4 || partes[0] !== 'ratificar' || !classe)
2341
+ throw new Error('resposta deve ser ratificar <thread> <assinatura> <classe>');
2342
+ selecao = [{ thread: partes[1], assinatura: partes[2], classe }];
2343
+ }
2344
+ else {
2345
+ selecao = (texto(args.opcoes.aceitar) ?? '').split(',').map(v => {
2346
+ const partes = v.trim().split(':');
2347
+ if (partes.length !== 2 || !/^[a-f0-9]{64}$/.test(partes[1]))
2348
+ throw new Error('seleção deve ser thread:assinatura');
2349
+ return { thread: partes[0], assinatura: partes[1] };
2350
+ });
2351
+ }
2352
+ console.log(JSON.stringify((0, master_batch_1.ratificarBatch)(carregado.raiz, selecao, texto(args.opcoes.por) ?? '').map(r => ({ thread: r.thread.id, score: r.masterLog.score, por: r.masterLog.avaliadoPor })), null, 2));
1114
2353
  return 0;
1115
2354
  }
1116
- const id = primeiro;
2355
+ // I-43 (T8): a FILA saiu. `--batch` recebe recusa tipada em vez de sumir em
2356
+ // silencio: quem tem o comando no dedo ou num script precisa SABER que o regime
2357
+ // mudou, e para onde ir. Desaparecer sem dizer nada seria o mesmo pecado da #TAG
2358
+ // aposentada virando default.
2359
+ if (args.opcoes.batch === true || primeiro === 'batch') {
2360
+ console.error('master.fila-aposentada: a fila de ratificacao de score saiu na I-43. ' +
2361
+ 'Entregue e aceito, a menos que voce diga o contrario.\n' +
2362
+ ' ork master as entregas, com o indice ja derivado do ledger\n' +
2363
+ ' ork master --aceitar-omissao aceita as entregues, com indice e insumos no ledger\n' +
2364
+ ' ork master <id> --score <0-5> --justificativa "<por que>" --por <humano> para reclamar');
2365
+ return 2;
2366
+ }
2367
+ if (args.opcoes['aceitar-omissao'] === true) {
2368
+ const aceitos = (0, master_2.aceitarPendentesPorOmissao)(carregado.raiz);
2369
+ if (args.opcoes.json === true) {
2370
+ console.log(JSON.stringify(aceitos, null, 2));
2371
+ return 0;
2372
+ }
2373
+ if (aceitos.length === 0) {
2374
+ console.log('Nenhuma entrega esperando decisao.');
2375
+ return 0;
2376
+ }
2377
+ console.log(`Aceitas por omissao: ${aceitos.length}. O indice e os insumos foram ao ledger.`);
2378
+ for (const a of aceitos)
2379
+ console.log(` ${a.thread.padEnd(20)} indice ${a.indice.valor}/${a.indice.base}`);
2380
+ console.log('');
2381
+ console.log('Discordou? A nota humana sobrescreve, e o registro da omissao permanece.');
2382
+ return 0;
2383
+ }
2384
+ if (primeiro === undefined) {
2385
+ console.log(args.opcoes.json
2386
+ ? JSON.stringify({ entregas: (0, master_batch_1.listarBatch)(carregado.raiz, args.opcoes.todas === true),
2387
+ aceitasPorOmissao: (0, master_2.aceitosPorOmissao)(carregado.raiz) }, null, 2)
2388
+ : (0, master_2.tabelaDeEntregas)(carregado.raiz, args.opcoes.todas === true));
2389
+ return 0;
2390
+ }
2391
+ const propor = primeiro === 'propor';
2392
+ const id = propor ? args.posicionais[2] : primeiro;
2393
+ if (!id)
2394
+ throw new Error('informe a thread para propor MASTER');
1117
2395
  const brutoScore = texto(args.opcoes.score);
1118
2396
  const justificativa = texto(args.opcoes.justificativa) ?? texto(args.opcoes.porque);
1119
2397
  if (brutoScore === undefined) {
@@ -1130,28 +2408,51 @@ function comandoMaster(args) {
1130
2408
  const brutasClasses = texto(args.opcoes.classe) ?? texto(args.opcoes.classes);
1131
2409
  const classes = [];
1132
2410
  for (const bruta of (brutasClasses ?? '').split(',').map((c) => c.trim()).filter(Boolean)) {
1133
- const classe = (0, master_1.parseClasse)(bruta);
2411
+ const classe = (0, master_2.parseClasse)(bruta);
1134
2412
  if (!classe) {
1135
2413
  console.error(`classe de falha invalida: "${bruta}".`);
1136
- console.error(` classes fixas: ${master_1.ORDEM_DAS_CLASSES.join(', ')}`);
2414
+ console.error(` classes fixas: ${master_2.ORDEM_DAS_CLASSES.join(', ')}`);
1137
2415
  return 2;
1138
2416
  }
1139
2417
  classes.push(classe);
1140
2418
  }
1141
- const r = (0, master_1.registrarMaster)(carregado.raiz, id, {
2419
+ const opcoesMaster = {
1142
2420
  score: Number(brutoScore),
1143
2421
  justificativa,
1144
2422
  classes,
1145
2423
  resumo: texto(args.opcoes.resumo),
1146
2424
  por: texto(args.opcoes.por) ?? texto(args.opcoes.quem),
1147
2425
  refazer: args.opcoes.refazer === true,
1148
- });
1149
- console.log((0, master_1.textoDoMaster)(r));
2426
+ };
2427
+ if (propor) {
2428
+ console.log(JSON.stringify((0, master_1.proporMaster)(carregado.raiz, id, opcoesMaster), null, 2));
2429
+ return 0;
2430
+ }
2431
+ const r = (0, master_2.registrarMaster)(carregado.raiz, id, opcoesMaster);
2432
+ console.log((0, master_2.textoDoMaster)(r));
1150
2433
  // Bloco B6: fechada a thread, a licao (POSTMORTEM + score) vai para a colecao
1151
2434
  // `learning`, e e o que uma thread NOVA do mesmo produto recebe no GOAL.
1152
2435
  relatarPublicacao((0, memoria_1.publicar)(carregado, id));
2436
+ // I-55 (RM-008): a thread fechada pode fazer uma falha recorrente passar do piso. A proposta
2437
+ // vai ao ledger do projeto uma vez por janela; virar policy continua sendo do dono.
2438
+ for (const p of (0, licoes_1.registrarPropostasNovas)(carregado.raiz)) {
2439
+ console.log('');
2440
+ console.log(`Proposta de policy: ${p.chave} em ${p.threads.length} threads nos ultimos ${p.janelaDias} dias.`);
2441
+ console.log(` ${p.sugestao}`);
2442
+ console.log(' So proposta: vira policy quando voce a declara em policies: no orkastery.yaml (ork licoes).');
2443
+ }
1153
2444
  console.log('');
1154
- console.log(`Proximo passo: ork board --all | fila de score: ork master --batch`);
2445
+ console.log(`Proximo passo: ork board --all | entregas e indice: ork master`);
2446
+ return 0;
2447
+ }
2448
+ /** I-55 (RM-008): `ork licoes` mostra o que volta no proximo GOAL e PLAN, e as propostas de policy. */
2449
+ function comandoLicoes(args) {
2450
+ const carregado = (0, manifest_1.exigirManifesto)();
2451
+ if (args.opcoes.json === true) {
2452
+ console.log(JSON.stringify({ resumo: (0, licoes_1.resumoDasLicoes)(carregado.raiz, null), propostas: (0, licoes_1.propostasDePolicy)(carregado.raiz) }, null, 2));
2453
+ return 0;
2454
+ }
2455
+ console.log((0, licoes_1.textoDeLicoes)(carregado.raiz));
1155
2456
  return 0;
1156
2457
  }
1157
2458
  /**
@@ -1161,6 +2462,81 @@ function comandoMaster(args) {
1161
2462
  * exato com o mesmo sha256 que iria para o ledger, para o builder revisar texto sem gastar
1162
2463
  * uma sessao do runtime para descobrir o que foi pedido.
1163
2464
  */
2465
+ /**
2466
+ * I-44: documentacao como codigo. `verificar` le docs e git (roda no CI); `sincronizar` le tambem
2467
+ * o estado das threads, que nao e versionado, e por isso roda na maquina do projeto.
2468
+ */
2469
+ /** I-47: reservas de item do roadmap entre maquinas (`ork roadmap reservas|pegar|soltar`). */
2470
+ function comandoRoadmap(args) {
2471
+ const carregado = (0, manifest_1.exigirManifesto)();
2472
+ const sub = args.posicionais[1] ?? 'reservas';
2473
+ const remoto = texto(args.opcoes.remoto);
2474
+ if (sub === 'reservas') {
2475
+ const painel = (0, roadmap_reservas_1.listarReservas)(carregado.raiz, { remoto });
2476
+ console.log(args.opcoes.json === true ? JSON.stringify(painel, null, 2) : (0, roadmap_reservas_1.textoDasReservas)(painel));
2477
+ return 0;
2478
+ }
2479
+ const item = args.posicionais[2];
2480
+ if ((sub !== 'pegar' && sub !== 'soltar') || !item) {
2481
+ console.error('uso: ork roadmap reservas | pegar <RM-NNN> [--thread T] [--nota N] | soltar <RM-NNN> [--forcar --motivo M]');
2482
+ return 2;
2483
+ }
2484
+ const opcoes = {
2485
+ remoto,
2486
+ por: texto(args.opcoes.por),
2487
+ maquina: texto(args.opcoes.maquina),
2488
+ ...(texto(args.opcoes.thread) !== undefined ? { thread: texto(args.opcoes.thread) } : {}),
2489
+ ...(texto(args.opcoes.nota) !== undefined ? { nota: texto(args.opcoes.nota) } : {}),
2490
+ forcar: args.opcoes.forcar === true,
2491
+ motivo: texto(args.opcoes.motivo),
2492
+ };
2493
+ const r = sub === 'pegar' ? (0, roadmap_reservas_1.pegarItem)(carregado.raiz, item, opcoes) : (0, roadmap_reservas_1.soltarItem)(carregado.raiz, item, opcoes);
2494
+ if (args.opcoes.json === true) {
2495
+ console.log(JSON.stringify(r, null, 2));
2496
+ return 0;
2497
+ }
2498
+ const verbo = { pegou: 'reservado para esta maquina', renovou: 'reserva renovada', tomou: 'reserva TOMADA de outra maquina',
2499
+ soltou: 'devolvido', nada: 'ja estava livre' }[r.acao];
2500
+ console.log(`${r.item}: ${verbo}.`);
2501
+ if (r.reserva && r.acao !== 'soltou')
2502
+ console.log(` com ${r.reserva.por} em ${r.reserva.maquina}${r.reserva.thread ? `, thread ${r.reserva.thread}` : ''}`);
2503
+ if (r.commit)
2504
+ console.log(` branch ork/roadmap-reservas em ${r.commit.slice(0, 7)}`);
2505
+ return 0;
2506
+ }
2507
+ function comandoDocs(args) {
2508
+ const sub = args.posicionais[1] ?? 'verificar';
2509
+ const carregado = (0, manifest_1.carregarManifesto)();
2510
+ const raiz = carregado?.raiz ?? process.cwd();
2511
+ const baseBranch = carregado?.manifesto.worktree?.base_branch ?? 'main';
2512
+ if (sub === 'verificar') {
2513
+ const { docs, achados } = (0, docs_1.verificarDocs)(raiz, { baseBranch, ajudaDoCli: AJUDA });
2514
+ if (args.opcoes.json === true) {
2515
+ console.log(JSON.stringify({ paginas: docs.length, erros: achados.filter((a) => a.gravidade === 'erro').length,
2516
+ achados }, null, 2));
2517
+ }
2518
+ else {
2519
+ console.log((0, docs_1.textoDaVerificacao)(docs, achados));
2520
+ }
2521
+ return achados.some((a) => a.gravidade === 'erro') ? 2 : 0;
2522
+ }
2523
+ if (sub === 'sincronizar') {
2524
+ const escrever = args.opcoes.escrever === true;
2525
+ const r = (0, docs_1.sincronizarDocs)(raiz, { baseBranch, escrever });
2526
+ console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2) : (0, docs_1.textoDaSincronizacao)(r, escrever));
2527
+ return 0;
2528
+ }
2529
+ if (sub === 'init') {
2530
+ const criados = (0, docs_1.iniciarDocs)(raiz);
2531
+ console.log(criados.length === 0
2532
+ ? 'Documentacao como codigo ja estava no projeto: nada criado.'
2533
+ : ['Criado:', ...criados.map((c) => ` ${c}`), '',
2534
+ 'Proximo passo: copie docs/produto/_modelo-feature.md e docs/roadmap/_modelo-item.md, e rode ork docs verificar'].join('\n'));
2535
+ return 0;
2536
+ }
2537
+ console.error(`uso: ork docs verificar [--json] | sincronizar [--escrever] | init`);
2538
+ return 2;
2539
+ }
1164
2540
  function comandoPrompt(args) {
1165
2541
  const sub = args.posicionais[1] ?? 'list';
1166
2542
  const carregado = (0, manifest_1.carregarManifesto)();
@@ -1186,9 +2562,12 @@ function comandoPrompt(args) {
1186
2562
  // abrir trabalho. Nada e gravado, e o `ork` diz em voz alta que a thread e ficticia.
1187
2563
  if (args.opcoes.exemplo === true || args.opcoes.modo !== undefined || args.opcoes.mode !== undefined) {
1188
2564
  const bruto = texto(args.opcoes.modo) ?? texto(args.opcoes.mode) ?? 'classic';
1189
- const modo = (0, modos_1.parseModo)(bruto);
1190
- if (!modo) {
1191
- console.error(`modo invalido: "${bruto}". Use um de: ${Object.values(modos_1.MODOS).map((m) => m.tag).join(', ')}`);
2565
+ let modo;
2566
+ try {
2567
+ modo = (0, modos_1.exigirModoVivo)(bruto);
2568
+ }
2569
+ catch (e) {
2570
+ console.error(e.message);
1192
2571
  return 2;
1193
2572
  }
1194
2573
  const exemplo = (0, prompts_1.threadDeExemplo)(modo, fase, carregado?.manifesto.project);
@@ -1266,6 +2645,10 @@ function comandoAdapter(args) {
1266
2645
  force: args.opcoes.force === true || args.opcoes.forcar === true,
1267
2646
  orkBin: texto(args.opcoes.ork),
1268
2647
  versao: VERSAO,
2648
+ // I-43 (D5): a decisao por ARQUIVO, que e o que faz `--force` deixar de ser o
2649
+ // unico caminho de saida. `;` separa varios, como o resto do CLI ja faz.
2650
+ aceitarCatalogo: (texto(args.opcoes['aceitar-catalogo']) ?? '').split(';').map(x => x.trim()).filter(Boolean),
2651
+ manterCopia: (texto(args.opcoes['manter-copia']) ?? '').split(';').map(x => x.trim()).filter(Boolean),
1269
2652
  });
1270
2653
  console.log((0, hosts_1.textoDaInstalacao)(r));
1271
2654
  return r.ok ? 0 : 2;
@@ -1308,6 +2691,12 @@ function comandoEval(args) {
1308
2691
  * diferente de zero quando reprova, para o agendador do host perceber sem ler texto.
1309
2692
  */
1310
2693
  function comandoAudit(args) {
2694
+ if (args.posicionais[1] === 'process') {
2695
+ const r = (0, process_audit_1.auditarProcesso)((0, manifest_1.exigirManifesto)(), args.opcoes.registrar === true);
2696
+ console.log(JSON.stringify(r, null, 2));
2697
+ const chave = texto(args.opcoes['exigir-achado']);
2698
+ return chave && !r.achados.some(a => a.chave === chave) ? 1 : 0;
2699
+ }
1311
2700
  const sub = args.posicionais[1] ?? 'packs';
1312
2701
  // `audit packs` e `audit lint` funcionam sem manifesto: sao catalogo, nao estado.
1313
2702
  if (sub === 'packs' || sub === 'pack') {
@@ -1673,6 +3062,10 @@ function comandoAudit(args) {
1673
3062
  * que sempre teve. E o que garante que ligar o B6 nao muda o que o builder ja conhece.
1674
3063
  */
1675
3064
  function relatarPublicacao(r) {
3065
+ if (r.publicacao?.estado === 'pendente') {
3066
+ console.log(`Memoria: publicacao pendente (${r.publicacao.motivo}); ativacao explicita necessaria.`);
3067
+ return;
3068
+ }
1676
3069
  if (r.regime !== 'orkmind')
1677
3070
  return;
1678
3071
  const gravados = [
@@ -1687,9 +3080,18 @@ function relatarPublicacao(r) {
1687
3080
  if (r.falhas > 0)
1688
3081
  console.log(` ${r.falhas} gravacao(oes) nao concluida(s); veja ork memory status.`);
1689
3082
  }
3083
+ /** Janela de origem e corte de apresentação são inteiros positivos explícitos. */
3084
+ function limiteDeLeitura(valor) {
3085
+ if (valor === undefined)
3086
+ return undefined;
3087
+ if (typeof valor !== 'string' || !/^[0-9]+$/.test(valor) ||
3088
+ Number(valor) < 1 || Number(valor) > 1000)
3089
+ throw Error('memory.query.invalid');
3090
+ return Number(valor);
3091
+ }
1690
3092
  /** `ork recall`: recuperacao tardia dos ponteiros do handoff, no momento indicado. */
1691
3093
  function comandoRecall(args) {
1692
- const carregado = (0, manifest_1.exigirManifesto)();
3094
+ const carregado = (0, project_state_1.memoryState)((0, manifest_1.exigirManifesto)()).loaded;
1693
3095
  const id = args.posicionais[1];
1694
3096
  if (!id) {
1695
3097
  console.error('uso: ork recall <thread-id> [--fase FASE] [--id ptr-N] [--todos] [--forcar]');
@@ -1698,7 +3100,7 @@ function comandoRecall(args) {
1698
3100
  const thread = (0, thread_1.lerThread)(carregado.raiz, id);
1699
3101
  const faseBruta = texto(args.opcoes.fase) ?? texto(args.opcoes.momento);
1700
3102
  const momento = faseBruta ? (0, thread_1.exigirFase)(thread, faseBruta) : undefined;
1701
- const memoria = (0, memoria_1.abrirMemoria)(carregado);
3103
+ const memoria = (0, memoria_1.abrirMemoria)(carregado, { leituraRestrita: { thread: id, limite: limiteDeLeitura(args.opcoes.janela) } });
1702
3104
  const r = (0, recall_1.recallDaThread)(carregado, memoria, id, {
1703
3105
  momento,
1704
3106
  id: texto(args.opcoes.id),
@@ -1716,32 +3118,96 @@ function comandoRecall(args) {
1716
3118
  }
1717
3119
  /** `ork memory`: o regime, a publicacao e a busca deterministica por tag. */
1718
3120
  function comandoMemory(args) {
1719
- const carregado = (0, manifest_1.exigirManifesto)();
3121
+ const candidate = (0, manifest_1.exigirManifesto)();
3122
+ const carregado = (0, project_state_1.memoryState)(candidate).loaded;
1720
3123
  const sub = args.posicionais[1] ?? 'status';
1721
- const memoria = (0, memoria_1.abrirMemoria)(carregado);
3124
+ const escopo = texto(args.opcoes.escopo)?.split(',').map(s => s.trim());
3125
+ if (sub === 'inventory' || (sub === 'migrate' && args.opcoes['dry-run'] === true)) {
3126
+ const r = (0, memory_migration_1.inventariarHandoffs)(carregado, escopo);
3127
+ if (args.opcoes.json === true)
3128
+ console.log(JSON.stringify(r, null, 2));
3129
+ else {
3130
+ console.log(`Inventario do tenant ${r.tenant}: ${r.incluidos} incluidos, ${r.excluidos} excluidos.`);
3131
+ for (const f of r.fontes)
3132
+ console.log(` ${f.incluir ? 'incluir' : 'excluir'} ${f.arquivo}: ${f.motivo}`);
3133
+ }
3134
+ return r.fontes.some(f => f.bloqueante) ? 1 : 0;
3135
+ }
3136
+ if (sub === 'migrate') {
3137
+ const operadora = texto(args.opcoes.operadora);
3138
+ if (!operadora || !escopo)
3139
+ throw new Error('scope.write.required: --operadora <thread> --escopo <thread,...>');
3140
+ if (carregado.manifesto.memory.mode === 'orkmind') {
3141
+ const autorizacao = (0, write_activation_1.exigirAtivacao)(carregado, operadora, 'memory');
3142
+ if (escopo.some(id => !autorizacao.threads.includes(id)))
3143
+ throw Error('write.activation.scope-denied');
3144
+ }
3145
+ const r = (0, memory_migration_1.migrarHandoffs)(carregado, { operadora, escopo });
3146
+ if (args.opcoes.json === true)
3147
+ console.log(JSON.stringify(r, null, 2));
3148
+ else {
3149
+ console.log(`Migracao do tenant ${r.inventario.tenant}: ${r.resultados.filter(i => i.ok).length} confirmados, ${r.falhas} falhas, ${r.inventario.excluidos} excluidos.`);
3150
+ for (const item of r.resultados)
3151
+ console.log(` ${item.arquivo}: ${item.ok ? item.gravacao?.id : item.erro}`);
3152
+ }
3153
+ return r.ok ? 0 : 1;
3154
+ }
3155
+ if (sub === 'sync' && args.posicionais[2])
3156
+ (0, escopo_escrita_1.validarDiretorioDeThread)(carregado.raiz, args.posicionais[2]);
1722
3157
  if (sub === 'status') {
3158
+ const memoria = (0, memoria_1.abrirMemoria)(candidate);
1723
3159
  if (args.opcoes.json === true) {
1724
- console.log(JSON.stringify(memoria.estado, null, 2));
3160
+ console.log(JSON.stringify({ ...memoria.estado, configSource: memoria.configSource, configDivergent: memoria.configDivergent }, null, 2));
1725
3161
  return 0;
1726
3162
  }
1727
3163
  console.log((0, memoria_1.textoDoEstado)(memoria.estado));
1728
3164
  return 0;
1729
3165
  }
1730
3166
  if (sub === 'sync') {
3167
+ const memoria = (0, memoria_1.abrirMemoria)(carregado);
1731
3168
  const threadId = args.posicionais[2];
1732
3169
  // Thread inexistente reprova aqui, e nao no meio da gravacao.
1733
3170
  if (threadId)
1734
3171
  (0, thread_1.lerThread)(carregado.raiz, threadId);
1735
- const r = (0, memoria_1.sincronizarMemoria)(carregado, memoria, threadId ?? null);
3172
+ const perfil = (texto(args.opcoes.perfil) ?? 'integral');
3173
+ if (!['fabrica', 'integral'].includes(perfil))
3174
+ throw Error('memory.publication.profile-invalid');
3175
+ if (carregado.manifesto.memory.mode === 'orkmind') {
3176
+ try {
3177
+ const autorizacao = (0, write_activation_1.exigirAtivacao)(carregado, threadId ?? '', 'memory');
3178
+ if (autorizacao.perfil !== 'integral' && perfil !== autorizacao.perfil)
3179
+ throw Error('write.activation.profile-denied');
3180
+ }
3181
+ catch (error) {
3182
+ const motivo = error instanceof Error
3183
+ ? /^(?:write\.activation|scope|memory)\.[a-z.-]+/.exec(error.message)?.[0] ?? 'write.activation.invalid'
3184
+ : 'write.activation.invalid';
3185
+ const detalhe = 'sync nao executado; colisao legada nao foi reavaliada';
3186
+ if (args.opcoes.json === true)
3187
+ console.log(JSON.stringify({
3188
+ regime: memoria.regime, estado: memoria.estado, thread: threadId ?? null, perfil,
3189
+ publicacao: { estado: 'pendente', motivo }, falhas: 1, gravadas: [], erro: motivo, detalhe,
3190
+ }, null, 2));
3191
+ console.error(`${motivo}: ${detalhe}`);
3192
+ return 1;
3193
+ }
3194
+ }
3195
+ const r = (0, memoria_1.sincronizarMemoria)(carregado, memoria, threadId ?? null, undefined, perfil);
1736
3196
  if (args.opcoes.json === true) {
1737
3197
  console.log(JSON.stringify(r, null, 2));
1738
3198
  }
1739
3199
  else {
1740
3200
  console.log((0, memoria_1.textoDoSync)(r));
1741
3201
  }
1742
- return 0;
3202
+ return r.estado.pedido === 'orkmind' && r.falhas > 0 ? 1 : 0;
1743
3203
  }
1744
3204
  if (sub === 'search') {
3205
+ const threadId = texto(args.opcoes.thread);
3206
+ if ((args.opcoes.restrito !== undefined || args.opcoes.thread !== undefined ||
3207
+ args.opcoes.janela !== undefined) && !threadId) {
3208
+ throw Error('memory.query.thread-required: use --thread <id>');
3209
+ }
3210
+ const janela = limiteDeLeitura(args.opcoes.janela);
1745
3211
  const tagsBrutas = texto(args.opcoes.tags);
1746
3212
  if (!tagsBrutas) {
1747
3213
  console.error('uso: ork memory search --tags \'{"project":["orkastery"],"skill":["orkastery-decision"]}\'');
@@ -1757,11 +3223,19 @@ function comandoMemory(args) {
1757
3223
  }
1758
3224
  const colecao = texto(args.opcoes.colecao) ?? texto(args.opcoes.collection);
1759
3225
  const limiteBruto = texto(args.opcoes.limite);
3226
+ const limite = threadId ? limiteDeLeitura(args.opcoes.limite) : limiteBruto ? Number(limiteBruto) : undefined;
3227
+ if (threadId)
3228
+ (0, orkmind_1.validarConsultaDelimitada)({ collection: colecao,
3229
+ escopo: (0, orkmind_1.criarEscopoDeLeitura)(carregado.manifesto, threadId), tags,
3230
+ limite: janela ?? orkmind_1.LIMITE_CONSULTA_PADRAO });
3231
+ const memoria = (0, memoria_1.abrirMemoria)(carregado, threadId ? { leituraRestrita: { thread: threadId, limite: janela } } : {});
1760
3232
  const entradas = memoria.buscar({
1761
3233
  collection: colecao,
1762
3234
  tags,
1763
- limite: limiteBruto ? Number(limiteBruto) : undefined,
3235
+ limite,
1764
3236
  });
3237
+ if (threadId && memoria.regime === 'files')
3238
+ console.error(`memory.query.files: ${memoria.estado.motivo}; resultado nao comprova ausencia na memoria semantica`);
1765
3239
  if (args.opcoes.json === true) {
1766
3240
  console.log(JSON.stringify(entradas, null, 2));
1767
3241
  return 0;
@@ -1785,19 +3259,93 @@ function comandoMemory(args) {
1785
3259
  return 2;
1786
3260
  }
1787
3261
  function main(argv) {
3262
+ // I-35: todo horário para pessoa sai no fuso do dono deste projeto (lido só se for preciso).
3263
+ (0, horario_1.registrarFonteDoFuso)(() => (0, horario_1.fusoDoManifesto)((0, manifest_1.carregarManifesto)()));
3264
+ // Helper fixo do host confiável: o projeto vem da instalação, nunca de toolargs.
3265
+ if (argv[0] === 'receipt-verifiers') {
3266
+ if (argv.length !== 2 || argv[1] !== '--json')
3267
+ throw Error('uso: ork receipt-verifiers --json');
3268
+ const root = process.env.ORK_HITL_ROOT;
3269
+ const privateKey = Object.keys(process.env).some(name => /^ORK_HITL_(?:INGRESS_KEY|NATIVE_KEY)/.test(name));
3270
+ if (root !== undefined || privateKey) {
3271
+ if (!root || !(0, node_path_1.isAbsolute)(root) || fs.realpathSync(root) !== root)
3272
+ throw Error('hitl.receipt.project-unavailable');
3273
+ const carregado = (0, manifest_1.exigirManifesto)(root);
3274
+ if (carregado.raiz !== root)
3275
+ throw Error('hitl.receipt.project-unavailable');
3276
+ for (const id of (0, thread_1.listarIds)(root))
3277
+ (0, hitl_ingress_receipt_1.prepararRecibosParaDespacho)(root, id);
3278
+ }
3279
+ console.log((0, hitl_public_receipt_1.publicHitlVerifiers)() ?? 'null');
3280
+ return 0;
3281
+ }
3282
+ if (argv[0] === 'maestro')
3283
+ return (0, maestro_cli_1.runMaestroCli)(argv.slice(1));
1788
3284
  const args = parseArgs(argv);
1789
3285
  const comando = args.posicionais[0];
3286
+ // `ork --version` tambem chega sem comando: a versao e conferida antes da ajuda.
3287
+ if (args.opcoes.version === true || comando === 'version') {
3288
+ console.log(VERSAO);
3289
+ return 0;
3290
+ }
1790
3291
  if (!comando || args.opcoes.help === true || comando === 'help') {
1791
3292
  console.log(AJUDA);
1792
3293
  return 0;
1793
3294
  }
1794
- if (args.opcoes.version === true || comando === 'version') {
1795
- console.log(VERSAO);
1796
- return 0;
3295
+ const nomesHerdados = (0, runtime_ambiente_1.nomesDeProviderAtivos)();
3296
+ const ambienteManifesto = (0, manifest_1.carregarManifesto)();
3297
+ if (ambienteManifesto?.manifesto.runtime.provider_policy === 'subscription-only') {
3298
+ // Avaliar ANTES de limpar: um redirecionamento bloqueante não pode desaparecer.
3299
+ const violacoes = (0, policies_1.avaliarPolicies)(ambienteManifesto.manifesto, { gate: 'phase.dispatch' });
3300
+ // O gate oficial precisa observar e registrar a violação (inclusive warn).
3301
+ // Diagnósticos continuam acessíveis; os adapters sanitizam seus filhos sempre.
3302
+ if (violacoes.length === 0)
3303
+ for (const nome of runtime_ambiente_1.ENVS_DE_PROVIDER_PAGO)
3304
+ delete process.env[nome];
1797
3305
  }
1798
3306
  switch (comando) {
3307
+ case 'mcp': {
3308
+ const projeto = texto(args.opcoes.project), host = texto(args.opcoes.host), threadId = texto(args.opcoes.thread);
3309
+ // I-36 (D4): a identidade do despacho so chega com a thread vinculada da sessao filha.
3310
+ const dispatchId = texto(args.opcoes.dispatch);
3311
+ const transporteShip = texto(args.opcoes['ship-transport']) ?? 'github-ssh';
3312
+ const permissoesFilho = texto(args.opcoes['child-permissions']) ?? 'interactive';
3313
+ const permissoesDono = texto(args.opcoes['owner-permissions']);
3314
+ const acao = args.posicionais[1];
3315
+ if (args.posicionais.length !== 2 || !['serve', 'install'].includes(acao) || !projeto ||
3316
+ (host !== 'codex' && host !== 'claude-code') ||
3317
+ Object.keys(args.opcoes).some(k => !['project', 'host', 'ship-transport', 'child-permissions', ...(acao === 'install' ? ['dry-run', 'owner-permissions'] : ['thread', 'dispatch'])].includes(k)) ||
3318
+ (args.opcoes.dispatch !== undefined && (!threadId || !dispatchId || !/^[a-f0-9-]{36}$/.test(dispatchId))) ||
3319
+ argv.filter(a => a === '--ship-transport' || a.startsWith('--ship-transport=')).length > 1 ||
3320
+ argv.filter(a => a === '--child-permissions' || a.startsWith('--child-permissions=')).length > 1 ||
3321
+ (args.opcoes['owner-permissions'] !== undefined && (host !== 'codex' || typeof args.opcoes['owner-permissions'] !== 'string' || !['interactive', 'orchestrate'].includes(permissoesDono ?? ''))) ||
3322
+ argv.filter(a => a === '--owner-permissions' || a.startsWith('--owner-permissions=')).length > 1 ||
3323
+ !['interactive', 'worktree'].includes(permissoesFilho) ||
3324
+ (args.opcoes['child-permissions'] !== undefined && typeof args.opcoes['child-permissions'] !== 'string') ||
3325
+ !['github-ssh', 'bare-local'].includes(transporteShip) ||
3326
+ (args.opcoes['ship-transport'] !== undefined && typeof args.opcoes['ship-transport'] !== 'string') ||
3327
+ (args.opcoes.thread !== undefined && (!threadId || !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/.test(threadId))) ||
3328
+ (args.opcoes['dry-run'] !== undefined && args.opcoes['dry-run'] !== true))
3329
+ throw new Error('uso: ork mcp serve|install --project <raiz absoluta> --host codex|claude-code [--ship-transport github-ssh|bare-local] [--child-permissions interactive|worktree] [--owner-permissions interactive|orchestrate somente install Codex] [--dry-run somente install]');
3330
+ if (acao === 'install') {
3331
+ void Promise.resolve().then(() => __importStar(require('./mcp-install'))).then(({ instalarMcp, textoInstalacaoMcp }) => console.log(textoInstalacaoMcp(instalarMcp({ projeto, host, dryRun: args.opcoes['dry-run'] === true, transporteShip: transporteShip, permissoesFilho: permissoesFilho, permissoesDono: permissoesDono }))))
3332
+ .catch(e => { console.error(`mcp: ${e.message}`); process.exitCode = 1; });
3333
+ return 0;
3334
+ }
3335
+ void Promise.resolve().then(() => __importStar(require('./mcp-server'))).then(({ servirMcp }) => servirMcp({ projeto, host, threadId, dispatchId, nomesProviderHerdados: nomesHerdados, transporteShip: transporteShip, permissoesFilho: permissoesFilho })).catch(e => { console.error(`mcp: ${e.message}`); process.exitCode = 1; });
3336
+ return 0;
3337
+ }
1799
3338
  case 'doctor': {
1800
- const r = (0, doctor_1.doctor)();
3339
+ if (args.opcoes.modo !== undefined) {
3340
+ const bruto = texto(args.opcoes.modo);
3341
+ if (args.posicionais.length !== 1 || !bruto ||
3342
+ Object.keys(args.opcoes).some(k => k !== 'modo') || argv.filter(a => a === '--modo' || a.startsWith('--modo=')).length !== 1)
3343
+ throw Error(`uso: ork doctor --modo ${modos_1.ORDEM_DOS_MODOS.join('|')}`);
3344
+ const r = (0, preflight_1.preflight)(process.cwd(), (0, modos_1.exigirModoVivo)(bruto), nomesHerdados);
3345
+ console.log((0, preflight_1.textoPreflight)(r));
3346
+ return r.prontoPrimeiroBloco ? 0 : 1;
3347
+ }
3348
+ const r = (0, doctor_1.doctor)(process.cwd(), nomesHerdados);
1801
3349
  console.log(r.texto);
1802
3350
  return r.codigo;
1803
3351
  }
@@ -1807,9 +3355,12 @@ function main(argv) {
1807
3355
  nome: texto(args.opcoes.name) ?? texto(args.opcoes.nome),
1808
3356
  abbrev: texto(args.opcoes.abbrev),
1809
3357
  });
3358
+ const carregado = (0, manifest_1.exigirManifesto)(r.deteccao.raiz);
3359
+ const agents = (0, agents_md_1.atualizarAgentsMd)(r.deteccao.raiz, carregado.manifesto);
1810
3360
  if (!r.criado) {
1811
3361
  console.log(`Manifesto ja existe: ${r.caminho}`);
1812
3362
  console.log('Nada foi sobrescrito. Use --force para regerar.');
3363
+ console.log(`AGENTS.md ${agents.estado}: ${agents.caminho}`);
1813
3364
  return 0;
1814
3365
  }
1815
3366
  console.log(`Manifesto criado: ${r.caminho}`);
@@ -1817,17 +3368,37 @@ function main(argv) {
1817
3368
  console.log(` branch base ${r.deteccao.baseBranch}`);
1818
3369
  console.log(` gerenciador ${r.deteccao.gerenciador}`);
1819
3370
  console.log(` verify ${Object.entries(r.deteccao.verify).map(([k, v]) => `${k}="${v}"`).join(', ') || '(nenhum script detectado)'}`);
3371
+ console.log(` AGENTS.md ${agents.estado}: ${agents.caminho}`);
1820
3372
  console.log('');
1821
- console.log('Proximo passo: ork doctor');
3373
+ console.log(init_2.PROXIMO_PASSO_INIT);
1822
3374
  return 0;
1823
3375
  }
1824
3376
  case 'modos': {
3377
+ // I-43 (T4): `ork modos migrar` tira modo aposentado da CONFIGURACAO do projeto
3378
+ // (`orkastery.yaml` e `setup.json`) e nao toca em historico nenhum. Idempotente:
3379
+ // rodar de novo num projeto ja migrado nao escreve nada.
3380
+ if (args.posicionais[1] === 'migrar') {
3381
+ const carregado = (0, manifest_1.exigirManifesto)();
3382
+ const r = (0, modos_migracao_1.migrarModosAposentados)(carregado.raiz, {
3383
+ dryRun: args.opcoes['dry-run'] === true,
3384
+ por: texto(args.opcoes.por),
3385
+ });
3386
+ console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2) : (0, modos_migracao_1.textoDaMigracaoModos)(r));
3387
+ return 0;
3388
+ }
1825
3389
  // `--do-pedido` existe para os adaptadores de host: eles extraem a #TAG do texto do
1826
3390
  // builder SEM reimplementar o parse, e repassam `--mode` ao `ork`. A validacao contra
1827
3391
  // `conduction.allowed_modes` continua sendo do nucleo, no `ork thread new`.
1828
3392
  const pedido = texto(args.opcoes['do-pedido']);
1829
3393
  if (pedido !== undefined) {
1830
3394
  const carregado = (0, manifest_1.carregarManifesto)();
3395
+ // I-43: `#Look` no pedido nao pode cair no default em silencio. O adaptador
3396
+ // recebe a recusa tipada e saida != 0, e quem escreveu a #TAG fica sabendo.
3397
+ const aposentado = (0, modos_1.extrairTagAposentadaDoPedido)(pedido);
3398
+ if (aposentado) {
3399
+ console.error((0, modos_1.recusaDeModoAposentado)(aposentado));
3400
+ return 2;
3401
+ }
1831
3402
  const extraido = (0, modos_1.extrairTagDoPedido)(pedido);
1832
3403
  const modo = extraido ?? carregado?.manifesto.conduction.default_mode ?? 'classic';
1833
3404
  if (args.opcoes.json === true) {
@@ -1847,16 +3418,59 @@ function main(argv) {
1847
3418
  console.log((0, modos_1.tabelaDeModos)());
1848
3419
  return 0;
1849
3420
  }
3421
+ case 'setup':
3422
+ return comandoSetup(args);
3423
+ case 'accounts':
3424
+ return comandoAccounts(args);
3425
+ case 'onboarding':
3426
+ return comandoOnboarding(args);
1850
3427
  case 'thread':
1851
3428
  return comandoThread(args);
3429
+ case 'objective':
3430
+ return comandoObjective(args);
3431
+ case 'creation':
3432
+ return comandoCreation(args);
3433
+ case 'portfolio':
3434
+ return comandoPortfolio(args);
1852
3435
  case 'phase':
1853
3436
  return comandoPhase(args);
3437
+ case 'ledger':
3438
+ return comandoLedger(args);
1854
3439
  case 'sessions':
1855
3440
  return comandoSessions(args);
3441
+ case 'pulse': {
3442
+ if (args.posicionais[1] === 'responder') {
3443
+ // I-41 (GO-FIX 1, B1 e B2): o caminho de volta do resumo. So o ingresso autenticado chama;
3444
+ // argv traz identificadores e o envelope assinado vem por stdin, como no `gate answer`.
3445
+ if (args.opcoes['resposta-stdin'] !== true || args.opcoes.resposta !== undefined || args.posicionais.length !== 2) {
3446
+ throw new Error('pulse responder exige --resposta-stdin e o envelope do ingresso autenticado');
3447
+ }
3448
+ const carregado = (0, manifest_1.exigirManifesto)();
3449
+ const envelope = (0, hitl_gates_1.lerRespostaStdin)({ por: texto(args.opcoes.por), mensagem: texto(args.opcoes.mensagem),
3450
+ origem: texto(args.opcoes.origem), canal: texto(args.opcoes.canal), conta: texto(args.opcoes.conta) });
3451
+ const formato = texto(args.opcoes.formato);
3452
+ if (formato !== undefined && formato !== 'telegram' && formato !== 'terminal')
3453
+ throw new Error('pulse responder: --formato telegram|terminal');
3454
+ console.log(JSON.stringify((0, pulse_resposta_1.responderPeloPulse)(carregado.raiz, envelope, { canal: formato ?? 'telegram' })));
3455
+ return 0;
3456
+ }
3457
+ if (args.posicionais[1] === 'cadencia')
3458
+ return comandoCadenciaDoPulse(args);
3459
+ const p = (0, pulse_1.montarPulse)((0, manifest_1.exigirManifesto)(), { registrar: args.opcoes.registrar === true,
3460
+ escopo: texto(args.opcoes.escopo)?.split(',').map(s => s.trim()),
3461
+ semRuntime: args.opcoes['sem-runtime'] === true,
3462
+ linhasLogs: texto(args.opcoes.linhas) === undefined ? undefined : Number(texto(args.opcoes.linhas)) });
3463
+ console.log(args.opcoes.json === true ? JSON.stringify(p, null, 2) : (0, pulse_1.textoDoPulse)(p));
3464
+ return p.runtime.ok || args.opcoes['sem-runtime'] === true ? 0 : 1;
3465
+ }
1856
3466
  case 'claims':
1857
3467
  return comandoClaims(args);
3468
+ case 'decisao':
3469
+ return comandoDecisao(args);
1858
3470
  case 'verify':
1859
3471
  return comandoVerify(args);
3472
+ case 'ci':
3473
+ return comandoCi(args);
1860
3474
  case 'gate':
1861
3475
  return comandoGate(args);
1862
3476
  case 'retry':
@@ -1867,12 +3481,21 @@ function main(argv) {
1867
3481
  return comandoHandoff(args);
1868
3482
  case 'recall':
1869
3483
  return comandoRecall(args);
3484
+ case 'brain': {
3485
+ const result = (0, company_brain_cli_1.runBrain)((0, manifest_1.exigirManifesto)(), args.posicionais[1] ?? 'status', args.opcoes, args.posicionais.slice(2));
3486
+ console.log(JSON.stringify(result, null, 2));
3487
+ return ['ok', 'empty', 'unknown', 'withheld', 'applied', 'rolled-back'].includes(result.state) ? 0 : 1;
3488
+ }
1870
3489
  case 'memory':
1871
3490
  return comandoMemory(args);
1872
3491
  case 'ship':
1873
3492
  return comandoShip(args);
3493
+ case 'activation':
3494
+ return (0, write_activation_1.comandoAtivacao)((0, manifest_1.exigirManifesto)(), args);
1874
3495
  case 'lease':
1875
3496
  return comandoLease(args);
3497
+ case 'conducao':
3498
+ return comandoConducao(args);
1876
3499
  case 'board':
1877
3500
  return comandoBoard(args);
1878
3501
  case 'orquestracao':
@@ -1890,6 +3513,19 @@ function main(argv) {
1890
3513
  return comandoAdapter(args);
1891
3514
  case 'prompt':
1892
3515
  return comandoPrompt(args);
3516
+ case 'docs':
3517
+ return comandoDocs(args);
3518
+ case 'roadmap':
3519
+ return comandoRoadmap(args);
3520
+ case 'demo': {
3521
+ // I-56 (RM-046): a promessa em trinta segundos, offline, sem runtime e sem tocar o projeto.
3522
+ const r = (0, demo_1.executarDemo)({ dir: texto(args.opcoes.dir), manter: args.opcoes.manter === true, escrever: (l) => console.log(l) });
3523
+ return r.ok ? 0 : 1;
3524
+ }
3525
+ case 'fabrica':
3526
+ return comandoFabrica(args);
3527
+ case 'licoes':
3528
+ return comandoLicoes(args);
1893
3529
  case 'ciclos':
1894
3530
  console.log((0, ciclos_1.tabelaDeVariantes)());
1895
3531
  return 0;
@@ -1904,7 +3540,14 @@ if (require.main === module) {
1904
3540
  process.exitCode = main(process.argv.slice(2));
1905
3541
  }
1906
3542
  catch (e) {
1907
- console.error(`erro: ${e.message}`);
1908
- process.exitCode = 1;
3543
+ // I-36 (T12): a recusa de conducao e resposta, nao erro: o texto para o humano, ou o JSON.
3544
+ if (e instanceof conducao_1.ErroDeConducao) {
3545
+ console.log(process.argv.includes('--json') ? JSON.stringify(e.recusa, null, 2) : e.recusa.texto);
3546
+ process.exitCode = 3;
3547
+ }
3548
+ else {
3549
+ console.error(`erro: ${e.message}`);
3550
+ process.exitCode = 1;
3551
+ }
1909
3552
  }
1910
3553
  }