@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
@@ -0,0 +1,279 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.repositorioAlvoDeclarado = repositorioAlvoDeclarado;
37
+ exports.inventariarHandoffs = inventariarHandoffs;
38
+ exports.verificarHandoffMigrado = verificarHandoffMigrado;
39
+ exports.migrarHandoffs = migrarHandoffs;
40
+ /** Migracao aditiva de fontes canonicas. Nenhum arquivo ou registro antigo e removido. */
41
+ const fs = __importStar(require("node:fs"));
42
+ const path = __importStar(require("node:path"));
43
+ const node_crypto_1 = require("node:crypto");
44
+ const node_util_1 = require("node:util");
45
+ const estado_thread_1 = require("./estado-thread");
46
+ const thread_1 = require("./thread");
47
+ const ledger_1 = require("./ledger");
48
+ const escopo_escrita_1 = require("./escopo-escrita");
49
+ const memoria_1 = require("./memoria");
50
+ const orkmind_1 = require("./orkmind");
51
+ const hash = (bytes) => (0, node_crypto_1.createHash)('sha256').update(bytes).digest('hex');
52
+ function arquivos(dir) {
53
+ if (!fs.existsSync(dir))
54
+ return [];
55
+ if (fs.lstatSync(dir).isSymbolicLink())
56
+ throw new Error('memory.inventory.special-file');
57
+ return fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name)).flatMap(e => {
58
+ if (e.isSymbolicLink() || (!e.isFile() && !e.isDirectory()))
59
+ throw new Error('memory.inventory.special-file');
60
+ const nome = path.join(dir, e.name);
61
+ return e.isDirectory() ? arquivos(nome) : [nome];
62
+ });
63
+ }
64
+ /**
65
+ * O repositorio alvo que um handoff em Markdown declara na linha `Repo alvo: <caminho>`.
66
+ *
67
+ * So a declaracao explicita conta: o nome solto no texto nunca classifica tenant. O tenant e o
68
+ * ultimo segmento do caminho, normalizado (`/srv/projetos/Outro-Board` vira `outro-board`).
69
+ */
70
+ function repositorioAlvoDeclarado(texto) {
71
+ const linha = /^\s*Repo alvo:\s*`?([^`\n]+?)`?\s*\.?\s*$/mi.exec(texto);
72
+ const nome = linha?.[1].replace(/[\\/]+$/, '').split(/[\\/]/).pop()?.trim();
73
+ if (!nome)
74
+ return null;
75
+ const tenant = nome.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
76
+ return tenant ? { nome, tenant } : null;
77
+ }
78
+ /**
79
+ * Inclui o snapshot atual e todo o historico das threads EXPLICITAMENTE autorizadas, e so isso.
80
+ * D23: a caixa compartilhada `.orkastery/handoffs` e as threads fora da allowlist nao sao
81
+ * consultadas, enumeradas, lidas nem hasheadas em nenhum ponto -- a allowlist limita a LEITURA,
82
+ * nao apenas a selecao. Por isso `incluidos`/`excluidos` contam somente fontes autorizadas
83
+ * efetivamente inspecionadas: a ausencia de uma fonte fora do escopo neste resultado nao afirma
84
+ * que ela nao existe nem classifica o tenant dela.
85
+ */
86
+ function inventariarHandoffs(carregado, escopo) {
87
+ const autorizadas = (0, escopo_escrita_1.exigirEscopoDeEscrita)(escopo);
88
+ const raiz = (0, estado_thread_1.raizDoEstado)(carregado.raiz), estado = path.join(raiz, '.orkastery');
89
+ const tenant = carregado.manifesto.memory.tenant || carregado.manifesto.project.name;
90
+ const candidatos = new Map();
91
+ const threads = path.join(estado, 'threads');
92
+ for (const id of autorizadas) {
93
+ (0, escopo_escrita_1.validarDiretorioDeThread)(carregado.raiz, id);
94
+ const dir = path.join(threads, id), atual = path.join(dir, 'handoff.json');
95
+ if (!fs.existsSync(dir) || fs.lstatSync(dir).isSymbolicLink())
96
+ throw new Error('memory.inventory.thread-invalid');
97
+ if (fs.existsSync(atual))
98
+ candidatos.set(atual, id);
99
+ for (const nome of arquivos(path.join(dir, 'handoffs')))
100
+ candidatos.set(nome, id);
101
+ }
102
+ const fontes = [...candidatos].sort(([a], [b]) => a.localeCompare(b)).map(([absoluto, dono]) => {
103
+ // Invariante da allowlist: nenhum candidato nasce fora dela, porque nada fora dela e percorrido.
104
+ if (!autorizadas.has(dono))
105
+ throw new Error('scope.thread.unauthorized');
106
+ if (fs.lstatSync(absoluto).isSymbolicLink())
107
+ throw new Error('memory.inventory.special-file');
108
+ const bytes = fs.readFileSync(absoluto), texto = bytes.toString('utf8');
109
+ const formato = path.extname(absoluto).slice(1).toLowerCase();
110
+ const fonte = { arquivo: path.relative(raiz, absoluto).split(path.sep).join('/'),
111
+ sha256: hash(bytes), bytes: bytes.length, formato, tenant: null, thread: dono,
112
+ origem: null, destino: null, incluir: false, motivo: 'origem_nao_confirmada', bloqueante: false };
113
+ // Declaracao explicita do repositorio alvo de OUTRO projeto, nao uma ocorrencia casual do nome.
114
+ const alvo = formato === 'md' ? repositorioAlvoDeclarado(texto) : null;
115
+ if (alvo && alvo.tenant !== tenant) {
116
+ return { ...fonte, tenant: alvo.tenant, origem: `${alvo.nome} (declarado na fonte)`,
117
+ destino: alvo.nome, motivo: 'tenant_externo_reservado' };
118
+ }
119
+ let h;
120
+ if (formato === 'json') {
121
+ try {
122
+ h = JSON.parse(texto);
123
+ }
124
+ catch {
125
+ fonte.motivo = 'json_invalido';
126
+ }
127
+ }
128
+ // A propriedade vem do diretorio autorizado que continha o arquivo; `h.thread` declarado
129
+ // dentro do proprio JSON nunca autoriza nada, so e conferido contra o dono real mais abaixo.
130
+ const id = dono;
131
+ if (!fs.existsSync(path.join(threads, id, 'thread.json')))
132
+ return fonte;
133
+ const thread = (0, thread_1.lerThread)(carregado.raiz, id);
134
+ fonte.thread = id;
135
+ fonte.tenant = thread.projeto.name === carregado.manifesto.project.name ? tenant : thread.projeto.name;
136
+ if (fonte.tenant !== tenant)
137
+ return { ...fonte, motivo: 'tenant_externo_reservado' };
138
+ if (formato !== 'json')
139
+ return { ...fonte, motivo: 'formato_sem_contrato' };
140
+ if (!h || h.thread !== id || h.versao !== 1 || !h.de?.slug || !h.para?.slug ||
141
+ !Array.isArray(h.inline) || !Array.isArray(h.pointers) || !Array.isArray(h.summaries)) {
142
+ return { ...fonte, motivo: 'handoff_invalido', bloqueante: true };
143
+ }
144
+ return { ...fonte, origem: `${h.de.slug}:${h.de.fase ?? 'desconhecida'}`,
145
+ destino: `${h.para.slug}:${h.para.fase ?? 'desconhecida'}`, incluir: true, motivo: 'tenant_confirmado' };
146
+ });
147
+ return { tenant, fontes, incluidos: fontes.filter(f => f.incluir).length, excluidos: fontes.filter(f => !f.incluir).length };
148
+ }
149
+ function lerFonte(carregado, fonte) {
150
+ const raiz = (0, estado_thread_1.raizDoEstado)(carregado.raiz), absoluto = path.resolve(raiz, fonte.arquivo);
151
+ if (!absoluto.startsWith(path.join(raiz, '.orkastery') + path.sep) ||
152
+ !fs.realpathSync(absoluto).startsWith(fs.realpathSync(path.join(raiz, '.orkastery')) + path.sep)) {
153
+ throw new Error('memory.migration.source-outside-state');
154
+ }
155
+ const bytes = fs.readFileSync(absoluto);
156
+ if (hash(bytes) !== fonte.sha256 || bytes.length !== fonte.bytes)
157
+ throw new Error('memory.migration.source-changed');
158
+ const texto = bytes.toString('utf8');
159
+ if (!Buffer.from(texto).equals(bytes))
160
+ throw new Error('memory.migration.invalid-utf8');
161
+ return texto;
162
+ }
163
+ /** Readback de manutencao pela biblioteca instalada. Nao altera filtros do recall. */
164
+ function verificarHandoffMigrado(driver, p, r) {
165
+ if (!r.ok || !r.readback || !r.id || !r.session_entry_id || !r.package_entry_id || !r.package_id || !driver.recuperar) {
166
+ throw new Error('memory.migration.readback-missing');
167
+ }
168
+ const session = driver.recuperar('session', r.session_entry_id);
169
+ const handoff = driver.recuperar('handoff', r.id);
170
+ const pacote = driver.recuperar('semantic_log', r.package_entry_id);
171
+ if (!session || !handoff || !pacote || handoff.parent_id !== session.id || pacote.parent_id !== session.id ||
172
+ session.metadata.session_id !== p.sessionId || handoff.metadata.package_id !== r.package_id ||
173
+ pacote.metadata.package_id !== r.package_id || handoff.metadata.package_entry_id !== pacote.id ||
174
+ !(0, node_util_1.isDeepStrictEqual)(JSON.parse(pacote.content), p.payload))
175
+ throw new Error('memory.migration.readback-mismatch');
176
+ for (const entry of [session, handoff, pacote]) {
177
+ if (entry.source !== 'agent' || entry.mandatory || entry.priority === 'critical' ||
178
+ !Object.entries(p.tags).every(([k, values]) => values.every(v => entry.tags[k]?.includes(v)))) {
179
+ throw new Error('memory.migration.readback-tags');
180
+ }
181
+ }
182
+ for (const entry of [handoff, pacote])
183
+ for (const [k, value] of Object.entries(p.metadata)) {
184
+ if (!(0, node_util_1.isDeepStrictEqual)(entry.metadata[k], value))
185
+ throw new Error('memory.migration.readback-provenance');
186
+ }
187
+ if (handoff.metadata.orkastery_identity !== p.identidade || pacote.metadata.orkastery_identity !== p.identidade) {
188
+ throw new Error('memory.migration.readback-identity');
189
+ }
190
+ return { session: session.id, handoff: handoff.id, semantic_log: pacote.id, parent_id: session.id,
191
+ package_id: r.package_id, sha256: p.metadata.sha256, tags: p.tags, originalIntegral: true };
192
+ }
193
+ function migrarHandoffs(carregado, opcoes) {
194
+ const operacaoId = opcoes.operacaoId ?? (0, node_crypto_1.randomUUID)();
195
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(operacaoId))
196
+ throw new Error('memory.migration.operation-invalid');
197
+ const autorizadas = (0, escopo_escrita_1.exigirEscopoDeEscrita)(opcoes?.escopo);
198
+ if (!autorizadas.has(opcoes.operadora))
199
+ throw new Error('scope.thread.unauthorized');
200
+ (0, escopo_escrita_1.validarDiretorioDeThread)(carregado.raiz, opcoes.operadora);
201
+ const operadora = (0, thread_1.lerThread)(carregado.raiz, opcoes.operadora);
202
+ if (operadora.projeto.name !== carregado.manifesto.project.name)
203
+ throw new Error('memory.tenant.mismatch');
204
+ const auditoria = (0, thread_1.dirThread)(carregado.raiz, operadora.id);
205
+ const atual = inventariarHandoffs(carregado, opcoes.escopo), inventario = opcoes.inventario ?? atual;
206
+ if (!(0, node_util_1.isDeepStrictEqual)(inventario.fontes.map(f => [f.arquivo, f.thread, f.incluir, f.tenant]), atual.fontes.map(f => [f.arquivo, f.thread, f.incluir, f.tenant]))) {
207
+ throw new Error('memory.migration.incomplete-inventory');
208
+ }
209
+ const tenant = carregado.manifesto.memory.tenant || carregado.manifesto.project.name;
210
+ if (inventario.tenant !== tenant || inventario.fontes.some(f => f.incluir && f.tenant !== tenant))
211
+ throw new Error('memory.tenant.mismatch');
212
+ if (inventario.fontes.some(f => f.bloqueante))
213
+ throw new Error('memory.migration.invalid-inventory');
214
+ // Preflight de todas as fontes antes da primeira escrita. Snapshot nao autoriza outro tenant.
215
+ const pedidos = inventario.fontes.filter(f => f.incluir).map(fonte => {
216
+ if (!fonte.thread || !autorizadas.has(fonte.thread))
217
+ throw new Error('scope.thread.unauthorized');
218
+ const texto = lerFonte(carregado, fonte), thread = (0, thread_1.lerThread)(carregado.raiz, fonte.thread);
219
+ return { fonte, pedido: (0, memoria_1.prepararHandoffGovernado)(carregado.manifesto, thread, JSON.parse(texto), fonte.arquivo, texto, carregado.raiz) };
220
+ });
221
+ const operacaoHash = hash(JSON.stringify({ tenant, operadora: operadora.id, escopo: [...autorizadas].sort(),
222
+ fontes: pedidos.map(({ fonte, pedido }) => [fonte.arquivo, fonte.sha256, pedido.identidade]) }));
223
+ const eventos = (0, ledger_1.lerLedger)(auditoria);
224
+ const recibos = eventos.filter(e => ['memory_migrated', 'memory_migration_failed', 'memory_migration_attempt'].includes(e.tipo));
225
+ if (recibos.some(e => e.operacaoId === operacaoId && e.operacaoHash !== operacaoHash)) {
226
+ throw new Error('memory.migration.operation-conflict');
227
+ }
228
+ const publicados = new Set(recibos.filter(e => e.tipo === 'memory_migrated').map(e => e.identidade));
229
+ const anteriores = new Map(recibos.filter(e => e.operacaoId === operacaoId).map(e => [e.identidade, e]));
230
+ const driver = opcoes.driver ?? (0, orkmind_1.resolverRegime)(carregado.manifesto, null).driver;
231
+ if (!driver?.contagens || !driver.recuperar || !driver.submeterHandoff)
232
+ throw new Error('memory.migration.unavailable');
233
+ const memoria = (0, memoria_1.abrirMemoria)(carregado, { driver });
234
+ if (!memoria.ativo)
235
+ throw new Error('memory.migration.unavailable');
236
+ const antes = driver.contagens(); // Erro de leitura reprova; nunca assume base vazia.
237
+ const resultados = pedidos.map(({ fonte, pedido }) => {
238
+ const anterior = anteriores.get(pedido.identidade);
239
+ if (anterior) {
240
+ return { arquivo: fonte.arquivo, sha256: fonte.sha256, identidade: pedido.identidade,
241
+ ok: anterior.tipo !== 'memory_migration_failed', replay: true,
242
+ gravacao: anterior.gravacao,
243
+ readback: anterior.readback,
244
+ erro: anterior.tipo === 'memory_migration_failed' ? String(anterior.erro) : null };
245
+ }
246
+ try {
247
+ if (!fonte.thread || !autorizadas.has(fonte.thread))
248
+ throw new Error('scope.thread.unauthorized');
249
+ (0, escopo_escrita_1.validarDiretorioDeThread)(carregado.raiz, fonte.thread);
250
+ (0, escopo_escrita_1.validarDiretorioDeThread)(carregado.raiz, operadora.id);
251
+ lerFonte(carregado, fonte);
252
+ const gravacao = memoria.submeterHandoff(pedido);
253
+ const readback = verificarHandoffMigrado(driver, pedido, gravacao);
254
+ lerFonte(carregado, fonte);
255
+ const r = { arquivo: fonte.arquivo, sha256: fonte.sha256, identidade: pedido.identidade, ok: true,
256
+ gravacao, readback, erro: null, replay: false };
257
+ const evento = (0, ledger_1.registrar)(auditoria, operadora.id, publicados.has(pedido.identidade) ? 'memory_migration_attempt' : 'memory_migrated', { tenant, fonteThread: fonte.thread, operacaoId, operacaoHash, ...r });
258
+ anteriores.set(pedido.identidade, evento);
259
+ publicados.add(pedido.identidade);
260
+ return r;
261
+ }
262
+ catch (e) {
263
+ // Nunca propaga texto arbitrario da fonte ou do subprocesso ao CLI/ledger.
264
+ const codigo = e instanceof Error && /^memory\.(migration\.[a-z-]+|tenant\.mismatch)$/.test(e.message) ? e.message : 'memory.migration.failed';
265
+ const r = { arquivo: fonte.arquivo, sha256: fonte.sha256, identidade: pedido.identidade, ok: false,
266
+ gravacao: null, readback: null, erro: codigo, replay: false };
267
+ const evento = (0, ledger_1.registrar)(auditoria, operadora.id, 'memory_migration_failed', { tenant, fonteThread: fonte.thread, operacaoId, operacaoHash, ...r });
268
+ anteriores.set(pedido.identidade, evento);
269
+ return r;
270
+ }
271
+ });
272
+ const depois = driver.contagens();
273
+ if (Object.entries(antes).some(([c, n]) => (depois[c] ?? 0) < n))
274
+ throw new Error('memory.migration.count-decreased');
275
+ const falhas = resultados.filter(r => !r.ok).length;
276
+ return { ok: falhas === 0, operacaoId, inventario, antes, depois, resultados, falhas,
277
+ replay: resultados.length > 0 && resultados.every(r => r.replay),
278
+ contrato: 'mesmo ID recupera terminais e retoma somente sem recibo; falha exige novo ID para nova tentativa' };
279
+ }
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.CAMPOS_NATIVOS = exports.hashProspectivo = void 0;
37
+ exports.prepararVersaoProspectiva = prepararVersaoProspectiva;
38
+ /** Preparacao prospectiva exclusivamente offline; dados privados entram por recibo restrito. */
39
+ const fs = __importStar(require("node:fs"));
40
+ const path = __importStar(require("node:path"));
41
+ const estado_thread_1 = require("./estado-thread");
42
+ const node_crypto_1 = require("node:crypto");
43
+ const node_child_process_1 = require("node:child_process");
44
+ const manifest_1 = require("./manifest");
45
+ const escopo_escrita_1 = require("./escopo-escrita");
46
+ const memoria_1 = require("./memoria");
47
+ const orkmind_1 = require("./orkmind");
48
+ const hashProspectivo = (s) => (0, node_crypto_1.createHash)('sha256').update(s).digest('hex');
49
+ exports.hashProspectivo = hashProspectivo;
50
+ exports.CAMPOS_NATIVOS = (0, orkmind_1.camposNativos)();
51
+ function prepararVersaoProspectiva(carregado, recibo, autoria) {
52
+ const m = carregado.manifesto;
53
+ const tenant = m.memory.tenant || m.project.name;
54
+ if (recibo.tenant !== (autoria.tenantNativo ?? tenant))
55
+ throw new Error('memory.tenant.mismatch');
56
+ if (!/^[a-f0-9]{64}$/.test(autoria.reciboSha256) || !/^[a-f0-9]{40}$/.test(autoria.revisao) ||
57
+ !(0, orkmind_1.agenteProspectivoValido)(autoria.agente))
58
+ throw new Error('memory.prospective.authorship');
59
+ if (recibo.ids.length !== 3 || new Set(recibo.ids).size !== 3 || recibo.entries.length !== 3 ||
60
+ new Set(recibo.entries.map(e => e.id)).size !== 3 || recibo.entries.some(e => !recibo.ids.includes(e.id)) ||
61
+ recibo.ids.some(id => !/^[a-f0-9-]{36}$/.test(id)))
62
+ throw new Error('memory.prospective.scope');
63
+ const driver = new orkmind_1.DriverEmMemoria();
64
+ const local = { ...carregado, manifesto: { ...m, memory: { ...m.memory, mode: 'orkmind' } } };
65
+ const publicacao = (0, memoria_1.gravarPolicies)((0, memoria_1.abrirMemoria)(local, { driver }), m);
66
+ if (publicacao.falhas || driver.tudo().length !== 3)
67
+ throw new Error('memory.prospective.manifest-changed');
68
+ const hashes = new Set();
69
+ const entradas = [...recibo.entries].sort((a, b) => a.id.localeCompare(b.id)).map(old => {
70
+ if (exports.CAMPOS_NATIVOS.some(k => !(k in old)))
71
+ throw new Error('memory.prospective.snapshot-incomplete');
72
+ const atual = driver.tudo().find(e => (0, exports.hashProspectivo)(e.content) === old.content_hash);
73
+ if (!atual || (0, exports.hashProspectivo)(old.content) !== old.content_hash || hashes.has(old.content_hash))
74
+ throw new Error('memory.prospective.hash-mismatch');
75
+ hashes.add(old.content_hash);
76
+ if (old.collection !== 'rule' || old.source !== 'agent' || old.priority !== 'high' || old.mandatory !== false ||
77
+ old.protected !== false || old.version !== 1 || old.author_id !== null || old.visibility !== 'private' ||
78
+ old.scope !== 'project' || Object.keys(old.metadata).length || (old.tags.editors ?? []).length ||
79
+ old.tags.project?.length !== 1 || old.tags.project[0] !== tenant)
80
+ throw new Error('memory.prospective.legacy-changed');
81
+ const tags = Object.fromEntries([...new Set([...Object.keys(old.tags), ...Object.keys(atual.tags)])].map(k => [k, [...new Set([...(old.tags[k] ?? []), ...(atual.tags[k] ?? [])])].sort()]));
82
+ const originalJson = JSON.stringify(old);
83
+ const marcador = { schema: 'ork.prospective-origin/v1', historicalOrigin: 'unknown', source: 'agent',
84
+ agent: autoria.agente, revision: autoria.revisao, receiptSha256: autoria.reciboSha256,
85
+ entryId: old.id, originalJson, originalSha256: (0, exports.hashProspectivo)(originalJson) };
86
+ const proposta = { ...structuredClone(old), tags,
87
+ metadata: { ...structuredClone(atual.metadata), orkastery_prospective: marcador } };
88
+ return { id: old.id, sha256: old.content_hash, origemHistorica: 'desconhecida', antes: structuredClone(old), proposta };
89
+ });
90
+ return { versao: 2, tipo: 'memory.prospective.preparation', executavel: false, aplicacaoDisponivel: false,
91
+ impedimento: 'memory.legacy.provenance-collision', liberaShip: false, novaObservacaoOperacional: false,
92
+ motivo: 'memory.prospective.preconditions-missing', entradas, autoriaProspectiva: { ...autoria, source: 'agent' },
93
+ faltantes: ['autoridade nativa identificada para as entradas privadas orfas; nao omitir requester apos recusa',
94
+ 'recibo transacional e arquivo integral duravel; locks e compare integral na mesma transacao',
95
+ 'rollback compensatorio testado e CHECK independente no HEAD da operacao',
96
+ 'decisao tipada do condutor antes de qualquer aplicacao'],
97
+ };
98
+ }
99
+ if (require.main === module) {
100
+ try {
101
+ const args = process.argv.slice(2);
102
+ const value = (key) => args[args.indexOf(key) + 1];
103
+ const flags = ['--recibo', '--recibo-sha256', '--operadora', '--escopo', '--agente', '--tenant-nativo'];
104
+ if (args[0] !== '--dry-run' || args.length !== 1 + flags.length * 2 ||
105
+ flags.some(flag => args.filter(a => a === flag).length !== 1) ||
106
+ args.some(a => a.startsWith('--') && !['--dry-run', ...flags].includes(a)))
107
+ throw new Error('memory.prospective.apply-unavailable');
108
+ for (const flag of flags)
109
+ if (!value(flag) || value(flag).startsWith('--'))
110
+ throw new Error('memory.prospective.arguments');
111
+ const c = (0, manifest_1.exigirManifesto)();
112
+ const escopo = (0, escopo_escrita_1.exigirEscopoDeEscrita)(value('--escopo').split(','));
113
+ if (!escopo.has(value('--operadora')))
114
+ throw new Error('scope.thread.unauthorized');
115
+ for (const id of escopo)
116
+ (0, escopo_escrita_1.validarDiretorioDeThread)(c.raiz, id);
117
+ const evidence = path.join((0, estado_thread_1.estadoCanonico)(c.raiz, value('--operadora')), 'evidence');
118
+ const arquivo = path.resolve(value('--recibo'));
119
+ const evidenceLocal = path.join(c.raiz, '.orkastery/threads', value('--operadora'), 'evidence');
120
+ if (![evidence, evidenceLocal].includes(path.dirname(arquivo)))
121
+ throw new Error('scope.receipt.unauthorized');
122
+ const fd = fs.openSync(arquivo, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
123
+ let bruto;
124
+ try {
125
+ const st = fs.fstatSync(fd);
126
+ if (!st.isFile() || (st.mode & 0o777) !== 0o600 || st.uid !== process.getuid?.() ||
127
+ !fs.realpathSync(arquivo).startsWith(fs.realpathSync(evidence) + path.sep))
128
+ throw new Error('scope.receipt.unauthorized');
129
+ bruto = fs.readFileSync(fd, 'utf8');
130
+ }
131
+ finally {
132
+ fs.closeSync(fd);
133
+ }
134
+ if ((0, exports.hashProspectivo)(bruto) !== value('--recibo-sha256'))
135
+ throw new Error('memory.prospective.receipt-mismatch');
136
+ const plano = prepararVersaoProspectiva(c, JSON.parse(bruto), { reciboSha256: (0, exports.hashProspectivo)(bruto),
137
+ agente: value('--agente'), tenantNativo: value('--tenant-nativo'),
138
+ revisao: (0, node_child_process_1.execFileSync)('git', ['rev-parse', 'HEAD'], { cwd: c.raiz, encoding: 'utf8' }).trim() });
139
+ // O plano integral continua privado: stdout e somente resumo, sem IDs, hashes de linhas ou conteudo.
140
+ console.log(JSON.stringify({ ...plano, entradas: undefined, quantidade: plano.entradas.length,
141
+ operadora: value('--operadora'), escopo: [...escopo], manifestoSha256: (0, exports.hashProspectivo)(fs.readFileSync(c.caminho, 'utf8')) }, null, 2));
142
+ }
143
+ catch (e) {
144
+ const message = e instanceof Error ? e.message : '';
145
+ console.error(JSON.stringify({ erro: /^(memory|scope)\.[a-z.-]+$/.test(message) ? message : 'memory.prospective.invalid-input' }));
146
+ process.exitCode = 1;
147
+ }
148
+ }
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ /**
3
+ * Migracao idempotente dos modos aposentados (I-43, T4).
4
+ *
5
+ * DOMICILIO UNICO da migracao. Ela e o unico lugar do produto que REESCREVE estado
6
+ * ja gravado por causa da aposentadoria, e por isso mora sozinha: `setup.ts` nunca
7
+ * foi escritor de YAML, e transforma-lo em um so para caber esta rotina misturaria
8
+ * dois formatos de arquivo no mesmo dono.
9
+ *
10
+ * O que ela faz e estreito de proposito:
11
+ * - `orkastery.yaml`: tira modo aposentado de `conduction.allowed_modes`, e troca
12
+ * `conduction.default_mode` aposentado pelo primeiro modo vivo.
13
+ * - `.orkastery/setup.json`: descarta os blocos dos modos aposentados, que ja eram
14
+ * inertes desde que `ORDEM_DOS_MODOS` encolheu (`lerSetup` normaliza contra a
15
+ * matriz VIVA), mas continuavam ocupando o arquivo.
16
+ *
17
+ * O que ela NAO faz, e nao pode fazer: tocar em `thread.json`, `ledger.jsonl`,
18
+ * recibo ou MASTER log. P3 do GOAL e explicita, e e a metade que da sentido a outra
19
+ * metade: NENHUM HISTORICO E MIGRADO. Thread de 02/09 em `#Look` fica em `#Look` em
20
+ * disco para sempre, e e o leitor que continua aceitando (fx-modo-aposentado-leitor).
21
+ *
22
+ * IDEMPOTENTE: rodar de novo num projeto ja migrado nao escreve nada e devolve a
23
+ * lista vazia. Isso importa porque ela vai rodar em tres projetos deste VPS em
24
+ * momentos diferentes, e um deles pode ja ter sido migrado por outra sessao.
25
+ */
26
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
27
+ if (k2 === undefined) k2 = k;
28
+ var desc = Object.getOwnPropertyDescriptor(m, k);
29
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
30
+ desc = { enumerable: true, get: function() { return m[k]; } };
31
+ }
32
+ Object.defineProperty(o, k2, desc);
33
+ }) : (function(o, m, k, k2) {
34
+ if (k2 === undefined) k2 = k;
35
+ o[k2] = m[k];
36
+ }));
37
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
38
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
39
+ }) : function(o, v) {
40
+ o["default"] = v;
41
+ });
42
+ var __importStar = (this && this.__importStar) || (function () {
43
+ var ownKeys = function(o) {
44
+ ownKeys = Object.getOwnPropertyNames || function (o) {
45
+ var ar = [];
46
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
47
+ return ar;
48
+ };
49
+ return ownKeys(o);
50
+ };
51
+ return function (mod) {
52
+ if (mod && mod.__esModule) return mod;
53
+ var result = {};
54
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
55
+ __setModuleDefault(result, mod);
56
+ return result;
57
+ };
58
+ })();
59
+ Object.defineProperty(exports, "__esModule", { value: true });
60
+ exports.planejarMigracaoModos = planejarMigracaoModos;
61
+ exports.migrarModosAposentados = migrarModosAposentados;
62
+ exports.textoDaMigracaoModos = textoDaMigracaoModos;
63
+ const fs = __importStar(require("node:fs"));
64
+ const path = __importStar(require("node:path"));
65
+ const node_crypto_1 = require("node:crypto");
66
+ const manifest_1 = require("./manifest");
67
+ const ledger_1 = require("./ledger");
68
+ const modos_1 = require("./modos");
69
+ const util_1 = require("./util");
70
+ const MARCA_BACKUP = 'migracao-modos-i43';
71
+ /** Le a lista `[a, b, c]` de uma linha de YAML simples, como o manifesto escreve. */
72
+ function lerListaInline(linha) {
73
+ const m = /^\s*allowed_modes:\s*\[(.*)\]\s*$/.exec(linha);
74
+ if (!m)
75
+ return null;
76
+ return m[1].split(',').map((x) => x.trim()).filter((x) => x.length > 0);
77
+ }
78
+ /**
79
+ * Planeja a migracao sem escrever nada.
80
+ *
81
+ * Separado de `migrarModosAposentados` pelo mesmo motivo de `planejarMigracaoMaster`:
82
+ * o dono precisa poder ver o diff antes de autorizar, e `--dry-run` nao pode ser um
83
+ * caminho de codigo diferente do que roda de verdade.
84
+ */
85
+ function planejarMigracaoModos(raiz) {
86
+ const mudancas = [];
87
+ const yaml = path.join(raiz, manifest_1.NOME_MANIFESTO);
88
+ if (fs.existsSync(yaml)) {
89
+ for (const linha of fs.readFileSync(yaml, 'utf8').split('\n')) {
90
+ const lista = lerListaInline(linha);
91
+ if (lista) {
92
+ const vivos = lista.filter((m) => !(0, modos_1.modoAposentado)(m));
93
+ if (vivos.length !== lista.length) {
94
+ mudancas.push({ arquivo: manifest_1.NOME_MANIFESTO, campo: 'conduction.allowed_modes',
95
+ de: `[${lista.join(', ')}]`, para: `[${vivos.join(', ')}]` });
96
+ }
97
+ continue;
98
+ }
99
+ const d = /^\s*default_mode:\s*(\S+)\s*$/.exec(linha);
100
+ if (d && (0, modos_1.modoAposentado)(d[1])) {
101
+ mudancas.push({ arquivo: manifest_1.NOME_MANIFESTO, campo: 'conduction.default_mode',
102
+ de: d[1], para: modos_1.ORDEM_DOS_MODOS[0] });
103
+ }
104
+ }
105
+ }
106
+ const setup = path.join((0, manifest_1.dirEstado)(raiz), 'setup.json');
107
+ if (fs.existsSync(setup)) {
108
+ try {
109
+ const bruto = JSON.parse(fs.readFileSync(setup, 'utf8'));
110
+ for (const morto of modos_1.MODOS_APOSENTADOS) {
111
+ if (bruto.modos && Object.hasOwn(bruto.modos, morto)) {
112
+ mudancas.push({ arquivo: 'setup.json', campo: `modos.${morto}`, de: 'bloco inerte', para: '(removido)' });
113
+ }
114
+ }
115
+ }
116
+ catch { /* setup ilegivel nao e problema desta migracao; `lerSetup` ja reclama */ }
117
+ }
118
+ return mudancas;
119
+ }
120
+ /**
121
+ * Aplica a migracao, com backup e evento no ledger do projeto.
122
+ *
123
+ * O backup e condicao e nao cortesia: reescrever `orkastery.yaml` de um projeto vivo
124
+ * sem guardar o original seria exatamente o tipo de passo irreversivel silencioso que
125
+ * esta thread existe para remover do produto.
126
+ */
127
+ function migrarModosAposentados(raiz, opcoes = {}) {
128
+ const mudancas = planejarMigracaoModos(raiz);
129
+ if (opcoes.dryRun || mudancas.length === 0) {
130
+ return { dryRun: opcoes.dryRun === true, mudancas, backup: null };
131
+ }
132
+ const estado = (0, manifest_1.dirEstado)(raiz);
133
+ fs.mkdirSync(estado, { recursive: true });
134
+ const backup = path.join(estado, MARCA_BACKUP);
135
+ if (fs.existsSync(backup))
136
+ throw new Error(`backup anterior exige inspecao: ${backup}`);
137
+ fs.mkdirSync(backup);
138
+ const hashes = {};
139
+ const guardar = (nome, conteudo) => {
140
+ fs.writeFileSync(path.join(backup, nome), conteudo, { flag: 'wx', encoding: 'utf8' });
141
+ hashes[nome] = (0, node_crypto_1.createHash)('sha256').update(conteudo).digest('hex');
142
+ };
143
+ const yaml = path.join(raiz, manifest_1.NOME_MANIFESTO);
144
+ if (mudancas.some((m) => m.arquivo === manifest_1.NOME_MANIFESTO) && fs.existsSync(yaml)) {
145
+ const original = fs.readFileSync(yaml, 'utf8');
146
+ guardar(manifest_1.NOME_MANIFESTO, original);
147
+ const novo = original.split('\n').map((linha) => {
148
+ const lista = lerListaInline(linha);
149
+ if (lista) {
150
+ const vivos = lista.filter((m) => !(0, modos_1.modoAposentado)(m));
151
+ return vivos.length === lista.length ? linha : linha.replace(/\[.*\]/, `[${vivos.join(', ')}]`);
152
+ }
153
+ const d = /^(\s*default_mode:\s*)(\S+)(\s*)$/.exec(linha);
154
+ return d && (0, modos_1.modoAposentado)(d[2]) ? `${d[1]}${modos_1.ORDEM_DOS_MODOS[0]}${d[3]}` : linha;
155
+ }).join('\n');
156
+ fs.writeFileSync(yaml, novo, 'utf8');
157
+ }
158
+ const setup = path.join(estado, 'setup.json');
159
+ if (mudancas.some((m) => m.arquivo === 'setup.json') && fs.existsSync(setup)) {
160
+ const original = fs.readFileSync(setup, 'utf8');
161
+ guardar('setup.json', original);
162
+ const bruto = JSON.parse(original);
163
+ for (const morto of modos_1.MODOS_APOSENTADOS)
164
+ if (bruto.modos)
165
+ delete bruto.modos[morto];
166
+ bruto.atualizadoEm = (0, util_1.agora)();
167
+ fs.writeFileSync(setup, JSON.stringify(bruto, null, 2) + '\n', 'utf8');
168
+ }
169
+ (0, ledger_1.registrar)(estado, 'projeto', 'modos_migrados', {
170
+ versao: 1,
171
+ por: (opcoes.por ?? 'nucleo ork').trim(),
172
+ mudancas,
173
+ backup,
174
+ hashes,
175
+ razao: 'I-43: modo aposentado sai da configuracao; nenhum historico e migrado (P3)',
176
+ });
177
+ return { dryRun: false, mudancas, backup };
178
+ }
179
+ /** Texto do `ork modos migrar`, com o antes e o depois de cada campo. */
180
+ function textoDaMigracaoModos(r) {
181
+ if (r.mudancas.length === 0) {
182
+ return 'Nada a migrar: nenhum modo aposentado na configuracao deste projeto.';
183
+ }
184
+ const linhas = [r.dryRun ? 'Simulacao (--dry-run), nada foi gravado.' : 'Migracao aplicada.'];
185
+ for (const m of r.mudancas)
186
+ linhas.push(` ${m.arquivo} ${m.campo}`, ` de ${m.de}`, ` para ${m.para}`);
187
+ if (r.backup)
188
+ linhas.push(` backup ${r.backup}`);
189
+ linhas.push('', 'Nenhum historico foi tocado: thread, ledger e recibo em modo aposentado ficam como estao.');
190
+ return linhas.join('\n');
191
+ }