@orkastery/cli 0.2.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) 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/check.md +4 -3
  7. package/adapters/claude-code/commands/goal.md +3 -2
  8. package/adapters/claude-code/commands/master.md +3 -2
  9. package/adapters/claude-code/commands/onboarding.md +21 -0
  10. package/adapters/claude-code/commands/ork.md +99 -27
  11. package/adapters/claude-code/hooks/hooks.json +6 -1
  12. package/adapters/claude-code/hooks/ork-guard.js +1 -1
  13. package/adapters/claude-code/hooks/ork-sensor.js +66 -0
  14. package/adapters/codex/skills/ork/SKILL.md +57 -0
  15. package/adapters/hermes/README.md +161 -0
  16. package/adapters/hermes/bin/ork-abrir-thread.sh +2 -0
  17. package/adapters/hermes/bin/ork-brain.sh +4 -0
  18. package/adapters/hermes/bin/ork-hitl-answer.py +82 -0
  19. package/adapters/hermes/bin/ork-maestro.sh +6 -0
  20. package/adapters/hermes/bin/ork-master-enviar.py +84 -0
  21. package/adapters/hermes/bin/ork-pulse-enviar.py +47 -0
  22. package/adapters/hermes/hermes.plugin.json +24 -4
  23. package/adapters/hermes/hitl-ingress/__init__.py +356 -0
  24. package/adapters/hermes/hitl-ingress/plugin.yaml +4 -0
  25. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +75 -22
  26. package/adapters/openclaw/README.md +136 -27
  27. package/adapters/openclaw/bin/ork-brain.sh +4 -0
  28. package/adapters/openclaw/construir.sh +19 -0
  29. package/adapters/openclaw/dist/hitl-ingress.js +199 -0
  30. package/adapters/openclaw/dist/index.js +437 -0
  31. package/adapters/openclaw/openclaw.plugin.json +39 -134
  32. package/adapters/openclaw/package.json +26 -0
  33. package/adapters/openclaw/src/hitl-ingress.ts +180 -0
  34. package/adapters/openclaw/src/index.ts +460 -0
  35. package/adapters/openclaw/src/tipos-openclaw.d.ts +58 -0
  36. package/adapters/openclaw/tsconfig.json +15 -0
  37. package/assets/docs/markdownlint-cli2.jsonc +22 -0
  38. package/assets/docs/padroes/documentacao-de-produto.md +133 -0
  39. package/assets/docs/padroes/roadmap-de-produto.md +98 -0
  40. package/assets/docs/produto/README.md +14 -0
  41. package/assets/docs/produto/_modelo-feature.md +59 -0
  42. package/assets/docs/roadmap/README.md +14 -0
  43. package/assets/docs/roadmap/_modelo-item.md +73 -0
  44. package/assets/orkmind-native-schema.json +32 -0
  45. package/assets/orkmind_bridge.py +357 -0
  46. package/assets/orkmind_fixture.py +67 -0
  47. package/assets/orkmind_prospective.py +138 -0
  48. package/assets/reference-tariffs-i07.json +23 -0
  49. package/dist/adapters/claude-bg.js +488 -39
  50. package/dist/adapters/codex-controller-sensor.js +449 -0
  51. package/dist/adapters/codex-controller-worker.js +361 -0
  52. package/dist/adapters/codex-controller.js +252 -0
  53. package/dist/adapters/codex-events.js +205 -0
  54. package/dist/adapters/codex-question.js +26 -0
  55. package/dist/adapters/codex-runner.js +133 -0
  56. package/dist/adapters/codex.js +394 -0
  57. package/dist/agents-md.js +84 -0
  58. package/dist/auditoria.js +12 -9
  59. package/dist/auditrun.js +5 -4
  60. package/dist/board.js +174 -23
  61. package/dist/branch-de-estado.js +136 -0
  62. package/dist/canarios-hitl.js +177 -0
  63. package/dist/canarios-i43.js +543 -0
  64. package/dist/canarios-pulse.js +147 -0
  65. package/dist/canarios-sensores.js +129 -0
  66. package/dist/canarios.js +111 -2
  67. package/dist/catalogo.js +9 -0
  68. package/dist/ci.js +223 -0
  69. package/dist/ciclos.js +2 -1
  70. package/dist/claim-lint.js +64 -0
  71. package/dist/claims.js +60 -0
  72. package/dist/company-brain-capture.js +195 -0
  73. package/dist/company-brain-cli.js +123 -0
  74. package/dist/company-brain-client.js +61 -0
  75. package/dist/company-brain-contract.js +166 -0
  76. package/dist/company-brain-journal.js +192 -0
  77. package/dist/company-brain-mcp.js +33 -0
  78. package/dist/company-brain-migration.js +60 -0
  79. package/dist/company-brain-source.js +177 -0
  80. package/dist/company-brain-worker.js +18 -0
  81. package/dist/conducao-texto.js +61 -0
  82. package/dist/conducao.js +876 -0
  83. package/dist/contrato-publico.js +39 -0
  84. package/dist/creation-operation-store.js +251 -0
  85. package/dist/creation-operation.js +148 -0
  86. package/dist/decisao-autonoma.js +183 -0
  87. package/dist/delegation.js +79 -0
  88. package/dist/demo.js +120 -0
  89. package/dist/docs.js +828 -0
  90. package/dist/doctor.js +184 -25
  91. package/dist/entrega-pr.js +117 -0
  92. package/dist/escopo-escrita.js +71 -0
  93. package/dist/estado-thread.js +222 -0
  94. package/dist/evalrunner.js +12 -0
  95. package/dist/fabrica-estado.js +329 -0
  96. package/dist/fabrica-publicar.js +76 -0
  97. package/dist/fix.js +22 -1
  98. package/dist/gates.js +59 -11
  99. package/dist/handoff.js +39 -23
  100. package/dist/hitl-canais.js +333 -0
  101. package/dist/hitl-classificacao.js +131 -0
  102. package/dist/hitl-contract.js +465 -0
  103. package/dist/hitl-estado.js +136 -0
  104. package/dist/hitl-gates.js +554 -0
  105. package/dist/hitl-ingress-receipt.js +382 -0
  106. package/dist/hitl-local-atestado.js +57 -0
  107. package/dist/hitl-local-receipt.js +328 -0
  108. package/dist/hitl-local.js +143 -0
  109. package/dist/hitl-lock.js +139 -0
  110. package/dist/hitl-lote.js +223 -0
  111. package/dist/hitl-native-offer.js +97 -0
  112. package/dist/hitl-native.js +65 -0
  113. package/dist/hitl-presentation.js +209 -0
  114. package/dist/hitl-public-receipt.js +176 -0
  115. package/dist/hitl-resumo.js +209 -0
  116. package/dist/hitl-sessions.js +475 -0
  117. package/dist/hitl.js +711 -0
  118. package/dist/horario.js +269 -0
  119. package/dist/hosts.js +198 -22
  120. package/dist/index.js +1741 -94
  121. package/dist/indice.js +99 -0
  122. package/dist/init.js +28 -3
  123. package/dist/integracoes-locais.js +17 -0
  124. package/dist/leases.js +65 -21
  125. package/dist/ledger-stats.js +272 -0
  126. package/dist/ledger.js +109 -2
  127. package/dist/licoes.js +221 -0
  128. package/dist/liveness.js +218 -0
  129. package/dist/maestro-actions.js +51 -0
  130. package/dist/maestro-authority.js +152 -0
  131. package/dist/maestro-cli.js +97 -0
  132. package/dist/maestro-contract.js +55 -0
  133. package/dist/maestro-discovery.js +132 -0
  134. package/dist/maestro-runtime.js +268 -0
  135. package/dist/maestro-snapshot.js +86 -0
  136. package/dist/maestro-sources.js +224 -0
  137. package/dist/manifest.js +165 -6
  138. package/dist/maquina.js +102 -0
  139. package/dist/master-audit.js +101 -0
  140. package/dist/master-batch.js +43 -0
  141. package/dist/master-digest.js +149 -0
  142. package/dist/master-migracao.js +155 -0
  143. package/dist/master.js +361 -77
  144. package/dist/mcp-artifacts.js +234 -0
  145. package/dist/mcp-git.js +433 -0
  146. package/dist/mcp-install.js +310 -0
  147. package/dist/mcp-maestro.js +25 -0
  148. package/dist/mcp-server.js +469 -0
  149. package/dist/mcp-ship.js +436 -0
  150. package/dist/mcp-verify.js +173 -0
  151. package/dist/memoria-humana.js +207 -0
  152. package/dist/memoria.js +314 -78
  153. package/dist/memory-migration.js +279 -0
  154. package/dist/memory-prospective.js +148 -0
  155. package/dist/modos-migracao.js +191 -0
  156. package/dist/modos.js +151 -15
  157. package/dist/monitor-lock.js +110 -0
  158. package/dist/objective.js +449 -0
  159. package/dist/ocupacao.js +267 -0
  160. package/dist/onboarding.js +303 -0
  161. package/dist/orkmind.js +389 -90
  162. package/dist/orquestracao.js +96 -69
  163. package/dist/phase.js +612 -151
  164. package/dist/playbook-capabilities.js +150 -0
  165. package/dist/playbook-contracts.js +188 -0
  166. package/dist/policies.js +72 -0
  167. package/dist/portfolio-context.js +61 -0
  168. package/dist/portfolio.js +180 -0
  169. package/dist/preflight.js +207 -0
  170. package/dist/process-audit.js +112 -0
  171. package/dist/project-state.js +93 -0
  172. package/dist/prompts.js +25 -5
  173. package/dist/prova-minima.js +112 -0
  174. package/dist/pulse-cadencia.js +163 -0
  175. package/dist/pulse-consentimento.js +260 -0
  176. package/dist/pulse-delivery.js +323 -0
  177. package/dist/pulse-resposta.js +542 -0
  178. package/dist/pulse.js +262 -0
  179. package/dist/ratelimit.js +35 -2
  180. package/dist/recall.js +80 -3
  181. package/dist/redacao-saida.js +45 -0
  182. package/dist/redacao-url.js +66 -0
  183. package/dist/retry.js +640 -118
  184. package/dist/roadmap-reservas.js +243 -0
  185. package/dist/runtime-ambiente.js +38 -0
  186. package/dist/runtime-context.js +215 -0
  187. package/dist/runtime-profiles.js +869 -0
  188. package/dist/runtimes.js +103 -0
  189. package/dist/sandbox.js +9 -0
  190. package/dist/session-events.js +203 -0
  191. package/dist/session-watcher-claude.js +637 -0
  192. package/dist/session-watcher.js +700 -0
  193. package/dist/sessoes-adopt.js +154 -0
  194. package/dist/sessoes-inventario.js +159 -0
  195. package/dist/sessoes.js +16 -35
  196. package/dist/setup.js +691 -0
  197. package/dist/ship.js +168 -19
  198. package/dist/slug.js +1 -1
  199. package/dist/thread-close.js +115 -0
  200. package/dist/thread.js +142 -28
  201. package/dist/tokens.js +1 -1
  202. package/dist/util.js +4 -2
  203. package/dist/verify-sandbox.js +265 -0
  204. package/dist/verify.js +270 -25
  205. package/dist/versao.js +60 -0
  206. package/dist/worktree.js +31 -2
  207. package/dist/write-activation.js +291 -0
  208. package/dist/yaml.js +5 -1
  209. package/eval/casos/master-metrics.json +1 -1
  210. package/eval/casos/onboarding.json +102 -0
  211. package/eval/casos/orkastery-bootstrap.json +37 -3
  212. package/eval/casos/scope-check-capability-map.json +45 -7
  213. package/eval/casos/ship-release.json +3 -3
  214. package/eval/fixtures/b0-slug-e-modos/caso.json +35 -22
  215. package/eval/fixtures/b2-master-log/caso.json +1 -1
  216. package/eval/fixtures/fx-adapter-editado-detectado/caso.json +19 -0
  217. package/eval/fixtures/fx-auto-quiet/caso.json +11 -0
  218. package/eval/fixtures/fx-blanket-approve/caso.json +10 -0
  219. package/eval/fixtures/fx-check-runtime-cruzado/caso.json +20 -0
  220. package/eval/fixtures/fx-codex-dry/caso.json +18 -0
  221. package/eval/fixtures/fx-donewhen-executavel/caso.json +15 -0
  222. package/eval/fixtures/fx-estado-dividido/caso.json +15 -0
  223. package/eval/fixtures/fx-fase-orfa/caso.json +116 -0
  224. package/eval/fixtures/fx-happy/caso.json +6 -4
  225. package/eval/fixtures/fx-hitl-latency/caso.json +20 -0
  226. package/eval/fixtures/fx-indice-reversao/caso.json +25 -0
  227. package/eval/fixtures/fx-listagem-abertas/caso.json +16 -0
  228. package/eval/fixtures/fx-maestro-bootstrap/caso.json +21 -0
  229. package/eval/fixtures/fx-modo-aposentado-escritor/caso.json +21 -0
  230. package/eval/fixtures/fx-modo-aposentado-leitor/caso.json +16 -0
  231. package/eval/fixtures/fx-objective-oscillation/caso.json +14 -0
  232. package/eval/fixtures/fx-omnicanal/caso.json +17 -0
  233. package/eval/fixtures/fx-sensores-runtime/caso.json +17 -0
  234. package/monitor/company-brain.cjs +17 -0
  235. package/monitor/pulse-scope.cjs +45 -0
  236. package/monitor/pulse.cron +18 -0
  237. package/monitor/varredura-pulse.sh +27 -0
  238. package/package.json +28 -7
  239. package/references/definition-of-done.md +2 -2
  240. package/schemas/claims.schema.json +25 -0
  241. package/schemas/company-brain.schema.json +1158 -0
  242. package/schemas/creation-operation.schema.json +365 -0
  243. package/schemas/maestro-snapshot.schema.json +2716 -0
  244. package/skills/README.md +3 -3
  245. package/skills/core/onboarding/SKILL.md +50 -0
  246. package/skills/core/orkastery-bootstrap/SKILL.md +95 -65
  247. package/skills/core/thread-state/SKILL.md +3 -1
  248. package/skills/governance/decision-triage/SKILL.md +4 -4
  249. package/skills/governance/narrative-guardian/SKILL.md +1 -1
  250. package/skills/governance/roadmap-keeper/SKILL.md +1 -1
  251. package/skills/governance/scope-check-capability-map/SKILL.md +17 -7
  252. package/skills/observability/thread-tracing/SKILL.md +1 -1
  253. package/skills/phases/check-quality/SKILL.md +2 -2
  254. package/skills/phases/goal-definition/SKILL.md +1 -1
  255. package/skills/phases/master-metrics/SKILL.md +9 -7
  256. package/skills/phases/plan-specification/SKILL.md +1 -1
  257. package/skills/phases/ship-release/SKILL.md +1 -1
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,39 @@ 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(' ')}`);
1025
+ for (const l of (0, policies_1.linhasDeAviso)(r.violacoes ?? []))
1026
+ console.log(l);
423
1027
  return 0;
424
1028
  }
425
1029
  if (r.bloqueado) {
@@ -432,20 +1036,29 @@ function comandoPhase(args) {
432
1036
  return 1;
433
1037
  }
434
1038
  if (!r.sessionId) {
435
- console.error(`Despacho falhou: ${r.erro}`);
1039
+ // I-35: o erro vai ao ledger com o ISO; o dono le no fuso dele, com o fuso dito uma vez.
1040
+ console.error(`Despacho falhou: ${r.erro ? (0, horario_1.localizarTextoRotulado)(r.erro) : r.erro}`);
436
1041
  console.error(` evento registrado no ledger de ${id}`);
437
1042
  return 1;
438
1043
  }
439
1044
  console.log(`Fase ${fase} despachada como background agent.`);
1045
+ for (const l of (0, policies_1.linhasDeAviso)(r.violacoes ?? []))
1046
+ console.log(l);
440
1047
  console.log(` sessionId : ${r.sessionId}`);
441
1048
  console.log(` slug da sessao : ${r.slug} (${(0, phase_1.descreverSlug)(r.slug)})`);
442
1049
  console.log(` prompt : ${r.promptPath}`);
443
1050
  console.log(` sha256 : ${r.promptSha256}`);
1051
+ console.log(` runtime : ${r.runtime}`);
444
1052
  console.log(` modelo/esforco : ${r.model}/${r.effort} (gravado no ledger, veja \`ork phase list\`)`);
445
1053
  console.log(` verificada no runtime: ${r.verificada ? 'sim' : 'NAO (confira `ork sessions`)'}`);
446
1054
  console.log(` pausa ao fim do bloco: ${r.pausaAoFim ? 'sim' : 'nao (decisao autonoma no ledger)'}`);
447
1055
  console.log('');
448
- console.log(`Acompanhe: claude attach ${r.sessionId} | ork phase list ${id}`);
1056
+ if (r.runtime === 'claude-bg') {
1057
+ console.log(`Acompanhe: claude attach ${r.sessionId} | ork phase list ${id}`);
1058
+ }
1059
+ else {
1060
+ console.log(`Acompanhe: ork phase list ${id} (eventos do despacho no log da thread)`);
1061
+ }
449
1062
  return r.verificada ? 0 : 1;
450
1063
  }
451
1064
  if (sub === 'list') {
@@ -460,12 +1073,137 @@ function comandoPhase(args) {
460
1073
  console.error(`subcomando desconhecido: phase ${sub}`);
461
1074
  return 2;
462
1075
  }
1076
+ function comandoLedger(args) {
1077
+ const carregado = (0, manifest_1.exigirManifesto)();
1078
+ const sub = args.posicionais[1];
1079
+ if (sub === 'stats') {
1080
+ const desde = texto(args.opcoes.desde);
1081
+ if (!desde)
1082
+ throw Error('uso: ork ledger stats --desde 7d [--ate ISO] [--thread T] [--modo M] [--runtime R] [--json]');
1083
+ 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) });
1084
+ console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2) : (0, ledger_stats_1.textoDasEstatisticas)(r));
1085
+ return 0;
1086
+ }
1087
+ if (sub === 'estimate') {
1088
+ const thread = args.posicionais[2], semIa = Number(texto(args.opcoes['sem-ia'])), iaSemOrk = Number(texto(args.opcoes['ia-sem-ork']));
1089
+ const por = texto(args.opcoes.por), metodo = texto(args.opcoes.metodo), premissas = texto(args.opcoes.premissas);
1090
+ if (!thread || !por || !metodo || !premissas)
1091
+ throw Error('uso: ork ledger estimate <thread-id> --sem-ia H --ia-sem-ork H --por Q --metodo M --premissas P [--incerteza I]');
1092
+ const e = (0, ledger_stats_1.registrarEstimativaPlano)(carregado.raiz, thread, { semIaHoras: semIa, iaSemOrkHoras: iaSemOrk, por, metodo, premissas, incerteza: texto(args.opcoes.incerteza) });
1093
+ 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.`);
1094
+ return 0;
1095
+ }
1096
+ throw Error('uso: ork ledger stats|estimate ...');
1097
+ }
1098
+ /**
1099
+ * `ork sessions hitl`: quem, entre as sessoes do runtime, espera o humano AGORA.
1100
+ *
1101
+ * Complementa o `ork monitor`, que e thread-centrico: aqui a varredura parte das SESSOES,
1102
+ * entao ela enxerga a sessao `claude --bg` que travou em HITL sem ter thread nenhuma --
1103
+ * o buraco exato do incidente de 05/09/2026 (codigo 2FA do `npm publish`).
1104
+ *
1105
+ * O `--exigir-limpo` transforma o radar em watchdog: sai != 0 enquanto houver sessao
1106
+ * esperando humano, entao um cron ou o proprio orquestrador trata "tem gente esperando"
1107
+ * como falha acionavel, sem precisar interpretar texto.
1108
+ */
1109
+ function comandoSessionsHitl(args, raiz) {
1110
+ const bruto = texto(args.opcoes.atencao);
1111
+ const atencaoMin = bruto === undefined ? undefined : Number(bruto);
1112
+ if (atencaoMin !== undefined && (!Number.isFinite(atencaoMin) || atencaoMin < 0)) {
1113
+ console.error(`--atencao espera minutos (inteiro >= 0), recebeu "${bruto}"`);
1114
+ return 2;
1115
+ }
1116
+ const radar = (0, hitl_1.varrerSessoes)({
1117
+ raiz,
1118
+ registrar: args.opcoes.registrar === true,
1119
+ escopo: texto(args.opcoes.escopo)?.split(',').map(s => s.trim()),
1120
+ registrarMaquina: args.opcoes['registrar-maquina'] === true,
1121
+ linhasLogs: texto(args.opcoes.linhas) === undefined ? undefined : Number(texto(args.opcoes.linhas)),
1122
+ soDaRaiz: args.opcoes['so-da-raiz'] === true,
1123
+ soParadas: args.opcoes['so-paradas'] === true,
1124
+ semLogs: args.opcoes['sem-logs'] === true,
1125
+ atencaoMin,
1126
+ });
1127
+ console.log(args.opcoes.json === true ? JSON.stringify(radar, null, 2) : (0, hitl_1.textoDoRadar)(radar));
1128
+ if (!radar.runtimeConsultado)
1129
+ return 1;
1130
+ if (args.opcoes['exigir-limpo'] === true)
1131
+ return radar.resumo.precisamDeHumano > 0 ? 1 : 0;
1132
+ return 0;
1133
+ }
463
1134
  function comandoSessions(args) {
464
1135
  const sub = args.posicionais[1];
465
1136
  const carregado = (0, manifest_1.carregarManifesto)();
466
1137
  const raiz = carregado?.raiz ?? process.cwd();
1138
+ if (sub === 'watch') {
1139
+ const id = texto(args.opcoes.thread);
1140
+ if (!carregado || !id) {
1141
+ console.error('uso: ork sessions watch --thread T [--sessao ID] [--once]');
1142
+ return 2;
1143
+ }
1144
+ const thread = (0, thread_1.lerThread)(raiz, id);
1145
+ const sessionId = texto(args.opcoes.sessao) ?? thread.sessoes.at(-1)?.sessionId;
1146
+ if (!sessionId || !thread.sessoes.some(s => s.sessionId === sessionId))
1147
+ throw new Error('sessão não pertence à thread');
1148
+ console.log(JSON.stringify(args.opcoes.once === true ? (0, session_watcher_1.observarSessao)(carregado, sessionId) : { pid: (0, session_watcher_1.iniciarWatcher)(raiz, sessionId) }));
1149
+ return 0;
1150
+ }
1151
+ if (sub === 'event') {
1152
+ const tipo = texto(args.opcoes.tipo), sessao = texto(args.opcoes.sessao);
1153
+ if (!carregado || !tipo || !sessao) {
1154
+ console.error('uso: ork sessions event --tipo <tipo> --sessao <id> < payload.json (máximo 16384 bytes)');
1155
+ return 2;
1156
+ }
1157
+ try {
1158
+ console.log(JSON.stringify((0, session_events_1.ingerirEvento)(raiz, sessao, tipo, (0, session_events_1.lerPayloadSensor)())));
1159
+ return 0;
1160
+ }
1161
+ catch (e) {
1162
+ console.error(`evento recusado: ${e.message}`);
1163
+ return 1;
1164
+ }
1165
+ }
467
1166
  if (sub === undefined || sub === 'list') {
468
- console.log((0, sessoes_1.tabelaDeSessoes)(raiz, args.opcoes.all === true));
1167
+ const r = (0, sessoes_inventario_1.inventariarSessoes)(raiz, { todas: args.opcoes.all === true, global: args.opcoes.global === true });
1168
+ console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2) : (0, sessoes_1.textoDoInventario)(r));
1169
+ return !r.ok || (args.opcoes['exigir-limpo'] === true && r.semThread > 0) ? 1 : 0;
1170
+ }
1171
+ if (sub === 'hitl') {
1172
+ return comandoSessionsHitl(args, carregado ? raiz : '');
1173
+ }
1174
+ if (sub === 'request') {
1175
+ const id = args.posicionais[2], sessionId = args.posicionais[3];
1176
+ const fase = texto(args.opcoes.fase), runtime = texto(args.opcoes.runtime), pergunta = texto(args.opcoes.pergunta);
1177
+ if (!id || !sessionId || !fase || !types_1.FASES.includes(fase) || !runtime)
1178
+ throw new Error('sessions request exige thread, UUID, --fase e --runtime; --pergunta só confere o conteúdo nativo');
1179
+ console.log(JSON.stringify((0, hitl_sessions_1.abrirPedidoSessao)(raiz, id, sessionId, { fase: fase, runtime, pergunta, prazo: texto(args.opcoes.prazo) })));
1180
+ return 0;
1181
+ }
1182
+ if (sub === 'answer') {
1183
+ const id = args.posicionais[2], pedido = args.posicionais[3];
1184
+ if (!id || !pedido || args.opcoes.stdin !== true)
1185
+ throw new Error('sessions answer exige thread, pedido e envelope autenticado em --stdin');
1186
+ const r = (0, hitl_gates_1.lerRespostaStdin)({ origem: texto(args.opcoes.origem), por: texto(args.opcoes.por),
1187
+ mensagem: texto(args.opcoes.mensagem), canal: texto(args.opcoes.canal), conta: texto(args.opcoes.conta) });
1188
+ console.log(JSON.stringify((0, hitl_sessions_1.responderSessao)(raiz, id, pedido, r)));
1189
+ return 0;
1190
+ }
1191
+ if (sub === 'reconcile') {
1192
+ // FX3: fecha um envio pendente so com (thread, pedido). Nao reenvia e nao re-elicita:
1193
+ // pergunta ao receptor, pelo recibo correlacionado, se ele recebeu aquele envioId.
1194
+ const id = args.posicionais[2], pedido = args.posicionais[3];
1195
+ if (!id || !pedido)
1196
+ throw new Error('sessions reconcile exige thread e pedido');
1197
+ const r = (0, hitl_sessions_1.reconciliarEnvioDeSessao)(raiz, id, pedido);
1198
+ console.log(JSON.stringify(r));
1199
+ return r.estado === 'entregue' ? 0 : 1;
1200
+ }
1201
+ if (sub === 'supersede') {
1202
+ const id = args.posicionais[2], sessionId = args.posicionais[3];
1203
+ const fase = texto(args.opcoes.fase), runtime = texto(args.opcoes.runtime);
1204
+ if (!id || !sessionId || !fase || !types_1.FASES.includes(fase) || !runtime)
1205
+ throw new Error('sessions supersede exige thread, UUID, --fase e --runtime');
1206
+ console.log(JSON.stringify((0, hitl_sessions_1.superarSessao)(raiz, id, sessionId, fase, runtime)));
469
1207
  return 0;
470
1208
  }
471
1209
  const chave = args.posicionais[2];
@@ -473,25 +1211,110 @@ function comandoSessions(args) {
473
1211
  console.error(`uso: ork sessions ${sub} <sessao>`);
474
1212
  return 2;
475
1213
  }
1214
+ if (sub === 'adopt') {
1215
+ const r = (0, sessoes_adopt_1.adotarSessao)((0, manifest_1.exigirManifesto)(), chave);
1216
+ console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2) :
1217
+ `${r.detalhe}${r.vinculo ? `: ${r.sessionId} -> ${r.vinculo.thread} (${r.vinculo.raiz})` : ''}`);
1218
+ return r.ok ? 0 : 1;
1219
+ }
476
1220
  if (sub === 'logs') {
477
1221
  const n = Number(texto(args.opcoes.linhas) ?? '60');
478
- const r = (0, sessoes_1.logsDaSessao)(chave, Number.isFinite(n) ? n : 60);
1222
+ const r = (0, sessoes_2.logsDaSessao)(chave, Number.isFinite(n) ? n : 60);
479
1223
  console.log(r.texto);
480
1224
  return r.codigo;
481
1225
  }
482
1226
  if (sub === 'stop') {
483
- const r = (0, sessoes_1.pararSessao)(chave);
1227
+ const r = (0, sessoes_2.pararSessao)(chave);
484
1228
  console.log(r.texto);
485
1229
  return r.codigo;
486
1230
  }
487
1231
  if (sub === 'attach') {
488
- const r = (0, sessoes_1.comandoDeAttach)(chave);
1232
+ const r = (0, sessoes_2.comandoDeAttach)(chave);
489
1233
  console.log(r.texto);
490
1234
  return r.codigo;
491
1235
  }
492
1236
  console.error(`subcomando desconhecido: sessions ${sub}`);
493
1237
  return 2;
494
1238
  }
1239
+ /**
1240
+ * I-41 (GO-FIX 1, B4): a decisao que a sessao toma sem perguntar ao dono vai ao ledger por aqui,
1241
+ * com o que foi decidido, o porque, como mudar, o custo de reverter, o criterio escrito, quem
1242
+ * decidiu e a evidencia. E assim que ela chega ao dono no resumo, em vez de sumir na conversa.
1243
+ */
1244
+ function comandoDecisao(args) {
1245
+ const carregado = (0, manifest_1.exigirManifesto)();
1246
+ const sub = args.posicionais[1], id = args.posicionais[2];
1247
+ if (sub === 'registrar') {
1248
+ const campo = (nome) => {
1249
+ const v = texto(args.opcoes[nome]);
1250
+ if (!v)
1251
+ throw new Error(`decisao registrar exige --${nome}`);
1252
+ return v;
1253
+ };
1254
+ if (!id)
1255
+ throw new Error('uso: ork decisao registrar <thread-id> --decidido D --porque P ...');
1256
+ const bruto = campo('criterio'), separador = bruto.indexOf(':');
1257
+ const tipo = bruto.slice(0, separador), referencia = bruto.slice(separador + 1);
1258
+ if (separador < 1 || !['manifesto', 'ledger', 'medicao'].includes(tipo) || !referencia.trim()) {
1259
+ throw new Error('decisao registrar: --criterio manifesto:CHAVE, ledger:REF ou medicao:COMANDO');
1260
+ }
1261
+ const { pedido, evento } = (0, decisao_autonoma_1.registrarDecisao)(carregado.raiz, id, {
1262
+ decidido: campo('decidido'), porque: campo('porque'), comoMudar: campo('como-mudar'),
1263
+ custoDeReverter: { agora: campo('custo-agora'), depois: campo('custo-depois') },
1264
+ criterio: { tipo, referencia }, quemDecidiu: campo('quem'), evidencia: campo('evidencia'),
1265
+ razao: texto(args.opcoes.razao), reverte: texto(args.opcoes.reverte),
1266
+ });
1267
+ const placar = (0, decisao_autonoma_1.placarDaThread)((0, ledger_1.lerLedger)((0, thread_1.dirThread)(carregado.raiz, id))).find(f => f.fase === pedido.fase);
1268
+ console.log(JSON.stringify({ ok: true, pedidoId: pedido.id, eventId: evento.eventId, fase: pedido.fase, placar }));
1269
+ return 0;
1270
+ }
1271
+ if (sub === 'placar') {
1272
+ if (!id)
1273
+ throw new Error('uso: ork decisao placar <thread-id> [--json]');
1274
+ (0, thread_1.lerThread)(carregado.raiz, id);
1275
+ const placar = (0, decisao_autonoma_1.placarDaThread)((0, ledger_1.lerLedger)((0, thread_1.dirThread)(carregado.raiz, id)));
1276
+ const taxa = (0, decisao_autonoma_1.taxaDeReversao)(placar);
1277
+ if (args.opcoes.json === true) {
1278
+ console.log(JSON.stringify({ thread: id, limiar: decisao_autonoma_1.LIMIAR_DE_DECISOES_POR_FASE, taxaDeReversao: taxa, fases: placar }, null, 2));
1279
+ return 0;
1280
+ }
1281
+ 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),
1282
+ String(f.semRastro), f.acimaDoLimiar ? `acima de ${decisao_autonoma_1.LIMIAR_DE_DECISOES_POR_FASE}: revisar` : 'ok'])));
1283
+ console.log(`\ntaxa de reversão das decisões informadas: ${taxa === null ? 'sem decisão informada ainda' : `${Math.round(taxa * 100)}%`}`);
1284
+ return 0;
1285
+ }
1286
+ throw new Error('uso: ork decisao registrar|placar <thread-id>');
1287
+ }
1288
+ /**
1289
+ * I-50 (RM-039): a tag que o dono manda no Telegram, pelo terminal. Sem tag, mostra a cadencia em
1290
+ * vigor. O `#` e opcional porque o shell trata `#` no inicio da palavra como comentario.
1291
+ */
1292
+ function comandoCadenciaDoPulse(args) {
1293
+ const carregado = (0, manifest_1.exigirManifesto)();
1294
+ if (args.posicionais.length > 3)
1295
+ throw new Error('pulse cadencia: uma tag por vez');
1296
+ const bruta = args.posicionais[2];
1297
+ const agora = new Date().toISOString();
1298
+ if (bruta !== undefined) {
1299
+ const lido = (0, pulse_resposta_1.interpretarRespostaDoPulse)(bruta.trim().startsWith('#') ? bruta : `#${bruta.trim()}`);
1300
+ if (lido.forma !== 'cadencia') {
1301
+ throw new Error(`pulse cadencia: tag desconhecida "${bruta}"; use ${Object.keys(pulse_cadencia_1.CADENCIAS).join(', ')}`);
1302
+ }
1303
+ (0, pulse_cadencia_1.gravarCadencia)(carregado.raiz, lido.tag, { por: texto(args.opcoes.por) ?? (0, node_os_1.userInfo)().username,
1304
+ canal: texto(args.opcoes.canal) ?? 'terminal', em: agora });
1305
+ }
1306
+ const vigente = (0, pulse_cadencia_1.lerCadencia)(carregado.raiz);
1307
+ if (args.opcoes.json === true) {
1308
+ console.log(JSON.stringify({ tag: vigente.tag, janelaMin: vigente.janelaMin, ancoraMin: vigente.ancoraMin,
1309
+ descricao: vigente.descricao, gravada: vigente.gravada, proximaJanela: (0, pulse_cadencia_1.inicioDaProximaJanela)(vigente, agora) }, null, 2));
1310
+ return 0;
1311
+ }
1312
+ console.log((0, pulse_cadencia_1.textoDaCadencia)(vigente, agora));
1313
+ console.log(vigente.gravada
1314
+ ? `Trocada por ${vigente.gravada.por} (${vigente.gravada.canal}) em ${(0, horario_1.formatarDataHoraRotulada)(vigente.gravada.em)}.`
1315
+ : 'Nenhuma tag gravada: vale a cadência padrão.');
1316
+ return 0;
1317
+ }
495
1318
  function comandoClaims(args) {
496
1319
  const carregado = (0, manifest_1.exigirManifesto)();
497
1320
  const sub = args.posicionais[1];
@@ -522,6 +1345,11 @@ function comandoClaims(args) {
522
1345
  console.log('');
523
1346
  console.log('AVISO: alegacao negativa sem comando de verificacao reprova em `ork verify`.');
524
1347
  }
1348
+ // I-53 (RM-037, P6): o lint avisa aqui; a suite inteira e recusada no `ci prepare`.
1349
+ for (const a of claim.lint ?? []) {
1350
+ console.log('');
1351
+ console.log(`AVISO: ${(0, claim_lint_1.linhaDoLintDeClaim)(claim.id, a)}${a.regra === 'suite-inteira' ? '. O `ci prepare` recusa esta claim.' : ''}`);
1352
+ }
525
1353
  return 0;
526
1354
  }
527
1355
  if (sub === 'verificar') {
@@ -555,6 +1383,19 @@ function comandoClaims(args) {
555
1383
  console.log(' o historico da alegacao continua no claims.jsonl e no ledger.');
556
1384
  return 0;
557
1385
  }
1386
+ if (sub === 'ausente') {
1387
+ const id = args.posicionais[2];
1388
+ const paths = (texto(args.opcoes.paths) ?? '').split(',').map((p) => p.trim()).filter(Boolean);
1389
+ const motivo = texto(args.opcoes.motivo);
1390
+ if (!id || paths.length === 0 || !motivo) {
1391
+ console.error('uso: ork claims ausente <thread-id> --paths A,B --motivo "<motivo>" [--commit SHA]');
1392
+ return 2;
1393
+ }
1394
+ (0, prova_minima_1.registrarProvaAusente)(carregado.raiz, id, { paths, motivo, commit: texto(args.opcoes.commit) });
1395
+ console.log(`Ausencia de prova registrada na thread ${id}: ${paths.join(', ')}.`);
1396
+ console.log(` motivo ${motivo}`);
1397
+ return 0;
1398
+ }
558
1399
  if (sub === 'list' || sub === undefined) {
559
1400
  const id = args.posicionais[2];
560
1401
  if (!id) {
@@ -571,11 +1412,12 @@ function comandoVerify(args) {
571
1412
  const carregado = (0, manifest_1.exigirManifesto)();
572
1413
  const id = args.posicionais[1];
573
1414
  if (!id) {
574
- console.error('uso: ork verify <thread-id> [--baseline] [--so-claims]');
1415
+ console.error('uso: ork verify <thread-id> [--baseline] [--so-claims] [--canal C] [--esperar [min]]');
575
1416
  return 2;
576
1417
  }
1418
+ const conducao = conducaoDoCli(args);
577
1419
  if (args.opcoes.baseline === true) {
578
- const b = (0, verify_1.gravarBaseline)(carregado, id);
1420
+ const b = (0, verify_1.gravarBaseline)(carregado, id, undefined, conducao);
579
1421
  console.log(`Baseline gravada para a thread ${id}.`);
580
1422
  console.log(` commit ${b.commit}`);
581
1423
  for (const c of b.comandos) {
@@ -586,13 +1428,67 @@ function comandoVerify(args) {
586
1428
  }
587
1429
  return 0;
588
1430
  }
589
- const r = (0, verify_1.verificar)(carregado, id, { soClaims: args.opcoes['so-claims'] === true });
1431
+ const r = (0, verify_1.verificar)(carregado, id, { soClaims: args.opcoes['so-claims'] === true, conducao });
590
1432
  console.log((0, verify_1.textoDoVerify)(r));
591
1433
  return r.ok ? 0 : 1;
592
1434
  }
1435
+ /**
1436
+ * `ork conducao status|assumir` (I-36, T15): quem conduz a thread agora, e o handoff explicito. O
1437
+ * status tambem libera, com prova no ledger, a conducao que ficou sem dono (T16).
1438
+ */
1439
+ function comandoConducao(args) {
1440
+ const carregado = (0, manifest_1.exigirManifesto)();
1441
+ const sub = args.posicionais[1];
1442
+ const id = args.posicionais[2];
1443
+ if (sub === 'status') {
1444
+ if (!id)
1445
+ throw new Error('uso: ork conducao status <thread-id> [--json]');
1446
+ (0, thread_1.lerThread)(carregado.raiz, id);
1447
+ (0, conducao_1.liberarSeOrfa)(carregado.raiz, id);
1448
+ const atual = (0, conducao_1.conducaoDaThread)(carregado.raiz, id);
1449
+ console.log(args.opcoes.json === true ? JSON.stringify({ thread: id, conducao: atual }, null, 2) : (0, conducao_1.textoDoStatusDaConducao)(id, atual));
1450
+ return 0;
1451
+ }
1452
+ if (sub === 'assumir') {
1453
+ const por = texto(args.opcoes.por), motivo = texto(args.opcoes.motivo);
1454
+ if (!id || !por || !motivo)
1455
+ throw new Error('uso: ork conducao assumir <thread-id> --por <quem> --motivo "<por que>" [--canal C]');
1456
+ const r = (0, conducao_1.assumirConducao)(carregado.raiz, id, { por, motivo, canal: conducaoDoCli(args).canal });
1457
+ console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2) : `${r.ok ? 'Conducao assumida.' : 'Handoff recusado.'} ${r.detalhe}`);
1458
+ return r.ok ? 0 : 3;
1459
+ }
1460
+ throw new Error('uso: ork conducao status|assumir <thread-id>');
1461
+ }
593
1462
  function comandoGate(args) {
594
1463
  const carregado = (0, manifest_1.exigirManifesto)();
595
1464
  const sub = args.posicionais[1];
1465
+ if (sub === 'context') {
1466
+ const id = args.posicionais[2], pedido = args.posicionais[3];
1467
+ if (!id || !pedido || args.posicionais.length !== 4 ||
1468
+ Object.entries(args.opcoes).some(([k, v]) => k !== 'native-offer-stdin' || v !== true))
1469
+ throw Error('uso: ork gate context <thread> <pedido> [--native-offer-stdin]');
1470
+ const view = (0, hitl_gates_1.contextoDoPedidoNativo)(carregado.raiz, id, pedido);
1471
+ const callback = args.opcoes['native-offer-stdin'] ? (0, hitl_native_offer_1.readNativeOfferStdin)() : undefined;
1472
+ console.log(JSON.stringify({ ...view, canais: (0, hitl_presentation_1.ofertaDoPedido)(view.pedido, [], callback === undefined ? undefined : { callback, raiz: carregado.raiz }),
1473
+ apresentacao: (0, hitl_presentation_1.apresentarDecisao)(view.pedido), prazoLocal: (0, hitl_presentation_1.prazoLocalDoPedido)(view.pedido) }));
1474
+ return 0;
1475
+ }
1476
+ if (sub === 'request') {
1477
+ const id = args.posicionais[2];
1478
+ if (!id)
1479
+ throw new Error('gate request exige thread');
1480
+ console.log(JSON.stringify((0, hitl_gates_1.abrirPedidoGate)(carregado.raiz, id, texto(args.opcoes.motivo))));
1481
+ return 0;
1482
+ }
1483
+ if (sub === 'answer') {
1484
+ const id = args.posicionais[2], pedido = args.posicionais[3];
1485
+ if (!id || !pedido || args.opcoes['resposta-stdin'] !== true || args.opcoes.resposta !== undefined)
1486
+ throw new Error('gate answer exige thread, pedido e --resposta-stdin');
1487
+ const r = (0, hitl_gates_1.lerRespostaStdin)({ por: texto(args.opcoes.por), mensagem: texto(args.opcoes.mensagem),
1488
+ origem: texto(args.opcoes.origem), canal: texto(args.opcoes.canal), conta: texto(args.opcoes.conta) });
1489
+ console.log(JSON.stringify((0, hitl_gates_1.responderGate)(carregado.raiz, id, pedido, r)));
1490
+ return 0;
1491
+ }
596
1492
  if (sub === 'next') {
597
1493
  const id = args.posicionais[2];
598
1494
  if (!id) {
@@ -620,7 +1516,7 @@ function comandoGate(args) {
620
1516
  const sobre = args.posicionais[3];
621
1517
  const por = texto(args.opcoes.por) ?? texto(args.opcoes.quem);
622
1518
  if (!id || !sobre || !por) {
623
- console.error('uso: ork gate approve <thread-id> <sobre> --por <quem>');
1519
+ console.error('gate approve aposentado: aprovação sem pedido é recusada. Use ork gate request <thread-id> e responda pelo ingresso humano autenticado.');
624
1520
  return 2;
625
1521
  }
626
1522
  (0, thread_1.lerThread)(carregado.raiz, id);
@@ -628,7 +1524,7 @@ function comandoGate(args) {
628
1524
  console.log(`Autorizacao humana registrada no ledger da thread ${id}.`);
629
1525
  console.log(` sobre ${sobre}`);
630
1526
  console.log(` autorizado por ${por}`);
631
- console.log(` quando ${e.ts}`);
1527
+ console.log(` quando ${(0, horario_1.formatarDataHoraRotulada)(e.ts)}`);
632
1528
  return 0;
633
1529
  }
634
1530
  console.error(`subcomando desconhecido: gate ${sub}`);
@@ -694,7 +1590,7 @@ function comandoRetry(args) {
694
1590
  }
695
1591
  console.log('Sinal de rate limit reconhecido no stderr do runtime:');
696
1592
  console.log(` fonte da hora ${sinal.fonte}`);
697
- console.log(` reset em ${sinal.resetEm ?? '(o runtime nao disse a hora)'}`);
1593
+ console.log(` reset em ${sinal.resetEm ? (0, horario_1.formatarDataHoraRotulada)(sinal.resetEm) : '(o runtime nao disse a hora)'}`);
698
1594
  console.log(` trecho ${sinal.trecho}`);
699
1595
  if (sinal.resetEm === null) {
700
1596
  console.log('');
@@ -704,6 +1600,7 @@ function comandoRetry(args) {
704
1600
  return 0;
705
1601
  }
706
1602
  const carregado = (0, manifest_1.exigirManifesto)();
1603
+ avisarChavesDePerfis(carregado);
707
1604
  if (sub === 'plan' || sub === 'run') {
708
1605
  const id = args.posicionais[2];
709
1606
  if (!id) {
@@ -726,6 +1623,10 @@ function comandoRetry(args) {
726
1623
  console.log((0, retry_1.textoDoPlano)(plano));
727
1624
  return 0;
728
1625
  }
1626
+ // I-36 (D2): `--esperar` espera a conducao em andamento terminar antes de executar a retomada.
1627
+ const conducao = conducaoDoCli(args);
1628
+ if (conducao.esperarMs && args.opcoes['dry-run'] !== true)
1629
+ (0, conducao_1.esperarConducaoLivre)(carregado.raiz, id, conducao.esperarMs);
729
1630
  const r = (0, retry_1.executarRetry)(carregado, id, {
730
1631
  ...opcoes,
731
1632
  dryRun: args.opcoes['dry-run'] === true,
@@ -750,7 +1651,7 @@ function comandoRetry(args) {
750
1651
  const espera = (0, ratelimit_1.lerFilaDeRetomada)(carregado.raiz).filter((p) => p.estado === 'aguardando');
751
1652
  if (espera.length > 0) {
752
1653
  console.log('');
753
- console.log(`Proxima janela: ${espera[0].liberaEm} (${(0, ratelimit_1.faltaPara)(espera[0])}).`);
1654
+ console.log(`Proxima janela: ${(0, horario_1.formatarDataHora)(espera[0].liberaEm)} (${(0, ratelimit_1.faltaPara)(espera[0])}).`);
754
1655
  console.log('Retome com: ork retry resume');
755
1656
  }
756
1657
  return 0;
@@ -810,9 +1711,10 @@ function comandoFix(args) {
810
1711
  console.error('uso: ork fix open <thread-id> [--so-claims] [--reverify]');
811
1712
  return 2;
812
1713
  }
813
- const rodada = (0, fix_1.abrirRodada)(carregado, id, { soClaims: args.opcoes['so-claims'] === true });
1714
+ const conducao = conducaoDoCli(args);
1715
+ const rodada = (0, fix_1.abrirRodada)(carregado, id, { soClaims: args.opcoes['so-claims'] === true, conducao });
814
1716
  const reverify = args.opcoes.reverify === true && rodada.correcoes.length > 0
815
- ? (0, fix_1.reverificar)(carregado, id, { rodada: rodada.rodada })
1717
+ ? (0, fix_1.reverificar)(carregado, id, { rodada: rodada.rodada, conducao })
816
1718
  : null;
817
1719
  if (args.opcoes.json === true) {
818
1720
  console.log(JSON.stringify({ rodada, reverify }, null, 2));
@@ -864,6 +1766,7 @@ function comandoFix(args) {
864
1766
  }
865
1767
  const rodadaBruta = texto(args.opcoes.rodada);
866
1768
  const r = (0, fix_1.reverificar)(carregado, id, {
1769
+ conducao: conducaoDoCli(args),
867
1770
  rodada: rodadaBruta ? Number(rodadaBruta) : undefined,
868
1771
  parcial: args.opcoes.parcial === true,
869
1772
  });
@@ -918,6 +1821,30 @@ function comandoHandoff(args) {
918
1821
  }
919
1822
  function comandoShip(args) {
920
1823
  const carregado = (0, manifest_1.exigirManifesto)();
1824
+ if (args.posicionais[1] === 'registrar-pr') {
1825
+ // I-57 (RM-008): a entrega feita por PR vira ship_done, provada no remoto e no CI.
1826
+ const alvo = args.posicionais[2];
1827
+ const remoto = texto(args.opcoes.remoto);
1828
+ if (!alvo && args.opcoes.todas !== true) {
1829
+ console.error('uso: ork ship registrar-pr <thread-id> | --todas [--remoto R] [--json]');
1830
+ return 2;
1831
+ }
1832
+ const r = alvo ? [(0, entrega_pr_1.registrarEntregaPorPr)(carregado, alvo, { remoto })] : (0, entrega_pr_1.registrarEntregasPorPr)(carregado, { remoto });
1833
+ if (args.opcoes.json === true) {
1834
+ console.log(JSON.stringify(r, null, 2));
1835
+ return r.some((x) => x.acao === 'recusada') ? 1 : 0;
1836
+ }
1837
+ if (r.length === 0)
1838
+ console.log('Nenhuma thread aberta com merge ship(<thread>) na base.');
1839
+ for (const x of r)
1840
+ console.log(` ${x.thread.padEnd(20)} ${x.acao.padEnd(13)} ${x.motivo}`);
1841
+ const registradas = r.filter((x) => x.acao === 'registrou').length;
1842
+ if (registradas) {
1843
+ console.log('');
1844
+ console.log(`${registradas} entrega(s) registrada(s). Fechar pelo MASTER: ork master --aceitar-omissao (a nota humana sobrescreve).`);
1845
+ }
1846
+ return r.some((x) => x.acao === 'recusada') ? 1 : 0;
1847
+ }
921
1848
  const id = args.posicionais[1];
922
1849
  const para = texto(args.opcoes.para) ?? texto(args.opcoes.to);
923
1850
  if (!id || !para) {
@@ -937,6 +1864,190 @@ function comandoShip(args) {
937
1864
  console.log((0, ship_1.textoDoShip)(r));
938
1865
  return r.ok ? 0 : 1;
939
1866
  }
1867
+ function comandoPortfolio(args) {
1868
+ const root = (0, manifest_1.exigirManifesto)().raiz;
1869
+ const sub = args.posicionais[1] ?? 'list';
1870
+ if (sub === 'inspect') {
1871
+ const id = args.posicionais[2];
1872
+ if (!id) {
1873
+ console.error('uso: ork portfolio inspect <id> --json');
1874
+ return 2;
1875
+ }
1876
+ console.log(JSON.stringify((0, portfolio_context_1.inspectPortfolio)(root, id), null, 2));
1877
+ return 0;
1878
+ }
1879
+ const aliases = { product: 'product', project: 'project', initiative: 'initiative', prod: 'product', proj: 'project', init: 'initiative' };
1880
+ const split = (value, separator = ',') => value?.split(separator).map((item) => item.trim()).filter(Boolean) ?? [];
1881
+ if (sub === 'list') {
1882
+ const rawKind = args.posicionais[2];
1883
+ const kind = rawKind ? aliases[rawKind] : undefined;
1884
+ if (rawKind && !kind) {
1885
+ console.error('tipo deve ser product, project ou initiative');
1886
+ return 2;
1887
+ }
1888
+ const items = (0, portfolio_1.listEntities)(root, kind, texto(args.opcoes.parent));
1889
+ console.log(args.opcoes.json === true ? JSON.stringify({ schema: 'ork.portfolio-list/v1', updatedAt: (0, portfolio_1.readPortfolio)(root).updatedAt, items }, null, 2)
1890
+ : items.length ? items.map((item) => `${item.id}\t${item.kind}\t${item.status}\t${item.title}`).join('\n') : 'Portfólio vazio.');
1891
+ return 0;
1892
+ }
1893
+ if (sub === 'show') {
1894
+ const id = args.posicionais[2];
1895
+ if (!id) {
1896
+ console.error('uso: ork portfolio show <id>');
1897
+ return 2;
1898
+ }
1899
+ const item = (0, portfolio_1.findEntity)(root, id);
1900
+ if (!item) {
1901
+ console.error(`entidade ${id} não encontrada`);
1902
+ return 1;
1903
+ }
1904
+ console.log(args.opcoes.json === true ? JSON.stringify(item, null, 2) : `${item.id}\n${item.title}\nEstado: ${item.status}`);
1905
+ return 0;
1906
+ }
1907
+ if (sub === 'create') {
1908
+ const kind = aliases[args.posicionais[2] ?? ''];
1909
+ const id = args.posicionais[3], title = texto(args.opcoes.title), parent = texto(args.opcoes.parent);
1910
+ if (!kind || !id || !title) {
1911
+ console.error('uso: ork portfolio create <product|project|initiative> <id> --title T [--parent ID]');
1912
+ return 2;
1913
+ }
1914
+ 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), ';') };
1915
+ const item = kind === 'product' ? (0, portfolio_1.createProduct)(root, common)
1916
+ : kind === 'project' ? (0, portfolio_1.createProject)(root, { ...common, productId: parent ?? '', workspaceIds: split(texto(args.opcoes.workspaces)) })
1917
+ : (0, portfolio_1.createInitiative)(root, { ...common, projectId: parent ?? '', dependsOn: split(texto(args.opcoes.depends)) });
1918
+ console.log(JSON.stringify({ schema: 'ork.portfolio-created/v1', item }, null, 2));
1919
+ return 0;
1920
+ }
1921
+ console.error(`subcomando desconhecido: portfolio ${sub}`);
1922
+ return 2;
1923
+ }
1924
+ function comandoCreation(args) {
1925
+ const loaded = (0, manifest_1.exigirManifesto)();
1926
+ // CLI local opera com a autoridade do usuário do SO, assim como portfolio create.
1927
+ // Fachadas HTTP devem usar a API com principal e authorize autenticados no servidor.
1928
+ const actor = { principal: `local:uid:${(0, node_os_1.userInfo)().uid}`, authorize: () => { } };
1929
+ const sub = args.posicionais[1], id = args.posicionais[2];
1930
+ if (args.opcoes.principal !== undefined || args.opcoes.por !== undefined)
1931
+ throw new Error('creation.identity: payload não escolhe principal');
1932
+ let result;
1933
+ if (sub === 'session') {
1934
+ const portfolio = (0, portfolio_1.readPortfolio)(loaded.raiz);
1935
+ result = {
1936
+ schema: 'ork.creation-session/v1', principal: actor.principal,
1937
+ workspaceIds: [...new Set(portfolio.projects.flatMap((project) => project.workspaceIds))].sort(),
1938
+ modes: loaded.manifesto.conduction.allowed_modes,
1939
+ actions: ['create_entity', 'create_entity_with_ticket', 'open_ticket'],
1940
+ };
1941
+ }
1942
+ else if (sub === 'start') {
1943
+ const file = texto(args.opcoes['input-file']);
1944
+ if (!file) {
1945
+ console.error('uso: ork creation start --input-file F --json');
1946
+ return 2;
1947
+ }
1948
+ const content = fs.readFileSync(file, 'utf8');
1949
+ if (Buffer.byteLength(content) > 100_000)
1950
+ throw new Error('creation.input: arquivo excede limite');
1951
+ result = (0, creation_operation_1.startCreation)(loaded, actor, JSON.parse(content));
1952
+ }
1953
+ else if (sub === 'list')
1954
+ result = (0, creation_operation_store_1.listCreationOperations)(loaded.raiz, actor.principal);
1955
+ else if (!id) {
1956
+ console.error('creation exige id');
1957
+ return 2;
1958
+ }
1959
+ else if (sub === 'show' || sub === 'events') {
1960
+ const op = (0, creation_operation_store_1.readCreationOperation)(loaded.raiz, id, actor.principal);
1961
+ result = sub === 'events' ? { schema: 'ork.creation-events/v1', operationId: id, version: op.version, events: op.events } : op;
1962
+ }
1963
+ else if (sub === 'resume' || sub === 'compensate') {
1964
+ const version = Number(texto(args.opcoes['expected-version']));
1965
+ if (!Number.isSafeInteger(version) || version < 1) {
1966
+ console.error('creation exige --expected-version inteiro positivo');
1967
+ return 2;
1968
+ }
1969
+ result = sub === 'resume' ? (0, creation_operation_1.resumeCreation)(loaded, actor, id, version) : (0, creation_operation_1.compensateCreation)(loaded, actor, id, version);
1970
+ }
1971
+ else {
1972
+ console.error('subcomando creation desconhecido');
1973
+ return 2;
1974
+ }
1975
+ console.log(JSON.stringify(result, null, 2));
1976
+ return 0;
1977
+ }
1978
+ /**
1979
+ * `ork objective`: APOSENTADO na I-43 (D4).
1980
+ *
1981
+ * O Objective Envelope descrevia um gate que nao bloqueava nada, e a medida foi mais
1982
+ * dura que a suspeita do GOAL: das 137 threads do projeto, ZERO tinham
1983
+ * `creationOrigin`, e `creationOrigin` era a unica via pela qual `phase.ts` consultava
1984
+ * o envelope. O ramo nunca disparou para thread nenhuma. Havia um envelope em disco,
1985
+ * `obj-i27gatedomae`, em `awaiting_approval` desde 17/09, com tres threads de zero
1986
+ * sessoes: a unica pausa do `#Maestro` nao bloqueava o despacho das proprias threads
1987
+ * que ela criou, e aprova-la nao teria efeito.
1988
+ *
1989
+ * As DUAS VIGAS que ele guardava sairam vivas, e viraram propriedade de thread comum:
1990
+ * - validacao por runtime diferente -> `thread.exigeRuntimeDiferente` (T9);
1991
+ * - `doneWhen` executavel -> `thread.doneWhen`, que vira claim do nucleo (T10).
1992
+ *
1993
+ * A recusa e TIPADA e diz para onde ir. Sumir em silencio seria o mesmo pecado da
1994
+ * #TAG aposentada virando default: quem tem o comando num script precisa saber.
1995
+ */
1996
+ function comandoObjective(args) {
1997
+ const sub = args.posicionais[1] ?? 'list';
1998
+ console.error(`objective.aposentado: o Objective Envelope saiu do produto na I-43 (subcomando "${sub}").\n` +
1999
+ ' Ele descrevia um gate que nao bloqueava nada: das 137 threads do projeto, zero\n' +
2000
+ ' tinham creationOrigin, que era a unica via pela qual o despacho o consultava.\n' +
2001
+ ' As duas vigas que ele guardava viraram propriedade de thread comum:\n' +
2002
+ ' ork thread new "<nome>" --modo <MODO> --exige-runtime-diferente\n' +
2003
+ ' o CHECK precisa de runtime que o GO nao usou\n' +
2004
+ ' ork thread new "<nome>" --modo <MODO> --done "<criterio> :: <comando>"\n' +
2005
+ ' criterio de pronto EXECUTAVEL, que vira claim e roda no ork verify\n' +
2006
+ ' Os envelopes ja gravados continuam em .orkastery/objectives, intocados.');
2007
+ return 2;
2008
+ }
2009
+ function comandoCi(args) {
2010
+ const carregado = (0, manifest_1.exigirManifesto)();
2011
+ const sub = args.posicionais[1] ?? 'status';
2012
+ if (sub === 'prepare') {
2013
+ const thread = args.posicionais[2];
2014
+ if (!thread) {
2015
+ console.error('uso: ork ci prepare <thread-id>');
2016
+ return 2;
2017
+ }
2018
+ const arquivo = (0, ci_1.prepararBundleCi)(carregado, thread, { aoAvisar: (linha) => console.log(`AVISO: ${linha}`) });
2019
+ console.log(`Bundle de CI: ${arquivo}`);
2020
+ return 0;
2021
+ }
2022
+ if (sub === 'run') {
2023
+ const bundle = texto(args.opcoes.bundle);
2024
+ if (bundle) {
2025
+ const result = (0, ci_1.executarBundleCi)(carregado, bundle);
2026
+ console.log(JSON.stringify(result, null, 2));
2027
+ return result.ok ? 0 : 1;
2028
+ }
2029
+ const thread = args.posicionais[2];
2030
+ if (!thread) {
2031
+ console.error('uso: ork ci run <thread-id> [--json] | ork ci run --bundle <arquivo>');
2032
+ return 2;
2033
+ }
2034
+ const result = (0, ci_1.executarCi)(carregado, thread);
2035
+ console.log(args.opcoes.json === true ? JSON.stringify(result, null, 2) : `${result.status.ok ? 'CI APROVADO' : 'CI REPROVADO'}: ${result.status.detail}`);
2036
+ return result.status.ok ? 0 : 1;
2037
+ }
2038
+ if (sub === 'status') {
2039
+ const sha = texto(args.opcoes.sha) ?? args.posicionais[2] ?? (0, util_1.exec)('git', ['rev-parse', 'HEAD'], carregado.raiz).stdout.trim();
2040
+ if (!/^[0-9a-f]{40}$/.test(sha)) {
2041
+ console.error('uso: ork ci status --sha <commit> [--remoto origin]');
2042
+ return 2;
2043
+ }
2044
+ const result = (0, ci_1.consultarCi)(carregado, sha, texto(args.opcoes.remoto) ?? 'origin');
2045
+ console.log(args.opcoes.json === true ? JSON.stringify(result, null, 2) : `${result.ok ? 'CI VERDE' : 'CI NÃO LIBEROU'}: ${result.detail}`);
2046
+ return result.ok ? 0 : 1;
2047
+ }
2048
+ console.error(`subcomando desconhecido: ci ${sub}`);
2049
+ return 2;
2050
+ }
940
2051
  function comandoLease(args) {
941
2052
  const carregado = (0, manifest_1.exigirManifesto)();
942
2053
  const sub = args.posicionais[1];
@@ -956,14 +2067,14 @@ function comandoLease(args) {
956
2067
  const r = (0, leases_1.adquirirRegiao)(carregado.raiz, nome, { thread, motivo });
957
2068
  if (r.ok) {
958
2069
  console.log(`Lease ${r.nome} [${r.tipo}] adquirido pela thread ${thread}.`);
959
- console.log(` expira em ${r.lease?.expiraEm}`);
2070
+ console.log(` expira em ${(0, horario_1.formatarDataHoraRotulada)(r.lease?.expiraEm)}`);
960
2071
  if (r.tomadoDeVencido)
961
2072
  console.log(' (o lease anterior estava VENCIDO e foi tomado)');
962
2073
  return 0;
963
2074
  }
964
2075
  console.error(`Lease ${r.nome} NAO adquirido.`);
965
2076
  console.error(` motivo tipado: ${r.motivo}`);
966
- console.error(` detalhe: ${r.detalhe}`);
2077
+ console.error(` detalhe: ${(0, horario_1.localizarTextoRotulado)(r.detalhe)}`);
967
2078
  console.error(` posicao na fila: ${r.posicaoNaFila}`);
968
2079
  console.error(` correcao: ${r.correcao}`);
969
2080
  return 1;
@@ -985,14 +2096,105 @@ function comandoBoard(args) {
985
2096
  const carregado = (0, manifest_1.exigirManifesto)();
986
2097
  const sub = args.posicionais[1];
987
2098
  if (sub === 'plan' || sub === 'plano') {
988
- console.log((0, board_1.textoDoPlano)((0, board_1.planejar)(carregado)));
2099
+ const plano = (0, board_1.planejar)(carregado);
2100
+ console.log(args.opcoes.json === true ? JSON.stringify(plano, null, 2) : (0, board_1.textoDoPlano)(plano));
2101
+ return 0;
2102
+ }
2103
+ if (sub === 'reap') {
2104
+ const devolvidas = (0, board_1.devolverVagas)(carregado, { por: texto(args.opcoes.por) });
2105
+ if (args.opcoes.json === true)
2106
+ console.log(JSON.stringify(devolvidas, null, 2));
2107
+ else
2108
+ console.log((0, board_1.textoDoReap)(devolvidas));
989
2109
  return 0;
990
2110
  }
991
2111
  if (sub !== undefined && sub !== 'list') {
992
2112
  console.error(`subcomando desconhecido: board ${sub}`);
2113
+ console.error('uso: ork board [list|plan|reap] [--all] [--por <quem>] [--json]');
993
2114
  return 2;
994
2115
  }
995
- console.log((0, board_1.textoDoBoard)(carregado, args.opcoes.all === true || args.opcoes.todos === true));
2116
+ const todos = args.opcoes.all === true || args.opcoes.todos === true;
2117
+ if (args.opcoes.json === true) {
2118
+ console.log(JSON.stringify((0, board_1.threadsDeTodosOsPerfis)(carregado, todos), null, 2));
2119
+ return 0;
2120
+ }
2121
+ console.log((0, board_1.textoDoBoard)(carregado, todos));
2122
+ // I-51 (RM-047): com a fabrica compartilhada, o board mostra tambem as outras maquinas.
2123
+ if ((0, maquina_1.fabricaCompartilhada)(carregado.manifesto)) {
2124
+ const painel = (0, fabrica_estado_1.lerFabrica)(carregado.raiz, { remoto: carregado.manifesto.fabrica.remoto,
2125
+ semRemoto: args.opcoes['sem-remoto'] === true });
2126
+ console.log('');
2127
+ console.log((0, fabrica_estado_1.textoDasOutrasMaquinas)(painel, (0, maquina_1.nomeDaMaquina)()));
2128
+ }
2129
+ return 0;
2130
+ }
2131
+ /**
2132
+ * I-51 (RM-047): `ork fabrica` mostra o que cada maquina conduz; `ork fabrica publicar` grava o
2133
+ * retrato desta maquina na branch `ork/fabrica-estado`. O `--silencioso` e o da publicacao em
2134
+ * segundo plano: nada no terminal, uma linha em `.orkastery/monitor/fabrica.log`.
2135
+ */
2136
+ function comandoFabrica(args) {
2137
+ const carregado = (0, manifest_1.exigirManifesto)();
2138
+ const sub = args.posicionais[1];
2139
+ const remoto = texto(args.opcoes.remoto) ?? carregado.manifesto.fabrica.remoto;
2140
+ if (sub === 'publicar') {
2141
+ const silencioso = args.opcoes.silencioso === true;
2142
+ try {
2143
+ const r = (0, fabrica_estado_1.publicarMaquina)(carregado, { remoto, forcar: args.opcoes.forcar === true });
2144
+ if (silencioso) {
2145
+ (0, fabrica_estado_1.registrarPublicacao)(carregado.raiz, { ...r });
2146
+ return 0;
2147
+ }
2148
+ if (args.opcoes.json === true)
2149
+ console.log(JSON.stringify(r, null, 2));
2150
+ else
2151
+ console.log(r.acao === 'publicou'
2152
+ ? `Fabrica: ${r.maquina} publicou ${r.threads} thread(s) em ork/fabrica-estado (${r.commit?.slice(0, 7)}, ${r.tentativas} tentativa(s)).`
2153
+ : r.acao === 'ocupado'
2154
+ ? `Fabrica: outra publicacao desta maquina esta em andamento; tente de novo em instantes.`
2155
+ : `Fabrica: retrato de ${r.maquina} igual ao ultimo publicado; nada a enviar (use --forcar para publicar mesmo assim).`);
2156
+ if (!(0, maquina_1.fabricaCompartilhada)(carregado.manifesto) && !silencioso) {
2157
+ console.log(' esta maquina nao entrou na fabrica compartilhada: so publica quando voce pede (ork fabrica entrar liga).');
2158
+ }
2159
+ return 0;
2160
+ }
2161
+ catch (e) {
2162
+ if (silencioso) {
2163
+ (0, fabrica_estado_1.registrarPublicacao)(carregado.raiz, { acao: 'falhou', erro: e.message });
2164
+ return 1;
2165
+ }
2166
+ throw e;
2167
+ }
2168
+ }
2169
+ if (sub === 'entrar') {
2170
+ // A adesao e o nome ficam no arquivo do usuario: valem para o shell, o cron e os gateways.
2171
+ const config = (0, maquina_1.gravarConfigDaMaquina)({ nome: texto(args.opcoes.maquina) ?? (0, maquina_1.lerConfigDaMaquina)()?.nome ?? (0, maquina_1.nomeDaMaquina)(),
2172
+ fabricaCompartilhada: true });
2173
+ const r = (0, fabrica_estado_1.publicarMaquina)(carregado, { remoto, forcar: true });
2174
+ console.log(`Fabrica: esta maquina entrou como ${config.nome}; publica ao criar thread, despachar fase, entregar e fechar,`);
2175
+ console.log(` e a cada batida do pulse. Primeiro retrato: ${r.threads} thread(s) em ork/fabrica-estado (${r.commit?.slice(0, 7)}).`);
2176
+ if (process.env.ORK_MAQUINA && process.env.ORK_MAQUINA.trim() !== config.nome) {
2177
+ console.log(` AVISO: ORK_MAQUINA=${process.env.ORK_MAQUINA} neste shell vence o arquivo; alinhe os dois.`);
2178
+ }
2179
+ return 0;
2180
+ }
2181
+ if (sub === 'sair') {
2182
+ const config = (0, maquina_1.gravarConfigDaMaquina)({ fabricaCompartilhada: false });
2183
+ const r = (0, fabrica_estado_1.removerMaquina)(carregado, { remoto });
2184
+ console.log(`Fabrica: ${(0, maquina_1.nomeDaMaquina)()} saiu; nada mais e publicado daqui.` +
2185
+ (r ? ` Retrato removido de ork/fabrica-estado (${r.slice(0, 7)}).` : ' Nao havia retrato desta maquina na branch.'));
2186
+ if ((0, maquina_1.fabricaCompartilhada)(carregado.manifesto))
2187
+ console.log(' AVISO: o manifesto do projeto (ou ORK_FABRICA_COMPARTILHADA) ainda liga a fabrica aqui.');
2188
+ void config;
2189
+ return 0;
2190
+ }
2191
+ if (sub !== undefined && sub !== 'list') {
2192
+ console.error(`subcomando desconhecido: fabrica ${sub}`);
2193
+ console.error('uso: ork fabrica [--json] [--sem-remoto] | fabrica publicar [--forcar] [--json] | fabrica entrar [--maquina NOME] | fabrica sair');
2194
+ return 2;
2195
+ }
2196
+ const painel = (0, fabrica_estado_1.lerFabrica)(carregado.raiz, { remoto, semRemoto: args.opcoes['sem-remoto'] === true });
2197
+ console.log(args.opcoes.json === true ? JSON.stringify(painel, null, 2) : (0, fabrica_estado_1.textoDaFabrica)(painel, (0, maquina_1.nomeDaMaquina)()));
996
2198
  return 0;
997
2199
  }
998
2200
  /**
@@ -1105,15 +2307,95 @@ function comandoWorktree(args) {
1105
2307
  function comandoMaster(args) {
1106
2308
  const carregado = (0, manifest_1.exigirManifesto)();
1107
2309
  const primeiro = args.posicionais[1];
2310
+ if (primeiro === 'audit') {
2311
+ const r = (0, master_audit_1.auditarMaster)(carregado.raiz);
2312
+ console.log(JSON.stringify(r, null, 2));
2313
+ return r.ok ? 0 : 1;
2314
+ }
2315
+ if (primeiro === 'digest') {
2316
+ const sub = args.posicionais[2];
2317
+ if (sub === 'responder') {
2318
+ 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));
2319
+ return 0;
2320
+ }
2321
+ if (sub === 'preview') {
2322
+ console.log(JSON.stringify((0, master_digest_1.montarDigest)(carregado.raiz, new Date().toISOString()), null, 2));
2323
+ return 0;
2324
+ }
2325
+ if (sub !== 'enviar')
2326
+ throw new Error('uso: ork master digest <enviar|preview|responder>');
2327
+ const r = (0, master_digest_1.enviarDigest)({ raiz: carregado.raiz });
2328
+ console.log(JSON.stringify(r, null, 2));
2329
+ return r.code;
2330
+ }
2331
+ if (primeiro === 'migrar') {
2332
+ console.log(JSON.stringify((0, master_migracao_1.migrarMaster)(carregado.raiz, { dryRun: args.opcoes['dry-run'] === true, por: texto(args.opcoes.por) ?? '' }), null, 2));
2333
+ return 0;
2334
+ }
1108
2335
  if (primeiro === 'classes') {
1109
- console.log((0, master_1.tabelaDeClasses)());
2336
+ console.log((0, master_2.tabelaDeClasses)());
1110
2337
  return 0;
1111
2338
  }
1112
- if (args.opcoes.batch === true || primeiro === 'batch' || primeiro === undefined) {
1113
- console.log((0, master_1.tabelaDeBatch)(carregado.raiz, args.opcoes.todas === true));
2339
+ if (primeiro === 'ratificar' || ((args.opcoes.batch === true || primeiro === 'batch') && args.opcoes.aceitar)) {
2340
+ let selecao;
2341
+ if (primeiro === 'ratificar') {
2342
+ const partes = (texto(args.opcoes.resposta) ?? '').trim().split(/\s+/);
2343
+ const classe = (0, master_2.parseClasse)(partes[3]);
2344
+ if (partes.length !== 4 || partes[0] !== 'ratificar' || !classe)
2345
+ throw new Error('resposta deve ser ratificar <thread> <assinatura> <classe>');
2346
+ selecao = [{ thread: partes[1], assinatura: partes[2], classe }];
2347
+ }
2348
+ else {
2349
+ selecao = (texto(args.opcoes.aceitar) ?? '').split(',').map(v => {
2350
+ const partes = v.trim().split(':');
2351
+ if (partes.length !== 2 || !/^[a-f0-9]{64}$/.test(partes[1]))
2352
+ throw new Error('seleção deve ser thread:assinatura');
2353
+ return { thread: partes[0], assinatura: partes[1] };
2354
+ });
2355
+ }
2356
+ 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
2357
  return 0;
1115
2358
  }
1116
- const id = primeiro;
2359
+ // I-43 (T8): a FILA saiu. `--batch` recebe recusa tipada em vez de sumir em
2360
+ // silencio: quem tem o comando no dedo ou num script precisa SABER que o regime
2361
+ // mudou, e para onde ir. Desaparecer sem dizer nada seria o mesmo pecado da #TAG
2362
+ // aposentada virando default.
2363
+ if (args.opcoes.batch === true || primeiro === 'batch') {
2364
+ console.error('master.fila-aposentada: a fila de ratificacao de score saiu na I-43. ' +
2365
+ 'Entregue e aceito, a menos que voce diga o contrario.\n' +
2366
+ ' ork master as entregas, com o indice ja derivado do ledger\n' +
2367
+ ' ork master --aceitar-omissao aceita as entregues, com indice e insumos no ledger\n' +
2368
+ ' ork master <id> --score <0-5> --justificativa "<por que>" --por <humano> para reclamar');
2369
+ return 2;
2370
+ }
2371
+ if (args.opcoes['aceitar-omissao'] === true) {
2372
+ const aceitos = (0, master_2.aceitarPendentesPorOmissao)(carregado.raiz);
2373
+ if (args.opcoes.json === true) {
2374
+ console.log(JSON.stringify(aceitos, null, 2));
2375
+ return 0;
2376
+ }
2377
+ if (aceitos.length === 0) {
2378
+ console.log('Nenhuma entrega esperando decisao.');
2379
+ return 0;
2380
+ }
2381
+ console.log(`Aceitas por omissao: ${aceitos.length}. O indice e os insumos foram ao ledger.`);
2382
+ for (const a of aceitos)
2383
+ console.log(` ${a.thread.padEnd(20)} indice ${a.indice.valor}/${a.indice.base}`);
2384
+ console.log('');
2385
+ console.log('Discordou? A nota humana sobrescreve, e o registro da omissao permanece.');
2386
+ return 0;
2387
+ }
2388
+ if (primeiro === undefined) {
2389
+ console.log(args.opcoes.json
2390
+ ? JSON.stringify({ entregas: (0, master_batch_1.listarBatch)(carregado.raiz, args.opcoes.todas === true),
2391
+ aceitasPorOmissao: (0, master_2.aceitosPorOmissao)(carregado.raiz) }, null, 2)
2392
+ : (0, master_2.tabelaDeEntregas)(carregado.raiz, args.opcoes.todas === true));
2393
+ return 0;
2394
+ }
2395
+ const propor = primeiro === 'propor';
2396
+ const id = propor ? args.posicionais[2] : primeiro;
2397
+ if (!id)
2398
+ throw new Error('informe a thread para propor MASTER');
1117
2399
  const brutoScore = texto(args.opcoes.score);
1118
2400
  const justificativa = texto(args.opcoes.justificativa) ?? texto(args.opcoes.porque);
1119
2401
  if (brutoScore === undefined) {
@@ -1130,28 +2412,51 @@ function comandoMaster(args) {
1130
2412
  const brutasClasses = texto(args.opcoes.classe) ?? texto(args.opcoes.classes);
1131
2413
  const classes = [];
1132
2414
  for (const bruta of (brutasClasses ?? '').split(',').map((c) => c.trim()).filter(Boolean)) {
1133
- const classe = (0, master_1.parseClasse)(bruta);
2415
+ const classe = (0, master_2.parseClasse)(bruta);
1134
2416
  if (!classe) {
1135
2417
  console.error(`classe de falha invalida: "${bruta}".`);
1136
- console.error(` classes fixas: ${master_1.ORDEM_DAS_CLASSES.join(', ')}`);
2418
+ console.error(` classes fixas: ${master_2.ORDEM_DAS_CLASSES.join(', ')}`);
1137
2419
  return 2;
1138
2420
  }
1139
2421
  classes.push(classe);
1140
2422
  }
1141
- const r = (0, master_1.registrarMaster)(carregado.raiz, id, {
2423
+ const opcoesMaster = {
1142
2424
  score: Number(brutoScore),
1143
2425
  justificativa,
1144
2426
  classes,
1145
2427
  resumo: texto(args.opcoes.resumo),
1146
2428
  por: texto(args.opcoes.por) ?? texto(args.opcoes.quem),
1147
2429
  refazer: args.opcoes.refazer === true,
1148
- });
1149
- console.log((0, master_1.textoDoMaster)(r));
2430
+ };
2431
+ if (propor) {
2432
+ console.log(JSON.stringify((0, master_1.proporMaster)(carregado.raiz, id, opcoesMaster), null, 2));
2433
+ return 0;
2434
+ }
2435
+ const r = (0, master_2.registrarMaster)(carregado.raiz, id, opcoesMaster);
2436
+ console.log((0, master_2.textoDoMaster)(r));
1150
2437
  // Bloco B6: fechada a thread, a licao (POSTMORTEM + score) vai para a colecao
1151
2438
  // `learning`, e e o que uma thread NOVA do mesmo produto recebe no GOAL.
1152
2439
  relatarPublicacao((0, memoria_1.publicar)(carregado, id));
2440
+ // I-55 (RM-008): a thread fechada pode fazer uma falha recorrente passar do piso. A proposta
2441
+ // vai ao ledger do projeto uma vez por janela; virar policy continua sendo do dono.
2442
+ for (const p of (0, licoes_1.registrarPropostasNovas)(carregado.raiz)) {
2443
+ console.log('');
2444
+ console.log(`Proposta de policy: ${p.chave} em ${p.threads.length} threads nos ultimos ${p.janelaDias} dias.`);
2445
+ console.log(` ${p.sugestao}`);
2446
+ console.log(' So proposta: vira policy quando voce a declara em policies: no orkastery.yaml (ork licoes).');
2447
+ }
1153
2448
  console.log('');
1154
- console.log(`Proximo passo: ork board --all | fila de score: ork master --batch`);
2449
+ console.log(`Proximo passo: ork board --all | entregas e indice: ork master`);
2450
+ return 0;
2451
+ }
2452
+ /** I-55 (RM-008): `ork licoes` mostra o que volta no proximo GOAL e PLAN, e as propostas de policy. */
2453
+ function comandoLicoes(args) {
2454
+ const carregado = (0, manifest_1.exigirManifesto)();
2455
+ if (args.opcoes.json === true) {
2456
+ console.log(JSON.stringify({ resumo: (0, licoes_1.resumoDasLicoes)(carregado.raiz, null), propostas: (0, licoes_1.propostasDePolicy)(carregado.raiz) }, null, 2));
2457
+ return 0;
2458
+ }
2459
+ console.log((0, licoes_1.textoDeLicoes)(carregado.raiz));
1155
2460
  return 0;
1156
2461
  }
1157
2462
  /**
@@ -1161,6 +2466,81 @@ function comandoMaster(args) {
1161
2466
  * exato com o mesmo sha256 que iria para o ledger, para o builder revisar texto sem gastar
1162
2467
  * uma sessao do runtime para descobrir o que foi pedido.
1163
2468
  */
2469
+ /**
2470
+ * I-44: documentacao como codigo. `verificar` le docs e git (roda no CI); `sincronizar` le tambem
2471
+ * o estado das threads, que nao e versionado, e por isso roda na maquina do projeto.
2472
+ */
2473
+ /** I-47: reservas de item do roadmap entre maquinas (`ork roadmap reservas|pegar|soltar`). */
2474
+ function comandoRoadmap(args) {
2475
+ const carregado = (0, manifest_1.exigirManifesto)();
2476
+ const sub = args.posicionais[1] ?? 'reservas';
2477
+ const remoto = texto(args.opcoes.remoto);
2478
+ if (sub === 'reservas') {
2479
+ const painel = (0, roadmap_reservas_1.listarReservas)(carregado.raiz, { remoto });
2480
+ console.log(args.opcoes.json === true ? JSON.stringify(painel, null, 2) : (0, roadmap_reservas_1.textoDasReservas)(painel));
2481
+ return 0;
2482
+ }
2483
+ const item = args.posicionais[2];
2484
+ if ((sub !== 'pegar' && sub !== 'soltar') || !item) {
2485
+ console.error('uso: ork roadmap reservas | pegar <RM-NNN> [--thread T] [--nota N] | soltar <RM-NNN> [--forcar --motivo M]');
2486
+ return 2;
2487
+ }
2488
+ const opcoes = {
2489
+ remoto,
2490
+ por: texto(args.opcoes.por),
2491
+ maquina: texto(args.opcoes.maquina),
2492
+ ...(texto(args.opcoes.thread) !== undefined ? { thread: texto(args.opcoes.thread) } : {}),
2493
+ ...(texto(args.opcoes.nota) !== undefined ? { nota: texto(args.opcoes.nota) } : {}),
2494
+ forcar: args.opcoes.forcar === true,
2495
+ motivo: texto(args.opcoes.motivo),
2496
+ };
2497
+ const r = sub === 'pegar' ? (0, roadmap_reservas_1.pegarItem)(carregado.raiz, item, opcoes) : (0, roadmap_reservas_1.soltarItem)(carregado.raiz, item, opcoes);
2498
+ if (args.opcoes.json === true) {
2499
+ console.log(JSON.stringify(r, null, 2));
2500
+ return 0;
2501
+ }
2502
+ const verbo = { pegou: 'reservado para esta maquina', renovou: 'reserva renovada', tomou: 'reserva TOMADA de outra maquina',
2503
+ soltou: 'devolvido', nada: 'ja estava livre' }[r.acao];
2504
+ console.log(`${r.item}: ${verbo}.`);
2505
+ if (r.reserva && r.acao !== 'soltou')
2506
+ console.log(` com ${r.reserva.por} em ${r.reserva.maquina}${r.reserva.thread ? `, thread ${r.reserva.thread}` : ''}`);
2507
+ if (r.commit)
2508
+ console.log(` branch ork/roadmap-reservas em ${r.commit.slice(0, 7)}`);
2509
+ return 0;
2510
+ }
2511
+ function comandoDocs(args) {
2512
+ const sub = args.posicionais[1] ?? 'verificar';
2513
+ const carregado = (0, manifest_1.carregarManifesto)();
2514
+ const raiz = carregado?.raiz ?? process.cwd();
2515
+ const baseBranch = carregado?.manifesto.worktree?.base_branch ?? 'main';
2516
+ if (sub === 'verificar') {
2517
+ const { docs, achados } = (0, docs_1.verificarDocs)(raiz, { baseBranch, ajudaDoCli: AJUDA });
2518
+ if (args.opcoes.json === true) {
2519
+ console.log(JSON.stringify({ paginas: docs.length, erros: achados.filter((a) => a.gravidade === 'erro').length,
2520
+ achados }, null, 2));
2521
+ }
2522
+ else {
2523
+ console.log((0, docs_1.textoDaVerificacao)(docs, achados));
2524
+ }
2525
+ return achados.some((a) => a.gravidade === 'erro') ? 2 : 0;
2526
+ }
2527
+ if (sub === 'sincronizar') {
2528
+ const escrever = args.opcoes.escrever === true;
2529
+ const r = (0, docs_1.sincronizarDocs)(raiz, { baseBranch, escrever });
2530
+ console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2) : (0, docs_1.textoDaSincronizacao)(r, escrever));
2531
+ return 0;
2532
+ }
2533
+ if (sub === 'init') {
2534
+ const criados = (0, docs_1.iniciarDocs)(raiz);
2535
+ console.log(criados.length === 0
2536
+ ? 'Documentacao como codigo ja estava no projeto: nada criado.'
2537
+ : ['Criado:', ...criados.map((c) => ` ${c}`), '',
2538
+ 'Proximo passo: copie docs/produto/_modelo-feature.md e docs/roadmap/_modelo-item.md, e rode ork docs verificar'].join('\n'));
2539
+ return 0;
2540
+ }
2541
+ console.error(`uso: ork docs verificar [--json] | sincronizar [--escrever] | init`);
2542
+ return 2;
2543
+ }
1164
2544
  function comandoPrompt(args) {
1165
2545
  const sub = args.posicionais[1] ?? 'list';
1166
2546
  const carregado = (0, manifest_1.carregarManifesto)();
@@ -1186,9 +2566,12 @@ function comandoPrompt(args) {
1186
2566
  // abrir trabalho. Nada e gravado, e o `ork` diz em voz alta que a thread e ficticia.
1187
2567
  if (args.opcoes.exemplo === true || args.opcoes.modo !== undefined || args.opcoes.mode !== undefined) {
1188
2568
  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(', ')}`);
2569
+ let modo;
2570
+ try {
2571
+ modo = (0, modos_1.exigirModoVivo)(bruto);
2572
+ }
2573
+ catch (e) {
2574
+ console.error(e.message);
1192
2575
  return 2;
1193
2576
  }
1194
2577
  const exemplo = (0, prompts_1.threadDeExemplo)(modo, fase, carregado?.manifesto.project);
@@ -1266,6 +2649,10 @@ function comandoAdapter(args) {
1266
2649
  force: args.opcoes.force === true || args.opcoes.forcar === true,
1267
2650
  orkBin: texto(args.opcoes.ork),
1268
2651
  versao: VERSAO,
2652
+ // I-43 (D5): a decisao por ARQUIVO, que e o que faz `--force` deixar de ser o
2653
+ // unico caminho de saida. `;` separa varios, como o resto do CLI ja faz.
2654
+ aceitarCatalogo: (texto(args.opcoes['aceitar-catalogo']) ?? '').split(';').map(x => x.trim()).filter(Boolean),
2655
+ manterCopia: (texto(args.opcoes['manter-copia']) ?? '').split(';').map(x => x.trim()).filter(Boolean),
1269
2656
  });
1270
2657
  console.log((0, hosts_1.textoDaInstalacao)(r));
1271
2658
  return r.ok ? 0 : 2;
@@ -1308,6 +2695,12 @@ function comandoEval(args) {
1308
2695
  * diferente de zero quando reprova, para o agendador do host perceber sem ler texto.
1309
2696
  */
1310
2697
  function comandoAudit(args) {
2698
+ if (args.posicionais[1] === 'process') {
2699
+ const r = (0, process_audit_1.auditarProcesso)((0, manifest_1.exigirManifesto)(), args.opcoes.registrar === true);
2700
+ console.log(JSON.stringify(r, null, 2));
2701
+ const chave = texto(args.opcoes['exigir-achado']);
2702
+ return chave && !r.achados.some(a => a.chave === chave) ? 1 : 0;
2703
+ }
1311
2704
  const sub = args.posicionais[1] ?? 'packs';
1312
2705
  // `audit packs` e `audit lint` funcionam sem manifesto: sao catalogo, nao estado.
1313
2706
  if (sub === 'packs' || sub === 'pack') {
@@ -1673,6 +3066,10 @@ function comandoAudit(args) {
1673
3066
  * que sempre teve. E o que garante que ligar o B6 nao muda o que o builder ja conhece.
1674
3067
  */
1675
3068
  function relatarPublicacao(r) {
3069
+ if (r.publicacao?.estado === 'pendente') {
3070
+ console.log(`Memoria: publicacao pendente (${r.publicacao.motivo}); ativacao explicita necessaria.`);
3071
+ return;
3072
+ }
1676
3073
  if (r.regime !== 'orkmind')
1677
3074
  return;
1678
3075
  const gravados = [
@@ -1687,9 +3084,18 @@ function relatarPublicacao(r) {
1687
3084
  if (r.falhas > 0)
1688
3085
  console.log(` ${r.falhas} gravacao(oes) nao concluida(s); veja ork memory status.`);
1689
3086
  }
3087
+ /** Janela de origem e corte de apresentação são inteiros positivos explícitos. */
3088
+ function limiteDeLeitura(valor) {
3089
+ if (valor === undefined)
3090
+ return undefined;
3091
+ if (typeof valor !== 'string' || !/^[0-9]+$/.test(valor) ||
3092
+ Number(valor) < 1 || Number(valor) > 1000)
3093
+ throw Error('memory.query.invalid');
3094
+ return Number(valor);
3095
+ }
1690
3096
  /** `ork recall`: recuperacao tardia dos ponteiros do handoff, no momento indicado. */
1691
3097
  function comandoRecall(args) {
1692
- const carregado = (0, manifest_1.exigirManifesto)();
3098
+ const carregado = (0, project_state_1.memoryState)((0, manifest_1.exigirManifesto)()).loaded;
1693
3099
  const id = args.posicionais[1];
1694
3100
  if (!id) {
1695
3101
  console.error('uso: ork recall <thread-id> [--fase FASE] [--id ptr-N] [--todos] [--forcar]');
@@ -1698,7 +3104,7 @@ function comandoRecall(args) {
1698
3104
  const thread = (0, thread_1.lerThread)(carregado.raiz, id);
1699
3105
  const faseBruta = texto(args.opcoes.fase) ?? texto(args.opcoes.momento);
1700
3106
  const momento = faseBruta ? (0, thread_1.exigirFase)(thread, faseBruta) : undefined;
1701
- const memoria = (0, memoria_1.abrirMemoria)(carregado);
3107
+ const memoria = (0, memoria_1.abrirMemoria)(carregado, { leituraRestrita: { thread: id, limite: limiteDeLeitura(args.opcoes.janela) } });
1702
3108
  const r = (0, recall_1.recallDaThread)(carregado, memoria, id, {
1703
3109
  momento,
1704
3110
  id: texto(args.opcoes.id),
@@ -1716,32 +3122,96 @@ function comandoRecall(args) {
1716
3122
  }
1717
3123
  /** `ork memory`: o regime, a publicacao e a busca deterministica por tag. */
1718
3124
  function comandoMemory(args) {
1719
- const carregado = (0, manifest_1.exigirManifesto)();
3125
+ const candidate = (0, manifest_1.exigirManifesto)();
3126
+ const carregado = (0, project_state_1.memoryState)(candidate).loaded;
1720
3127
  const sub = args.posicionais[1] ?? 'status';
1721
- const memoria = (0, memoria_1.abrirMemoria)(carregado);
3128
+ const escopo = texto(args.opcoes.escopo)?.split(',').map(s => s.trim());
3129
+ if (sub === 'inventory' || (sub === 'migrate' && args.opcoes['dry-run'] === true)) {
3130
+ const r = (0, memory_migration_1.inventariarHandoffs)(carregado, escopo);
3131
+ if (args.opcoes.json === true)
3132
+ console.log(JSON.stringify(r, null, 2));
3133
+ else {
3134
+ console.log(`Inventario do tenant ${r.tenant}: ${r.incluidos} incluidos, ${r.excluidos} excluidos.`);
3135
+ for (const f of r.fontes)
3136
+ console.log(` ${f.incluir ? 'incluir' : 'excluir'} ${f.arquivo}: ${f.motivo}`);
3137
+ }
3138
+ return r.fontes.some(f => f.bloqueante) ? 1 : 0;
3139
+ }
3140
+ if (sub === 'migrate') {
3141
+ const operadora = texto(args.opcoes.operadora);
3142
+ if (!operadora || !escopo)
3143
+ throw new Error('scope.write.required: --operadora <thread> --escopo <thread,...>');
3144
+ if (carregado.manifesto.memory.mode === 'orkmind') {
3145
+ const autorizacao = (0, write_activation_1.exigirAtivacao)(carregado, operadora, 'memory');
3146
+ if (escopo.some(id => !autorizacao.threads.includes(id)))
3147
+ throw Error('write.activation.scope-denied');
3148
+ }
3149
+ const r = (0, memory_migration_1.migrarHandoffs)(carregado, { operadora, escopo });
3150
+ if (args.opcoes.json === true)
3151
+ console.log(JSON.stringify(r, null, 2));
3152
+ else {
3153
+ console.log(`Migracao do tenant ${r.inventario.tenant}: ${r.resultados.filter(i => i.ok).length} confirmados, ${r.falhas} falhas, ${r.inventario.excluidos} excluidos.`);
3154
+ for (const item of r.resultados)
3155
+ console.log(` ${item.arquivo}: ${item.ok ? item.gravacao?.id : item.erro}`);
3156
+ }
3157
+ return r.ok ? 0 : 1;
3158
+ }
3159
+ if (sub === 'sync' && args.posicionais[2])
3160
+ (0, escopo_escrita_1.validarDiretorioDeThread)(carregado.raiz, args.posicionais[2]);
1722
3161
  if (sub === 'status') {
3162
+ const memoria = (0, memoria_1.abrirMemoria)(candidate);
1723
3163
  if (args.opcoes.json === true) {
1724
- console.log(JSON.stringify(memoria.estado, null, 2));
3164
+ console.log(JSON.stringify({ ...memoria.estado, configSource: memoria.configSource, configDivergent: memoria.configDivergent }, null, 2));
1725
3165
  return 0;
1726
3166
  }
1727
3167
  console.log((0, memoria_1.textoDoEstado)(memoria.estado));
1728
3168
  return 0;
1729
3169
  }
1730
3170
  if (sub === 'sync') {
3171
+ const memoria = (0, memoria_1.abrirMemoria)(carregado);
1731
3172
  const threadId = args.posicionais[2];
1732
3173
  // Thread inexistente reprova aqui, e nao no meio da gravacao.
1733
3174
  if (threadId)
1734
3175
  (0, thread_1.lerThread)(carregado.raiz, threadId);
1735
- const r = (0, memoria_1.sincronizarMemoria)(carregado, memoria, threadId ?? null);
3176
+ const perfil = (texto(args.opcoes.perfil) ?? 'integral');
3177
+ if (!['fabrica', 'integral'].includes(perfil))
3178
+ throw Error('memory.publication.profile-invalid');
3179
+ if (carregado.manifesto.memory.mode === 'orkmind') {
3180
+ try {
3181
+ const autorizacao = (0, write_activation_1.exigirAtivacao)(carregado, threadId ?? '', 'memory');
3182
+ if (autorizacao.perfil !== 'integral' && perfil !== autorizacao.perfil)
3183
+ throw Error('write.activation.profile-denied');
3184
+ }
3185
+ catch (error) {
3186
+ const motivo = error instanceof Error
3187
+ ? /^(?:write\.activation|scope|memory)\.[a-z.-]+/.exec(error.message)?.[0] ?? 'write.activation.invalid'
3188
+ : 'write.activation.invalid';
3189
+ const detalhe = 'sync nao executado; colisao legada nao foi reavaliada';
3190
+ if (args.opcoes.json === true)
3191
+ console.log(JSON.stringify({
3192
+ regime: memoria.regime, estado: memoria.estado, thread: threadId ?? null, perfil,
3193
+ publicacao: { estado: 'pendente', motivo }, falhas: 1, gravadas: [], erro: motivo, detalhe,
3194
+ }, null, 2));
3195
+ console.error(`${motivo}: ${detalhe}`);
3196
+ return 1;
3197
+ }
3198
+ }
3199
+ const r = (0, memoria_1.sincronizarMemoria)(carregado, memoria, threadId ?? null, undefined, perfil);
1736
3200
  if (args.opcoes.json === true) {
1737
3201
  console.log(JSON.stringify(r, null, 2));
1738
3202
  }
1739
3203
  else {
1740
3204
  console.log((0, memoria_1.textoDoSync)(r));
1741
3205
  }
1742
- return 0;
3206
+ return r.estado.pedido === 'orkmind' && r.falhas > 0 ? 1 : 0;
1743
3207
  }
1744
3208
  if (sub === 'search') {
3209
+ const threadId = texto(args.opcoes.thread);
3210
+ if ((args.opcoes.restrito !== undefined || args.opcoes.thread !== undefined ||
3211
+ args.opcoes.janela !== undefined) && !threadId) {
3212
+ throw Error('memory.query.thread-required: use --thread <id>');
3213
+ }
3214
+ const janela = limiteDeLeitura(args.opcoes.janela);
1745
3215
  const tagsBrutas = texto(args.opcoes.tags);
1746
3216
  if (!tagsBrutas) {
1747
3217
  console.error('uso: ork memory search --tags \'{"project":["orkastery"],"skill":["orkastery-decision"]}\'');
@@ -1757,11 +3227,19 @@ function comandoMemory(args) {
1757
3227
  }
1758
3228
  const colecao = texto(args.opcoes.colecao) ?? texto(args.opcoes.collection);
1759
3229
  const limiteBruto = texto(args.opcoes.limite);
3230
+ const limite = threadId ? limiteDeLeitura(args.opcoes.limite) : limiteBruto ? Number(limiteBruto) : undefined;
3231
+ if (threadId)
3232
+ (0, orkmind_1.validarConsultaDelimitada)({ collection: colecao,
3233
+ escopo: (0, orkmind_1.criarEscopoDeLeitura)(carregado.manifesto, threadId), tags,
3234
+ limite: janela ?? orkmind_1.LIMITE_CONSULTA_PADRAO });
3235
+ const memoria = (0, memoria_1.abrirMemoria)(carregado, threadId ? { leituraRestrita: { thread: threadId, limite: janela } } : {});
1760
3236
  const entradas = memoria.buscar({
1761
3237
  collection: colecao,
1762
3238
  tags,
1763
- limite: limiteBruto ? Number(limiteBruto) : undefined,
3239
+ limite,
1764
3240
  });
3241
+ if (threadId && memoria.regime === 'files')
3242
+ console.error(`memory.query.files: ${memoria.estado.motivo}; resultado nao comprova ausencia na memoria semantica`);
1765
3243
  if (args.opcoes.json === true) {
1766
3244
  console.log(JSON.stringify(entradas, null, 2));
1767
3245
  return 0;
@@ -1785,19 +3263,93 @@ function comandoMemory(args) {
1785
3263
  return 2;
1786
3264
  }
1787
3265
  function main(argv) {
3266
+ // I-35: todo horário para pessoa sai no fuso do dono deste projeto (lido só se for preciso).
3267
+ (0, horario_1.registrarFonteDoFuso)(() => (0, horario_1.fusoDoManifesto)((0, manifest_1.carregarManifesto)()));
3268
+ // Helper fixo do host confiável: o projeto vem da instalação, nunca de toolargs.
3269
+ if (argv[0] === 'receipt-verifiers') {
3270
+ if (argv.length !== 2 || argv[1] !== '--json')
3271
+ throw Error('uso: ork receipt-verifiers --json');
3272
+ const root = process.env.ORK_HITL_ROOT;
3273
+ const privateKey = Object.keys(process.env).some(name => /^ORK_HITL_(?:INGRESS_KEY|NATIVE_KEY)/.test(name));
3274
+ if (root !== undefined || privateKey) {
3275
+ if (!root || !(0, node_path_1.isAbsolute)(root) || fs.realpathSync(root) !== root)
3276
+ throw Error('hitl.receipt.project-unavailable');
3277
+ const carregado = (0, manifest_1.exigirManifesto)(root);
3278
+ if (carregado.raiz !== root)
3279
+ throw Error('hitl.receipt.project-unavailable');
3280
+ for (const id of (0, thread_1.listarIds)(root))
3281
+ (0, hitl_ingress_receipt_1.prepararRecibosParaDespacho)(root, id);
3282
+ }
3283
+ console.log((0, hitl_public_receipt_1.publicHitlVerifiers)() ?? 'null');
3284
+ return 0;
3285
+ }
3286
+ if (argv[0] === 'maestro')
3287
+ return (0, maestro_cli_1.runMaestroCli)(argv.slice(1));
1788
3288
  const args = parseArgs(argv);
1789
3289
  const comando = args.posicionais[0];
3290
+ // `ork --version` tambem chega sem comando: a versao e conferida antes da ajuda.
3291
+ if (args.opcoes.version === true || comando === 'version') {
3292
+ console.log(VERSAO);
3293
+ return 0;
3294
+ }
1790
3295
  if (!comando || args.opcoes.help === true || comando === 'help') {
1791
3296
  console.log(AJUDA);
1792
3297
  return 0;
1793
3298
  }
1794
- if (args.opcoes.version === true || comando === 'version') {
1795
- console.log(VERSAO);
1796
- return 0;
3299
+ const nomesHerdados = (0, runtime_ambiente_1.nomesDeProviderAtivos)();
3300
+ const ambienteManifesto = (0, manifest_1.carregarManifesto)();
3301
+ if (ambienteManifesto?.manifesto.runtime.provider_policy === 'subscription-only') {
3302
+ // Avaliar ANTES de limpar: um redirecionamento bloqueante não pode desaparecer.
3303
+ const violacoes = (0, policies_1.avaliarPolicies)(ambienteManifesto.manifesto, { gate: 'phase.dispatch' });
3304
+ // O gate oficial precisa observar e registrar a violação (inclusive warn).
3305
+ // Diagnósticos continuam acessíveis; os adapters sanitizam seus filhos sempre.
3306
+ if (violacoes.length === 0)
3307
+ for (const nome of runtime_ambiente_1.ENVS_DE_PROVIDER_PAGO)
3308
+ delete process.env[nome];
1797
3309
  }
1798
3310
  switch (comando) {
3311
+ case 'mcp': {
3312
+ const projeto = texto(args.opcoes.project), host = texto(args.opcoes.host), threadId = texto(args.opcoes.thread);
3313
+ // I-36 (D4): a identidade do despacho so chega com a thread vinculada da sessao filha.
3314
+ const dispatchId = texto(args.opcoes.dispatch);
3315
+ const transporteShip = texto(args.opcoes['ship-transport']) ?? 'github-ssh';
3316
+ const permissoesFilho = texto(args.opcoes['child-permissions']) ?? 'interactive';
3317
+ const permissoesDono = texto(args.opcoes['owner-permissions']);
3318
+ const acao = args.posicionais[1];
3319
+ if (args.posicionais.length !== 2 || !['serve', 'install'].includes(acao) || !projeto ||
3320
+ (host !== 'codex' && host !== 'claude-code') ||
3321
+ Object.keys(args.opcoes).some(k => !['project', 'host', 'ship-transport', 'child-permissions', ...(acao === 'install' ? ['dry-run', 'owner-permissions'] : ['thread', 'dispatch'])].includes(k)) ||
3322
+ (args.opcoes.dispatch !== undefined && (!threadId || !dispatchId || !/^[a-f0-9-]{36}$/.test(dispatchId))) ||
3323
+ argv.filter(a => a === '--ship-transport' || a.startsWith('--ship-transport=')).length > 1 ||
3324
+ argv.filter(a => a === '--child-permissions' || a.startsWith('--child-permissions=')).length > 1 ||
3325
+ (args.opcoes['owner-permissions'] !== undefined && (host !== 'codex' || typeof args.opcoes['owner-permissions'] !== 'string' || !['interactive', 'orchestrate'].includes(permissoesDono ?? ''))) ||
3326
+ argv.filter(a => a === '--owner-permissions' || a.startsWith('--owner-permissions=')).length > 1 ||
3327
+ !['interactive', 'worktree'].includes(permissoesFilho) ||
3328
+ (args.opcoes['child-permissions'] !== undefined && typeof args.opcoes['child-permissions'] !== 'string') ||
3329
+ !['github-ssh', 'bare-local'].includes(transporteShip) ||
3330
+ (args.opcoes['ship-transport'] !== undefined && typeof args.opcoes['ship-transport'] !== 'string') ||
3331
+ (args.opcoes.thread !== undefined && (!threadId || !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/.test(threadId))) ||
3332
+ (args.opcoes['dry-run'] !== undefined && args.opcoes['dry-run'] !== true))
3333
+ 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]');
3334
+ if (acao === 'install') {
3335
+ 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 }))))
3336
+ .catch(e => { console.error(`mcp: ${e.message}`); process.exitCode = 1; });
3337
+ return 0;
3338
+ }
3339
+ 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; });
3340
+ return 0;
3341
+ }
1799
3342
  case 'doctor': {
1800
- const r = (0, doctor_1.doctor)();
3343
+ if (args.opcoes.modo !== undefined) {
3344
+ const bruto = texto(args.opcoes.modo);
3345
+ if (args.posicionais.length !== 1 || !bruto ||
3346
+ Object.keys(args.opcoes).some(k => k !== 'modo') || argv.filter(a => a === '--modo' || a.startsWith('--modo=')).length !== 1)
3347
+ throw Error(`uso: ork doctor --modo ${modos_1.ORDEM_DOS_MODOS.join('|')}`);
3348
+ const r = (0, preflight_1.preflight)(process.cwd(), (0, modos_1.exigirModoVivo)(bruto), nomesHerdados);
3349
+ console.log((0, preflight_1.textoPreflight)(r));
3350
+ return r.prontoPrimeiroBloco ? 0 : 1;
3351
+ }
3352
+ const r = (0, doctor_1.doctor)(process.cwd(), nomesHerdados);
1801
3353
  console.log(r.texto);
1802
3354
  return r.codigo;
1803
3355
  }
@@ -1807,9 +3359,12 @@ function main(argv) {
1807
3359
  nome: texto(args.opcoes.name) ?? texto(args.opcoes.nome),
1808
3360
  abbrev: texto(args.opcoes.abbrev),
1809
3361
  });
3362
+ const carregado = (0, manifest_1.exigirManifesto)(r.deteccao.raiz);
3363
+ const agents = (0, agents_md_1.atualizarAgentsMd)(r.deteccao.raiz, carregado.manifesto);
1810
3364
  if (!r.criado) {
1811
3365
  console.log(`Manifesto ja existe: ${r.caminho}`);
1812
3366
  console.log('Nada foi sobrescrito. Use --force para regerar.');
3367
+ console.log(`AGENTS.md ${agents.estado}: ${agents.caminho}`);
1813
3368
  return 0;
1814
3369
  }
1815
3370
  console.log(`Manifesto criado: ${r.caminho}`);
@@ -1817,17 +3372,37 @@ function main(argv) {
1817
3372
  console.log(` branch base ${r.deteccao.baseBranch}`);
1818
3373
  console.log(` gerenciador ${r.deteccao.gerenciador}`);
1819
3374
  console.log(` verify ${Object.entries(r.deteccao.verify).map(([k, v]) => `${k}="${v}"`).join(', ') || '(nenhum script detectado)'}`);
3375
+ console.log(` AGENTS.md ${agents.estado}: ${agents.caminho}`);
1820
3376
  console.log('');
1821
- console.log('Proximo passo: ork doctor');
3377
+ console.log(init_2.PROXIMO_PASSO_INIT);
1822
3378
  return 0;
1823
3379
  }
1824
3380
  case 'modos': {
3381
+ // I-43 (T4): `ork modos migrar` tira modo aposentado da CONFIGURACAO do projeto
3382
+ // (`orkastery.yaml` e `setup.json`) e nao toca em historico nenhum. Idempotente:
3383
+ // rodar de novo num projeto ja migrado nao escreve nada.
3384
+ if (args.posicionais[1] === 'migrar') {
3385
+ const carregado = (0, manifest_1.exigirManifesto)();
3386
+ const r = (0, modos_migracao_1.migrarModosAposentados)(carregado.raiz, {
3387
+ dryRun: args.opcoes['dry-run'] === true,
3388
+ por: texto(args.opcoes.por),
3389
+ });
3390
+ console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2) : (0, modos_migracao_1.textoDaMigracaoModos)(r));
3391
+ return 0;
3392
+ }
1825
3393
  // `--do-pedido` existe para os adaptadores de host: eles extraem a #TAG do texto do
1826
3394
  // builder SEM reimplementar o parse, e repassam `--mode` ao `ork`. A validacao contra
1827
3395
  // `conduction.allowed_modes` continua sendo do nucleo, no `ork thread new`.
1828
3396
  const pedido = texto(args.opcoes['do-pedido']);
1829
3397
  if (pedido !== undefined) {
1830
3398
  const carregado = (0, manifest_1.carregarManifesto)();
3399
+ // I-43: `#Look` no pedido nao pode cair no default em silencio. O adaptador
3400
+ // recebe a recusa tipada e saida != 0, e quem escreveu a #TAG fica sabendo.
3401
+ const aposentado = (0, modos_1.extrairTagAposentadaDoPedido)(pedido);
3402
+ if (aposentado) {
3403
+ console.error((0, modos_1.recusaDeModoAposentado)(aposentado));
3404
+ return 2;
3405
+ }
1831
3406
  const extraido = (0, modos_1.extrairTagDoPedido)(pedido);
1832
3407
  const modo = extraido ?? carregado?.manifesto.conduction.default_mode ?? 'classic';
1833
3408
  if (args.opcoes.json === true) {
@@ -1847,16 +3422,59 @@ function main(argv) {
1847
3422
  console.log((0, modos_1.tabelaDeModos)());
1848
3423
  return 0;
1849
3424
  }
3425
+ case 'setup':
3426
+ return comandoSetup(args);
3427
+ case 'accounts':
3428
+ return comandoAccounts(args);
3429
+ case 'onboarding':
3430
+ return comandoOnboarding(args);
1850
3431
  case 'thread':
1851
3432
  return comandoThread(args);
3433
+ case 'objective':
3434
+ return comandoObjective(args);
3435
+ case 'creation':
3436
+ return comandoCreation(args);
3437
+ case 'portfolio':
3438
+ return comandoPortfolio(args);
1852
3439
  case 'phase':
1853
3440
  return comandoPhase(args);
3441
+ case 'ledger':
3442
+ return comandoLedger(args);
1854
3443
  case 'sessions':
1855
3444
  return comandoSessions(args);
3445
+ case 'pulse': {
3446
+ if (args.posicionais[1] === 'responder') {
3447
+ // I-41 (GO-FIX 1, B1 e B2): o caminho de volta do resumo. So o ingresso autenticado chama;
3448
+ // argv traz identificadores e o envelope assinado vem por stdin, como no `gate answer`.
3449
+ if (args.opcoes['resposta-stdin'] !== true || args.opcoes.resposta !== undefined || args.posicionais.length !== 2) {
3450
+ throw new Error('pulse responder exige --resposta-stdin e o envelope do ingresso autenticado');
3451
+ }
3452
+ const carregado = (0, manifest_1.exigirManifesto)();
3453
+ const envelope = (0, hitl_gates_1.lerRespostaStdin)({ por: texto(args.opcoes.por), mensagem: texto(args.opcoes.mensagem),
3454
+ origem: texto(args.opcoes.origem), canal: texto(args.opcoes.canal), conta: texto(args.opcoes.conta) });
3455
+ const formato = texto(args.opcoes.formato);
3456
+ if (formato !== undefined && formato !== 'telegram' && formato !== 'terminal')
3457
+ throw new Error('pulse responder: --formato telegram|terminal');
3458
+ console.log(JSON.stringify((0, pulse_resposta_1.responderPeloPulse)(carregado.raiz, envelope, { canal: formato ?? 'telegram' })));
3459
+ return 0;
3460
+ }
3461
+ if (args.posicionais[1] === 'cadencia')
3462
+ return comandoCadenciaDoPulse(args);
3463
+ const p = (0, pulse_1.montarPulse)((0, manifest_1.exigirManifesto)(), { registrar: args.opcoes.registrar === true,
3464
+ escopo: texto(args.opcoes.escopo)?.split(',').map(s => s.trim()),
3465
+ semRuntime: args.opcoes['sem-runtime'] === true,
3466
+ linhasLogs: texto(args.opcoes.linhas) === undefined ? undefined : Number(texto(args.opcoes.linhas)) });
3467
+ console.log(args.opcoes.json === true ? JSON.stringify(p, null, 2) : (0, pulse_1.textoDoPulse)(p));
3468
+ return p.runtime.ok || args.opcoes['sem-runtime'] === true ? 0 : 1;
3469
+ }
1856
3470
  case 'claims':
1857
3471
  return comandoClaims(args);
3472
+ case 'decisao':
3473
+ return comandoDecisao(args);
1858
3474
  case 'verify':
1859
3475
  return comandoVerify(args);
3476
+ case 'ci':
3477
+ return comandoCi(args);
1860
3478
  case 'gate':
1861
3479
  return comandoGate(args);
1862
3480
  case 'retry':
@@ -1867,12 +3485,21 @@ function main(argv) {
1867
3485
  return comandoHandoff(args);
1868
3486
  case 'recall':
1869
3487
  return comandoRecall(args);
3488
+ case 'brain': {
3489
+ const result = (0, company_brain_cli_1.runBrain)((0, manifest_1.exigirManifesto)(), args.posicionais[1] ?? 'status', args.opcoes, args.posicionais.slice(2));
3490
+ console.log(JSON.stringify(result, null, 2));
3491
+ return ['ok', 'empty', 'unknown', 'withheld', 'applied', 'rolled-back'].includes(result.state) ? 0 : 1;
3492
+ }
1870
3493
  case 'memory':
1871
3494
  return comandoMemory(args);
1872
3495
  case 'ship':
1873
3496
  return comandoShip(args);
3497
+ case 'activation':
3498
+ return (0, write_activation_1.comandoAtivacao)((0, manifest_1.exigirManifesto)(), args);
1874
3499
  case 'lease':
1875
3500
  return comandoLease(args);
3501
+ case 'conducao':
3502
+ return comandoConducao(args);
1876
3503
  case 'board':
1877
3504
  return comandoBoard(args);
1878
3505
  case 'orquestracao':
@@ -1890,6 +3517,19 @@ function main(argv) {
1890
3517
  return comandoAdapter(args);
1891
3518
  case 'prompt':
1892
3519
  return comandoPrompt(args);
3520
+ case 'docs':
3521
+ return comandoDocs(args);
3522
+ case 'roadmap':
3523
+ return comandoRoadmap(args);
3524
+ case 'demo': {
3525
+ // I-56 (RM-046): a promessa em trinta segundos, offline, sem runtime e sem tocar o projeto.
3526
+ const r = (0, demo_1.executarDemo)({ dir: texto(args.opcoes.dir), manter: args.opcoes.manter === true, escrever: (l) => console.log(l) });
3527
+ return r.ok ? 0 : 1;
3528
+ }
3529
+ case 'fabrica':
3530
+ return comandoFabrica(args);
3531
+ case 'licoes':
3532
+ return comandoLicoes(args);
1893
3533
  case 'ciclos':
1894
3534
  console.log((0, ciclos_1.tabelaDeVariantes)());
1895
3535
  return 0;
@@ -1904,7 +3544,14 @@ if (require.main === module) {
1904
3544
  process.exitCode = main(process.argv.slice(2));
1905
3545
  }
1906
3546
  catch (e) {
1907
- console.error(`erro: ${e.message}`);
1908
- process.exitCode = 1;
3547
+ // I-36 (T12): a recusa de conducao e resposta, nao erro: o texto para o humano, ou o JSON.
3548
+ if (e instanceof conducao_1.ErroDeConducao) {
3549
+ console.log(process.argv.includes('--json') ? JSON.stringify(e.recusa, null, 2) : e.recusa.texto);
3550
+ process.exitCode = 3;
3551
+ }
3552
+ else {
3553
+ console.error(`erro: ${e.message}`);
3554
+ process.exitCode = 1;
3555
+ }
1909
3556
  }
1910
3557
  }