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.
- package/.claude-plugin/marketplace.json +28 -0
- package/LICENSE +26 -0
- package/README.md +79 -2
- package/agents/claude/docs-researcher.md +9 -0
- package/agents/claude/implementation-tutor.md +9 -0
- package/agents/claude/project-explorer.md +9 -0
- package/agents/claude/quality-reviewer.md +9 -0
- package/agents/claude/requirements-analyst.md +9 -0
- package/agents/claude/solution-architect.md +9 -0
- package/agents/codex/docs-researcher.toml +10 -0
- package/agents/codex/implementation-tutor.toml +10 -0
- package/agents/codex/project-explorer.toml +10 -0
- package/agents/codex/quality-reviewer.toml +10 -0
- package/agents/codex/requirements-analyst.toml +11 -0
- package/agents/codex/solution-architect.toml +10 -0
- package/assets/brand/README.md +38 -0
- package/assets/brand/agent-toolkit-mark.png +0 -0
- package/assets/brand/agent-toolkit-mark.svg +13 -0
- package/assets/brand/agent-toolkit-tui-hero.png +0 -0
- package/assets/brand/nexakit-readme-hero.png +0 -0
- package/assets/brand/nexakit-readme-hero.svg +21 -0
- package/assets/runtime/package-lock.json +1425 -0
- package/bin/agent-task.js +14 -0
- package/bin/agent-toolkit-gemini.js +13 -0
- package/bin/agent-toolkit-inbox.js +14 -0
- package/bin/agent-toolkit-mcp.js +17 -0
- package/bin/agent-toolkit.js +13 -0
- package/bin/nexakit.js +13 -0
- package/bin/project-memory-mcp.js +22 -0
- package/bin/project-memory.js +7 -0
- package/catalogs/skills/api-design-principles/LICENSE.txt +21 -0
- package/catalogs/skills/api-design-principles/SKILL.md +110 -0
- package/catalogs/skills/api-design-principles/assets/api-design-checklist.md +155 -0
- package/catalogs/skills/api-design-principles/assets/rest-api-template.py +185 -0
- package/catalogs/skills/api-design-principles/references/details.md +413 -0
- package/catalogs/skills/api-design-principles/references/graphql-schema-design.md +589 -0
- package/catalogs/skills/api-design-principles/references/rest-best-practices.md +408 -0
- package/catalogs/skills/nodejs-backend-patterns/LICENSE.txt +21 -0
- package/catalogs/skills/nodejs-backend-patterns/SKILL.md +45 -0
- package/catalogs/skills/nodejs-backend-patterns/references/advanced-patterns.md +430 -0
- package/catalogs/skills/nodejs-backend-patterns/references/details.md +599 -0
- package/catalogs/skills/supabase-postgres-best-practices/CHANGELOG.md +73 -0
- package/catalogs/skills/supabase-postgres-best-practices/LICENSE.txt +21 -0
- package/catalogs/skills/supabase-postgres-best-practices/SKILL.md +64 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/_contributing.md +170 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/_sections.md +39 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/_template.md +34 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
- package/catalogs/skills/supabase-postgres-best-practices/references/security-rls-performance.md +63 -0
- package/catalogs/skills/vercel-composition-patterns/AGENTS.md +946 -0
- package/catalogs/skills/vercel-composition-patterns/LICENSE.txt +27 -0
- package/catalogs/skills/vercel-composition-patterns/README.md +60 -0
- package/catalogs/skills/vercel-composition-patterns/SKILL.md +89 -0
- package/catalogs/skills/vercel-composition-patterns/metadata.json +11 -0
- package/catalogs/skills/vercel-composition-patterns/rules/_sections.md +29 -0
- package/catalogs/skills/vercel-composition-patterns/rules/_template.md +24 -0
- package/catalogs/skills/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
- package/catalogs/skills/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
- package/catalogs/skills/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
- package/catalogs/skills/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
- package/catalogs/skills/vercel-composition-patterns/rules/react19-no-forwardref.md +42 -0
- package/catalogs/skills/vercel-composition-patterns/rules/state-context-interface.md +191 -0
- package/catalogs/skills/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
- package/catalogs/skills/vercel-composition-patterns/rules/state-lift-state.md +125 -0
- package/catalogs/skills/vercel-react-best-practices/AGENTS.md +3810 -0
- package/catalogs/skills/vercel-react-best-practices/LICENSE.txt +27 -0
- package/catalogs/skills/vercel-react-best-practices/README.md +123 -0
- package/catalogs/skills/vercel-react-best-practices/SKILL.md +149 -0
- package/catalogs/skills/vercel-react-best-practices/metadata.json +15 -0
- package/catalogs/skills/vercel-react-best-practices/rules/_sections.md +46 -0
- package/catalogs/skills/vercel-react-best-practices/rules/_template.md +28 -0
- package/catalogs/skills/vercel-react-best-practices/rules/advanced-effect-event-deps.md +56 -0
- package/catalogs/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/catalogs/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
- package/catalogs/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
- package/catalogs/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/catalogs/skills/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
- package/catalogs/skills/vercel-react-best-practices/rules/async-defer-await.md +82 -0
- package/catalogs/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
- package/catalogs/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/catalogs/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/catalogs/skills/vercel-react-best-practices/rules/bundle-analyzable-paths.md +63 -0
- package/catalogs/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +60 -0
- package/catalogs/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/catalogs/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/catalogs/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/catalogs/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/catalogs/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/catalogs/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/catalogs/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/catalogs/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/catalogs/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/catalogs/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/catalogs/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/catalogs/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/catalogs/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/catalogs/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/catalogs/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +60 -0
- package/catalogs/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/catalogs/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/catalogs/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/catalogs/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/catalogs/skills/vercel-react-best-practices/rules/js-request-idle-callback.md +105 -0
- package/catalogs/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/catalogs/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +85 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +68 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +82 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/catalogs/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/catalogs/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/catalogs/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
- package/catalogs/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/catalogs/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
- package/catalogs/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
- package/catalogs/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +149 -0
- package/catalogs/skills/vercel-react-best-practices/rules/server-no-shared-module-state.md +50 -0
- package/catalogs/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/catalogs/skills/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +34 -0
- package/catalogs/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/catalogs/skills/webapp-testing/LICENSE.txt +202 -0
- package/catalogs/skills/webapp-testing/SKILL.md +96 -0
- package/catalogs/skills/webapp-testing/examples/console_logging.py +35 -0
- package/catalogs/skills/webapp-testing/examples/element_discovery.py +40 -0
- package/catalogs/skills/webapp-testing/examples/static_html_automation.py +33 -0
- package/catalogs/skills/webapp-testing/scripts/with_server.py +106 -0
- package/catalogs/skills.json +1115 -0
- package/docs/skills/evidencias/2026-10-28-evaluacion-inicial-mcp-seguridad.md +118 -0
- package/docs/skills/evidencias/2026-10-28-incorporacion-mcp-seguridad.json +152 -0
- package/docs/skills/evidencias/2026-10-28-recomendador-preparacion.md +50 -0
- package/package.json +73 -4
- package/plugins/nexakit-modelo/.claude-plugin/plugin.json +1 -0
- package/plugins/nexakit-modelo/hooks/hooks.json +1 -0
- package/plugins/nexakit-modelo/hooks/register.js +48 -0
- package/plugins/nexakit-modelo/hooks/status.js +8 -0
- package/plugins/nexakit-modelo/tests/register.test.ts +21 -0
- package/plugins/nexakit-panel/.claude-plugin/plugin.json +1 -0
- package/plugins/nexakit-panel/README.md +20 -0
- package/plugins/nexakit-panel/hooks/hooks.json +1 -0
- package/plugins/nexakit-panel/hooks/lienzo.js +382 -0
- package/plugins/nexakit-panel/hooks/panel.js +279 -0
- package/plugins/nexakit-panel/hooks/register.tsx +248 -0
- package/plugins/nexakit-panel/tests/lienzo.test.ts +142 -0
- package/plugins/nexakit-panel/tests/panel.test.ts +240 -0
- package/plugins/nexakit-panel/tests/register.test.ts +167 -0
- package/plugins/nexakit-panel/types/index.d.ts +41 -0
- package/plugins/nexakit-sesion/.claude-plugin/plugin.json +1 -0
- package/plugins/nexakit-sesion/README.md +12 -0
- package/plugins/nexakit-sesion/hooks/aviso.js +38 -0
- package/plugins/nexakit-sesion/hooks/hooks.json +1 -0
- package/plugins/nexakit-sesion/hooks/register.js +28 -0
- package/plugins/nexakit-sesion/tests/register.test.ts +96 -0
- package/plugins/niveles/.claude-plugin/plugin.json +5 -0
- package/plugins/niveles/agents/nivel-alto.md +13 -0
- package/plugins/niveles/agents/nivel-exigente.md +13 -0
- package/plugins/niveles/agents/nivel-ligero.md +13 -0
- package/plugins/niveles/agents/nivel-normal.md +13 -0
- package/schemas/agent-client-adapter.schema.json +786 -0
- package/schemas/agent-client-auth-diagnostic.schema.json +801 -0
- package/schemas/agent-client-isolated-variant.schema.json +105 -0
- package/schemas/agent-client-isolated-verification.schema.json +99 -0
- package/schemas/agent-client-managed-preferences-invocation.schema.json +67 -0
- package/schemas/agent-client-managed-preferences.schema.json +63 -0
- package/schemas/agent-client-native-diagnostics.schema.json +85 -0
- package/schemas/agent-client-native-evaluation.schema.json +171 -0
- package/schemas/agent-client-native-preflight.schema.json +90 -0
- package/schemas/agent-client-output.schema.json +551 -0
- package/schemas/agent-client-runtime-fixture.schema.json +90 -0
- package/schemas/agent-client-runtime-local.schema.json +95 -0
- package/schemas/agent-client-runtime.schema.json +1288 -0
- package/schemas/agent-client-selective-config.schema.json +77 -0
- package/schemas/agent-client-supervised-local.schema.json +135 -0
- package/schemas/agent-client-supervised.schema.json +186 -0
- package/schemas/agent-model-preference.schema.json +573 -0
- package/schemas/agent-model-selection.schema.json +311 -0
- package/schemas/agent-task-approvals.schema.json +362 -0
- package/schemas/agent-task-prepare.schema.json +1324 -0
- package/schemas/agent-task-verify.schema.json +198 -0
- package/schemas/project-memory-update.schema.json +33 -0
- package/schemas/project-memory.schema.json +298 -0
- package/schemas/skill-catalog.schema.json +246 -0
- package/schemas/task-workflow-plan-output.schema.json +35 -0
- package/scripts/prepare-package.js +6 -0
- package/scripts/validate-skill-catalog.js +41 -0
- package/skills/cerrar-avisens/SKILL.md +12 -0
- package/skills/cerrar-memoria/SKILL.md +96 -0
- package/skills/cerrar-memoria/references/cierre.md +76 -0
- package/skills/decision-records/SKILL.md +27 -0
- package/skills/decision-records/agents/openai.yaml +7 -0
- package/skills/decision-records/references/adr-template.md +35 -0
- package/skills/differential-review/LICENSE.txt +427 -0
- package/skills/differential-review/SKILL.md +225 -0
- package/skills/differential-review/adversarial.md +203 -0
- package/skills/differential-review/agents/openai.yaml +6 -0
- package/skills/differential-review/assets/trail-of-bits-mark.svg +1 -0
- package/skills/differential-review/methodology.md +234 -0
- package/skills/differential-review/patterns.md +300 -0
- package/skills/differential-review/reporting.md +369 -0
- package/skills/elegir-modelo/SKILL.md +68 -0
- package/skills/elegir-modelo/modelos.mjs +108 -0
- package/skills/frontend-design/LICENSE.txt +177 -0
- package/skills/frontend-design/SKILL.md +71 -0
- package/skills/gemini/SKILL.md +52 -0
- package/skills/imagen/SKILL.md +12 -0
- package/skills/investigar/SKILL.md +11 -0
- package/skills/mcp-builder/LICENSE.txt +202 -0
- package/skills/mcp-builder/SKILL.md +236 -0
- package/skills/mcp-builder/reference/evaluation.md +602 -0
- package/skills/mcp-builder/reference/mcp_best_practices.md +249 -0
- package/skills/mcp-builder/reference/node_mcp_server.md +970 -0
- package/skills/mcp-builder/reference/python_mcp_server.md +719 -0
- package/skills/mcp-builder/scripts/connections.py +151 -0
- package/skills/mcp-builder/scripts/evaluation.py +373 -0
- package/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/skills/mcp-builder/scripts/requirements.txt +2 -0
- package/skills/ordenar-proyecto/SKILL.md +56 -0
- package/skills/project-handoff/SKILL.md +53 -0
- package/skills/project-handoff/agents/openai.yaml +7 -0
- package/skills/project-handoff/references/handoff-template.md +35 -0
- package/skills/quality-gate/LICENSE.txt +26 -0
- package/skills/quality-gate/SKILL.md +44 -0
- package/skills/quality-gate/agents/openai.yaml +7 -0
- package/skills/quality-gate/references/review-checklist.md +42 -0
- package/skills/revisar/SKILL.md +11 -0
- package/skills/revisar-skill/LICENSE-find-skills.txt +26 -0
- package/skills/revisar-skill/SKILL.md +94 -0
- package/skills/revision-cruzada/SKILL.md +59 -0
- package/skills/web-design-guidelines/AGENTS.md +156 -0
- package/skills/web-design-guidelines/LICENSE.txt +21 -0
- package/skills/web-design-guidelines/SKILL.md +29 -0
- package/src/agent-models.js +131 -0
- package/src/brand.js +117 -0
- package/src/claude-code-runner.js +642 -0
- package/src/cli-executable.js +88 -0
- package/src/cli.js +778 -0
- package/src/client-adapter-plan.js +271 -0
- package/src/client-auth-diagnostic-parser.js +211 -0
- package/src/client-auth-diagnostic.js +257 -0
- package/src/client-isolated-variant.js +106 -0
- package/src/client-isolated-verification.js +130 -0
- package/src/client-local-platform.js +14 -0
- package/src/client-managed-preferences-invocation.js +209 -0
- package/src/client-managed-preferences.js +78 -0
- package/src/client-native-access.js +134 -0
- package/src/client-native-diagnostics.js +253 -0
- package/src/client-native-evaluation.js +106 -0
- package/src/client-native-preflight-files.js +68 -0
- package/src/client-native-preflight.js +95 -0
- package/src/client-output-json.js +118 -0
- package/src/client-output-parser.js +278 -0
- package/src/client-runtime-admission.js +80 -0
- package/src/client-runtime-coordinator.js +70 -0
- package/src/client-runtime-core.js +92 -0
- package/src/client-runtime-fixture-permit.js +20 -0
- package/src/client-runtime-fixture-protocol.js +39 -0
- package/src/client-runtime-state.js +67 -0
- package/src/client-runtime-store-files.js +91 -0
- package/src/client-runtime-store.js +239 -0
- package/src/client-runtime-supervisor.js +146 -0
- package/src/client-selective-config.js +195 -0
- package/src/client-selective-files.js +126 -0
- package/src/client-supervised-codes.js +32 -0
- package/src/client-supervised-contract.js +52 -0
- package/src/client-supervised-coordinator.js +36 -0
- package/src/client-supervised-permit.js +20 -0
- package/src/client-supervised-protocol.js +37 -0
- package/src/client-supervised-store.js +167 -0
- package/src/client-supervised-supervisor.js +167 -0
- package/src/client-supervised.js +160 -0
- package/src/codex-cli-runner.js +358 -0
- package/src/codex-delivery.js +101 -0
- package/src/connect.js +703 -0
- package/src/doctor.js +795 -0
- package/src/gemini-cli.js +76 -0
- package/src/gemini-files.js +45 -0
- package/src/gemini-tools.js +249 -0
- package/src/init.js +473 -0
- package/src/install-lock.js +127 -0
- package/src/install-registry.js +61 -0
- package/src/legacy-repair.js +71 -0
- package/src/level-agents.js +111 -0
- package/src/link-states.js +172 -0
- package/src/memory-connection-artifacts.js +192 -0
- package/src/memory-connection-descriptor.js +158 -0
- package/src/memory-connection-diagnostic.js +177 -0
- package/src/memory-connection-files.js +191 -0
- package/src/memory-connection-manifest.js +118 -0
- package/src/memory-connection-package.js +176 -0
- package/src/memory-connection-plan.js +211 -0
- package/src/memory-connection-skill.js +211 -0
- package/src/memory-connection-toml.js +153 -0
- package/src/memory-locator.js +118 -0
- package/src/memory-mcp-policy.js +181 -0
- package/src/memory-mcp-server.js +166 -0
- package/src/memory-mcp-transport.js +59 -0
- package/src/missing-dependencies.js +21 -0
- package/src/model-command.js +147 -0
- package/src/model-preference.js +235 -0
- package/src/model-selection.js +368 -0
- package/src/native/managed-preferences.c +100 -0
- package/src/native/managed-preferences.h +17 -0
- package/src/package-lock-path.js +13 -0
- package/src/panel-cli.js +182 -0
- package/src/peer-handoff.js +27 -0
- package/src/peer-inbox-cli.js +211 -0
- package/src/peer-review-mcp.js +210 -0
- package/src/peer-review-store.js +532 -0
- package/src/platform.js +24 -0
- package/src/project-root.js +41 -0
- package/src/project-signals.js +339 -0
- package/src/recommend-report.js +77 -0
- package/src/review-instructions.js +211 -0
- package/src/review-policy.js +35 -0
- package/src/revision-adapters.js +157 -0
- package/src/revision-context.js +86 -0
- package/src/revision-isolation.js +222 -0
- package/src/revision-process.js +103 -0
- package/src/revision-provenance.js +89 -0
- package/src/revision-snapshot.js +120 -0
- package/src/revision.js +242 -0
- package/src/runtime-fixtures/runtime-supervisor/child.cjs +3 -0
- package/src/runtime-fixtures/runtime-supervisor/fixture.cjs +49 -0
- package/src/runtime-fixtures/supervised/child.cjs +3 -0
- package/src/runtime-fixtures/supervised/fixture.cjs +47 -0
- package/src/sensitive-data.js +21 -0
- package/src/setup-apply.js +231 -0
- package/src/setup-plan.js +231 -0
- package/src/setup-state.js +277 -0
- package/src/setup-tui.js +555 -0
- package/src/skill-catalog-add.js +91 -0
- package/src/skill-catalog-audit.js +68 -0
- package/src/skill-catalog.js +170 -0
- package/src/skill-files.js +39 -0
- package/src/skill-recommendations.js +1673 -0
- package/src/skill-scan-report.js +14 -0
- package/src/skill-scan.js +178 -0
- package/src/stable-command.js +53 -0
- package/src/stable-install.js +222 -0
- package/src/status.js +200 -0
- package/src/superpowers.js +133 -0
- package/src/sync-apply.js +227 -0
- package/src/sync-files.js +109 -0
- package/src/sync-inspect.js +394 -0
- package/src/sync-ledger.js +94 -0
- package/src/sync-markdown.js +151 -0
- package/src/sync-proposal.js +84 -0
- package/src/sync-record.js +459 -0
- package/src/sync.js +360 -0
- package/src/task-approvals.js +367 -0
- package/src/task-cli.js +79 -0
- package/src/task-external-verifier.js +584 -0
- package/src/task-prepare-files.js +115 -0
- package/src/task-prepare.js +180 -0
- package/src/task-verify-cli.js +67 -0
- package/src/task-verify-files.js +188 -0
- package/src/task-verify.js +118 -0
- package/src/task-workflow-mcp.js +544 -0
- package/src/task-workflow-store.js +254 -0
- package/src/terminal-text.js +68 -0
- package/src/toolkit-cli.js +543 -0
- package/src/toolkit-commands-guide.js +107 -0
- package/src/toolkit-setup.js +614 -0
- package/src/usage-metrics.js +43 -0
- package/templates/agent-team/01-encargo.md +158 -0
- package/templates/agent-team/02-propuesta.md +132 -0
- package/templates/agent-team/03-revision.md +150 -0
- package/templates/agent-team/README.md +213 -0
- package/templates/model-inventory/01-inventario.md +154 -0
- package/templates/model-inventory/README.md +115 -0
- package/templates/project-memory/README.md +67 -0
- package/templates/project-memory/project-memory.example.json +53 -0
- package/templates/project-memory/skill/project-id/SKILL.md +37 -0
- package/templates/project-memory/skill/project-id/references/project-profile.md +44 -0
- package/templates/project-memory/vault/00-INICIO/Estado actual.md +44 -0
- package/templates/project-memory/vault/00-INICIO/Fuentes de verdad.md +30 -0
- package/templates/project-memory/vault/00-INICIO/Inicio del proyecto.md +44 -0
- package/templates/project-memory/vault/00-INICIO/Mantenimiento de la memoria.md +26 -0
- package/templates/project-memory/vault/00-INICIO/Mapa de la memoria.md +33 -0
- package/templates/project-memory/vault/00-INICIO/Registro de sincronizaci/303/263n.md" +28 -0
- package/templates/project-memory/vault/01-PRODUCTO/Producto.md +16 -0
- package/templates/project-memory/vault/02-ARQUITECTURA/Arquitectura.md +16 -0
- package/templates/project-memory/vault/03-IMPLEMENTACION/Implementaci/303/263n.md +15 -0
- package/templates/project-memory/vault/04-DECISIONES/Decisiones.md +19 -0
- package/templates/project-memory/vault/05-ENTREGAS/Entregas.md +12 -0
- package/templates/project-memory/vault/06-OPERACION/Operaci/303/263n.md +15 -0
- package/templates/project-memory/vault/07-AGENTES/Protocolo de agentes.md +33 -0
- package/templates/project-memory/vault/08-RECURSOS/Recursos.md +12 -0
- package/templates/project-memory/vault/09-ARCHIVO/README.md +5 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { describe, expect, test } from 'claude-code/testing';
|
|
2
|
+
|
|
3
|
+
const PANE = {
|
|
4
|
+
plugin: 'nexakit-panel',
|
|
5
|
+
component: 'Pane',
|
|
6
|
+
requestId: 'panel',
|
|
7
|
+
props: { title: 'Orquesta', isFocused: false, bodyColumns: 70, placement: 'dock', scroll: { offset: 0, bodyRows: 40 }, view: {} },
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
let reloj = 1_000_000;
|
|
11
|
+
const drain = async (stream: any) => {
|
|
12
|
+
for await (const _ of stream) { /* el panel solo observa */ }
|
|
13
|
+
return stream.result;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// Lo que el motor contestaría por debajo del mod.
|
|
17
|
+
function motor($: any, on: any, uso: any = { startedAt: 0, context: { window: 1000000, percent: 31 }, rateLimits: [{ kind: 'five_hour', percentUsed: 43 }, { kind: 'seven_day', percentUsed: 60 }] }, falla = false, salidaBash = '') {
|
|
18
|
+
on('command.register', () => ({ value: { command: 'panel' } }));
|
|
19
|
+
on('ui.open', () => ({ value: { isPlaced: true } }));
|
|
20
|
+
on('session.start', (_: any, e: any) => ({ cwd: e.cwd }));
|
|
21
|
+
on('clock.now', () => ({ value: (reloj += 1000) }));
|
|
22
|
+
on('session.cwd', () => ({ value: '/prueba/mi-app' }));
|
|
23
|
+
on('session.usage', () => { if (falla) throw new Error('sin datos'); return { value: uso }; });
|
|
24
|
+
on('tool.call', () => ({ result: { stdout: salidaBash, stderr: '' } }));
|
|
25
|
+
on('agent.spawn', (_: any, e: any) => ({ model: e.model ?? 'claude-haiku-5-5', agentId: `ag-${e.name ?? 'x'}` }));
|
|
26
|
+
on('turn.complete', () => ({ text: '' }));
|
|
27
|
+
on('turn.step', async function* (_: any, e: any) {
|
|
28
|
+
return { turnId: e.turnId, index: e.index, answer: '', toolUses: [], stopReason: 'end_turn', usage: null,
|
|
29
|
+
serverToolUses: e.index === 1 ? [{ id: 's1', name: 'advisor', input: {}, startedAt: 1, endedAt: 2 }]
|
|
30
|
+
: e.index === 2 ? [{ id: 's2', name: 'web_search', input: {}, startedAt: 3, endedAt: 4 }] : undefined };
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
const paso = ($: any, extra: any) =>
|
|
34
|
+
drain($.turn.step({ turnId: 't1', index: 0, model: 'claude-sonnet-5-5', effort: 'high', messageCount: 3, ...extra }));
|
|
35
|
+
const turnoListo = ($: any, extra: any) =>
|
|
36
|
+
$.turn.complete({ reason: 'answer', answer: 'ok', durationMs: 5, isAborted: false, turnId: 't1', ...extra });
|
|
37
|
+
|
|
38
|
+
describe('nexakit-panel · en la sesión', () => {
|
|
39
|
+
test('dibuja líder, subagentes, asesor, registro y límites con lo que informa el motor', async ($, on) => {
|
|
40
|
+
motor($, on);
|
|
41
|
+
await $.session.start({ surface: 'terminal', isInteractive: true, cwd: '/prueba' });
|
|
42
|
+
await paso($, {}); // líder: Sonnet 5.5 · high
|
|
43
|
+
await paso($, { index: 1 }); // el paso trae una consulta al asesor
|
|
44
|
+
await paso($, { index: 2 }); // otra llamada del servidor: no es el asesor
|
|
45
|
+
await $.agent.spawn({ prompt: 'mapea', name: 'search', subagentType: 'Explore', description: 'mapear el repo', model: 'claude-haiku-5-5' });
|
|
46
|
+
await $.tool.call({ tool: 'Read', file_path: 'src/auth.ts', agentId: 'ag-search' });
|
|
47
|
+
await turnoListo($, { agentId: 'ag-search' });
|
|
48
|
+
|
|
49
|
+
for (const surface of ['terminal', 'desktop'] as const) {
|
|
50
|
+
const ui = await $.ui.mount({ ...PANE, surface });
|
|
51
|
+
expect((await ui.find({ type: 'Text', text: /Sonnet 5\.5 · sesión principal/ }))?.text).toBeTruthy();
|
|
52
|
+
expect((await ui.find({ type: 'Text', text: /esfuerzo ▮▮▮▯ high/ }))?.text).toBeTruthy();
|
|
53
|
+
expect((await ui.find({ type: 'Text', text: /Asesor · consultas 1/ }))?.text).toBeTruthy();
|
|
54
|
+
expect((await ui.find({ type: 'Text', text: /search/ }))?.text).toBeTruthy();
|
|
55
|
+
expect((await ui.find({ type: 'Text', text: /Haiku 5\.5/ }))?.text).toBeTruthy();
|
|
56
|
+
expect((await ui.find({ type: 'Text', text: /✓ listo/ }))?.text).toBeTruthy();
|
|
57
|
+
expect((await ui.find({ type: 'Text', text: /Read · src\/auth\.ts/ }))?.text).toBeTruthy();
|
|
58
|
+
expect((await ui.find({ type: 'Text', text: /contexto .*31 % +5 h .*43 % +semana .*60 %/ }))?.text).toBeTruthy();
|
|
59
|
+
await ui.unmount();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('con ancho de sobra dibuja el diagrama completo con la estructura de la imagen', async ($, on) => {
|
|
64
|
+
motor($, on);
|
|
65
|
+
await $.session.start({ surface: 'terminal', isInteractive: true, cwd: '/prueba' });
|
|
66
|
+
await paso($, {});
|
|
67
|
+
await paso($, { index: 1 });
|
|
68
|
+
await $.agent.spawn({ prompt: 'mapea', name: 'search', subagentType: 'Explore', description: 'mapear', model: 'claude-haiku-5-5' });
|
|
69
|
+
await $.agent.spawn({ prompt: 'busca', name: 'grep', subagentType: 'Explore', description: 'buscar', model: 'claude-haiku-5-5' });
|
|
70
|
+
await $.tool.call({ tool: 'Read', file_path: 'src/auth.ts', agentId: 'ag-search' });
|
|
71
|
+
await turnoListo($, { agentId: 'ag-search' });
|
|
72
|
+
|
|
73
|
+
const ui = await $.ui.mount({ ...PANE, surface: 'terminal', props: { ...PANE.props, bodyColumns: 120 } });
|
|
74
|
+
const hay = async (texto: RegExp) => expect((await ui.find({ type: 'Text', text: texto }))?.text, String(texto)).toBeTruthy();
|
|
75
|
+
for (const t of [/NEXAKIT/, /SONNET 5\.5 DIRIGE/, /HAIKU 5\.5 EN ENJAMBRE/, /═{50,}/, /sonnet 5\.5 · líder/, /ASESOR/,
|
|
76
|
+
/◆ \d\d:\d\d:\d\d consulta/, /Sonnet 5\.5 · sesión principal/, /pasos 2 · herramientas 0/, /DELEGACIÓN · subagentes/,
|
|
77
|
+
/delegar a subagentes/, /search/, /✓ listo/, /◐ corriendo/, /de vuelta en Sonnet 5\.5 · líder/, /esperando 1 subagente/,
|
|
78
|
+
/registro de sesión/, /→ src\/auth\.ts/, /claude --model sonnet/, /\[enjambre\]/, /\[consultado 1\]/, /31 %/, /43 %/, /60 %/]) {
|
|
79
|
+
await hay(t);
|
|
80
|
+
}
|
|
81
|
+
await ui.unmount();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('en el diagrama ancho sin actividad no inventa cajas ni números', async ($, on) => {
|
|
85
|
+
motor($, on, { startedAt: 0, context: { window: 1000000 }, rateLimits: [] });
|
|
86
|
+
await $.session.start({ surface: 'terminal', isInteractive: true, cwd: '/prueba' });
|
|
87
|
+
const ui = await $.ui.mount({ ...PANE, surface: 'terminal', props: { ...PANE.props, bodyColumns: 120 } });
|
|
88
|
+
expect((await ui.find({ type: 'Text', text: /Aún no hay actividad/ }))?.text).toBeTruthy();
|
|
89
|
+
for (const falso of [/DELEGACIÓN/, /ASESOR/, /de vuelta en/, /registro de sesión/]) expect(await ui.find({ type: 'Text', text: falso })).toBeFalsy();
|
|
90
|
+
await ui.unmount();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('con más subagentes de los que caben avisa de los que no caben y no los pierde en silencio', async ($, on) => {
|
|
94
|
+
motor($, on);
|
|
95
|
+
await $.session.start({ surface: 'terminal', isInteractive: true, cwd: '/prueba' });
|
|
96
|
+
await paso($, {});
|
|
97
|
+
for (let i = 0; i < 6; i++) await $.agent.spawn({ prompt: 'x', name: 'tarea' + i, description: 'd', model: 'claude-haiku-5-5' });
|
|
98
|
+
const ui = await $.ui.mount({ ...PANE, surface: 'terminal', props: { ...PANE.props, bodyColumns: 120 } });
|
|
99
|
+
expect((await ui.find({ type: 'Text', text: /\+3 más/ }))?.text).toBeTruthy();
|
|
100
|
+
expect((await ui.find({ type: 'Text', text: /DELEGACIÓN · subagentes/ }))?.text).toBeTruthy();
|
|
101
|
+
expect((await ui.find({ type: 'Text', text: /^ *6 *$/ }))?.text).toBeTruthy();
|
|
102
|
+
await ui.unmount();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('/panel-demo enseña datos de ejemplo marcados como ficticios, y el panel real no se contamina', async ($, on) => {
|
|
106
|
+
motor($, on);
|
|
107
|
+
await $.session.start({ surface: 'terminal', isInteractive: true, cwd: '/prueba' });
|
|
108
|
+
await $.command.run({ command: 'panel-demo', args: '' } as any);
|
|
109
|
+
let ui = await $.ui.mount({ ...PANE, surface: 'terminal', props: { ...PANE.props, bodyColumns: 120 } });
|
|
110
|
+
expect((await ui.find({ type: 'Text', text: /EJEMPLO · datos ficticios/ }))?.text).toBeTruthy();
|
|
111
|
+
expect((await ui.find({ type: 'Text', text: /DELEGACIÓN/ }))?.text).toBeTruthy();
|
|
112
|
+
await ui.unmount();
|
|
113
|
+
await $.command.run({ command: 'panel-demo', args: '' } as any);
|
|
114
|
+
ui = await $.ui.mount({ ...PANE, surface: 'terminal', props: { ...PANE.props, bodyColumns: 120 } });
|
|
115
|
+
expect(await ui.find({ type: 'Text', text: /EJEMPLO/ })).toBeFalsy();
|
|
116
|
+
expect((await ui.find({ type: 'Text', text: /Aún no hay actividad/ }))?.text).toBeTruthy();
|
|
117
|
+
await ui.unmount();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('guarda una foto del estado real en ~/.nexakit/panel para nexakit panel, sin secretos', async ($, on) => {
|
|
121
|
+
const escritos: Record<string, string> = {};
|
|
122
|
+
motor($, on);
|
|
123
|
+
on('env.get', (_: any, e: any) => ({ value: e.name === 'HOME' ? '/home/prueba' : undefined }));
|
|
124
|
+
on('session.id', () => ({ value: 'sesion-123' }));
|
|
125
|
+
on('fs.write', (_: any, e: any) => { escritos[e.path] = e.text; return { value: undefined }; });
|
|
126
|
+
await $.session.start({ surface: 'terminal', isInteractive: true, cwd: '/prueba' });
|
|
127
|
+
await paso($, {});
|
|
128
|
+
await $.tool.call({ tool: 'Bash', command: 'export API_TOKEN=abc123 && npm test' } as any);
|
|
129
|
+
const foto = JSON.parse(escritos['/home/prueba/.nexakit/panel/actual.json']);
|
|
130
|
+
expect(foto).toMatchObject({ version: 1, sesion: 'sesion-123', carpeta: 'mi-app' });
|
|
131
|
+
expect(foto.estado.lider.modelo).toBe('claude-sonnet-5-5');
|
|
132
|
+
expect(foto.uso.context.percent).toBe(31);
|
|
133
|
+
expect(JSON.stringify(foto)).not.toContain('abc123');
|
|
134
|
+
expect(escritos['/home/prueba/.nexakit/panel/sesion-123.json']).toBe(escritos['/home/prueba/.nexakit/panel/actual.json']);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('una revisión que Claude manda a Codex aparece con su modelo y los tokens que informa', async ($, on) => {
|
|
138
|
+
motor($, on, undefined, false, 'informe\nModelo pedido: gpt-6.1-sol · high · Modelo que respondió: gpt-6.1-sol · high (registro)\nTokens: entrada 41000 (caché 3000) · salida 900\n');
|
|
139
|
+
await $.session.start({ surface: 'terminal', isInteractive: true, cwd: '/prueba' });
|
|
140
|
+
await paso($, {});
|
|
141
|
+
await $.tool.call({ tool: 'Bash', command: '~/.nexakit/nexakit revision --con codex --modelo gpt-6.1-sol --esfuerzo high --encargo /tmp/e.md' } as any);
|
|
142
|
+
const ui = await $.ui.mount({ ...PANE, surface: 'terminal', props: { ...PANE.props, bodyColumns: 120 } });
|
|
143
|
+
for (const t of [/REVISIÓN/, /Codex/, /✓ lista/, /tokens 42k/, /codex · revisa/, /\[revisó\]/]) {
|
|
144
|
+
expect((await ui.find({ type: 'Text', text: t }))?.text, String(t)).toBeTruthy();
|
|
145
|
+
}
|
|
146
|
+
await ui.unmount();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test('sin actividad el panel lo dice y no inventa nada', async ($, on) => {
|
|
150
|
+
motor($, on, { startedAt: 0, context: { window: 1000000 }, rateLimits: [] });
|
|
151
|
+
await $.session.start({ surface: 'terminal', isInteractive: true, cwd: '/prueba' });
|
|
152
|
+
const ui = await $.ui.mount({ ...PANE, surface: 'terminal' });
|
|
153
|
+
expect((await ui.find({ type: 'Text', text: /Aún no hay actividad/ }))?.text).toBeTruthy();
|
|
154
|
+
expect(await ui.find({ type: 'Text', text: /Asesor/ })).toBeFalsy();
|
|
155
|
+
expect(await ui.find({ type: 'Text', text: /contexto/ })).toBeFalsy();
|
|
156
|
+
await ui.unmount();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test('si falla la lectura del uso, el panel se dibuja igual', async ($, on) => {
|
|
160
|
+
motor($, on, undefined, true);
|
|
161
|
+
await $.session.start({ surface: 'terminal', isInteractive: true, cwd: '/prueba' });
|
|
162
|
+
await paso($, {});
|
|
163
|
+
const ui = await $.ui.mount({ ...PANE, surface: 'terminal' });
|
|
164
|
+
expect((await ui.find({ type: 'Text', text: /Sonnet 5\.5/ }))?.text).toBeTruthy();
|
|
165
|
+
await ui.unmount();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export type PanelAgente = {
|
|
2
|
+
id: string;
|
|
3
|
+
nombre: string;
|
|
4
|
+
modelo: string;
|
|
5
|
+
estado: 'corriendo' | 'listo' | 'error';
|
|
6
|
+
inicio: number;
|
|
7
|
+
fin: number | null;
|
|
8
|
+
herramientas: number;
|
|
9
|
+
leidos: number;
|
|
10
|
+
escritos: number;
|
|
11
|
+
ultimo: string;
|
|
12
|
+
};
|
|
13
|
+
export type PanelRevision = {
|
|
14
|
+
id: string;
|
|
15
|
+
ia: string;
|
|
16
|
+
modelo: string | null;
|
|
17
|
+
esfuerzo: string | null;
|
|
18
|
+
estado: 'revisando' | 'lista' | 'error';
|
|
19
|
+
inicio: number;
|
|
20
|
+
fin: number | null;
|
|
21
|
+
entrada: number | null;
|
|
22
|
+
cache: number | null;
|
|
23
|
+
salida: number | null;
|
|
24
|
+
respondio: string | null;
|
|
25
|
+
};
|
|
26
|
+
export type PanelRegistro = { t: number; quien: string; texto: string; ms?: number };
|
|
27
|
+
export type PanelEstado = {
|
|
28
|
+
lider: { modelo: string | null; esfuerzo: string | null; leidos: number; escritos: number; herramientas: number };
|
|
29
|
+
agentes: PanelAgente[];
|
|
30
|
+
asesor: { llamadas: number; ultimo: number | null; tiempo: number };
|
|
31
|
+
registro: PanelRegistro[];
|
|
32
|
+
pasos: number;
|
|
33
|
+
recomendacion: { modelo: string; esfuerzo: string; motivo: string } | null;
|
|
34
|
+
revisiones: PanelRevision[];
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
declare module 'claude-code' {
|
|
38
|
+
interface PluginState {
|
|
39
|
+
'nexakit-panel': { panel: Shaped<PanelEstado>; demo: Shaped<boolean> };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name": "nexakit-sesion", "version": "0.1.0", "description": "Muestra cuánto contexto y cuota llevas y avisa cuándo conviene cerrar la sesión y abrir otra, sin cerrarla por ti.", "license": "MIT"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# nexakit-sesion
|
|
2
|
+
|
|
3
|
+
Muestra en la línea de estado de Claude Code cuánto contexto llevas y tus límites de uso de 5 horas y semanal,
|
|
4
|
+
por ejemplo `contexto 42 % · 5 h 14 % · semana 79 %`. Al pasar del 60 % y del 80 % de contexto avisa una vez de
|
|
5
|
+
que es buen momento para escribir el traspaso y abrir una sesión nueva. Solo avisa: nunca cierra la sesión.
|
|
6
|
+
|
|
7
|
+
Los datos salen de Claude Code (`$.session.usage()`); los límites se mueven en puntos enteros y solo cuando una
|
|
8
|
+
respuesta de la API informa un valor nuevo.
|
|
9
|
+
|
|
10
|
+
## Pruebas
|
|
11
|
+
|
|
12
|
+
`claude plugin test plugins/nexakit-sesion`
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Umbrales de contexto a partir de los cuales conviene pensar en una sesión nueva.
|
|
2
|
+
export const UMBRAL_AVISO = 60;
|
|
3
|
+
export const UMBRAL_URGENTE = 80;
|
|
4
|
+
|
|
5
|
+
const entero = (valor) => Math.round(valor);
|
|
6
|
+
const esNumero = (valor) => typeof valor === 'number' && Number.isFinite(valor);
|
|
7
|
+
|
|
8
|
+
// 0 = sin aviso, 1 = conviene, 2 = urgente. Sin dato nunca avisa.
|
|
9
|
+
export function avisoDeContexto(percent) {
|
|
10
|
+
if (!esNumero(percent)) return 0;
|
|
11
|
+
if (percent >= UMBRAL_URGENTE) return 2;
|
|
12
|
+
if (percent >= UMBRAL_AVISO) return 1;
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Línea de estado: solo lo que se conoce; undefined si no hay nada que mostrar.
|
|
17
|
+
export function textoDeEstado(usage) {
|
|
18
|
+
const partes = [];
|
|
19
|
+
if (esNumero(usage?.context?.percent)) partes.push(`contexto ${entero(usage.context.percent)} %`);
|
|
20
|
+
for (const limite of usage?.rateLimits ?? []) {
|
|
21
|
+
if (!esNumero(limite?.percentUsed)) continue;
|
|
22
|
+
if (limite.kind === 'five_hour') partes.push(`5 h ${entero(limite.percentUsed)} %`);
|
|
23
|
+
if (limite.kind === 'seven_day') partes.push(`semana ${entero(limite.percentUsed)} %`);
|
|
24
|
+
}
|
|
25
|
+
return partes.length > 0 ? partes.join(' · ') : undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// El aviso solo recomienda: nunca promete ni hace el cierre por la persona.
|
|
29
|
+
export function mensajeDeAviso(nivel, percent) {
|
|
30
|
+
const p = entero(percent);
|
|
31
|
+
if (nivel === 1) {
|
|
32
|
+
return `Contexto al ${p} %. Si vas a cambiar de tarea, es buen momento: escribe el traspaso y abre una sesión nueva.`;
|
|
33
|
+
}
|
|
34
|
+
if (nivel === 2) {
|
|
35
|
+
return `Contexto al ${p} %. Cada turno relee más contexto: cierra esta tarea, escribe el traspaso y abre una sesión nueva.`;
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"modules":["./register.js"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { avisoDeContexto, mensajeDeAviso, textoDeEstado } from './aviso.js';
|
|
2
|
+
|
|
3
|
+
export function register(on) {
|
|
4
|
+
// Último nivel avisado: solo se vuelve a avisar al subir de nivel o tras bajar y volver a subir.
|
|
5
|
+
let ultimoAviso = 0;
|
|
6
|
+
|
|
7
|
+
on('turn.complete', async ($, e, next) => {
|
|
8
|
+
try {
|
|
9
|
+
if (!e.agentId) {
|
|
10
|
+
const usage = await $.session.usage();
|
|
11
|
+
$.ui.status(textoDeEstado(usage));
|
|
12
|
+
const percent = usage?.context?.percent;
|
|
13
|
+
const nivel = avisoDeContexto(percent);
|
|
14
|
+
if (nivel > ultimoAviso) $.ui.toast(mensajeDeAviso(nivel, percent), { timeoutMs: 10000 });
|
|
15
|
+
ultimoAviso = nivel;
|
|
16
|
+
}
|
|
17
|
+
} catch {
|
|
18
|
+
// Medir nunca debe romper el turno.
|
|
19
|
+
}
|
|
20
|
+
return next(e);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
on('session.end', async ($, e, next) => {
|
|
24
|
+
ultimoAviso = 0;
|
|
25
|
+
$.ui.status(undefined);
|
|
26
|
+
return next(e);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { describe, expect, test } from 'claude-code/testing';
|
|
2
|
+
import { avisoDeContexto, textoDeEstado, mensajeDeAviso } from '../hooks/aviso.js';
|
|
3
|
+
|
|
4
|
+
describe('nexakit-sesion · lógica', () => {
|
|
5
|
+
test('los umbrales avisan al 60 % y al 80 %, y nunca sin dato', () => {
|
|
6
|
+
expect(avisoDeContexto(0)).toBe(0);
|
|
7
|
+
expect(avisoDeContexto(59.9)).toBe(0);
|
|
8
|
+
expect(avisoDeContexto(60)).toBe(1);
|
|
9
|
+
expect(avisoDeContexto(79.9)).toBe(1);
|
|
10
|
+
expect(avisoDeContexto(80)).toBe(2);
|
|
11
|
+
expect(avisoDeContexto(100)).toBe(2);
|
|
12
|
+
expect(avisoDeContexto(undefined)).toBe(0);
|
|
13
|
+
expect(avisoDeContexto(Number.NaN)).toBe(0);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('la línea de estado junta contexto y límites de Claude, y omite lo que no se conoce', () => {
|
|
17
|
+
const usage = {
|
|
18
|
+
context: { window: 1000000, percent: 41.6 },
|
|
19
|
+
rateLimits: [
|
|
20
|
+
{ kind: 'five_hour', percentUsed: 88 },
|
|
21
|
+
{ kind: 'seven_day', percentUsed: 14.5 },
|
|
22
|
+
{ kind: 'spend_limit', percentUsed: 3 },
|
|
23
|
+
],
|
|
24
|
+
};
|
|
25
|
+
expect(textoDeEstado(usage)).toBe('contexto 42 % · 5 h 88 % · semana 15 %');
|
|
26
|
+
expect(textoDeEstado({ context: { window: 1000 }, rateLimits: [] })).toBeUndefined();
|
|
27
|
+
expect(textoDeEstado({ context: { window: 1000, percent: 5 }, rateLimits: [] })).toBe('contexto 5 %');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('cada aviso dice el porcentaje, propone el traspaso y no promete cerrar nada', () => {
|
|
31
|
+
const uno = mensajeDeAviso(1, 62.2);
|
|
32
|
+
const dos = mensajeDeAviso(2, 83.7);
|
|
33
|
+
expect(uno).toContain('62 %');
|
|
34
|
+
expect(dos).toContain('84 %');
|
|
35
|
+
for (const texto of [uno, dos]) {
|
|
36
|
+
expect(texto).toContain('traspaso');
|
|
37
|
+
expect(texto).toContain('sesión nueva');
|
|
38
|
+
}
|
|
39
|
+
expect(mensajeDeAviso(0, 10)).toBeUndefined();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('nexakit-sesion · en la sesión', () => {
|
|
44
|
+
const montar = async ($: any, on: any, porcentajes: number[]) => {
|
|
45
|
+
const estados: (string | undefined)[] = [];
|
|
46
|
+
const avisos: string[] = [];
|
|
47
|
+
let turno = 0;
|
|
48
|
+
on('session.start', (_: any, e: any) => ({ cwd: e.cwd }));
|
|
49
|
+
on('turn.complete', () => ({ text: 'listo' }));
|
|
50
|
+
on('session.end', () => ({ sessionId: 's1' }));
|
|
51
|
+
on('clock.now', () => ({ value: 0 }));
|
|
52
|
+
on('fs.write', () => ({ value: undefined }));
|
|
53
|
+
on('session.usage', () => ({
|
|
54
|
+
value: { startedAt: 0, context: { window: 1000000, percent: porcentajes[Math.min(turno, porcentajes.length - 1)] }, rateLimits: [] },
|
|
55
|
+
}));
|
|
56
|
+
on('ui.status', (_: any, e: any) => {
|
|
57
|
+
estados.push(e.text);
|
|
58
|
+
return { value: undefined };
|
|
59
|
+
});
|
|
60
|
+
on('ui.toast', (_: any, e: any) => {
|
|
61
|
+
avisos.push(e.text);
|
|
62
|
+
return { value: undefined };
|
|
63
|
+
});
|
|
64
|
+
await $.session.start({ surface: 'terminal', isInteractive: true, cwd: '/prueba' });
|
|
65
|
+
const terminar = async () => {
|
|
66
|
+
await $.turn.complete({ reason: 'answer', answer: 'ok', durationMs: 5, isAborted: false, turnId: `t${turno}` });
|
|
67
|
+
turno += 1;
|
|
68
|
+
};
|
|
69
|
+
return { estados, avisos, terminar };
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
test('avisa una sola vez por umbral y vuelve a avisar si el contexto baja y vuelve a subir', async ($, on) => {
|
|
73
|
+
const { estados, avisos, terminar } = await montar($, on, [30, 61, 65, 82, 85, 20, 70]);
|
|
74
|
+
await terminar(); // 30
|
|
75
|
+
expect(avisos).toHaveLength(0);
|
|
76
|
+
await terminar(); // 61 -> primer aviso
|
|
77
|
+
expect(avisos).toHaveLength(1);
|
|
78
|
+
await terminar(); // 65 -> sin repetir
|
|
79
|
+
expect(avisos).toHaveLength(1);
|
|
80
|
+
await terminar(); // 82 -> aviso urgente
|
|
81
|
+
expect(avisos).toHaveLength(2);
|
|
82
|
+
expect(avisos[1]).toContain('82 %');
|
|
83
|
+
await terminar(); // 85 -> sin repetir
|
|
84
|
+
expect(avisos).toHaveLength(2);
|
|
85
|
+
await terminar(); // 20 -> tras compactar o limpiar
|
|
86
|
+
await terminar(); // 70 -> vuelve a avisar
|
|
87
|
+
expect(avisos).toHaveLength(3);
|
|
88
|
+
expect(estados.at(-1)).toBe('contexto 70 %');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('al terminar la sesión limpia su línea de estado', async ($, on) => {
|
|
92
|
+
const { estados } = await montar($, on, [10]);
|
|
93
|
+
await $.session.end({ reason: 'exit' });
|
|
94
|
+
expect(estados.at(-1)).toBeUndefined();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nivel-alto
|
|
3
|
+
description: Ejecuta una tarea delegada de nivel Alto (opus, high). Úsalo solo cuando la skill revision-cruzada indique este nivel para la tarea.
|
|
4
|
+
model: opus
|
|
5
|
+
effort: high
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Ejecutas una tarea que te delega la sesión principal de la revisión cruzada, con el nivel Alto (opus, high).
|
|
9
|
+
|
|
10
|
+
- Haz solo lo que pide la delegación y respeta las reglas del proyecto (CLAUDE.md, AGENTS.md y sus skills).
|
|
11
|
+
- Si la tarea es de código: cambio mínimo, pruebas que lo cubran, y ejecútalas junto con el lint o la compilación que correspondan.
|
|
12
|
+
- No hagas commit, push ni PR, y no envíes, apruebes ni reclames encargos de revisión.
|
|
13
|
+
- Termina con los cambios por archivo, las comprobaciones ejecutadas con su resultado real y lo que no comprobaste.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nivel-exigente
|
|
3
|
+
description: Ejecuta una tarea delegada de nivel Exigente (sonnet, high). Úsalo solo cuando la skill revision-cruzada indique este nivel para la tarea.
|
|
4
|
+
model: sonnet
|
|
5
|
+
effort: high
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Ejecutas una tarea que te delega la sesión principal de la revisión cruzada, con el nivel Exigente (sonnet, high).
|
|
9
|
+
|
|
10
|
+
- Haz solo lo que pide la delegación y respeta las reglas del proyecto (CLAUDE.md, AGENTS.md y sus skills).
|
|
11
|
+
- Si la tarea es de código: cambio mínimo, pruebas que lo cubran, y ejecútalas junto con el lint o la compilación que correspondan.
|
|
12
|
+
- No hagas commit, push ni PR, y no envíes, apruebes ni reclames encargos de revisión.
|
|
13
|
+
- Termina con los cambios por archivo, las comprobaciones ejecutadas con su resultado real y lo que no comprobaste.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nivel-ligero
|
|
3
|
+
description: Ejecuta una tarea delegada de nivel Ligero (haiku, low). Úsalo solo cuando la skill revision-cruzada indique este nivel para la tarea.
|
|
4
|
+
model: haiku
|
|
5
|
+
effort: low
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Ejecutas una tarea que te delega la sesión principal de la revisión cruzada, con el nivel Ligero (haiku, low).
|
|
9
|
+
|
|
10
|
+
- Haz solo lo que pide la delegación y respeta las reglas del proyecto (CLAUDE.md, AGENTS.md y sus skills).
|
|
11
|
+
- Si la tarea es de código: cambio mínimo, pruebas que lo cubran, y ejecútalas junto con el lint o la compilación que correspondan.
|
|
12
|
+
- No hagas commit, push ni PR, y no envíes, apruebes ni reclames encargos de revisión.
|
|
13
|
+
- Termina con los cambios por archivo, las comprobaciones ejecutadas con su resultado real y lo que no comprobaste.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nivel-normal
|
|
3
|
+
description: Ejecuta una tarea delegada de nivel Normal (sonnet, medium). Úsalo solo cuando la skill revision-cruzada indique este nivel para la tarea.
|
|
4
|
+
model: sonnet
|
|
5
|
+
effort: medium
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Ejecutas una tarea que te delega la sesión principal de la revisión cruzada, con el nivel Normal (sonnet, medium).
|
|
9
|
+
|
|
10
|
+
- Haz solo lo que pide la delegación y respeta las reglas del proyecto (CLAUDE.md, AGENTS.md y sus skills).
|
|
11
|
+
- Si la tarea es de código: cambio mínimo, pruebas que lo cubran, y ejecútalas junto con el lint o la compilación que correspondan.
|
|
12
|
+
- No hagas commit, push ni PR, y no envíes, apruebes ni reclames encargos de revisión.
|
|
13
|
+
- Termina con los cambios por archivo, las comprobaciones ejecutadas con su resultado real y lo que no comprobaste.
|