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 fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import { createStoreFiles, bytesHash } from "./client-runtime-store-files.js";
|
|
5
|
+
import { createSupervisedPermit, revokeSupervisedPermit } from "./client-supervised-permit.js";
|
|
6
|
+
import { createSupervisedContract, hash, same, taskKey, zeroMetrics, terminalStates, errorCode, fail, copyInertJson } from "./client-supervised-contract.js";
|
|
7
|
+
|
|
8
|
+
const names = ["0000.json", "0001.json", "0002.json", "0003.json"];
|
|
9
|
+
const unfinished = new Set(["reserved", "start-claimed", "started"]);
|
|
10
|
+
|
|
11
|
+
/** Separate one-attempt store; construction never initializes or repairs paths. */
|
|
12
|
+
export function createSupervisedStore(schema, configuration, dependencies = {}) {
|
|
13
|
+
const contract = createSupervisedContract(schema), cfg = copyInertJson(configuration);
|
|
14
|
+
if (Object.keys(cfg).join() !== "root" || typeof cfg.root !== "string" || !path.isAbsolute(cfg.root) || path.normalize(cfg.root) !== cfg.root) throw Error("Invalid supervised store configuration");
|
|
15
|
+
const files = createStoreFiles(dependencies.io), checkpoint = dependencies.checkpoint ?? (async () => {});
|
|
16
|
+
const clock = dependencies.clock ?? Date.now;
|
|
17
|
+
let rootIdentity;
|
|
18
|
+
async function root() {
|
|
19
|
+
const tmp = await fs.realpath(os.tmpdir());
|
|
20
|
+
// S2 is experiments only: do not activate a permanent project/user store.
|
|
21
|
+
if (path.dirname(cfg.root) !== tmp || !/^agent-supervised-[a-zA-Z0-9-]+$/.test(path.basename(cfg.root))) fail("supervised-root-not-temporary");
|
|
22
|
+
const s = await files.directory(cfg.root, rootIdentity); rootIdentity ??= s; return s;
|
|
23
|
+
}
|
|
24
|
+
function stamp() {
|
|
25
|
+
const n = clock(); if (!Number.isFinite(n)) fail("supervised-clock-unavailable");
|
|
26
|
+
return new Date(n).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
27
|
+
}
|
|
28
|
+
async function readChain(dir, identity, expectedDirectory) {
|
|
29
|
+
await root(); await files.directory(dir, expectedDirectory); await files.contents(dir, [...names, "confirmed.json"]);
|
|
30
|
+
const events = [], bytesHashes = []; let missingSeen = false;
|
|
31
|
+
for (const name of names) {
|
|
32
|
+
const p = path.join(dir, name);
|
|
33
|
+
if (!await files.exists(p)) { missingSeen = true; continue; }
|
|
34
|
+
if (missingSeen) fail("supervised-event-gap");
|
|
35
|
+
const { bytes } = await files.read(p, 131072); const e = contract.event(bytes);
|
|
36
|
+
if (e.limits.graceMs + e.limits.confirmationMs >= e.limits.timeoutMs || e.limits.maxLineBytes > e.limits.maxOutputBytes) fail("supervised-incompatible-limits");
|
|
37
|
+
const prior = events.at(-1);
|
|
38
|
+
if (e.sequence !== events.length || taskKey(e.identity) !== taskKey(identity) ||
|
|
39
|
+
e.previousSha256 !== (bytesHashes.at(-1) ?? null)) fail("supervised-event-chain-mismatch");
|
|
40
|
+
if (!prior) {
|
|
41
|
+
if (e.state !== "reserved" || !same(e.metrics, zeroMetrics()) || e.reasons.length) fail("supervised-invalid-reservation");
|
|
42
|
+
} else {
|
|
43
|
+
if (!same(e.identity, prior.identity) || e.attemptId !== prior.attemptId || e.fixtureId !== prior.fixtureId ||
|
|
44
|
+
e.requestSha256 !== prior.requestSha256 || !same(e.limits, prior.limits) || Date.parse(e.observedAt) < Date.parse(prior.observedAt)) fail("supervised-event-binding-mismatch");
|
|
45
|
+
const allowed = prior.state === "reserved" ? ["start-claimed", "canceled", "failed", "timed-out", "indeterminate"]
|
|
46
|
+
: prior.state === "start-claimed" ? ["started", "failed", "canceled", "timed-out", "indeterminate"]
|
|
47
|
+
: prior.state === "started" ? [...terminalStates] : [];
|
|
48
|
+
if (!allowed.includes(e.state) || e.metrics.spawnAttempts < prior.metrics.spawnAttempts ||
|
|
49
|
+
e.metrics.mainStartsObserved < prior.metrics.mainStartsObserved || e.metrics.mainStartsObserved > e.metrics.spawnAttempts ||
|
|
50
|
+
["stdoutBytes", "stderrBytes", "events", "elapsedMs"].some(k => e.metrics[k] < prior.metrics[k])) fail("supervised-invalid-transition");
|
|
51
|
+
if (e.state === "start-claimed" && (e.metrics.spawnAttempts !== 1 || e.metrics.mainStartsObserved !== 0 || e.reasons.length)) fail("supervised-invalid-claim");
|
|
52
|
+
if (e.state === "started" && (e.metrics.spawnAttempts !== 1 || e.metrics.mainStartsObserved !== 1 || e.reasons.length)) fail("supervised-invalid-start");
|
|
53
|
+
if (terminalStates.has(e.state)) {
|
|
54
|
+
if (!e.reasons.length || e.state !== "indeterminate" && !e.metrics.terminationConfirmed) fail("supervised-unconfirmed-terminal");
|
|
55
|
+
if (e.state === "completed-for-review" && (prior.state !== "started" || e.metrics.mainStartsObserved !== 1 ||
|
|
56
|
+
e.metrics.stdoutBytes > e.limits.maxOutputBytes || e.metrics.stderrBytes > e.limits.maxStderrBytes ||
|
|
57
|
+
e.metrics.events > e.limits.maxEvents || e.metrics.elapsedMs > e.limits.timeoutMs)) fail("supervised-invalid-completion");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
events.push(e); bytesHashes.push(bytesHash(bytes));
|
|
61
|
+
}
|
|
62
|
+
if (!events.length) fail("supervised-empty-reservation");
|
|
63
|
+
let receipt = false;
|
|
64
|
+
if (await files.exists(path.join(dir, "confirmed.json"))) {
|
|
65
|
+
const seal = contract.receipt((await files.read(path.join(dir, "confirmed.json"), 131072)).bytes);
|
|
66
|
+
if (!terminalStates.has(events.at(-1).state) || events.at(-1).state === "indeterminate" || seal.terminalSha256 !== bytesHashes.at(-1)) fail("supervised-receipt-mismatch");
|
|
67
|
+
receipt = true;
|
|
68
|
+
}
|
|
69
|
+
return { events, bytesHashes, last: events.at(-1), receipt };
|
|
70
|
+
}
|
|
71
|
+
async function observe(input) {
|
|
72
|
+
const r = { state: "clear", budgetConsumed: false, eventCount: 0, lastState: null, spawnAttempts: null,
|
|
73
|
+
mainStartsObserved: null, fixtureModelCalls: 0, actualModelCalls: null, internalCallCeiling: null,
|
|
74
|
+
remoteCancellationVerified: false, reasons: [] };
|
|
75
|
+
try {
|
|
76
|
+
const i = contract.identity(input); await root(); const dir = path.join(cfg.root, taskKey(i));
|
|
77
|
+
if (!await files.exists(dir)) return contract.observation(r);
|
|
78
|
+
r.budgetConsumed = true;
|
|
79
|
+
const c = await readChain(dir, i); const e = c.last;
|
|
80
|
+
r.eventCount = c.events.length; r.lastState = e.state;
|
|
81
|
+
r.spawnAttempts = e.metrics.spawnAttempts; r.mainStartsObserved = e.metrics.mainStartsObserved;
|
|
82
|
+
// Recorded zeros before observation do not prove that no process started.
|
|
83
|
+
if (unfinished.has(e.state) || e.state === "indeterminate" || !c.receipt) {
|
|
84
|
+
r.state = "reconciliation-required"; r.mainStartsObserved = e.metrics.mainStartsObserved === 1 ? 1 : null;
|
|
85
|
+
if (e.state === "reserved") r.spawnAttempts = null;
|
|
86
|
+
} else r.state = "consumed";
|
|
87
|
+
r.reasons = [r.state === "consumed" ? "supervised-budget-consumed" : "supervised-reconciliation-required"];
|
|
88
|
+
} catch (e) {
|
|
89
|
+
r.state = "reconciliation-required"; r.budgetConsumed = true; r.reasons = [errorCode(e)];
|
|
90
|
+
r.spawnAttempts = null; r.mainStartsObserved = null;
|
|
91
|
+
}
|
|
92
|
+
return contract.observation(r);
|
|
93
|
+
}
|
|
94
|
+
async function withReservation(input, consumer) {
|
|
95
|
+
const r = { state: "blocked", durability: "unconfirmed", reasons: [], value: null };
|
|
96
|
+
let handle, created = false;
|
|
97
|
+
try {
|
|
98
|
+
const d = contract.request(input); if (typeof consumer !== "function") fail("supervised-consumer-required");
|
|
99
|
+
const rootStat = await root(), dir = path.join(cfg.root, taskKey(d.identity));
|
|
100
|
+
await checkpoint("before-reserve");
|
|
101
|
+
try { await files.io.mkdir(dir, { mode: 0o700 }); created = true; }
|
|
102
|
+
catch (e) { if (e.code === "EEXIST") fail("supervised-budget-reserved"); throw e; }
|
|
103
|
+
const dirStat = await files.directory(dir); await files.syncDirectory(cfg.root, rootStat);
|
|
104
|
+
await checkpoint("after-directory");
|
|
105
|
+
let chain = [];
|
|
106
|
+
async function append(state, metrics, reasons = []) {
|
|
107
|
+
await root(); await files.directory(dir, dirStat);
|
|
108
|
+
if (chain.length) {
|
|
109
|
+
const current = await readChain(dir, d.identity, dirStat);
|
|
110
|
+
if (!same(current.events, chain)) fail("supervised-reservation-changed");
|
|
111
|
+
} else await files.contents(dir, []);
|
|
112
|
+
const prev = chain.at(-1);
|
|
113
|
+
const e = contract.event({ schemaVersion: "1.0.0", scope: "fixture-only", sequence: chain.length,
|
|
114
|
+
previousSha256: prev ? bytesHash((await files.read(path.join(dir, names[chain.length - 1]), 131072)).bytes) : null,
|
|
115
|
+
identity: d.identity, attemptId: d.attemptId, fixtureId: d.fixtureId, requestSha256: hash(d), limits: d.limits,
|
|
116
|
+
state, observedAt: stamp(), metrics, reasons: [...new Set(reasons)].sort(), fixtureModelCalls: 0,
|
|
117
|
+
actualModelCalls: null, internalCallCeiling: null, remoteCancellationVerified: false });
|
|
118
|
+
if (chain.length >= names.length) fail("supervised-event-limit");
|
|
119
|
+
const resource = await files.exclusive(path.join(dir, names[chain.length]));
|
|
120
|
+
try {
|
|
121
|
+
await files.write(resource, Buffer.from(JSON.stringify(e) + "\n"));
|
|
122
|
+
await checkpoint("after-write-" + state);
|
|
123
|
+
await files.syncDirectory(dir, dirStat); await files.owned(resource);
|
|
124
|
+
} finally { await resource.handle.close(); }
|
|
125
|
+
const read = await readChain(dir, d.identity, dirStat);
|
|
126
|
+
if (!same(read.last, e)) fail("supervised-write-not-confirmed");
|
|
127
|
+
chain = read.events;
|
|
128
|
+
await checkpoint("durable-" + state);
|
|
129
|
+
}
|
|
130
|
+
await append("reserved", zeroMetrics()); r.durability = "confirmed";
|
|
131
|
+
handle = createSupervisedPermit(hash(d), async () => {
|
|
132
|
+
await append("start-claimed", { ...zeroMetrics(), spawnAttempts: 1 });
|
|
133
|
+
}, async () => {
|
|
134
|
+
await append("started", { ...zeroMetrics(), spawnAttempts: 1, mainStartsObserved: 1 });
|
|
135
|
+
});
|
|
136
|
+
await checkpoint("before-consumer");
|
|
137
|
+
const value = contract.processReport(await consumer(handle)); r.value = value;
|
|
138
|
+
revokeSupervisedPermit(handle);
|
|
139
|
+
// An unfinished started write may still be completing. Do not race it by
|
|
140
|
+
// appending a terminal event; keep the reservation for reconciliation.
|
|
141
|
+
if (value.state === "indeterminate") {
|
|
142
|
+
r.state = "reconciliation-required"; r.reasons = ["supervised-reconciliation-required"]; return r;
|
|
143
|
+
}
|
|
144
|
+
const c = await readChain(dir, d.identity, dirStat);
|
|
145
|
+
if (!same(c.events, chain)) fail("supervised-reservation-changed");
|
|
146
|
+
const finalState = value.state === "not-started" ? "failed" : value.state;
|
|
147
|
+
await append(finalState, value.metrics, value.reasons.length ? value.reasons : ["supervised-local-result"]);
|
|
148
|
+
// Only write the receipt after terminal data, directory sync and readback
|
|
149
|
+
// have completed. A partial terminal append alone never proves settlement.
|
|
150
|
+
const terminal = await readChain(dir, d.identity, dirStat);
|
|
151
|
+
const receipt = contract.receipt({ schemaVersion: "1.0.0", scope: "fixture-only", terminalSha256: terminal.bytesHashes.at(-1) });
|
|
152
|
+
const seal = await files.exclusive(path.join(dir, "confirmed.json"));
|
|
153
|
+
try {
|
|
154
|
+
await files.write(seal, Buffer.from(JSON.stringify(receipt) + "\n"));
|
|
155
|
+
await files.syncDirectory(dir, dirStat); await files.owned(seal);
|
|
156
|
+
} finally { await seal.handle.close(); }
|
|
157
|
+
if (!(await readChain(dir, d.identity, dirStat)).receipt) fail("supervised-write-not-confirmed");
|
|
158
|
+
r.state = finalState === "indeterminate" ? "reconciliation-required" : "recorded";
|
|
159
|
+
r.reasons = r.state === "recorded" ? ["supervised-result-recorded"] : ["supervised-reconciliation-required"];
|
|
160
|
+
} catch (e) {
|
|
161
|
+
r.state = created ? "reconciliation-required" : "blocked";
|
|
162
|
+
r.durability = "unconfirmed"; r.reasons = [errorCode(e)];
|
|
163
|
+
} finally { if (handle) revokeSupervisedPermit(handle); }
|
|
164
|
+
return r;
|
|
165
|
+
}
|
|
166
|
+
return Object.freeze({ observe, withReservation });
|
|
167
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { supportsLocalPosix } from "./client-local-platform.js";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { spawn as nativeSpawn } from "node:child_process";
|
|
7
|
+
import { claimSupervisedPermit } from "./client-supervised-permit.js";
|
|
8
|
+
import { createSupervisedProtocol } from "./client-supervised-protocol.js";
|
|
9
|
+
import { createSupervisedContract, hash, monotonicMs, zeroMetrics, errorCode, fail } from "./client-supervised-contract.js";
|
|
10
|
+
|
|
11
|
+
const script = fileURLToPath(new URL("./runtime-fixtures/supervised/fixture.cjs", import.meta.url));
|
|
12
|
+
const childScript = fileURLToPath(new URL("./runtime-fixtures/supervised/child.cjs", import.meta.url));
|
|
13
|
+
|
|
14
|
+
/** Trusted fixture runner, not a native subscription runner. */
|
|
15
|
+
export function createSupervisedSupervisor(schema, dependencies = {}) {
|
|
16
|
+
const contract = createSupervisedContract(schema);
|
|
17
|
+
const spawn = dependencies.spawn ?? nativeSpawn, kill = dependencies.kill ?? process.kill.bind(process);
|
|
18
|
+
const mono = dependencies.monotonic ?? monotonicMs, checkpoint = dependencies.checkpoint ?? (async () => {});
|
|
19
|
+
return async function supervise(handle, input, { signal, beganAt = mono() } = {}) {
|
|
20
|
+
const r = { scope: "fixture-only", state: "not-started", fixtureExecuted: false, nativeExecuted: false,
|
|
21
|
+
runtimeReady: false, verifiedAdmission: false, actualModelCalls: null, fixtureModelCalls: 0,
|
|
22
|
+
internalCallCeiling: null, remoteCancellationVerified: false, metrics: zeroMetrics(),
|
|
23
|
+
exitObserved: false, pipesClosed: false, groupObservation: "not-started", reasons: [] };
|
|
24
|
+
const elapsed = () => Math.max(0, Math.ceil(mono() - beganAt));
|
|
25
|
+
let cwd, owned, spawnReturned = false, attempted = false;
|
|
26
|
+
try {
|
|
27
|
+
const d = contract.request(input), l = d.limits;
|
|
28
|
+
if (!supportsLocalPosix(process.platform)) fail("supervised-platform-not-admitted");
|
|
29
|
+
if (!Number.isFinite(beganAt) || beganAt > mono()) fail("supervised-invalid-deadline");
|
|
30
|
+
const budget = () => {
|
|
31
|
+
if (signal?.aborted) fail("supervised-canceled-before-start");
|
|
32
|
+
if (elapsed() >= l.timeoutMs - l.graceMs - l.confirmationMs) fail("supervised-deadline-before-start");
|
|
33
|
+
};
|
|
34
|
+
budget();
|
|
35
|
+
for (const file of [script, childScript]) {
|
|
36
|
+
const s = await fs.lstat(file);
|
|
37
|
+
if (!s.isFile() || s.isSymbolicLink() || (s.mode & 0o022)) fail("supervised-fixture-source-unsafe");
|
|
38
|
+
}
|
|
39
|
+
const parent = await fs.lstat(path.dirname(script));
|
|
40
|
+
if (!parent.isDirectory() || parent.isSymbolicLink() || (parent.mode & 0o022)) fail("supervised-fixture-directory-unsafe");
|
|
41
|
+
const workspaceParent = dependencies.workspaceParent ?? await fs.realpath(os.tmpdir());
|
|
42
|
+
if (dependencies.workspaceParent !== undefined) {
|
|
43
|
+
const s = await fs.lstat(workspaceParent);
|
|
44
|
+
if (await fs.realpath(workspaceParent) !== workspaceParent || !s.isDirectory() || s.isSymbolicLink() ||
|
|
45
|
+
(s.mode & 0o7777) !== 0o700 || s.uid !== process.getuid()) fail("supervised-workspace-parent-unsafe");
|
|
46
|
+
}
|
|
47
|
+
cwd = await fs.realpath(await fs.mkdtemp(path.join(workspaceParent, "agent-supervised-work-")));
|
|
48
|
+
await fs.chmod(cwd, 0o700); owned = await fs.lstat(cwd);
|
|
49
|
+
budget(); await checkpoint("before-claim");
|
|
50
|
+
const capability = await claimSupervisedPermit(handle, hash(d));
|
|
51
|
+
// Claim consumed the only local start right; no reuse if later checks fail.
|
|
52
|
+
budget(); await checkpoint("before-spawn"); budget();
|
|
53
|
+
r.metrics.spawnAttempts = 1; attempted = true;
|
|
54
|
+
const child = spawn(process.execPath, [script, d.fixtureId], {
|
|
55
|
+
shell: false, detached: true, cwd, env: { LANG: "C", LC_ALL: "C" }, stdio: ["pipe", "pipe", "pipe"]
|
|
56
|
+
});
|
|
57
|
+
spawnReturned = true;
|
|
58
|
+
// Register all lifecycle handlers synchronously, before awaiting storage.
|
|
59
|
+
await new Promise(resolve => {
|
|
60
|
+
const protocol = createSupervisedProtocol(l), stderr = new TextDecoder("utf-8", { fatal: true });
|
|
61
|
+
let done = false, spawned = false, spawnFailed = false, canceled = false, cancelAt = null, forced = false;
|
|
62
|
+
let groupGone = false, startedWritePending = false, startedWriteFailed = false;
|
|
63
|
+
let stdinClosed = false, stdoutClosed = false, stderrClosed = false, closed = false, exitCode = null;
|
|
64
|
+
let timer, hardTimer;
|
|
65
|
+
const add = c => { if (!r.reasons.includes(c)) r.reasons.push(c); };
|
|
66
|
+
const groupAlive = () => {
|
|
67
|
+
if (groupGone || spawnFailed) return false;
|
|
68
|
+
if (!spawned) return true;
|
|
69
|
+
try { kill(-child.pid, 0); return true; }
|
|
70
|
+
catch (e) { if (e?.code === "ESRCH") { groupGone = true; return false; } add("supervised-group-unconfirmed"); return true; }
|
|
71
|
+
};
|
|
72
|
+
const send = sig => {
|
|
73
|
+
if (!spawned || groupGone) return;
|
|
74
|
+
try { kill(-child.pid, sig); }
|
|
75
|
+
catch (e) { if (e?.code === "ESRCH") groupGone = true; else add("supervised-signal-unconfirmed"); }
|
|
76
|
+
};
|
|
77
|
+
const cancel = (code, state = "failed") => {
|
|
78
|
+
if (done) return; add(code);
|
|
79
|
+
if (canceled) return;
|
|
80
|
+
canceled = true; cancelAt = mono(); r.state = state;
|
|
81
|
+
child.stdin.destroy(); send("SIGTERM");
|
|
82
|
+
};
|
|
83
|
+
const finish = uncertain => {
|
|
84
|
+
if (done) return; done = true;
|
|
85
|
+
clearInterval(timer); clearTimeout(hardTimer); signal?.removeEventListener("abort", abort);
|
|
86
|
+
const counts = protocol.counts();
|
|
87
|
+
Object.assign(r.metrics, { stdoutBytes: counts.stdoutBytes, events: counts.events, elapsedMs: elapsed() });
|
|
88
|
+
r.pipesClosed = stdinClosed && stdoutClosed && stderrClosed && closed;
|
|
89
|
+
r.groupObservation = spawnFailed ? "not-started" : groupGone ? "absent" : "unconfirmed";
|
|
90
|
+
r.metrics.terminationConfirmed = spawnFailed || r.exitObserved && r.pipesClosed && groupGone;
|
|
91
|
+
if (uncertain || startedWriteFailed || r.metrics.elapsedMs > l.timeoutMs) {
|
|
92
|
+
r.state = "indeterminate"; add("supervised-reconciliation-required");
|
|
93
|
+
} else if (spawnFailed) { r.state = "not-started"; }
|
|
94
|
+
else if (!canceled && r.state !== "failed") r.state = "completed-for-review";
|
|
95
|
+
if (!r.reasons.length) add("supervised-fixture-completed");
|
|
96
|
+
child.stdin.destroy(); child.stdout.destroy(); child.stderr.destroy(); resolve();
|
|
97
|
+
};
|
|
98
|
+
const poll = () => {
|
|
99
|
+
if (done) return;
|
|
100
|
+
if (elapsed() >= l.timeoutMs - l.graceMs - l.confirmationMs && !canceled) cancel("supervised-deadline", "timed-out");
|
|
101
|
+
if (canceled && !forced && mono() - cancelAt >= l.graceMs) { forced = true; send("SIGKILL"); }
|
|
102
|
+
const alive = groupAlive();
|
|
103
|
+
if (r.exitObserved && closed && stdinClosed && stdoutClosed && stderrClosed && !startedWritePending && !alive) {
|
|
104
|
+
if (!canceled && !spawnFailed) {
|
|
105
|
+
try { if (exitCode !== 0) fail("supervised-exit-failed"); protocol.finish(); stderr.decode(); }
|
|
106
|
+
catch (e) { r.state = "failed"; add(errorCode(e)); }
|
|
107
|
+
}
|
|
108
|
+
finish(false);
|
|
109
|
+
} else if (r.exitObserved && alive && !canceled) cancel("supervised-descendants-live");
|
|
110
|
+
if (spawnFailed && closed) finish(false);
|
|
111
|
+
};
|
|
112
|
+
const abort = () => cancel("supervised-canceled", "canceled");
|
|
113
|
+
child.on("spawn", () => {
|
|
114
|
+
spawned = true;
|
|
115
|
+
if (done) { send("SIGKILL"); return; }
|
|
116
|
+
r.fixtureExecuted = true; r.metrics.mainStartsObserved = 1; startedWritePending = true;
|
|
117
|
+
if (canceled) send("SIGTERM");
|
|
118
|
+
Promise.resolve().then(() => checkpoint("spawn-observed")).then(() => capability.started())
|
|
119
|
+
.catch(() => { startedWriteFailed = true; cancel("supervised-start-record-unconfirmed"); })
|
|
120
|
+
.finally(() => { startedWritePending = false; poll(); });
|
|
121
|
+
});
|
|
122
|
+
child.on("error", () => { if (done) return; if (!spawned) { spawnFailed = true; add("supervised-spawn-failed"); } else cancel("supervised-process-error"); });
|
|
123
|
+
child.on("exit", code => { if (done) return; r.exitObserved = true; exitCode = code; poll(); });
|
|
124
|
+
child.on("close", () => { closed = true; poll(); });
|
|
125
|
+
child.stdin.on("close", () => { stdinClosed = true; poll(); });
|
|
126
|
+
child.stdout.on("close", () => { stdoutClosed = true; poll(); });
|
|
127
|
+
child.stderr.on("close", () => { stderrClosed = true; poll(); });
|
|
128
|
+
for (const [stream, name] of [[child.stdin, "stdin"], [child.stdout, "stdout"], [child.stderr, "stderr"]]) {
|
|
129
|
+
stream.on("error", () => cancel("supervised-" + name + "-error"));
|
|
130
|
+
}
|
|
131
|
+
child.stdout.on("data", chunk => {
|
|
132
|
+
if (done || canceled) return;
|
|
133
|
+
try { protocol.push(chunk); } catch (e) { cancel(errorCode(e)); }
|
|
134
|
+
});
|
|
135
|
+
child.stderr.on("data", chunk => {
|
|
136
|
+
if (done || canceled) return;
|
|
137
|
+
r.metrics.stderrBytes += chunk.length;
|
|
138
|
+
if (r.metrics.stderrBytes > l.maxStderrBytes) cancel("supervised-stderr-limit");
|
|
139
|
+
else try { stderr.decode(chunk, { stream: true }); } catch { cancel("supervised-stderr-invalid-utf8"); }
|
|
140
|
+
});
|
|
141
|
+
signal?.addEventListener("abort", abort, { once: true }); if (signal?.aborted) abort();
|
|
142
|
+
timer = setInterval(poll, 10);
|
|
143
|
+
hardTimer = setTimeout(() => { send("SIGKILL"); poll(); if (!done) finish(true); }, Math.max(1, l.timeoutMs - elapsed()));
|
|
144
|
+
try { child.stdin.end(d.inputText, e => { if (e) cancel("supervised-stdin-error"); }); }
|
|
145
|
+
catch { cancel("supervised-stdin-error"); }
|
|
146
|
+
});
|
|
147
|
+
} catch (e) {
|
|
148
|
+
r.reasons = [errorCode(e)]; r.metrics.elapsedMs = elapsed();
|
|
149
|
+
r.metrics.terminationConfirmed = !spawnReturned;
|
|
150
|
+
if (spawnReturned) r.state = "indeterminate";
|
|
151
|
+
else if (e?.code === "supervised-canceled-before-start") r.state = "canceled";
|
|
152
|
+
else if (e?.code === "supervised-deadline-before-start") r.state = "timed-out";
|
|
153
|
+
// attempted is distinct from a returned ChildProcess and a spawn event.
|
|
154
|
+
if (attempted) r.metrics.spawnAttempts = 1;
|
|
155
|
+
} finally {
|
|
156
|
+
if (cwd && (!spawnReturned || r.metrics.terminationConfirmed)) {
|
|
157
|
+
try {
|
|
158
|
+
const s = await fs.lstat(cwd);
|
|
159
|
+
if (s.dev !== owned.dev || s.ino !== owned.ino || !s.isDirectory() || s.isSymbolicLink()) throw Error("changed");
|
|
160
|
+
await fs.rmdir(cwd);
|
|
161
|
+
} catch { r.state = "indeterminate"; r.reasons.push("supervised-workspace-cleanup-required"); }
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
r.reasons = [...new Set(r.reasons)].sort();
|
|
165
|
+
return contract.processReport(r);
|
|
166
|
+
};
|
|
167
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import Ajv2020 from "ajv/dist/2020.js";
|
|
2
|
+
import { copyInertJson, copyBytes, decode, parseEventJson, ParseFailure, fail } from "./client-output-json.js";
|
|
3
|
+
import { CONTROLS, EFFECTS, hash, same, unique, fresh } from "./client-runtime-core.js";
|
|
4
|
+
|
|
5
|
+
const SCHEMA_ID = "https://agent-toolkit.local/schemas/agent-client-supervised.schema.json";
|
|
6
|
+
const MAX_INPUT_BYTES = 131072;
|
|
7
|
+
const REQUIRED_CONTROLS = CONTROLS.filter(id => id !== "internal-call-limit");
|
|
8
|
+
const SECTIONS = ["selection", "binding", "expectedBinding", "limits", "context", "authorization", "limitations", "history", "installation", "controls", "effects", "access", "observations"];
|
|
9
|
+
const GATES = ["trusted-authorization-and-limitations", "native-installation-and-controls", "subscription-and-billing", "selection-and-private-context", "supervised-history-and-durable-reservation", "local-supervision-and-termination", "human-result-review"];
|
|
10
|
+
|
|
11
|
+
function declarationScope(data, policySha256) {
|
|
12
|
+
const summary = value => {
|
|
13
|
+
if (!value) return null;
|
|
14
|
+
const { assessment, billingAssessment, ...declaration } = value;
|
|
15
|
+
return declaration;
|
|
16
|
+
};
|
|
17
|
+
const ordered = (items, key) => (items ?? []).map(summary).sort((a, b) => a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : 0);
|
|
18
|
+
const authorization = summary(data.authorization);
|
|
19
|
+
if (authorization) authorization.effectsApproved = [...authorization.effectsApproved].sort();
|
|
20
|
+
return hash({ profile: data.profile, intentId: data.intentId, identity: data.identity,
|
|
21
|
+
selection: summary(data.selection), binding: data.binding ?? null, expectedBinding: data.expectedBinding ?? null,
|
|
22
|
+
limits: data.limits ?? null, context: summary(data.context), authorization,
|
|
23
|
+
limitations: summary(data.limitations), history: summary(data.history), access: summary(data.access),
|
|
24
|
+
controls: ordered(data.controls, "controlId"), effects: ordered(data.effects, "effectId"),
|
|
25
|
+
observations: [...(data.observations ?? [])].sort(), policySha256 });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// A separate pure review of declarations. This is not a C1 admission or a launcher.
|
|
29
|
+
export function createClientSupervisedEvaluator(schema, trustedPolicy) {
|
|
30
|
+
let contract; let policy;
|
|
31
|
+
try { contract = copyInertJson(schema); policy = copyInertJson(trustedPolicy); }
|
|
32
|
+
catch { throw Error("Invalid supervised evaluation configuration"); }
|
|
33
|
+
if (contract?.$id !== SCHEMA_ID) throw Error("Unsupported supervised evaluation schema");
|
|
34
|
+
const ajv = new Ajv2020({ strict: true, allErrors: true });
|
|
35
|
+
ajv.addFormat("date-time", { type: "string", validate: value => {
|
|
36
|
+
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/.test(value)) return false;
|
|
37
|
+
const time = Date.parse(value);
|
|
38
|
+
return Number.isFinite(time) && new Date(time).toISOString() === value.replace(/Z$/, ".000Z");
|
|
39
|
+
} });
|
|
40
|
+
ajv.addSchema(contract);
|
|
41
|
+
const validator = name => ajv.compile({ $ref: `${SCHEMA_ID}#/$defs/${name}` });
|
|
42
|
+
const validInput = validator("input"), validPolicy = validator("policy"), validReport = validator("report");
|
|
43
|
+
if (!validPolicy(policy) || policy.limits.terminationGraceSeconds >= policy.limits.timeoutSeconds ||
|
|
44
|
+
policy.limits.maxEventBytes > policy.limits.maxStdoutBytes) throw Error("Invalid supervised evaluation policy");
|
|
45
|
+
const revoked = new Set(policy.revokedEvidenceRefs), policySha256 = hash(policy);
|
|
46
|
+
|
|
47
|
+
return function evaluateSupervisedIntent(input) {
|
|
48
|
+
const report = { schemaVersion: "1.0.0", profile: "supervised-subscription", intentId: null, state: "invalid",
|
|
49
|
+
executed: false, runtimeReady: false, verifiedAdmission: false, externalBillingVerified: false,
|
|
50
|
+
selectionVerified: false, internalCallCeiling: null, remoteCancellationVerified: false,
|
|
51
|
+
reasons: [], missing: [], externalGates: [...GATES], audit: { inputSha256: null, scopeSha256: null, policySha256 } };
|
|
52
|
+
const blockers = new Set(), missing = new Set();
|
|
53
|
+
const block = reason => blockers.add(reason);
|
|
54
|
+
function finish(state, reasons = []) {
|
|
55
|
+
report.state = state; report.reasons = [...new Set(reasons)].sort(); report.missing = [...missing].sort();
|
|
56
|
+
if (!validReport(report)) throw Error("Supervised evaluation report invariant failed");
|
|
57
|
+
return report;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
const parsed = typeof input === "string" || (input && typeof input === "object" && ArrayBuffer.isView(input))
|
|
61
|
+
? parseEventJson(decode(copyBytes(input, MAX_INPUT_BYTES))) : input;
|
|
62
|
+
const data = copyInertJson(parsed);
|
|
63
|
+
const serialized = JSON.stringify(data);
|
|
64
|
+
parseEventJson(decode(copyBytes(serialized, MAX_INPUT_BYTES))); // Validate Unicode in copied object strings too.
|
|
65
|
+
if (!validInput(data)) fail("invalid-supervised-input");
|
|
66
|
+
if (data.controls && !unique(data.controls.map(c => c.controlId))) fail("duplicate-supervised-control");
|
|
67
|
+
if (data.effects && !unique(data.effects.map(e => e.effectId))) fail("duplicate-supervised-effect");
|
|
68
|
+
report.intentId = data.intentId; report.audit.inputSha256 = hash(data);
|
|
69
|
+
for (const section of SECTIONS) if (data[section] === undefined) missing.add(section);
|
|
70
|
+
|
|
71
|
+
// Evidence is bound to the whole intent, not just an installation or a task name.
|
|
72
|
+
const { assessment: selectionAssessment, ...selection } = data.selection ?? {};
|
|
73
|
+
const { assessment: contextAssessment, ...context } = data.context ?? {};
|
|
74
|
+
const scope = declarationScope(data, policySha256);
|
|
75
|
+
report.audit.scopeSha256 = scope;
|
|
76
|
+
function reference(id, label) {
|
|
77
|
+
if (id === null) missing.add(`${label}.reference`);
|
|
78
|
+
else if (revoked.has(id)) block(`supervised-reference-revoked:${label}`);
|
|
79
|
+
}
|
|
80
|
+
function assess(a, label, sources) {
|
|
81
|
+
if (!a) return;
|
|
82
|
+
reference(a.evidenceRef, label);
|
|
83
|
+
if (a.scopeSha256 !== scope) block(`supervised-scope-mismatch:${label}`);
|
|
84
|
+
if (!fresh(a, data.now, policy.maxEvidenceAgeSeconds)) block(`supervised-evidence-not-fresh:${label}`);
|
|
85
|
+
if (a.status === "rejected") block(`supervised-evidence-rejected:${label}`);
|
|
86
|
+
else if (a.status !== "confirmed") missing.add(`${label}.confirmation`);
|
|
87
|
+
else if (!sources.includes(a.source)) block(`supervised-source-conflict:${label}`);
|
|
88
|
+
}
|
|
89
|
+
const human = ["operator-attestation"], test = ["installation-test"], attested = [...human, ...test];
|
|
90
|
+
if (data.binding && data.expectedBinding && !same(data.binding, data.expectedBinding)) block("supervised-binding-mismatch");
|
|
91
|
+
if (data.selection) {
|
|
92
|
+
assess(selectionAssessment, "selection", attested);
|
|
93
|
+
if (["latest", "default", "opus", "sonnet", "haiku", "fable"].includes(selection.model) || selection.model.split("-").includes("latest")) block("supervised-model-not-pinned");
|
|
94
|
+
if (data.binding && (selection.client !== data.binding.client || selection.provider !== data.binding.provider)) block("supervised-selection-binding-mismatch");
|
|
95
|
+
if (selection.source === "operator-choice" && selectionAssessment.source !== "operator-attestation") block("supervised-selection-source-conflict");
|
|
96
|
+
}
|
|
97
|
+
if (data.limits) {
|
|
98
|
+
for (const key of Object.keys(policy.limits)) if (data.limits[key] > policy.limits[key]) block("supervised-limits-exceed-policy");
|
|
99
|
+
if (data.limits.terminationGraceSeconds >= data.limits.timeoutSeconds) block("supervised-grace-outside-deadline");
|
|
100
|
+
if (data.limits.maxEventBytes > data.limits.maxStdoutBytes) block("supervised-event-limit-inconsistent");
|
|
101
|
+
}
|
|
102
|
+
if (data.context) {
|
|
103
|
+
assess(contextAssessment, "context", attested);
|
|
104
|
+
if (data.limits && context.inputBytes > data.limits.maxInputBytes) block("supervised-context-exceeds-budget");
|
|
105
|
+
}
|
|
106
|
+
if (data.authorization) {
|
|
107
|
+
const a = data.authorization;
|
|
108
|
+
assess(a.assessment, "authorization", human);
|
|
109
|
+
if (a.status !== "approved") block("supervised-authorization-not-approved");
|
|
110
|
+
if (data.limits && !same(a.limits, data.limits)) block("supervised-authorization-limits-mismatch");
|
|
111
|
+
if (data.identity.mode === "tutor" && a.writer !== "user") block("supervised-tutor-authority-conflict");
|
|
112
|
+
}
|
|
113
|
+
if (data.identity.role === "tutor" && data.identity.mode !== "tutor") block("supervised-tutor-mode-conflict");
|
|
114
|
+
if (data.limitations) {
|
|
115
|
+
assess(data.limitations.assessment, "limitations", human);
|
|
116
|
+
if (!data.limitations.internalCallsUnknownAccepted || !data.limitations.remoteCancellationUnknownAccepted) block("supervised-limitations-not-accepted");
|
|
117
|
+
}
|
|
118
|
+
if (data.history) {
|
|
119
|
+
const h = data.history;
|
|
120
|
+
assess(h.assessment, "history", attested);
|
|
121
|
+
if (h.projectId !== data.identity.projectId || h.taskId !== data.identity.taskId) block("supervised-history-identity-mismatch");
|
|
122
|
+
if (h.state !== "clear") block("supervised-history-reconciliation-required");
|
|
123
|
+
if (h.mainStartsUsed === 0 && (h.durationUsedSeconds > 0 || (h.actualModelCalls !== null && h.actualModelCalls > 0))) block("supervised-history-counters-inconsistent");
|
|
124
|
+
if (data.limits && (h.mainStartsUsed >= data.limits.maxMainStarts || h.durationUsedSeconds >= data.limits.timeoutSeconds)) block("supervised-budget-exhausted");
|
|
125
|
+
if (h.mainStartsUsed > 0 && h.actualModelCalls === null) block("supervised-prior-consumption-unresolved");
|
|
126
|
+
}
|
|
127
|
+
if (data.installation) assess(data.installation.assessment, "installation", test);
|
|
128
|
+
for (const id of REQUIRED_CONTROLS) {
|
|
129
|
+
const c = data.controls?.find(c => c.controlId === id), label = `controls.${id}`;
|
|
130
|
+
if (!c) { missing.add(label); continue; }
|
|
131
|
+
assess(c.assessment, label, test);
|
|
132
|
+
for (const key of ["mechanismId", "positiveEvidenceRef", "negativeEvidenceRef"]) {
|
|
133
|
+
if (c[key] === null) missing.add(`${label}.${key.toLowerCase()}`);
|
|
134
|
+
else if (key !== "mechanismId") reference(c[key], `${label}.${key.toLowerCase()}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
for (const id of EFFECTS) {
|
|
138
|
+
const e = data.effects?.find(e => e.effectId === id), label = `effects.${id}`;
|
|
139
|
+
if (!e) { missing.add(label); continue; }
|
|
140
|
+
assess(e.assessment, label, test);
|
|
141
|
+
if (e.presence === "unknown" || e.disposition !== "allowed") block(`supervised-effect-unconfirmed:${id}`);
|
|
142
|
+
if (["native-auth", "provider-inference"].includes(id) && e.presence === "absent") block(`supervised-required-effect-absent:${id}`);
|
|
143
|
+
if (e.presence === "present" && !data.authorization?.effectsApproved.includes(id)) block(`supervised-effect-not-authorized:${id}`);
|
|
144
|
+
}
|
|
145
|
+
if (data.access) {
|
|
146
|
+
assess(data.access.assessment, "access", attested);
|
|
147
|
+
assess(data.access.billingAssessment, "billing", attested);
|
|
148
|
+
if (data.access.method !== "subscription-session") block("supervised-subscription-required");
|
|
149
|
+
if (data.access.externalBilling !== "disabled") block("supervised-external-billing-not-disabled");
|
|
150
|
+
}
|
|
151
|
+
for (const code of data.observations ?? []) block(`supervised-unresolved:${code}`);
|
|
152
|
+
if (blockers.size) return finish("blocked", [...blockers]);
|
|
153
|
+
if (missing.size) return finish("incomplete", ["supervised-declarations-incomplete"]);
|
|
154
|
+
return finish("ready-for-supervised-review", ["supervised-declarations-only"]);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
if (!(error instanceof ParseFailure)) throw error;
|
|
157
|
+
return finish("invalid", [error.code]);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|