nexakit 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (438) hide show
  1. package/.claude-plugin/marketplace.json +28 -0
  2. package/LICENSE +26 -0
  3. package/README.md +79 -2
  4. package/agents/claude/docs-researcher.md +9 -0
  5. package/agents/claude/implementation-tutor.md +9 -0
  6. package/agents/claude/project-explorer.md +9 -0
  7. package/agents/claude/quality-reviewer.md +9 -0
  8. package/agents/claude/requirements-analyst.md +9 -0
  9. package/agents/claude/solution-architect.md +9 -0
  10. package/agents/codex/docs-researcher.toml +10 -0
  11. package/agents/codex/implementation-tutor.toml +10 -0
  12. package/agents/codex/project-explorer.toml +10 -0
  13. package/agents/codex/quality-reviewer.toml +10 -0
  14. package/agents/codex/requirements-analyst.toml +11 -0
  15. package/agents/codex/solution-architect.toml +10 -0
  16. package/assets/brand/README.md +38 -0
  17. package/assets/brand/agent-toolkit-mark.png +0 -0
  18. package/assets/brand/agent-toolkit-mark.svg +13 -0
  19. package/assets/brand/agent-toolkit-tui-hero.png +0 -0
  20. package/assets/brand/nexakit-readme-hero.png +0 -0
  21. package/assets/brand/nexakit-readme-hero.svg +21 -0
  22. package/assets/runtime/package-lock.json +1425 -0
  23. package/bin/agent-task.js +14 -0
  24. package/bin/agent-toolkit-gemini.js +13 -0
  25. package/bin/agent-toolkit-inbox.js +14 -0
  26. package/bin/agent-toolkit-mcp.js +17 -0
  27. package/bin/agent-toolkit.js +13 -0
  28. package/bin/nexakit.js +13 -0
  29. package/bin/project-memory-mcp.js +22 -0
  30. package/bin/project-memory.js +7 -0
  31. package/catalogs/skills/api-design-principles/LICENSE.txt +21 -0
  32. package/catalogs/skills/api-design-principles/SKILL.md +110 -0
  33. package/catalogs/skills/api-design-principles/assets/api-design-checklist.md +155 -0
  34. package/catalogs/skills/api-design-principles/assets/rest-api-template.py +185 -0
  35. package/catalogs/skills/api-design-principles/references/details.md +413 -0
  36. package/catalogs/skills/api-design-principles/references/graphql-schema-design.md +589 -0
  37. package/catalogs/skills/api-design-principles/references/rest-best-practices.md +408 -0
  38. package/catalogs/skills/nodejs-backend-patterns/LICENSE.txt +21 -0
  39. package/catalogs/skills/nodejs-backend-patterns/SKILL.md +45 -0
  40. package/catalogs/skills/nodejs-backend-patterns/references/advanced-patterns.md +430 -0
  41. package/catalogs/skills/nodejs-backend-patterns/references/details.md +599 -0
  42. package/catalogs/skills/supabase-postgres-best-practices/CHANGELOG.md +73 -0
  43. package/catalogs/skills/supabase-postgres-best-practices/LICENSE.txt +21 -0
  44. package/catalogs/skills/supabase-postgres-best-practices/SKILL.md +64 -0
  45. package/catalogs/skills/supabase-postgres-best-practices/references/_contributing.md +170 -0
  46. package/catalogs/skills/supabase-postgres-best-practices/references/_sections.md +39 -0
  47. package/catalogs/skills/supabase-postgres-best-practices/references/_template.md +34 -0
  48. package/catalogs/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
  49. package/catalogs/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
  50. package/catalogs/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
  51. package/catalogs/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
  52. package/catalogs/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
  53. package/catalogs/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
  54. package/catalogs/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
  55. package/catalogs/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
  56. package/catalogs/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
  57. package/catalogs/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
  58. package/catalogs/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
  59. package/catalogs/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
  60. package/catalogs/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
  61. package/catalogs/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
  62. package/catalogs/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
  63. package/catalogs/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
  64. package/catalogs/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
  65. package/catalogs/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
  66. package/catalogs/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
  67. package/catalogs/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -0
  68. package/catalogs/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
  69. package/catalogs/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
  70. package/catalogs/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -0
  71. package/catalogs/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
  72. package/catalogs/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
  73. package/catalogs/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
  74. package/catalogs/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
  75. package/catalogs/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
  76. package/catalogs/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
  77. package/catalogs/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
  78. package/catalogs/skills/supabase-postgres-best-practices/references/security-rls-performance.md +63 -0
  79. package/catalogs/skills/vercel-composition-patterns/AGENTS.md +946 -0
  80. package/catalogs/skills/vercel-composition-patterns/LICENSE.txt +27 -0
  81. package/catalogs/skills/vercel-composition-patterns/README.md +60 -0
  82. package/catalogs/skills/vercel-composition-patterns/SKILL.md +89 -0
  83. package/catalogs/skills/vercel-composition-patterns/metadata.json +11 -0
  84. package/catalogs/skills/vercel-composition-patterns/rules/_sections.md +29 -0
  85. package/catalogs/skills/vercel-composition-patterns/rules/_template.md +24 -0
  86. package/catalogs/skills/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
  87. package/catalogs/skills/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
  88. package/catalogs/skills/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
  89. package/catalogs/skills/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
  90. package/catalogs/skills/vercel-composition-patterns/rules/react19-no-forwardref.md +42 -0
  91. package/catalogs/skills/vercel-composition-patterns/rules/state-context-interface.md +191 -0
  92. package/catalogs/skills/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
  93. package/catalogs/skills/vercel-composition-patterns/rules/state-lift-state.md +125 -0
  94. package/catalogs/skills/vercel-react-best-practices/AGENTS.md +3810 -0
  95. package/catalogs/skills/vercel-react-best-practices/LICENSE.txt +27 -0
  96. package/catalogs/skills/vercel-react-best-practices/README.md +123 -0
  97. package/catalogs/skills/vercel-react-best-practices/SKILL.md +149 -0
  98. package/catalogs/skills/vercel-react-best-practices/metadata.json +15 -0
  99. package/catalogs/skills/vercel-react-best-practices/rules/_sections.md +46 -0
  100. package/catalogs/skills/vercel-react-best-practices/rules/_template.md +28 -0
  101. package/catalogs/skills/vercel-react-best-practices/rules/advanced-effect-event-deps.md +56 -0
  102. package/catalogs/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  103. package/catalogs/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
  104. package/catalogs/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
  105. package/catalogs/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
  106. package/catalogs/skills/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
  107. package/catalogs/skills/vercel-react-best-practices/rules/async-defer-await.md +82 -0
  108. package/catalogs/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
  109. package/catalogs/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
  110. package/catalogs/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
  111. package/catalogs/skills/vercel-react-best-practices/rules/bundle-analyzable-paths.md +63 -0
  112. package/catalogs/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +60 -0
  113. package/catalogs/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
  114. package/catalogs/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
  115. package/catalogs/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  116. package/catalogs/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
  117. package/catalogs/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
  118. package/catalogs/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
  119. package/catalogs/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
  120. package/catalogs/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
  121. package/catalogs/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
  122. package/catalogs/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
  123. package/catalogs/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
  124. package/catalogs/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
  125. package/catalogs/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
  126. package/catalogs/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
  127. package/catalogs/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +60 -0
  128. package/catalogs/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
  129. package/catalogs/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
  130. package/catalogs/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
  131. package/catalogs/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
  132. package/catalogs/skills/vercel-react-best-practices/rules/js-request-idle-callback.md +105 -0
  133. package/catalogs/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
  134. package/catalogs/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
  135. package/catalogs/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
  136. package/catalogs/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  137. package/catalogs/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
  138. package/catalogs/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
  139. package/catalogs/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  140. package/catalogs/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  141. package/catalogs/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
  142. package/catalogs/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +85 -0
  143. package/catalogs/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +68 -0
  144. package/catalogs/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
  145. package/catalogs/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  146. package/catalogs/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
  147. package/catalogs/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
  148. package/catalogs/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  149. package/catalogs/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
  150. package/catalogs/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
  151. package/catalogs/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  152. package/catalogs/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
  153. package/catalogs/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
  154. package/catalogs/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  155. package/catalogs/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +82 -0
  156. package/catalogs/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  157. package/catalogs/skills/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
  158. package/catalogs/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
  159. package/catalogs/skills/vercel-react-best-practices/rules/rerender-use-deferred-value.md +59 -0
  160. package/catalogs/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  161. package/catalogs/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
  162. package/catalogs/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
  163. package/catalogs/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
  164. package/catalogs/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
  165. package/catalogs/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
  166. package/catalogs/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +149 -0
  167. package/catalogs/skills/vercel-react-best-practices/rules/server-no-shared-module-state.md +50 -0
  168. package/catalogs/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
  169. package/catalogs/skills/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +34 -0
  170. package/catalogs/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
  171. package/catalogs/skills/webapp-testing/LICENSE.txt +202 -0
  172. package/catalogs/skills/webapp-testing/SKILL.md +96 -0
  173. package/catalogs/skills/webapp-testing/examples/console_logging.py +35 -0
  174. package/catalogs/skills/webapp-testing/examples/element_discovery.py +40 -0
  175. package/catalogs/skills/webapp-testing/examples/static_html_automation.py +33 -0
  176. package/catalogs/skills/webapp-testing/scripts/with_server.py +106 -0
  177. package/catalogs/skills.json +1115 -0
  178. package/docs/skills/evidencias/2026-10-28-evaluacion-inicial-mcp-seguridad.md +118 -0
  179. package/docs/skills/evidencias/2026-10-28-incorporacion-mcp-seguridad.json +152 -0
  180. package/docs/skills/evidencias/2026-10-28-recomendador-preparacion.md +50 -0
  181. package/package.json +73 -4
  182. package/plugins/nexakit-modelo/.claude-plugin/plugin.json +1 -0
  183. package/plugins/nexakit-modelo/hooks/hooks.json +1 -0
  184. package/plugins/nexakit-modelo/hooks/register.js +48 -0
  185. package/plugins/nexakit-modelo/hooks/status.js +8 -0
  186. package/plugins/nexakit-modelo/tests/register.test.ts +21 -0
  187. package/plugins/nexakit-panel/.claude-plugin/plugin.json +1 -0
  188. package/plugins/nexakit-panel/README.md +20 -0
  189. package/plugins/nexakit-panel/hooks/hooks.json +1 -0
  190. package/plugins/nexakit-panel/hooks/lienzo.js +382 -0
  191. package/plugins/nexakit-panel/hooks/panel.js +279 -0
  192. package/plugins/nexakit-panel/hooks/register.tsx +248 -0
  193. package/plugins/nexakit-panel/tests/lienzo.test.ts +142 -0
  194. package/plugins/nexakit-panel/tests/panel.test.ts +240 -0
  195. package/plugins/nexakit-panel/tests/register.test.ts +167 -0
  196. package/plugins/nexakit-panel/types/index.d.ts +41 -0
  197. package/plugins/nexakit-sesion/.claude-plugin/plugin.json +1 -0
  198. package/plugins/nexakit-sesion/README.md +12 -0
  199. package/plugins/nexakit-sesion/hooks/aviso.js +38 -0
  200. package/plugins/nexakit-sesion/hooks/hooks.json +1 -0
  201. package/plugins/nexakit-sesion/hooks/register.js +28 -0
  202. package/plugins/nexakit-sesion/tests/register.test.ts +96 -0
  203. package/plugins/niveles/.claude-plugin/plugin.json +5 -0
  204. package/plugins/niveles/agents/nivel-alto.md +13 -0
  205. package/plugins/niveles/agents/nivel-exigente.md +13 -0
  206. package/plugins/niveles/agents/nivel-ligero.md +13 -0
  207. package/plugins/niveles/agents/nivel-normal.md +13 -0
  208. package/schemas/agent-client-adapter.schema.json +786 -0
  209. package/schemas/agent-client-auth-diagnostic.schema.json +801 -0
  210. package/schemas/agent-client-isolated-variant.schema.json +105 -0
  211. package/schemas/agent-client-isolated-verification.schema.json +99 -0
  212. package/schemas/agent-client-managed-preferences-invocation.schema.json +67 -0
  213. package/schemas/agent-client-managed-preferences.schema.json +63 -0
  214. package/schemas/agent-client-native-diagnostics.schema.json +85 -0
  215. package/schemas/agent-client-native-evaluation.schema.json +171 -0
  216. package/schemas/agent-client-native-preflight.schema.json +90 -0
  217. package/schemas/agent-client-output.schema.json +551 -0
  218. package/schemas/agent-client-runtime-fixture.schema.json +90 -0
  219. package/schemas/agent-client-runtime-local.schema.json +95 -0
  220. package/schemas/agent-client-runtime.schema.json +1288 -0
  221. package/schemas/agent-client-selective-config.schema.json +77 -0
  222. package/schemas/agent-client-supervised-local.schema.json +135 -0
  223. package/schemas/agent-client-supervised.schema.json +186 -0
  224. package/schemas/agent-model-preference.schema.json +573 -0
  225. package/schemas/agent-model-selection.schema.json +311 -0
  226. package/schemas/agent-task-approvals.schema.json +362 -0
  227. package/schemas/agent-task-prepare.schema.json +1324 -0
  228. package/schemas/agent-task-verify.schema.json +198 -0
  229. package/schemas/project-memory-update.schema.json +33 -0
  230. package/schemas/project-memory.schema.json +298 -0
  231. package/schemas/skill-catalog.schema.json +246 -0
  232. package/schemas/task-workflow-plan-output.schema.json +35 -0
  233. package/scripts/prepare-package.js +6 -0
  234. package/scripts/validate-skill-catalog.js +41 -0
  235. package/skills/cerrar-avisens/SKILL.md +12 -0
  236. package/skills/cerrar-memoria/SKILL.md +96 -0
  237. package/skills/cerrar-memoria/references/cierre.md +76 -0
  238. package/skills/decision-records/SKILL.md +27 -0
  239. package/skills/decision-records/agents/openai.yaml +7 -0
  240. package/skills/decision-records/references/adr-template.md +35 -0
  241. package/skills/differential-review/LICENSE.txt +427 -0
  242. package/skills/differential-review/SKILL.md +225 -0
  243. package/skills/differential-review/adversarial.md +203 -0
  244. package/skills/differential-review/agents/openai.yaml +6 -0
  245. package/skills/differential-review/assets/trail-of-bits-mark.svg +1 -0
  246. package/skills/differential-review/methodology.md +234 -0
  247. package/skills/differential-review/patterns.md +300 -0
  248. package/skills/differential-review/reporting.md +369 -0
  249. package/skills/elegir-modelo/SKILL.md +68 -0
  250. package/skills/elegir-modelo/modelos.mjs +108 -0
  251. package/skills/frontend-design/LICENSE.txt +177 -0
  252. package/skills/frontend-design/SKILL.md +71 -0
  253. package/skills/gemini/SKILL.md +52 -0
  254. package/skills/imagen/SKILL.md +12 -0
  255. package/skills/investigar/SKILL.md +11 -0
  256. package/skills/mcp-builder/LICENSE.txt +202 -0
  257. package/skills/mcp-builder/SKILL.md +236 -0
  258. package/skills/mcp-builder/reference/evaluation.md +602 -0
  259. package/skills/mcp-builder/reference/mcp_best_practices.md +249 -0
  260. package/skills/mcp-builder/reference/node_mcp_server.md +970 -0
  261. package/skills/mcp-builder/reference/python_mcp_server.md +719 -0
  262. package/skills/mcp-builder/scripts/connections.py +151 -0
  263. package/skills/mcp-builder/scripts/evaluation.py +373 -0
  264. package/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
  265. package/skills/mcp-builder/scripts/requirements.txt +2 -0
  266. package/skills/ordenar-proyecto/SKILL.md +56 -0
  267. package/skills/project-handoff/SKILL.md +53 -0
  268. package/skills/project-handoff/agents/openai.yaml +7 -0
  269. package/skills/project-handoff/references/handoff-template.md +35 -0
  270. package/skills/quality-gate/LICENSE.txt +26 -0
  271. package/skills/quality-gate/SKILL.md +44 -0
  272. package/skills/quality-gate/agents/openai.yaml +7 -0
  273. package/skills/quality-gate/references/review-checklist.md +42 -0
  274. package/skills/revisar/SKILL.md +11 -0
  275. package/skills/revisar-skill/LICENSE-find-skills.txt +26 -0
  276. package/skills/revisar-skill/SKILL.md +94 -0
  277. package/skills/revision-cruzada/SKILL.md +59 -0
  278. package/skills/web-design-guidelines/AGENTS.md +156 -0
  279. package/skills/web-design-guidelines/LICENSE.txt +21 -0
  280. package/skills/web-design-guidelines/SKILL.md +29 -0
  281. package/src/agent-models.js +131 -0
  282. package/src/brand.js +117 -0
  283. package/src/claude-code-runner.js +642 -0
  284. package/src/cli-executable.js +88 -0
  285. package/src/cli.js +778 -0
  286. package/src/client-adapter-plan.js +271 -0
  287. package/src/client-auth-diagnostic-parser.js +211 -0
  288. package/src/client-auth-diagnostic.js +257 -0
  289. package/src/client-isolated-variant.js +106 -0
  290. package/src/client-isolated-verification.js +130 -0
  291. package/src/client-local-platform.js +14 -0
  292. package/src/client-managed-preferences-invocation.js +209 -0
  293. package/src/client-managed-preferences.js +78 -0
  294. package/src/client-native-access.js +134 -0
  295. package/src/client-native-diagnostics.js +253 -0
  296. package/src/client-native-evaluation.js +106 -0
  297. package/src/client-native-preflight-files.js +68 -0
  298. package/src/client-native-preflight.js +95 -0
  299. package/src/client-output-json.js +118 -0
  300. package/src/client-output-parser.js +278 -0
  301. package/src/client-runtime-admission.js +80 -0
  302. package/src/client-runtime-coordinator.js +70 -0
  303. package/src/client-runtime-core.js +92 -0
  304. package/src/client-runtime-fixture-permit.js +20 -0
  305. package/src/client-runtime-fixture-protocol.js +39 -0
  306. package/src/client-runtime-state.js +67 -0
  307. package/src/client-runtime-store-files.js +91 -0
  308. package/src/client-runtime-store.js +239 -0
  309. package/src/client-runtime-supervisor.js +146 -0
  310. package/src/client-selective-config.js +195 -0
  311. package/src/client-selective-files.js +126 -0
  312. package/src/client-supervised-codes.js +32 -0
  313. package/src/client-supervised-contract.js +52 -0
  314. package/src/client-supervised-coordinator.js +36 -0
  315. package/src/client-supervised-permit.js +20 -0
  316. package/src/client-supervised-protocol.js +37 -0
  317. package/src/client-supervised-store.js +167 -0
  318. package/src/client-supervised-supervisor.js +167 -0
  319. package/src/client-supervised.js +160 -0
  320. package/src/codex-cli-runner.js +358 -0
  321. package/src/codex-delivery.js +101 -0
  322. package/src/connect.js +703 -0
  323. package/src/doctor.js +795 -0
  324. package/src/gemini-cli.js +76 -0
  325. package/src/gemini-files.js +45 -0
  326. package/src/gemini-tools.js +249 -0
  327. package/src/init.js +473 -0
  328. package/src/install-lock.js +127 -0
  329. package/src/install-registry.js +61 -0
  330. package/src/legacy-repair.js +71 -0
  331. package/src/level-agents.js +111 -0
  332. package/src/link-states.js +172 -0
  333. package/src/memory-connection-artifacts.js +192 -0
  334. package/src/memory-connection-descriptor.js +158 -0
  335. package/src/memory-connection-diagnostic.js +177 -0
  336. package/src/memory-connection-files.js +191 -0
  337. package/src/memory-connection-manifest.js +118 -0
  338. package/src/memory-connection-package.js +176 -0
  339. package/src/memory-connection-plan.js +211 -0
  340. package/src/memory-connection-skill.js +211 -0
  341. package/src/memory-connection-toml.js +153 -0
  342. package/src/memory-locator.js +118 -0
  343. package/src/memory-mcp-policy.js +181 -0
  344. package/src/memory-mcp-server.js +166 -0
  345. package/src/memory-mcp-transport.js +59 -0
  346. package/src/missing-dependencies.js +21 -0
  347. package/src/model-command.js +147 -0
  348. package/src/model-preference.js +235 -0
  349. package/src/model-selection.js +368 -0
  350. package/src/native/managed-preferences.c +100 -0
  351. package/src/native/managed-preferences.h +17 -0
  352. package/src/package-lock-path.js +13 -0
  353. package/src/panel-cli.js +182 -0
  354. package/src/peer-handoff.js +27 -0
  355. package/src/peer-inbox-cli.js +211 -0
  356. package/src/peer-review-mcp.js +210 -0
  357. package/src/peer-review-store.js +532 -0
  358. package/src/platform.js +24 -0
  359. package/src/project-root.js +41 -0
  360. package/src/project-signals.js +339 -0
  361. package/src/recommend-report.js +77 -0
  362. package/src/review-instructions.js +211 -0
  363. package/src/review-policy.js +35 -0
  364. package/src/revision-adapters.js +157 -0
  365. package/src/revision-context.js +86 -0
  366. package/src/revision-isolation.js +222 -0
  367. package/src/revision-process.js +103 -0
  368. package/src/revision-provenance.js +89 -0
  369. package/src/revision-snapshot.js +120 -0
  370. package/src/revision.js +242 -0
  371. package/src/runtime-fixtures/runtime-supervisor/child.cjs +3 -0
  372. package/src/runtime-fixtures/runtime-supervisor/fixture.cjs +49 -0
  373. package/src/runtime-fixtures/supervised/child.cjs +3 -0
  374. package/src/runtime-fixtures/supervised/fixture.cjs +47 -0
  375. package/src/sensitive-data.js +21 -0
  376. package/src/setup-apply.js +231 -0
  377. package/src/setup-plan.js +231 -0
  378. package/src/setup-state.js +277 -0
  379. package/src/setup-tui.js +555 -0
  380. package/src/skill-catalog-add.js +91 -0
  381. package/src/skill-catalog-audit.js +68 -0
  382. package/src/skill-catalog.js +170 -0
  383. package/src/skill-files.js +39 -0
  384. package/src/skill-recommendations.js +1673 -0
  385. package/src/skill-scan-report.js +14 -0
  386. package/src/skill-scan.js +178 -0
  387. package/src/stable-command.js +53 -0
  388. package/src/stable-install.js +222 -0
  389. package/src/status.js +200 -0
  390. package/src/superpowers.js +133 -0
  391. package/src/sync-apply.js +227 -0
  392. package/src/sync-files.js +109 -0
  393. package/src/sync-inspect.js +394 -0
  394. package/src/sync-ledger.js +94 -0
  395. package/src/sync-markdown.js +151 -0
  396. package/src/sync-proposal.js +84 -0
  397. package/src/sync-record.js +459 -0
  398. package/src/sync.js +360 -0
  399. package/src/task-approvals.js +367 -0
  400. package/src/task-cli.js +79 -0
  401. package/src/task-external-verifier.js +584 -0
  402. package/src/task-prepare-files.js +115 -0
  403. package/src/task-prepare.js +180 -0
  404. package/src/task-verify-cli.js +67 -0
  405. package/src/task-verify-files.js +188 -0
  406. package/src/task-verify.js +118 -0
  407. package/src/task-workflow-mcp.js +544 -0
  408. package/src/task-workflow-store.js +254 -0
  409. package/src/terminal-text.js +68 -0
  410. package/src/toolkit-cli.js +543 -0
  411. package/src/toolkit-commands-guide.js +107 -0
  412. package/src/toolkit-setup.js +614 -0
  413. package/src/usage-metrics.js +43 -0
  414. package/templates/agent-team/01-encargo.md +158 -0
  415. package/templates/agent-team/02-propuesta.md +132 -0
  416. package/templates/agent-team/03-revision.md +150 -0
  417. package/templates/agent-team/README.md +213 -0
  418. package/templates/model-inventory/01-inventario.md +154 -0
  419. package/templates/model-inventory/README.md +115 -0
  420. package/templates/project-memory/README.md +67 -0
  421. package/templates/project-memory/project-memory.example.json +53 -0
  422. package/templates/project-memory/skill/project-id/SKILL.md +37 -0
  423. package/templates/project-memory/skill/project-id/references/project-profile.md +44 -0
  424. package/templates/project-memory/vault/00-INICIO/Estado actual.md +44 -0
  425. package/templates/project-memory/vault/00-INICIO/Fuentes de verdad.md +30 -0
  426. package/templates/project-memory/vault/00-INICIO/Inicio del proyecto.md +44 -0
  427. package/templates/project-memory/vault/00-INICIO/Mantenimiento de la memoria.md +26 -0
  428. package/templates/project-memory/vault/00-INICIO/Mapa de la memoria.md +33 -0
  429. package/templates/project-memory/vault/00-INICIO/Registro de sincronizaci/303/263n.md" +28 -0
  430. package/templates/project-memory/vault/01-PRODUCTO/Producto.md +16 -0
  431. package/templates/project-memory/vault/02-ARQUITECTURA/Arquitectura.md +16 -0
  432. package/templates/project-memory/vault/03-IMPLEMENTACION/Implementaci/303/263n.md +15 -0
  433. package/templates/project-memory/vault/04-DECISIONES/Decisiones.md +19 -0
  434. package/templates/project-memory/vault/05-ENTREGAS/Entregas.md +12 -0
  435. package/templates/project-memory/vault/06-OPERACION/Operaci/303/263n.md +15 -0
  436. package/templates/project-memory/vault/07-AGENTES/Protocolo de agentes.md +33 -0
  437. package/templates/project-memory/vault/08-RECURSOS/Recursos.md +12 -0
  438. package/templates/project-memory/vault/09-ARCHIVO/README.md +5 -0
@@ -0,0 +1,118 @@
1
+ import Ajv2020 from "ajv/dist/2020.js";
2
+ import { copyInertJson } from "./client-output-json.js";
3
+ import { copyTaskJson, taskRelativePath, taskHash } from "./task-prepare.js";
4
+
5
+ export const VERIFY_SCHEMA_ID = "https://agent-toolkit.local/schemas/agent-task-verify.schema.json";
6
+ // totalBytes bounds bytes read from observed entries only; the contract has its own contractBytes cap.
7
+ export const VERIFY_LIMITS = Object.freeze({ contractBytes: 524288, entries: 128, fileBytes: 8388608,
8
+ totalBytes: 33554432, chunkBytes: 65536, reportBytes: 131072 });
9
+ export const VERIFY_FACTS = Object.freeze({ scopeCoverage: "listed-files-only", unlistedChangesVerified: false,
10
+ contentQualityVerified: false, testsExecuted: false, permissionVerified: false, approvalGranted: false,
11
+ gitStateVerified: false, modelVerified: false, nativeAdmission: false, runtimeReady: false,
12
+ wrote: false, sent: false, executed: false, humanReviewRequired: true });
13
+ // Internal key for task-verify-files.js. A report stays copyable data and never authorizes anything.
14
+ export const LOCAL_READ = Symbol("agent-task-verify.local-read");
15
+ const EXPECTATIONS = Object.freeze({
16
+ inspect: (before, after) => before !== null && after === before,
17
+ modify: (before, after) => before !== null && after !== null,
18
+ create: (before, after) => before === null && after !== null,
19
+ delete: (before, after) => before !== null && after === null });
20
+ const CLIENT_DIRS = [".claude", ".codex", ".gemini", ".agents"];
21
+ const pathKey = (root, p) => root + "/" + p.normalize("NFC").toLowerCase();
22
+ const shaOrNull = v => typeof v === "string" && /^[a-f0-9]{64}$/.test(v) ? v : null;
23
+
24
+ export function verifyRelativePath(p) {
25
+ return taskRelativePath(p) && p.split("/").every(part => !CLIENT_DIRS.includes(part.toLowerCase()));
26
+ }
27
+ function contractReasons(c) {
28
+ const reasons = new Set(), ids = new Set(), keys = [];
29
+ for (const e of c.entries) {
30
+ if (ids.has(e.id)) reasons.add("verify-duplicate-id");
31
+ ids.add(e.id);
32
+ if (!verifyRelativePath(e.path)) reasons.add("verify-path-invalid");
33
+ if (!EXPECTATIONS[e.operation](e.before, e.after)) reasons.add("verify-expectation-conflict");
34
+ keys.push(pathKey(e.root, e.path));
35
+ }
36
+ // The same path twice, or a listed file that is also a listed entry's directory, is ambiguous.
37
+ if (keys.some((k, i) => keys.some((o, j) => i !== j && (o === k || o.startsWith(k + "/"))))) reasons.add("verify-path-collision");
38
+ return [...reasons];
39
+ }
40
+
41
+ export function createTaskVerifier(trustedSchema) {
42
+ let schema, validContract, validInput, validReport;
43
+ try {
44
+ schema = copyInertJson(trustedSchema);
45
+ if (schema.$id !== VERIFY_SCHEMA_ID) throw Error();
46
+ const ajv = new Ajv2020({ strict: true, allErrors: false });
47
+ ajv.addSchema(schema);
48
+ [validContract, validInput, validReport] = ["contract", "input", "report"].map(d => ajv.compile({ $ref: `${VERIFY_SCHEMA_ID}#/$defs/${d}` }));
49
+ } catch { throw Error("Invalid trusted verify schema"); }
50
+ const schemaSha256 = taskHash(schema);
51
+ const blank = audit => ({ command: "agent-task verify", schemaVersion: "1.0.0", state: "invalid", phase: null, identity: null,
52
+ provenance: "none", results: [], reasons: [], audit: { verifySchemaSha256: schemaSha256, contractSha256: null,
53
+ contractByteSha256: shaOrNull(audit?.contractByteSha256), expectedPinSha256: shaOrNull(audit?.expectedPinSha256) }, ...VERIFY_FACTS });
54
+ const finish = (out, state, codes) => {
55
+ out.state = state; out.reasons = [...new Set(codes)].sort();
56
+ if (state !== "matched" && state !== "mismatched") { out.results = []; out.provenance = "none"; }
57
+ // Never truncate results to look complete: an oversized report becomes invalid.
58
+ if (Buffer.byteLength(JSON.stringify(out)) > VERIFY_LIMITS.reportBytes) Object.assign(out, { state: "invalid", results: [], provenance: "none", reasons: ["verify-output-limit"] });
59
+ if (!validReport(out)) throw Error("Task verify invariant failed");
60
+ return out;
61
+ };
62
+ const checkContract = value => {
63
+ let c;
64
+ try { c = copyTaskJson(value); } catch { return { ok: false, reasons: ["verify-contract-invalid"] }; }
65
+ if (!validContract(c)) return { ok: false, reasons: ["verify-contract-invalid"] };
66
+ const reasons = contractReasons(c);
67
+ return reasons.length ? { ok: false, reasons } : { ok: true, contract: c };
68
+ };
69
+ function run(input, provenance, audit) {
70
+ let a = null;
71
+ try { a = audit === null || audit === undefined ? null : copyInertJson(audit); } catch { a = null; }
72
+ const out = blank(a);
73
+ let d;
74
+ try { d = copyTaskJson(input); } catch { return finish(out, "invalid", ["verify-invalid-input"]); }
75
+ if (!validInput(d)) return finish(out, "invalid", ["verify-invalid-input"]);
76
+ out.phase = d.phase;
77
+ const checked = checkContract(d.contract);
78
+ if (!checked.ok) return finish(out, "invalid", checked.reasons);
79
+ const c = checked.contract;
80
+ out.identity = { ...c.identity }; out.audit.contractSha256 = taskHash(c);
81
+ if (provenance === "local-read" && (out.audit.contractByteSha256 === null || out.audit.contractByteSha256 !== out.audit.expectedPinSha256))
82
+ return finish(out, "blocked", ["verify-pin-mismatch"]);
83
+ const byId = new Map();
84
+ for (const o of d.observations) {
85
+ if (byId.has(o.id)) return finish(out, "invalid", ["verify-observation-mismatch"]);
86
+ byId.set(o.id, o);
87
+ }
88
+ if (byId.size !== c.entries.length || c.entries.some(e => !byId.has(e.id))) return finish(out, "invalid", ["verify-observation-mismatch"]);
89
+ // A present file whose hash is expected must carry that observed hash.
90
+ if (c.entries.some(e => e[d.phase] !== null && byId.get(e.id).status === "present" && byId.get(e.id).sha256 === null))
91
+ return finish(out, "invalid", ["verify-observation-mismatch"]);
92
+ if (d.observations.some(o => o.status === "blocked")) return finish(out, "blocked", ["verify-observation-blocked"]);
93
+ const differences = [], notes = [];
94
+ out.results = c.entries.map(e => {
95
+ const expected = e[d.phase], o = byId.get(e.id), observed = o.status === "present" ? o.sha256 : null;
96
+ const outcome = expected === null ? (o.status === "absent" ? "matched-absent" : "unexpected-present")
97
+ : o.status === "absent" ? "missing" : observed === expected ? "matched-hash" : "hash-differs";
98
+ if (!outcome.startsWith("matched-")) differences.push("verify-" + outcome);
99
+ if (e.operation === "modify" && e.before === e.after) notes.push("verify-modify-without-delta");
100
+ return { id: e.id, root: e.root, operation: e.operation, outcome, expected, observed };
101
+ });
102
+ out.provenance = provenance;
103
+ return finish(out, differences.length ? "mismatched" : "matched", [...(differences.length ? differences : ["verify-matched"]), ...notes]);
104
+ }
105
+ function failure(state, codes, context = {}) {
106
+ if (state !== "blocked" && state !== "invalid") throw Error("Verify failure state required");
107
+ const ctx = copyInertJson(context), out = blank(ctx.audit);
108
+ out.phase = ctx.phase === "before" || ctx.phase === "after" ? ctx.phase : null;
109
+ if (ctx.contract) {
110
+ const checked = checkContract(ctx.contract);
111
+ if (checked.ok) { out.identity = { ...checked.contract.identity }; out.audit.contractSha256 = taskHash(checked.contract); }
112
+ }
113
+ return finish(out, state, copyInertJson(codes));
114
+ }
115
+ return Object.freeze({ checkContract, failure,
116
+ evaluate: input => run(input, "declared-observations", null),
117
+ [LOCAL_READ]: (input, audit) => run(input, "local-read", audit) });
118
+ }
@@ -0,0 +1,544 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { McpServer } from "@modelcontextprotocol/server";
3
+ import { z } from "zod/v4";
4
+
5
+ import { createClaudeCodeRunner } from "./claude-code-runner.js";
6
+ import { createCodexCliRunner } from "./codex-cli-runner.js";
7
+ import { createTaskWorkflowStore } from "./task-workflow-store.js";
8
+ import { createPeerReviewStore } from "./peer-review-store.js";
9
+ import { registerPeerReviewTools, PEER_REVIEW_INSTRUCTIONS } from "./peer-review-mcp.js";
10
+
11
+ const TASK_INPUT = z.object({
12
+ title: z.string().trim().min(1).max(180),
13
+ project: z.string().trim().min(1).max(240),
14
+ objective: z.string().trim().min(1).max(4_000),
15
+ mode: z.enum(["tutor", "autonomous"]),
16
+ scope: z.string().max(4_000).optional().default(""),
17
+ acceptance: z.string().max(4_000).optional().default(""),
18
+ checks: z.string().max(2_000).optional().default(""),
19
+ allowImplementation: z.boolean().optional().default(false),
20
+ allowFinalReview: z.boolean().optional().default(false)
21
+ }).strict();
22
+
23
+ function result(value) {
24
+ return { content: [{ type: "text", text: JSON.stringify(value, null, 2) }] };
25
+ }
26
+
27
+ async function invoke(operation, context) {
28
+ try {
29
+ return result(await operation(context));
30
+ } catch (error) {
31
+ return { isError: true, content: [{ type: "text", text: error instanceof Error ? error.message : "La operación no se pudo completar." }] };
32
+ }
33
+ }
34
+
35
+ function quoteCommandArgument(value) {
36
+ return /^[A-Za-z0-9_./:=+-]+$/u.test(value) ? value : `'${value.replaceAll("'", "'\\''")}'`;
37
+ }
38
+
39
+ async function requestExecutionApproval(context, preview) {
40
+ if (typeof context?.mcpReq?.elicitInput !== "function") {
41
+ throw new Error("Este cliente MCP no ofrece una confirmación interactiva; la ejecución quedó bloqueada.");
42
+ }
43
+ const command = [preview.command.executable, ...preview.command.args].map(quoteCommandArgument).join(" ");
44
+ const details = [
45
+ "Agent Toolkit solicita tu aprobación para llamar a un modelo local.",
46
+ `Cliente: ${preview.client} ${preview.version}`,
47
+ `Sesión o cuenta detectada: ${preview.account}`,
48
+ `Modelo y esfuerzo: ${preview.model} / ${preview.effort}`,
49
+ `Proyecto local: ${preview.command.cwd}`,
50
+ `Permisos de la etapa: ${JSON.stringify(preview.limits ?? {})}`,
51
+ `Comando exacto (shell desactivado): ${command}`,
52
+ `Entrada completa por stdin (${preview.promptBytes} bytes; SHA-256 ${preview.promptSha256}):`,
53
+ preview.command.stdin,
54
+ "Elige aprobar solo si coincide con la vista previa que revisaste. Cancelar no ejecutará el modelo."
55
+ ].join("\n\n");
56
+ const response = await context.mcpReq.elicitInput({
57
+ message: details,
58
+ requestedSchema: {
59
+ type: "object",
60
+ properties: { decision: { type: "string", enum: ["approve", "cancel"], title: "Decisión" } },
61
+ required: ["decision"]
62
+ }
63
+ });
64
+ if (response.action !== "accept" || response.content?.decision !== "approve") {
65
+ throw new Error("La ejecución fue cancelada; no se llamó al modelo.");
66
+ }
67
+ }
68
+
69
+ const PREVIEW_TTL_MS = 20 * 60 * 1000;
70
+ const MAX_PENDING_PREVIEWS = 8;
71
+ const MAX_EXECUTIONS = 32;
72
+ const MAX_ACTIVITY_EVENTS = 40;
73
+ const MAX_ACTIVITY_WAIT_MS = 15_000;
74
+ const CLAUDE_EFFORT = z.enum(["low", "medium", "high", "xhigh", "max"]);
75
+ const CODEX_EFFORT = z.enum(["low", "medium", "high", "xhigh", "max", "ultra"]);
76
+ const EXECUTION_DIAGNOSTIC_CATEGORIES = new Set([
77
+ "authentication", "cli-arguments", "model", "usage-limit", "network", "permissions", "result-error", "unclassified"
78
+ ]);
79
+ const EXECUTION_DIAGNOSTIC_SUBTYPES = new Set([
80
+ "error_during_execution", "error_max_turns", "error_max_budget_usd",
81
+ "error_max_structured_output_retries", "error_max_thinking_tokens"
82
+ ]);
83
+
84
+ function safeExecutionDiagnostic(value) {
85
+ if (!value || typeof value !== "object") return null;
86
+ const diagnostic = {};
87
+ if (value.kind === "process-exit" || value.kind === "result-error") diagnostic.kind = value.kind;
88
+ if (Number.isInteger(value.exitCode) && value.exitCode >= 0 && value.exitCode <= 255) diagnostic.exitCode = value.exitCode;
89
+ if (typeof value.signal === "string" && /^SIG[A-Z0-9]{1,16}$/u.test(value.signal)) diagnostic.signal = value.signal;
90
+ if (EXECUTION_DIAGNOSTIC_CATEGORIES.has(value.category)) diagnostic.category = value.category;
91
+ if (EXECUTION_DIAGNOSTIC_SUBTYPES.has(value.resultSubtype)) diagnostic.resultSubtype = value.resultSubtype;
92
+ return Object.keys(diagnostic).length ? diagnostic : null;
93
+ }
94
+
95
+ function registerTools(server, store, codexRunner, claudeRunner) {
96
+ const previews = new Map();
97
+ const executions = new Map();
98
+ const activeExecutionByTask = new Map();
99
+
100
+ function publishActivity(execution, message) {
101
+ const event = { sequence: ++execution.sequence, at: new Date().toISOString(), message };
102
+ execution.events.push(event);
103
+ if (execution.events.length > MAX_ACTIVITY_EVENTS) execution.events.shift();
104
+ for (const resume of execution.waiters) resume();
105
+ execution.waiters.clear();
106
+ }
107
+
108
+ function executionSnapshot(execution, afterSequence = 0) {
109
+ return {
110
+ taskId: execution.taskId,
111
+ executionId: execution.id,
112
+ stage: execution.stage,
113
+ state: execution.state,
114
+ events: execution.events.filter(event => event.sequence > afterSequence),
115
+ nextSequence: execution.sequence,
116
+ activityMayBeTruncated: afterSequence < (execution.events[0]?.sequence ?? 1) - 1,
117
+ ...(execution.diagnostic ? { diagnostic: execution.diagnostic } : {})
118
+ };
119
+ }
120
+
121
+ async function waitForActivity(execution, afterSequence, waitMs) {
122
+ if (execution.sequence > afterSequence || !["starting", "running", "cancelling"].includes(execution.state) || waitMs === 0) {
123
+ return executionSnapshot(execution, afterSequence);
124
+ }
125
+ await new Promise(resolve => {
126
+ let timer;
127
+ const resume = () => {
128
+ clearTimeout(timer);
129
+ execution.waiters.delete(resume);
130
+ resolve();
131
+ };
132
+ execution.waiters.add(resume);
133
+ timer = setTimeout(resume, waitMs);
134
+ });
135
+ return executionSnapshot(execution, afterSequence);
136
+ }
137
+
138
+ function beginClaudeExecution({ taskId, stage, pending }) {
139
+ const activeId = activeExecutionByTask.get(taskId);
140
+ const active = activeId ? executions.get(activeId) : null;
141
+ if (active && ["starting", "running", "cancelling"].includes(active.state)) {
142
+ throw new Error("Ya hay una llamada de Claude activa para esta tarea; consulta su actividad antes de iniciar otra.");
143
+ }
144
+ for (const execution of executions.values()) {
145
+ if (["completed", "failed"].includes(execution.state) && executions.size >= MAX_EXECUTIONS) executions.delete(execution.id);
146
+ }
147
+ if (executions.size >= MAX_EXECUTIONS) throw new Error("Hay demasiadas llamadas activas; espera a que terminen antes de iniciar otra.");
148
+
149
+ const execution = {
150
+ id: randomUUID(), taskId, stage, state: "starting", sequence: 0,
151
+ controller: new AbortController(),
152
+ events: [], waiters: new Set(), startedAt: new Date().toISOString(), outputKey: stage === "claude-proposal" ? "proposal" : "implementation"
153
+ };
154
+ executions.set(execution.id, execution);
155
+ activeExecutionByTask.set(taskId, execution.id);
156
+ publishActivity(execution, "Agent Toolkit autorizó la llamada y está preparando Claude Code.");
157
+
158
+ void (async () => {
159
+ try {
160
+ const resultValue = await pending.runner.run(pending.preview, {
161
+ signal: execution.controller.signal,
162
+ onActivity(message) {
163
+ if (execution.state === "starting") execution.state = "running";
164
+ publishActivity(execution, message);
165
+ }
166
+ });
167
+ const content = stage === "claude-proposal" ? resultValue : resultValue?.response;
168
+ if (typeof content !== "string" || !content.trim()) throw new Error("Claude no devolvió una entrega válida.");
169
+ const updated = await store.recordStageOutput({ taskId, stage, content });
170
+ execution.state = "completed";
171
+ execution.taskStatus = updated.status;
172
+ execution.currentStage = updated.currentStage;
173
+ execution.outputSha256 = updated.outputs[execution.outputKey]?.sha256 ?? null;
174
+ if (stage === "claude-implementation") {
175
+ execution.filesChanged = resultValue.filesChanged ?? false;
176
+ execution.changedFiles = resultValue.changedFiles ?? [];
177
+ execution.branch = resultValue.branch ?? null;
178
+ execution.baseCommit = resultValue.baseCommit ?? null;
179
+ execution.workspaceVerified = resultValue.workspaceVerified ?? false;
180
+ execution.checksExecuted = false;
181
+ } else {
182
+ execution.filesChanged = false;
183
+ execution.checksExecuted = false;
184
+ }
185
+ publishActivity(execution, "La respuesta de Claude quedó guardada en la tarea.");
186
+ } catch (error) {
187
+ execution.state = execution.controller.signal.aborted ? "cancelled" : "failed";
188
+ execution.error = execution.state === "cancelled"
189
+ ? "Se detuvo la llamada de Claude. Revisa el repositorio por si quedaron cambios parciales antes de volver a intentarlo."
190
+ : error instanceof Error ? error.message : "La llamada de Claude no pudo completarse.";
191
+ const diagnostic = safeExecutionDiagnostic(error?.diagnostic);
192
+ if (diagnostic) execution.diagnostic = diagnostic;
193
+ if (activeExecutionByTask.get(taskId) === execution.id) activeExecutionByTask.delete(taskId);
194
+ publishActivity(execution, `La llamada terminó sin guardar una entrega: ${execution.error}`);
195
+ } finally {
196
+ try { await pending.runner.cleanup?.(pending.preview); } catch {}
197
+ for (const resume of execution.waiters) resume();
198
+ execution.waiters.clear();
199
+ }
200
+ })();
201
+ return execution;
202
+ }
203
+
204
+ async function prunePreviews() {
205
+ const threshold = Date.now() - PREVIEW_TTL_MS;
206
+ for (const [id, pending] of previews) {
207
+ if (pending.createdAt < threshold) {
208
+ previews.delete(id);
209
+ await pending.runner.cleanup?.(pending.preview);
210
+ }
211
+ }
212
+ while (previews.size >= MAX_PENDING_PREVIEWS) {
213
+ const [id, pending] = previews.entries().next().value;
214
+ previews.delete(id);
215
+ await pending.runner.cleanup?.(pending.preview);
216
+ }
217
+ }
218
+
219
+ async function savePreview(runner, preview, taskId, stage) {
220
+ await prunePreviews();
221
+ if (preview.state !== "ready") {
222
+ await runner.cleanup?.(preview);
223
+ return preview;
224
+ }
225
+ previews.set(preview.previewId, { preview, taskId, stage, runner, createdAt: Date.now() });
226
+ return preview;
227
+ }
228
+
229
+ async function takePreview(previewId, confirmationCode, stage) {
230
+ const pending = previews.get(previewId);
231
+ if (!pending || Date.now() - pending.createdAt > PREVIEW_TTL_MS || pending.stage !== stage ||
232
+ pending.preview.confirmationCode !== confirmationCode) {
233
+ if (pending) {
234
+ previews.delete(previewId);
235
+ await pending.runner.cleanup?.(pending.preview);
236
+ }
237
+ throw new Error("La vista previa venció o la confirmación no coincide; prepara otra antes de ejecutar.");
238
+ }
239
+ previews.delete(previewId);
240
+ return pending;
241
+ }
242
+
243
+ server.registerTool("start_task", {
244
+ description: "Inicia una tarea compartida entre Codex y Claude Code. No genera un plan ni inicia llamadas. El campo project es una etiqueta, no una ruta de repositorio.",
245
+ inputSchema: TASK_INPUT
246
+ }, args => invoke(() => store.createTask(args)));
247
+
248
+ server.registerTool("get_task", {
249
+ description: "Lee la tarea activa de un proyecto o una tarea por su identificador, incluidas las entregas que los clientes CLI guardaron automáticamente.",
250
+ inputSchema: z.object({
251
+ project: z.string().trim().min(1).max(240).optional(),
252
+ taskId: z.string().uuid().optional()
253
+ }).strict().refine(value => Boolean(value.project) !== Boolean(value.taskId), "Indica exactamente project o taskId.")
254
+ }, args => invoke(() => store.getTask(args)));
255
+
256
+ server.registerTool("wait_for_task_activity", {
257
+ description: "Espera y devuelve los nuevos hitos visibles de una ejecución de Claude, sin mostrar contenido leído ni razonamiento privado. Si state es starting o running, vuelve a llamar esta herramienta con nextSequence como afterSequence para seguir mostrando actividad hasta que termine. Al fallar, puede incluir un código de salida y una categoría de error permitida, nunca el texto bruto de stderr o la respuesta fallida. Cada espera dura como máximo 15 segundos y no inicia otra llamada al modelo.",
258
+ inputSchema: z.object({
259
+ taskId: z.string().uuid(),
260
+ executionId: z.string().uuid(),
261
+ afterSequence: z.number().int().min(0).optional().default(0),
262
+ waitMs: z.number().int().min(0).max(MAX_ACTIVITY_WAIT_MS).optional().default(MAX_ACTIVITY_WAIT_MS)
263
+ }).strict()
264
+ }, args => invoke(async () => {
265
+ const execution = executions.get(args.executionId);
266
+ if (!execution || execution.taskId !== args.taskId) throw new Error("No se encontró una ejecución activa con esos identificadores.");
267
+ const snapshot = await waitForActivity(execution, args.afterSequence, args.waitMs);
268
+ if (["completed", "failed", "cancelled"].includes(snapshot.state)) {
269
+ const task = await store.getTask({ taskId: args.taskId });
270
+ const output = task.outputs[execution.outputKey];
271
+ return {
272
+ ...snapshot,
273
+ taskStatus: task.status,
274
+ currentStage: task.currentStage,
275
+ ...(output ? { output: output.content, outputSha256: output.sha256 } : {}),
276
+ ...(execution.error ? { error: execution.error } : {}),
277
+ ...(execution.filesChanged !== undefined ? {
278
+ filesChanged: execution.filesChanged,
279
+ changedFiles: execution.changedFiles ?? [],
280
+ branch: execution.branch ?? null,
281
+ baseCommit: execution.baseCommit ?? null,
282
+ workspaceVerified: execution.workspaceVerified ?? false,
283
+ checksExecuted: execution.checksExecuted ?? false
284
+ } : {})
285
+ };
286
+ }
287
+ return { ...snapshot, message: snapshot.events.length ? undefined : "Claude sigue trabajando; aún no reporta una acción nueva." };
288
+ }));
289
+
290
+ server.registerTool("cancel_task_execution", {
291
+ description: "Solicita detener una ejecución activa de Claude. No inicia otra llamada ni revierte cambios parciales; tras cancelarla, revisa el estado de los archivos antes de reintentar.",
292
+ inputSchema: z.object({ taskId: z.string().uuid(), executionId: z.string().uuid() }).strict()
293
+ }, args => invoke(async () => {
294
+ const execution = executions.get(args.executionId);
295
+ if (!execution || execution.taskId !== args.taskId) throw new Error("No se encontró una ejecución con esos identificadores.");
296
+ if (!["starting", "running"].includes(execution.state)) {
297
+ return { taskId: args.taskId, executionId: execution.id, state: execution.state, message: "La ejecución ya terminó." };
298
+ }
299
+ execution.state = "cancelling";
300
+ publishActivity(execution, "Se solicitó detener Claude Code; espera la confirmación de cierre del proceso.");
301
+ execution.controller.abort();
302
+ return { taskId: args.taskId, executionId: execution.id, state: execution.state, message: "Se solicitó la cancelación. Usa wait_for_task_activity para confirmar que el proceso terminó." };
303
+ }));
304
+
305
+ server.registerTool("preview_codex_plan", {
306
+ description: "Prepara, sin llamar al modelo, una vista previa exacta de Codex CLI para planificar en modo de solo lectura. El plan elegirá un modelo y esfuerzo de Claude entre las opciones permitidas. Muestra la cuenta/sesión detectada, el comando, la ruta del proyecto y el prompt. No llames a run_codex_plan hasta que el usuario haya aprobado directamente esta vista previa.",
307
+ inputSchema: z.object({
308
+ taskId: z.string().uuid(),
309
+ projectRoot: z.string().trim().min(1).max(4096),
310
+ model: z.string().trim().min(1).max(80),
311
+ effort: CODEX_EFFORT,
312
+ claudeModels: z.array(z.string().trim().min(1).max(80)).min(1).max(12).optional(),
313
+ claudeEfforts: z.array(CLAUDE_EFFORT).min(1).max(5).optional()
314
+ }).strict()
315
+ }, args => invoke(async () => {
316
+ const task = await store.getTask({ taskId: args.taskId });
317
+ if (task.status !== "in_progress" || task.currentStage !== "codex-plan") throw new Error("La etapa activa no es la planificación de Codex.");
318
+ const preview = await codexRunner.preview({ ...args, task: task.task });
319
+ return savePreview(codexRunner, preview, task.id, "codex-plan");
320
+ }));
321
+
322
+ server.registerTool("run_codex_plan", {
323
+ description: "Ejecuta una vista previa vigente de Codex CLI después de una confirmación interactiva del usuario en el cliente MCP. El diálogo muestra comando, sesión, cuenta, modelo, esfuerzo y prompt. Si el cliente no presenta ese diálogo, la ejecución queda bloqueada. La tarea se guarda automáticamente. No repitas ni reintentes una ejecución fallida.",
324
+ annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
325
+ inputSchema: z.object({
326
+ previewId: z.string().regex(/^[a-f0-9]{32}$/u),
327
+ confirmationCode: z.string().regex(/^[A-F0-9]{8}$/u)
328
+ }).strict()
329
+ }, (args, context) => invoke(async () => {
330
+ const pending = await takePreview(args.previewId, args.confirmationCode, "codex-plan");
331
+ const task = await store.getTask({ taskId: pending.taskId });
332
+ if (task.status !== "in_progress" || task.currentStage !== "codex-plan") {
333
+ await pending.runner.cleanup?.(pending.preview);
334
+ throw new Error("La tarea ya avanzó; prepara una nueva vista previa para la etapa activa.");
335
+ }
336
+ try {
337
+ await requestExecutionApproval(context, pending.preview);
338
+ const plan = await pending.runner.run(pending.preview);
339
+ const updated = await store.recordStageOutput({
340
+ taskId: task.id,
341
+ stage: "codex-plan",
342
+ content: JSON.stringify(plan),
343
+ model: pending.preview.model,
344
+ effort: pending.preview.effort
345
+ });
346
+ return { task: updated, plan, modelAvailabilityVerified: false, checksExecuted: false };
347
+ } finally { await pending.runner.cleanup?.(pending.preview); }
348
+ }));
349
+
350
+ server.registerTool("preview_claude_proposal", {
351
+ description: "Prepara una vista previa exacta de Claude Code CLI para contrastar el plan en modo de solo lectura. Usa el modelo y esfuerzo recomendados por el plan de Codex. Muestra el método de autenticación detectado, el comando y el prompt. No llames a run_claude_proposal hasta recibir aprobación directa del usuario.",
352
+ inputSchema: z.object({
353
+ taskId: z.string().uuid(),
354
+ projectRoot: z.string().trim().min(1).max(4096)
355
+ }).strict()
356
+ }, args => invoke(async () => {
357
+ const task = await store.getTask({ taskId: args.taskId });
358
+ if (task.status !== "in_progress" || task.currentStage !== "claude-proposal" || !task.outputs.plan?.content) {
359
+ throw new Error("La etapa activa todavía no tiene un plan de Codex para revisar.");
360
+ }
361
+ let plan;
362
+ try { plan = JSON.parse(task.outputs.plan.content); } catch { throw new Error("El plan guardado no tiene el formato estructurado esperado."); }
363
+ const preview = await claudeRunner.preview({
364
+ task: task.task,
365
+ plan: task.outputs.plan.content,
366
+ projectRoot: args.projectRoot,
367
+ model: plan.claude?.model,
368
+ effort: plan.claude?.effort
369
+ });
370
+ return savePreview(claudeRunner, preview, task.id, "claude-proposal");
371
+ }));
372
+
373
+ server.registerTool("run_claude_proposal", {
374
+ description: "Después de confirmar interactivamente la vista previa, inicia Claude Code CLI en segundo plano y devuelve un executionId. No llama al modelo antes de la aprobación. Claude recibe solo lectura; usa wait_for_task_activity con ese id para mostrar acciones y recibir la respuesta guardada. Si el cliente no presenta la confirmación, la ejecución queda bloqueada. No repitas ni reintentes una ejecución fallida.",
375
+ annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
376
+ inputSchema: z.object({
377
+ previewId: z.string().regex(/^[a-f0-9]{32}$/u),
378
+ confirmationCode: z.string().regex(/^[A-F0-9]{8}$/u)
379
+ }).strict()
380
+ }, (args, context) => invoke(async () => {
381
+ const pending = await takePreview(args.previewId, args.confirmationCode, "claude-proposal");
382
+ const task = await store.getTask({ taskId: pending.taskId });
383
+ if (task.status !== "in_progress" || task.currentStage !== "claude-proposal") {
384
+ await pending.runner.cleanup?.(pending.preview);
385
+ throw new Error("La tarea ya avanzó; prepara una nueva vista previa para la etapa activa.");
386
+ }
387
+ let launched = false;
388
+ try {
389
+ await requestExecutionApproval(context, pending.preview);
390
+ const execution = beginClaudeExecution({ taskId: task.id, stage: "claude-proposal", pending });
391
+ launched = true;
392
+ return {
393
+ task,
394
+ executionId: execution.id,
395
+ state: execution.state,
396
+ message: "Claude Code inició en segundo plano. Usa wait_for_task_activity para ver sus acciones y recibir la entrega al terminar.",
397
+ model: pending.preview.model,
398
+ effort: pending.preview.effort
399
+ };
400
+ } finally {
401
+ if (!launched) await pending.runner.cleanup?.(pending.preview);
402
+ }
403
+ }));
404
+
405
+ server.registerTool("preview_claude_implementation", {
406
+ description: "Prepara, sin llamar a Claude, una vista previa para la etapa de implementación. En modo tutor Claude devuelve código e instrucciones sin editar; en modo autonomous puede editar solo si start_task activó allowImplementation=true y el usuario aprueba la propuesta vigente. El modo autónomo no tiene shell, MCP ni red y exige una rama limpia distinta de main/master. No llames a run_claude_implementation hasta que el usuario apruebe directamente la vista previa completa.",
407
+ inputSchema: z.object({
408
+ taskId: z.string().uuid(),
409
+ projectRoot: z.string().trim().min(1).max(4096)
410
+ }).strict()
411
+ }, args => invoke(async () => {
412
+ const task = await store.getTask({ taskId: args.taskId });
413
+ const tutorStage = task.task.mode === "tutor" && task.currentStage === "claude-implementation";
414
+ const awaitingApproval = task.currentStage === "awaiting-authorization" && task.authorization.status === "pending";
415
+ const retryAfterApprovedFailure = task.currentStage === "claude-implementation" && task.authorization.status === "approved";
416
+ const autonomousStage = task.task.mode === "autonomous" && task.task.allowImplementation === true &&
417
+ (awaitingApproval || retryAfterApprovedFailure) &&
418
+ (!awaitingApproval || task.authorization.proposalSha256 === task.outputs.proposal?.sha256);
419
+ if (task.status !== "in_progress" || (!tutorStage && !autonomousStage) ||
420
+ !task.outputs.plan?.content || !task.outputs.proposal?.content) {
421
+ throw new Error("Esta tarea no tiene una propuesta vigente y habilitada para implementación autónoma.");
422
+ }
423
+ let plan;
424
+ try { plan = JSON.parse(task.outputs.plan.content); } catch { throw new Error("El plan guardado no tiene el formato estructurado esperado."); }
425
+ const preview = await claudeRunner.previewImplementation({
426
+ task: task.task,
427
+ plan: task.outputs.plan.content,
428
+ proposal: task.outputs.proposal.content,
429
+ proposalSha256: task.authorization.proposalSha256 ?? task.outputs.proposal.sha256,
430
+ projectRoot: args.projectRoot,
431
+ model: plan.claude?.model,
432
+ effort: plan.claude?.effort
433
+ });
434
+ return savePreview(claudeRunner, preview, task.id, "claude-implementation");
435
+ }));
436
+
437
+ server.registerTool("run_claude_implementation", {
438
+ description: "Después de confirmar interactivamente la vista previa, inicia Claude Code CLI en segundo plano y devuelve un executionId. No llama al modelo antes de la aprobación. En modo tutor solo devuelve una solución; en modo autonomous puede escribir archivos y la autorización queda ligada a la huella exacta de la propuesta. Usa wait_for_task_activity para mostrar acciones y recibir la entrega guardada; cancel_task_execution la detiene a petición del usuario. La implementación autónoma no tiene shell, MCP ni red. Si el cliente MCP no presenta la confirmación, la ejecución queda bloqueada. No repitas ni reintentes una ejecución fallida.",
439
+ annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
440
+ inputSchema: z.object({
441
+ previewId: z.string().regex(/^[a-f0-9]{32}$/u),
442
+ confirmationCode: z.string().regex(/^[A-F0-9]{8}$/u)
443
+ }).strict()
444
+ }, (args, context) => invoke(async () => {
445
+ const pending = await takePreview(args.previewId, args.confirmationCode, "claude-implementation");
446
+ const task = await store.getTask({ taskId: pending.taskId });
447
+ const tutorStage = task.task.mode === "tutor" && task.currentStage === "claude-implementation";
448
+ const awaitingApproval = task.currentStage === "awaiting-authorization" && task.authorization.status === "pending";
449
+ const retryAfterApprovedFailure = task.currentStage === "claude-implementation" && task.authorization.status === "approved";
450
+ const autonomousStage = task.task.mode === "autonomous" && task.task.allowImplementation === true &&
451
+ (awaitingApproval || retryAfterApprovedFailure) && pending.preview.proposalSha256 === task.authorization.proposalSha256;
452
+ if (task.status !== "in_progress" || (!tutorStage && !autonomousStage) ||
453
+ pending.preview.proposalSha256 !== task.outputs.proposal?.sha256) {
454
+ await pending.runner.cleanup?.(pending.preview);
455
+ throw new Error("La propuesta o la autorización cambió; prepara una nueva vista previa de la etapa pendiente.");
456
+ }
457
+ let launched = false;
458
+ try {
459
+ await requestExecutionApproval(context, pending.preview);
460
+ if (!tutorStage && awaitingApproval) await store.authorizeImplementation({ taskId: task.id, proposalSha256: pending.preview.proposalSha256 });
461
+ const execution = beginClaudeExecution({ taskId: task.id, stage: "claude-implementation", pending });
462
+ launched = true;
463
+ return {
464
+ task: !tutorStage && awaitingApproval ? await store.getTask({ taskId: task.id }) : task,
465
+ executionId: execution.id,
466
+ state: execution.state,
467
+ message: "Claude Code inició en segundo plano. Usa wait_for_task_activity para ver sus acciones y recibir la entrega al terminar.",
468
+ model: pending.preview.model,
469
+ effort: pending.preview.effort
470
+ };
471
+ } finally {
472
+ if (!launched) await pending.runner.cleanup?.(pending.preview);
473
+ }
474
+ }));
475
+
476
+ server.registerTool("preview_codex_review", {
477
+ description: "Prepara, sin llamar al modelo, la vista previa de revisión final de Codex sobre el repositorio y las tres entregas guardadas. Requiere allowFinalReview=true al iniciar la tarea y la etapa codex-review. Reutiliza el modelo y esfuerzo de la planificación, salvo que indiques juntos otros valores. Muestra la sesión, modelo, esfuerzo, comando y prompt. No llames a run_codex_review hasta la aprobación directa del usuario.",
478
+ inputSchema: z.object({
479
+ taskId: z.string().uuid(),
480
+ projectRoot: z.string().trim().min(1).max(4096),
481
+ model: z.string().trim().min(1).max(80).optional(),
482
+ effort: CODEX_EFFORT.optional()
483
+ }).strict().refine(value => Boolean(value.model) === Boolean(value.effort), "Indica juntos model y effort o déjalos ambos vacíos para reutilizar la selección de la planificación.")
484
+ }, args => invoke(async () => {
485
+ const task = await store.getTask({ taskId: args.taskId });
486
+ if (task.status !== "in_progress" || task.currentStage !== "codex-review" ||
487
+ task.task.mode !== "autonomous" || task.task.allowFinalReview !== true ||
488
+ !task.outputs.plan?.content || !task.outputs.proposal?.content || !task.outputs.implementation?.content) {
489
+ throw new Error("La tarea no está habilitada o no tiene una implementación para la revisión final de Codex.");
490
+ }
491
+ const model = args.model ?? task.outputs.plan.model;
492
+ const effort = args.effort ?? task.outputs.plan.effort;
493
+ if (!model || !effort) throw new Error("La planificación no guardó modelo y esfuerzo de Codex; indícalos explícitamente para la revisión final.");
494
+ const preview = await codexRunner.previewReview({
495
+ task: task.task,
496
+ plan: task.outputs.plan.content,
497
+ proposal: task.outputs.proposal.content,
498
+ implementation: task.outputs.implementation.content,
499
+ projectRoot: args.projectRoot,
500
+ model,
501
+ effort
502
+ });
503
+ return savePreview(codexRunner, preview, task.id, "codex-review");
504
+ }));
505
+
506
+ server.registerTool("run_codex_review", {
507
+ description: "Ejecuta una vista previa vigente de Codex CLI después de la confirmación interactiva del usuario. Codex revisa en sandbox de solo lectura y guarda su dictamen; no modifica archivos ni afirma pruebas no verificadas. No repitas ni reintentes una ejecución fallida.",
508
+ annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
509
+ inputSchema: z.object({
510
+ previewId: z.string().regex(/^[a-f0-9]{32}$/u),
511
+ confirmationCode: z.string().regex(/^[A-F0-9]{8}$/u)
512
+ }).strict()
513
+ }, (args, context) => invoke(async () => {
514
+ const pending = await takePreview(args.previewId, args.confirmationCode, "codex-review");
515
+ const task = await store.getTask({ taskId: pending.taskId });
516
+ if (task.status !== "in_progress" || task.currentStage !== "codex-review" || task.task.allowFinalReview !== true) {
517
+ await pending.runner.cleanup?.(pending.preview);
518
+ throw new Error("La tarea ya avanzó o no habilita la revisión final; prepara otra vista previa de la etapa activa.");
519
+ }
520
+ try {
521
+ await requestExecutionApproval(context, pending.preview);
522
+ const review = await pending.runner.run(pending.preview);
523
+ const updated = await store.recordStageOutput({ taskId: task.id, stage: "codex-review", content: review });
524
+ return { task: updated, review, modelAvailabilityVerified: false, filesChanged: false, checksExecuted: false };
525
+ } finally { await pending.runner.cleanup?.(pending.preview); }
526
+ }));
527
+
528
+ }
529
+
530
+ export function createTaskWorkflowMcp({
531
+ store = createTaskWorkflowStore(),
532
+ codexRunner = createCodexCliRunner(),
533
+ claudeRunner = createClaudeCodeRunner(),
534
+ peerStore = createPeerReviewStore()
535
+ } = {}) {
536
+ const server = new McpServer({
537
+ name: "agent-toolkit",
538
+ version: "0.1.0",
539
+ instructions: PEER_REVIEW_INSTRUCTIONS + " " + "Agent Toolkit coordina Codex CLI y Claude Code CLI mediante vistas previas de un solo uso. Las tareas tutor usan Claude para devolver una solución sin editar. Las tareas autonomous solo habilitan la implementación de Claude y la revisión final de Codex si allowImplementation y allowFinalReview se activaron al crearla; ambos están desactivados por defecto. Codex planifica en modo de solo lectura y elige modelo/esfuerzo de Claude entre valores permitidos. Claude contrasta el plan en modo de solo lectura. Después de revisar su propuesta, el usuario puede autorizar por separado la implementación; esa llamada puede editar archivos únicamente en una rama de trabajo limpia, con herramientas Read, Glob, Grep, Edit y Write, sin shell, red ni MCP. Codex revisa el resultado en modo read-only. Antes de cada llamada, solicita aprobación interactiva y muestra comando, cuenta/sesión, modelo, esfuerzo, permisos y prompt. Las llamadas a Claude devuelven un identificador y corren en segundo plano; después llama wait_for_task_activity para mostrar acciones sanitizadas hasta que termine. Si el usuario pide detener la ejecución, usa cancel_task_execution y luego confirma el cierre con wait_for_task_activity; si era una escritura, pídele inspeccionar posibles cambios parciales. Si el cliente no ofrece confirmación, la llamada queda bloqueada. No inventes cuentas, disponibilidad, pruebas o resultados; nunca hagas commits ni pushes."
540
+ });
541
+ registerTools(server, store, codexRunner, claudeRunner);
542
+ registerPeerReviewTools(server, peerStore);
543
+ return server;
544
+ }