@thebackstoryis/engineering-with-ai 0.2.9
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/Docs/README.md +50 -0
- package/Docs/adoption/consultancy-and-multi-project-rollout.md +135 -0
- package/Docs/adoption/non-technical-team-guide.md +126 -0
- package/Docs/archaeology-technology-and-hosting-discovery.md +212 -0
- package/Docs/blast-radius-and-impact-routing-guide.md +325 -0
- package/Docs/blueprints/internal-blueprint-catalogue.md +146 -0
- package/Docs/blueprints/maintaining-organisation-blueprints.md +154 -0
- package/Docs/blueprints/validation-and-troubleshooting.md +168 -0
- package/Docs/cli-reference.md +113 -0
- package/Docs/completed-phase-evidence-amendments.md +74 -0
- package/Docs/consultancy-network-rollout-control-plane-guide.md +202 -0
- package/Docs/context-aware-delivery-companion-guide.md +198 -0
- package/Docs/context-aware-delivery-companion-user-guide.md +184 -0
- package/Docs/context-management-and-token-efficiency.md +113 -0
- package/Docs/design-systems/design-system-implementation-guide.md +85 -0
- package/Docs/design-systems/design-system-pack-authoring-guide.md +95 -0
- package/Docs/design-systems/design-system-review-guide.md +51 -0
- package/Docs/design-systems/design-system-user-guide.md +96 -0
- package/Docs/design-systems/product-owner-guide.md +49 -0
- package/Docs/designing-organisation-blueprint-packs.md +384 -0
- package/Docs/developer-delivery-guide.md +224 -0
- package/Docs/error-reporting-guide.md +110 -0
- package/Docs/error-reporting-provider-guide.md +49 -0
- package/Docs/examples/error-report-adapter.md +70 -0
- package/Docs/examples/meeting-review.md +76 -0
- package/Docs/examples/minimal-design-system.md +67 -0
- package/Docs/examples/prototype-review-inputs.md +175 -0
- package/Docs/examples/reproducible-archaeology-depth-example.md +144 -0
- package/Docs/examples/test-scenario-input.md +68 -0
- package/Docs/examples/worked-examples.md +147 -0
- package/Docs/existing-project-onboarding-guide.md +214 -0
- package/Docs/explanation/core-concepts.md +26 -0
- package/Docs/explanation/delivery-workflow.md +48 -0
- package/Docs/governance/governance-team-guide.md +139 -0
- package/Docs/governed-starter-project-materialisation-guide.md +284 -0
- package/Docs/guide-catalogue.md +117 -0
- package/Docs/guided-discovery-facilitator-guide.md +172 -0
- package/Docs/guided-intent-workspace-guide.md +109 -0
- package/Docs/guided-phase-evidence-drafting-guide.md +119 -0
- package/Docs/human-approval-and-assurance-guide.md +146 -0
- package/Docs/knowledge-proposals-implementer-guide.md +106 -0
- package/Docs/knowledge-proposals-user-guide.md +247 -0
- package/Docs/maintainers/context-benchmarks.md +29 -0
- package/Docs/maintainers/contributing.md +58 -0
- package/Docs/maintainers/evidence-depth-acceptance.md +72 -0
- package/Docs/maintainers/verification-walkthroughs.md +104 -0
- package/Docs/meeting-evidence-implementer-guide.md +132 -0
- package/Docs/meeting-evidence-user-guide.md +200 -0
- package/Docs/operations/dashboard-and-delivery-state.md +153 -0
- package/Docs/operations/dashboard-configuration.md +87 -0
- package/Docs/operations/installation-updating-and-entitlements.md +135 -0
- package/Docs/operations/premium-personas-setup.md +76 -0
- package/Docs/operations/troubleshooting-and-recovery.md +205 -0
- package/Docs/organisation-rollout-guide.md +142 -0
- package/Docs/persona-entitlement-provider-guide.md +199 -0
- package/Docs/persona-guided-prototype-iteration.md +129 -0
- package/Docs/personas/organisation-specific-personas.md +103 -0
- package/Docs/personas/persona-authoring-cookbook.md +176 -0
- package/Docs/personas/persona-engagement-ui.md +133 -0
- package/Docs/personas/persona-governance.md +118 -0
- package/Docs/platform-export-analysis-guide.md +336 -0
- package/Docs/policies/governance-owner-guide.md +36 -0
- package/Docs/policies/implementation-guide.md +42 -0
- package/Docs/policies/organisation-policy-design-gates.md +58 -0
- package/Docs/policies/policy-pack-authoring-guide.md +108 -0
- package/Docs/policies/product-owner-guide.md +43 -0
- package/Docs/policies/technical-owner-guide.md +37 -0
- package/Docs/product-owner-guide.md +327 -0
- package/Docs/project-portfolio-orchestration-guide.md +199 -0
- package/Docs/quality/manual-qa-and-acceptance.md +162 -0
- package/Docs/quality/persona-driven-test-scenarios.md +172 -0
- package/Docs/quality/reproducible-archaeology-depth-review-checklist.md +89 -0
- package/Docs/reference/capabilities-and-project-layout.md +678 -0
- package/Docs/reference/cli-and-configuration.md +398 -0
- package/Docs/reference/contributions-api.md +23 -0
- package/Docs/reference/security-adapter-authoring.md +81 -0
- package/Docs/reference/starter-adapter-authoring.md +74 -0
- package/Docs/repository-source-map-guide.md +381 -0
- package/Docs/reproducible-archaeology-and-discovery-depth.md +292 -0
- package/Docs/screen-prototype-creation-guide.md +324 -0
- package/Docs/security-validation-guide.md +353 -0
- package/Docs/solution-readiness-review-guide.md +123 -0
- package/Docs/standards/project-standards-authoring.md +157 -0
- package/Docs/team-hub-guide.md +162 -0
- package/Docs/team-hub-resource-registry-guide.md +167 -0
- package/Docs/tutorials/first-delivery.md +83 -0
- package/Docs/tutorials/first-session.md +62 -0
- package/Docs/using-lifecycle-hooks.md +381 -0
- package/Docs/working-with-personas.md +274 -0
- package/LICENSE +165 -0
- package/README.md +96 -0
- package/agents-src/claude/ewai-security-reviewer.md +15 -0
- package/bin/ewai +5 -0
- package/config/archaeology-record-families.yaml +59 -0
- package/config/delivery-artifacts.yaml +121 -0
- package/config/delivery-stages.yaml +77 -0
- package/config/design-system.schema.json +46 -0
- package/config/error-reporting.schema.json +79 -0
- package/config/evidence-depth.schema.json +53 -0
- package/config/intent.schema.json +90 -0
- package/config/knowledge-proposals-proposal.schema.json +34 -0
- package/config/lifecycle-event.schema.json +68 -0
- package/config/lifecycle-handler.schema.json +45 -0
- package/config/lifecycle-hook-ack.schema.json +19 -0
- package/config/meeting-evidence-candidate.schema.json +102 -0
- package/config/organisation-policy.schema.json +137 -0
- package/config/pack.schema.json +250 -0
- package/config/persona-pack.schema.json +21 -0
- package/config/persona.schema.json +17 -0
- package/config/policy-evaluation.schema.json +77 -0
- package/config/policy-facts.schema.json +140 -0
- package/config/portfolio.schema.json +68 -0
- package/config/project.schema.json +313 -0
- package/config/prototype-iteration.schema.json +128 -0
- package/config/rollout.schema.json +87 -0
- package/config/security-adapter.schema.json +31 -0
- package/config/security-scan-request.schema.json +64 -0
- package/config/security-scan-response.schema.json +52 -0
- package/config/security-validation-policy.schema.json +74 -0
- package/config/starter-source-acknowledgement.schema.json +13 -0
- package/config/starter-source-adapter.schema.json +38 -0
- package/config/starter-source-request.schema.json +61 -0
- package/package.json +77 -0
- package/packs/core/pack.yaml +7 -0
- package/packs/design-systems/default/experience-promise.md +9 -0
- package/packs/design-systems/default/intentional-review.md +10 -0
- package/packs/design-systems/default/interaction-and-entry.md +9 -0
- package/packs/design-systems/default/meaningful-content-and-states.md +9 -0
- package/packs/design-systems/default/pack.yaml +44 -0
- package/packs/design-systems/default/principles.md +10 -0
- package/packs/personas/core/pack.yaml +7 -0
- package/packs/personas/core/personas/archaeologist.md +37 -0
- package/packs/personas/core/personas/end-user.md +17 -0
- package/packs/personas/core/personas/maintainer.md +17 -0
- package/packs/personas/core/personas/operator.md +17 -0
- package/packs/personas/core/personas/specs-knowledge-curator.md +35 -0
- package/packs/technologies/laravel/pack.yaml +30 -0
- package/packs/technologies/laravel-nuxt/pack.yaml +30 -0
- package/packs/technologies/nuxt/pack.yaml +30 -0
- package/packs/technologies/power-platform/pack.yaml +31 -0
- package/packs/technologies/salesforce/pack.yaml +25 -0
- package/public/app.js +4896 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/assets/backstory-icon.png +0 -0
- package/public/dashboard-navigation.js +98 -0
- package/public/favicon-16.png +0 -0
- package/public/favicon-32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +789 -0
- package/public/styles.css +2693 -0
- package/public/team-hub/app.js +202 -0
- package/public/team-hub/index.html +79 -0
- package/public/team-hub/styles.css +90 -0
- package/scripts/publication-check.mjs +140 -0
- package/scripts/setup.mjs +21 -0
- package/skills-src/ewai-archaeology/SKILL.md +334 -0
- package/skills-src/ewai-archaeology/agents/openai.yaml +4 -0
- package/skills-src/ewai-archaeology/references/archaeology-contract.md +201 -0
- package/skills-src/ewai-archaeology/references/lifecycle-reconstruction.md +177 -0
- package/skills-src/ewai-archaeology/references/maximum-detail-reconstruction.md +97 -0
- package/skills-src/ewai-archaeology/references/model-routing.md +26 -0
- package/skills-src/ewai-architecture/SKILL.md +108 -0
- package/skills-src/ewai-architecture/agents/openai.yaml +4 -0
- package/skills-src/ewai-architecture/references/architecture-contract.md +176 -0
- package/skills-src/ewai-context/SKILL.md +68 -0
- package/skills-src/ewai-context/agents/openai.yaml +4 -0
- package/skills-src/ewai-context-import/SKILL.md +118 -0
- package/skills-src/ewai-context-import/agents/openai.yaml +4 -0
- package/skills-src/ewai-context-import/references/context-import-contract.md +106 -0
- package/skills-src/ewai-dashboard-configuration/SKILL.md +20 -0
- package/skills-src/ewai-deliver/SKILL.md +122 -0
- package/skills-src/ewai-deliver/references/delivery-evidence.md +92 -0
- package/skills-src/ewai-deliver/references/phase-routing.md +31 -0
- package/skills-src/ewai-design-system-apply/SKILL.md +27 -0
- package/skills-src/ewai-design-system-apply/agents/openai.yaml +4 -0
- package/skills-src/ewai-design-system-apply/references/application-contract.md +36 -0
- package/skills-src/ewai-design-system-author/SKILL.md +28 -0
- package/skills-src/ewai-design-system-author/agents/openai.yaml +4 -0
- package/skills-src/ewai-design-system-author/references/authoring-contract.md +38 -0
- package/skills-src/ewai-design-system-review/SKILL.md +26 -0
- package/skills-src/ewai-design-system-review/agents/openai.yaml +4 -0
- package/skills-src/ewai-design-system-review/references/review-contract.md +40 -0
- package/skills-src/ewai-error-reporting/SKILL.md +46 -0
- package/skills-src/ewai-error-reporting/agents/openai.yaml +4 -0
- package/skills-src/ewai-error-reporting/references/provider-contract.md +74 -0
- package/skills-src/ewai-evidence-depth/SKILL.md +72 -0
- package/skills-src/ewai-evidence-depth/agents/openai.yaml +4 -0
- package/skills-src/ewai-evidence-depth/references/evidence-depth-contract.md +127 -0
- package/skills-src/ewai-intent/SKILL.md +68 -0
- package/skills-src/ewai-intent/agents/openai.yaml +4 -0
- package/skills-src/ewai-intent/references/intent-contract.md +42 -0
- package/skills-src/ewai-knowledge-proposals/SKILL.md +105 -0
- package/skills-src/ewai-knowledge-proposals/agents/openai.yaml +4 -0
- package/skills-src/ewai-knowledge-proposals/references/proposal-contract.md +59 -0
- package/skills-src/ewai-meeting-evidence/SKILL.md +106 -0
- package/skills-src/ewai-meeting-evidence/agents/openai.yaml +4 -0
- package/skills-src/ewai-meeting-evidence/references/candidate-contract.md +64 -0
- package/skills-src/ewai-organisation-policy/SKILL.md +62 -0
- package/skills-src/ewai-organisation-policy/agents/openai.yaml +4 -0
- package/skills-src/ewai-organisation-policy/references/policy-contract.md +94 -0
- package/skills-src/ewai-palace-housekeeping/SKILL.md +55 -0
- package/skills-src/ewai-palace-housekeeping/agents/openai.yaml +4 -0
- package/skills-src/ewai-persona-entitlement/SKILL.md +60 -0
- package/skills-src/ewai-persona-entitlement/agents/openai.yaml +4 -0
- package/skills-src/ewai-phase-evidence/SKILL.md +79 -0
- package/skills-src/ewai-phase-evidence/agents/openai.yaml +4 -0
- package/skills-src/ewai-pipeline/SKILL.md +130 -0
- package/skills-src/ewai-pipeline/agents/openai.yaml +4 -0
- package/skills-src/ewai-pipeline/references/cli.md +86 -0
- package/skills-src/ewai-pipeline/references/specs-contract.md +16 -0
- package/skills-src/ewai-portfolio/SKILL.md +70 -0
- package/skills-src/ewai-portfolio/agents/openai.yaml +4 -0
- package/skills-src/ewai-portfolio/references/portfolio-contract.md +67 -0
- package/skills-src/ewai-project-discovery/SKILL.md +95 -0
- package/skills-src/ewai-project-discovery/agents/openai.yaml +4 -0
- package/skills-src/ewai-project-discovery/references/discovery-contract.md +34 -0
- package/skills-src/ewai-prototype-iteration/SKILL.md +30 -0
- package/skills-src/ewai-prototype-iteration/agents/openai.yaml +4 -0
- package/skills-src/ewai-prototype-iteration/references/review-contract.md +49 -0
- package/skills-src/ewai-retro/SKILL.md +48 -0
- package/skills-src/ewai-retro/agents/openai.yaml +4 -0
- package/skills-src/ewai-retro/references/asset-routing.md +14 -0
- package/skills-src/ewai-rollout/SKILL.md +74 -0
- package/skills-src/ewai-rollout/agents/openai.yaml +4 -0
- package/skills-src/ewai-rollout/references/rollout-contract.md +74 -0
- package/skills-src/ewai-shape-intents/SKILL.md +84 -0
- package/skills-src/ewai-shape-intents/agents/openai.yaml +4 -0
- package/skills-src/ewai-shape-intents/references/intent-mapping-contract.md +109 -0
- package/skills-src/ewai-solution-readiness/SKILL.md +55 -0
- package/skills-src/ewai-solution-readiness/agents/openai.yaml +4 -0
- package/skills-src/ewai-standards-check/SKILL.md +93 -0
- package/skills-src/ewai-standards-check/agents/openai.yaml +4 -0
- package/skills-src/ewai-standards-check/references/report-contract.md +116 -0
- package/skills-src/ewai-test-scenarios/SKILL.md +94 -0
- package/skills-src/ewai-test-scenarios/agents/openai.yaml +4 -0
- package/skills-src/ewai-test-scenarios/references/scenario-contract.md +88 -0
- package/src/afk-worker.mjs +16 -0
- package/src/archaeology.mjs +1333 -0
- package/src/checkin.mjs +261 -0
- package/src/cli.mjs +2427 -0
- package/src/companion-guidance.mjs +257 -0
- package/src/companion-opening.mjs +62 -0
- package/src/companion.mjs +256 -0
- package/src/context.mjs +210 -0
- package/src/dashboard-preferences.mjs +80 -0
- package/src/delivery-artifacts.mjs +204 -0
- package/src/delivery-documents.mjs +248 -0
- package/src/delivery-gates.mjs +317 -0
- package/src/delivery.mjs +1433 -0
- package/src/design-system-application.mjs +291 -0
- package/src/design-system-authoring.mjs +101 -0
- package/src/design-systems.mjs +466 -0
- package/src/discovery.mjs +1314 -0
- package/src/error-reporting.mjs +323 -0
- package/src/evidence-depth.mjs +543 -0
- package/src/execution-state.mjs +243 -0
- package/src/install.mjs +166 -0
- package/src/intent-dependencies.mjs +117 -0
- package/src/intent-maps.mjs +402 -0
- package/src/intents.mjs +747 -0
- package/src/knowledge-proposals.mjs +717 -0
- package/src/launcher.mjs +51 -0
- package/src/meeting-evidence.mjs +703 -0
- package/src/network-rollout.mjs +386 -0
- package/src/organisation-blueprints.mjs +438 -0
- package/src/organisation-policies.mjs +448 -0
- package/src/packs.mjs +44 -0
- package/src/paths.mjs +62 -0
- package/src/persona-entitlements.mjs +438 -0
- package/src/persona-licence-config.mjs +98 -0
- package/src/persona-website-provider.mjs +134 -0
- package/src/persona-zip.mjs +87 -0
- package/src/personas.mjs +159 -0
- package/src/platform-metadata-analysis.mjs +314 -0
- package/src/policy-design-gates.mjs +623 -0
- package/src/policy-gate-integration.mjs +318 -0
- package/src/portfolio.mjs +509 -0
- package/src/power-platform-source-map.mjs +190 -0
- package/src/project.mjs +449 -0
- package/src/prototype-iterations.mjs +730 -0
- package/src/repository-source-map.mjs +603 -0
- package/src/runtime/afk-conductor.mjs +973 -0
- package/src/runtime/context-assembly.mjs +457 -0
- package/src/runtime/context-benchmarks.mjs +115 -0
- package/src/runtime/dashboard-actions.mjs +109 -0
- package/src/runtime/dashboard-handoffs.mjs +149 -0
- package/src/runtime/dashboard-server.mjs +1272 -0
- package/src/runtime/dashboard.mjs +197 -0
- package/src/runtime/database.mjs +789 -0
- package/src/runtime/error-reporting.mjs +581 -0
- package/src/runtime/evidence-depth-workspace.mjs +412 -0
- package/src/runtime/execution-leases.mjs +299 -0
- package/src/runtime/guided-discovery.mjs +350 -0
- package/src/runtime/guided-intents.mjs +517 -0
- package/src/runtime/impact-analysis.mjs +535 -0
- package/src/runtime/intents.mjs +222 -0
- package/src/runtime/knowledge.mjs +86 -0
- package/src/runtime/lifecycle-hooks.mjs +1239 -0
- package/src/runtime/mcp-config.mjs +110 -0
- package/src/runtime/mcp-server.mjs +1885 -0
- package/src/runtime/palace.mjs +362 -0
- package/src/runtime/paths.mjs +58 -0
- package/src/runtime/persona-engagement.mjs +255 -0
- package/src/runtime/phase-contributions.mjs +594 -0
- package/src/runtime/policy-workspace.mjs +170 -0
- package/src/runtime/prototype-iterations.mjs +235 -0
- package/src/runtime/provider-adapters.mjs +163 -0
- package/src/runtime/repository-index.mjs +838 -0
- package/src/runtime/runs.mjs +185 -0
- package/src/runtime/security-validation.mjs +1230 -0
- package/src/runtime/starter-materialisation.mjs +1155 -0
- package/src/runtime/team-hub-client.mjs +479 -0
- package/src/runtime/team-hub-database.mjs +288 -0
- package/src/runtime/team-hub-server.mjs +191 -0
- package/src/runtime/team-hub.mjs +110 -0
- package/src/runtime/tree-sitter-index.mjs +390 -0
- package/src/runtime/version.mjs +1 -0
- package/src/runtime/work.mjs +633 -0
- package/src/salesforce-source-map.mjs +212 -0
- package/src/security-validation-config.mjs +224 -0
- package/src/solution-readiness.mjs +620 -0
- package/src/starter-materialisation-contract.mjs +407 -0
- package/src/task-graph.mjs +544 -0
- package/src/team-hub-resources.mjs +239 -0
- package/src/team-hub.mjs +242 -0
- package/src/test-scenarios.mjs +622 -0
- package/src/validation-config.mjs +289 -0
- package/templates/SPECS/1.Scope/personas/registry.yaml +12 -0
- package/templates/SPECS/5.Strategy/patterns/context-packet.md +119 -0
- package/templates/SPECS/6.Build/_tracker-template.md +16 -0
- package/templates/SPECS/pipeline.yaml +62 -0
- package/templates/discovery-answers.yaml +86 -0
- package/templates/intent-body.md +21 -0
- package/tests/fixtures/context-benchmarks.json +9 -0
|
@@ -0,0 +1,1885 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { z } from 'zod/v4';
|
|
5
|
+
import { readFileSync } from 'node:fs';
|
|
6
|
+
import { resolve } from 'node:path';
|
|
7
|
+
import { premiumPersonaRoot } from '../checkin.mjs';
|
|
8
|
+
import { auditIntentStateCopies, createIntent } from '../intents.mjs';
|
|
9
|
+
import { createIntentMap } from '../intent-maps.mjs';
|
|
10
|
+
import {
|
|
11
|
+
beginDelivery,
|
|
12
|
+
completeDeliveryPhase,
|
|
13
|
+
continueDelivery,
|
|
14
|
+
phaseGateTemplate,
|
|
15
|
+
readDeliveryState,
|
|
16
|
+
recordBuildApproval,
|
|
17
|
+
recordExternalValidationCycle,
|
|
18
|
+
recordManualQaApproval,
|
|
19
|
+
recordPhaseGate,
|
|
20
|
+
resumeShelvedDelivery,
|
|
21
|
+
startDeliveryPhase
|
|
22
|
+
} from '../delivery.mjs';
|
|
23
|
+
import {
|
|
24
|
+
configureExternalValidation,
|
|
25
|
+
configureValidationCheckpoint,
|
|
26
|
+
loadProjectConfig,
|
|
27
|
+
validationStatus,
|
|
28
|
+
} from '../project.mjs';
|
|
29
|
+
import { listPersonas, personalPersonaRoot, projectPersonaRoot } from '../personas.mjs';
|
|
30
|
+
import { readPortfolioWorkspace } from '../portfolio.mjs';
|
|
31
|
+
import { readRolloutWorkspace } from '../network-rollout.mjs';
|
|
32
|
+
import { readCompanionGuidance } from '../companion-guidance.mjs';
|
|
33
|
+
import {
|
|
34
|
+
prepareMeetingExtraction,
|
|
35
|
+
promoteMeetingEvidence,
|
|
36
|
+
readMeetingEvidenceWorkspace,
|
|
37
|
+
recordMeetingReview,
|
|
38
|
+
registerMeetingSource,
|
|
39
|
+
} from '../meeting-evidence.mjs';
|
|
40
|
+
import {
|
|
41
|
+
KNOWLEDGE_PROPOSALS_DISCLAIMER,
|
|
42
|
+
listKnowledgeSources,
|
|
43
|
+
materialiseKnowledgeProposals,
|
|
44
|
+
prepareKnowledgeProposals,
|
|
45
|
+
readKnowledgeProposalWorkspace,
|
|
46
|
+
recordKnowledgeProposalBundle,
|
|
47
|
+
recordKnowledgeProposalReview,
|
|
48
|
+
recoverKnowledgeMaterialisation,
|
|
49
|
+
} from '../knowledge-proposals.mjs';
|
|
50
|
+
import { requiredPhaseArtefacts } from '../delivery-artifacts.mjs';
|
|
51
|
+
import { deliveryPaths } from '../delivery-documents.mjs';
|
|
52
|
+
import { dashboardStatus } from './dashboard.mjs';
|
|
53
|
+
import { prepareProjectContext } from './context-assembly.mjs';
|
|
54
|
+
import {
|
|
55
|
+
confirmPolicyFactsAction,
|
|
56
|
+
evaluatePolicyDesignAction,
|
|
57
|
+
readPolicyWorkspace,
|
|
58
|
+
recordPolicyExceptionAction,
|
|
59
|
+
recordPolicyReviewAction,
|
|
60
|
+
} from './policy-workspace.mjs';
|
|
61
|
+
import {
|
|
62
|
+
compareEvidenceDepthWorkspaceRuns,
|
|
63
|
+
prepareEvidenceDepthWorkspace,
|
|
64
|
+
readEvidenceDepthWorkspace,
|
|
65
|
+
recordEvidenceDepthWorkspaceRun,
|
|
66
|
+
} from './evidence-depth-workspace.mjs';
|
|
67
|
+
import {
|
|
68
|
+
comparePrototypeWorkspaceReviews,
|
|
69
|
+
preparePrototypeCycleWorkspace,
|
|
70
|
+
preparePrototypePlanWorkspace,
|
|
71
|
+
readPrototypeIterationWorkspace,
|
|
72
|
+
recordPrototypeCycleWorkspaceReview,
|
|
73
|
+
recordPrototypePlanWorkspaceReview,
|
|
74
|
+
} from './prototype-iterations.mjs';
|
|
75
|
+
import { initializeRuntime } from './database.mjs';
|
|
76
|
+
import {
|
|
77
|
+
refreshRepositoryIndex,
|
|
78
|
+
repositoryGraph,
|
|
79
|
+
repositoryIndexFreshness,
|
|
80
|
+
repositoryIndexStatus,
|
|
81
|
+
repositorySourceMapCoverage,
|
|
82
|
+
repositorySourceMapFiles,
|
|
83
|
+
repositorySourceMapProfiles,
|
|
84
|
+
repositoryStandards,
|
|
85
|
+
repositoryStandardsCoverage,
|
|
86
|
+
repositoryTruth,
|
|
87
|
+
searchRepositoryIndex,
|
|
88
|
+
similarRepositoryCapabilities
|
|
89
|
+
} from './repository-index.mjs';
|
|
90
|
+
import { listRuntimeIntents, readRuntimeIntent, syncIntentIndex } from './intents.mjs';
|
|
91
|
+
import { listCommandRuns, markStaleCommandRuns } from './runs.mjs';
|
|
92
|
+
import {
|
|
93
|
+
acquireExecutionLease,
|
|
94
|
+
heartbeatExecutionLease,
|
|
95
|
+
listExecutionLeases,
|
|
96
|
+
releaseExecutionLease,
|
|
97
|
+
} from './execution-leases.mjs';
|
|
98
|
+
import { palaceTidiness, searchPalace } from './palace.mjs';
|
|
99
|
+
import {
|
|
100
|
+
afkRunStatus,
|
|
101
|
+
cancelAfkRun,
|
|
102
|
+
pauseAfkRun,
|
|
103
|
+
preflightAfkRun,
|
|
104
|
+
resumeAfkRun,
|
|
105
|
+
startAfkRun,
|
|
106
|
+
} from './afk-conductor.mjs';
|
|
107
|
+
import { listDashboardHandoffs, resolveDashboardHandoff } from './dashboard-handoffs.mjs';
|
|
108
|
+
import {
|
|
109
|
+
addActivityEvent,
|
|
110
|
+
addArtefact,
|
|
111
|
+
finishActiveSession,
|
|
112
|
+
listActiveSessions,
|
|
113
|
+
listWorkItems,
|
|
114
|
+
readWorkItemView,
|
|
115
|
+
startActiveSession,
|
|
116
|
+
updateWorkItem
|
|
117
|
+
} from './work.mjs';
|
|
118
|
+
import {
|
|
119
|
+
archiveErrorReport,
|
|
120
|
+
createLocalErrorReport,
|
|
121
|
+
deleteErrorReport,
|
|
122
|
+
finaliseLocalErrorReport,
|
|
123
|
+
listErrorReportProviders,
|
|
124
|
+
listErrorReportReceipts,
|
|
125
|
+
listLocalErrorReports,
|
|
126
|
+
prepareErrorReportEmail,
|
|
127
|
+
readLocalErrorReport,
|
|
128
|
+
submitErrorReportProvider,
|
|
129
|
+
updateErrorReportSettings,
|
|
130
|
+
updateLocalErrorReport,
|
|
131
|
+
} from './error-reporting.mjs';
|
|
132
|
+
|
|
133
|
+
function option(name, fallback = '') {
|
|
134
|
+
const index = process.argv.indexOf(name);
|
|
135
|
+
return index === -1 ? fallback : process.argv[index + 1] ?? fallback;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const projectRoot = option('--project', process.cwd());
|
|
139
|
+
const packageVersion = JSON.parse(
|
|
140
|
+
readFileSync(new URL('../../package.json', import.meta.url), 'utf8')
|
|
141
|
+
).version;
|
|
142
|
+
const { config, paths } = loadProjectConfig(projectRoot);
|
|
143
|
+
initializeRuntime(paths.projectRoot);
|
|
144
|
+
syncIntentIndex(paths.projectRoot);
|
|
145
|
+
|
|
146
|
+
const server = new McpServer(
|
|
147
|
+
{ name: 'ewai-pipeline', version: packageVersion },
|
|
148
|
+
{
|
|
149
|
+
instructions: 'Treat SPECS Markdown as project truth. Use EWAI intent resources and read tools before proposing changes. Creation tools write project-owned SPECS artefacts; do not invoke them without the user asking for a new intent.'
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
function result(value) {
|
|
154
|
+
return {
|
|
155
|
+
content: [{ type: 'text', text: JSON.stringify(value ?? null, null, 2) }],
|
|
156
|
+
structuredContent: value ?? null
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function portfolioPersonas() {
|
|
161
|
+
return listPersonas([
|
|
162
|
+
resolve(import.meta.dirname, '../../packs/personas/core/personas'),
|
|
163
|
+
premiumPersonaRoot(),
|
|
164
|
+
personalPersonaRoot(),
|
|
165
|
+
projectPersonaRoot(paths.projectRoot),
|
|
166
|
+
]);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const personaAttachmentSchema = z.object({
|
|
170
|
+
ref: z.string().min(1),
|
|
171
|
+
role: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).optional(),
|
|
172
|
+
depth: z.number().int().min(1).max(5).optional(),
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const intentRelationshipSchema = z.object({
|
|
176
|
+
type: z.enum([
|
|
177
|
+
'depends-on',
|
|
178
|
+
'enables',
|
|
179
|
+
'complements',
|
|
180
|
+
'conflicts-with',
|
|
181
|
+
'supersedes',
|
|
182
|
+
'relates-to',
|
|
183
|
+
]),
|
|
184
|
+
target: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*\/[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
185
|
+
rationale: z.string().optional(),
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const deliveryShapeSchema = z.object({
|
|
189
|
+
recommendation: z.enum(['single', 'split', 'decision-required']),
|
|
190
|
+
reason: z.string().min(1),
|
|
191
|
+
suggested_children: z.array(z.object({
|
|
192
|
+
domain: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).optional(),
|
|
193
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).optional(),
|
|
194
|
+
title: z.string().optional(),
|
|
195
|
+
outcome: z.string(),
|
|
196
|
+
depends_on: z.array(z.string()).optional(),
|
|
197
|
+
})).optional(),
|
|
198
|
+
blocking_questions: z.array(z.string()).optional(),
|
|
199
|
+
reviewed_decision: z.enum(['keep-as-one', 'split', 'refine-split', 'defer']).nullable().optional(),
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const mappedIntentSchema = z.object({
|
|
203
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
204
|
+
domain: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).optional(),
|
|
205
|
+
title: z.string().min(1),
|
|
206
|
+
problem: z.string().min(1),
|
|
207
|
+
desiredOutcome: z.string().min(1),
|
|
208
|
+
users: z.array(z.string()).optional(),
|
|
209
|
+
journeys: z.array(z.string()).optional(),
|
|
210
|
+
acceptanceCriteria: z.array(z.string()).optional(),
|
|
211
|
+
constraints: z.array(z.string()).optional(),
|
|
212
|
+
evidence: z.array(z.string()).optional(),
|
|
213
|
+
openDecisions: z.array(z.string()).optional(),
|
|
214
|
+
personas: z.array(personaAttachmentSchema).optional(),
|
|
215
|
+
relationships: z.array(intentRelationshipSchema).optional(),
|
|
216
|
+
deliveryShape: deliveryShapeSchema.optional(),
|
|
217
|
+
delivery_shape: deliveryShapeSchema.optional(),
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
server.registerResource(
|
|
221
|
+
'ewai-intent-library',
|
|
222
|
+
'ewai://intents',
|
|
223
|
+
{
|
|
224
|
+
title: `${config.project.name} intent library`,
|
|
225
|
+
description: 'Project intents indexed from SPECS/2.Purpose/intents.',
|
|
226
|
+
mimeType: 'application/json'
|
|
227
|
+
},
|
|
228
|
+
(uri) => ({
|
|
229
|
+
contents: [{
|
|
230
|
+
uri: uri.href,
|
|
231
|
+
mimeType: 'application/json',
|
|
232
|
+
text: JSON.stringify({ intents: listRuntimeIntents(paths.projectRoot) }, null, 2)
|
|
233
|
+
}]
|
|
234
|
+
})
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
server.registerResource(
|
|
238
|
+
'ewai-intent',
|
|
239
|
+
new ResourceTemplate('ewai://intents/{reference}', {
|
|
240
|
+
list: () => ({
|
|
241
|
+
resources: listRuntimeIntents(paths.projectRoot).map((intent) => ({
|
|
242
|
+
uri: `ewai://intents/${encodeURIComponent(intent.id)}`,
|
|
243
|
+
name: intent.id,
|
|
244
|
+
title: intent.title,
|
|
245
|
+
description: intent.excerpt,
|
|
246
|
+
mimeType: 'text/markdown'
|
|
247
|
+
}))
|
|
248
|
+
}),
|
|
249
|
+
complete: { reference: () => listRuntimeIntents(paths.projectRoot).map((intent) => intent.id) }
|
|
250
|
+
}),
|
|
251
|
+
{
|
|
252
|
+
title: 'EWAI project intent',
|
|
253
|
+
description: 'Authoritative intent Markdown from the project SPECS.',
|
|
254
|
+
mimeType: 'text/markdown'
|
|
255
|
+
},
|
|
256
|
+
(uri, { reference }) => {
|
|
257
|
+
const intent = readRuntimeIntent(paths.projectRoot, decodeURIComponent(String(reference)));
|
|
258
|
+
return {
|
|
259
|
+
contents: [{
|
|
260
|
+
uri: uri.href,
|
|
261
|
+
mimeType: 'text/markdown',
|
|
262
|
+
text: intent?.markdown ?? 'Intent not found.'
|
|
263
|
+
}]
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
server.registerTool(
|
|
269
|
+
'ewai_list_intents',
|
|
270
|
+
{
|
|
271
|
+
title: 'List project intents',
|
|
272
|
+
description: 'List and search project intents indexed from SPECS.',
|
|
273
|
+
inputSchema: {
|
|
274
|
+
query: z.string().optional(),
|
|
275
|
+
status: z.string().optional()
|
|
276
|
+
},
|
|
277
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
278
|
+
},
|
|
279
|
+
async ({ query = '', status = '' }) => result({
|
|
280
|
+
intents: listRuntimeIntents(paths.projectRoot, { query, status })
|
|
281
|
+
})
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
server.registerTool(
|
|
285
|
+
'ewai_read_intent',
|
|
286
|
+
{
|
|
287
|
+
title: 'Read a project intent',
|
|
288
|
+
description: 'Read one intent by its domain/slug identifier or slug.',
|
|
289
|
+
inputSchema: { reference: z.string().min(1) },
|
|
290
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
291
|
+
},
|
|
292
|
+
async ({ reference }) => result({ intent: readRuntimeIntent(paths.projectRoot, reference) })
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
server.registerTool(
|
|
296
|
+
'ewai_context_prepare',
|
|
297
|
+
{
|
|
298
|
+
title: 'Prepare governed model context',
|
|
299
|
+
description: 'Prepare a bounded revision-bound context pack for a supported EWAI profile. The trusted MCP host receives transient model context plus a body-free safe manifest. This cannot approve or execute delivery work.',
|
|
300
|
+
inputSchema: {
|
|
301
|
+
profile: z.enum(['companion', 'intent', 'plan', 'build-task', 'fresh-context-review', 'phase-contribution-review']),
|
|
302
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
303
|
+
taskId: z.string().regex(/^T-\d{3,}$/).optional(),
|
|
304
|
+
phase: z.string().max(80).optional(),
|
|
305
|
+
focus: z.string().max(2000).optional(),
|
|
306
|
+
budgetTokens: z.number().int().min(1).max(200000).optional(),
|
|
307
|
+
previousDigest: z.string().regex(/^[a-f0-9]{64}$/).optional(),
|
|
308
|
+
},
|
|
309
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
310
|
+
},
|
|
311
|
+
async (input) => result(prepareProjectContext(paths.projectRoot, {
|
|
312
|
+
...input,
|
|
313
|
+
personaCatalogue: portfolioPersonas(),
|
|
314
|
+
})),
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
server.registerTool(
|
|
318
|
+
'ewai_policy_status',
|
|
319
|
+
{
|
|
320
|
+
title: 'Read organisation policy design-gate status',
|
|
321
|
+
description: 'Read one safe business or technical projection of the optional design-time policy workspace, including the active advisory personas. This is not production enforcement or release authority.',
|
|
322
|
+
inputSchema: {
|
|
323
|
+
intentReference: z.string().max(240).optional(),
|
|
324
|
+
mode: z.enum(['business', 'technical']).optional(),
|
|
325
|
+
},
|
|
326
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
327
|
+
},
|
|
328
|
+
async ({ intentReference = '', mode = 'business' }) => result(readPolicyWorkspace(paths.projectRoot, {
|
|
329
|
+
intentReference,
|
|
330
|
+
mode,
|
|
331
|
+
personas: portfolioPersonas(),
|
|
332
|
+
})),
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
server.registerTool(
|
|
336
|
+
'ewai_policy_confirm_facts',
|
|
337
|
+
{
|
|
338
|
+
title: 'Confirm policy design facts',
|
|
339
|
+
description: 'Persist a complete named-human confirmation of the digest-bound proposed design facts. Personas remain advisory.',
|
|
340
|
+
inputSchema: {
|
|
341
|
+
intentReference: z.string().min(1).max(240),
|
|
342
|
+
expectedRevision: z.number().int().positive(),
|
|
343
|
+
expectedProposalDigest: z.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
344
|
+
confirmed: z.literal(true),
|
|
345
|
+
authority: z.literal('human'),
|
|
346
|
+
confirmedBy: z.string().min(1).max(160),
|
|
347
|
+
decisions: z.array(z.object({
|
|
348
|
+
factId: z.string().min(1).max(160),
|
|
349
|
+
disposition: z.enum(['confirmed', 'rejected']),
|
|
350
|
+
values: z.array(z.string().min(1).max(120)).min(1).max(40).optional(),
|
|
351
|
+
}).strict()).min(1).max(100),
|
|
352
|
+
},
|
|
353
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
354
|
+
},
|
|
355
|
+
async (input) => result(confirmPolicyFactsAction(paths.projectRoot, input, { personas: portfolioPersonas() })),
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
server.registerTool(
|
|
359
|
+
'ewai_policy_evaluate',
|
|
360
|
+
{
|
|
361
|
+
title: 'Evaluate a policy design',
|
|
362
|
+
description: 'Run the deterministic organisation-policy design evaluation against current confirmed facts and an exact baseline digest.',
|
|
363
|
+
inputSchema: {
|
|
364
|
+
intentReference: z.string().min(1).max(240),
|
|
365
|
+
expectedIntentRevision: z.number().int().positive(),
|
|
366
|
+
expectedPolicyDigest: z.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
367
|
+
expectedFactsDigest: z.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
368
|
+
},
|
|
369
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
370
|
+
},
|
|
371
|
+
async (input) => result(evaluatePolicyDesignAction(paths.projectRoot, input, { personas: portfolioPersonas() })),
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
server.registerTool(
|
|
375
|
+
'ewai_policy_record_review',
|
|
376
|
+
{
|
|
377
|
+
title: 'Record a named policy review',
|
|
378
|
+
description: 'Record a named-human decision for one review-required rule on the current exact evaluation.',
|
|
379
|
+
inputSchema: {
|
|
380
|
+
intentReference: z.string().min(1).max(240),
|
|
381
|
+
evaluationDigest: z.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
382
|
+
ruleId: z.string().min(1).max(240),
|
|
383
|
+
authority: z.literal('human'),
|
|
384
|
+
reviewedBy: z.string().min(1).max(160),
|
|
385
|
+
reviewerRole: z.string().min(1).max(160),
|
|
386
|
+
decision: z.enum(['allow', 'deny', 'allow-with-controls']),
|
|
387
|
+
rationale: z.string().min(1).max(2000),
|
|
388
|
+
evidence: z.array(z.string().min(1).max(500)).min(1).max(40),
|
|
389
|
+
controls: z.array(z.string().min(1).max(500)).max(40).optional(),
|
|
390
|
+
},
|
|
391
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
392
|
+
},
|
|
393
|
+
async (input) => result(recordPolicyReviewAction(paths.projectRoot, input, { personas: portfolioPersonas() })),
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
server.registerTool(
|
|
397
|
+
'ewai_policy_record_exception',
|
|
398
|
+
{
|
|
399
|
+
title: 'Record a bounded policy exception',
|
|
400
|
+
description: 'Record an owned, time-limited, named-human exception only where the matched rule permits it.',
|
|
401
|
+
inputSchema: {
|
|
402
|
+
intentReference: z.string().min(1).max(240),
|
|
403
|
+
evaluationDigest: z.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
404
|
+
ruleId: z.string().min(1).max(240),
|
|
405
|
+
authority: z.literal('human'),
|
|
406
|
+
approvedBy: z.string().min(1).max(160),
|
|
407
|
+
owner: z.string().min(1).max(160),
|
|
408
|
+
reviewerRole: z.string().min(1).max(160),
|
|
409
|
+
scope: z.record(z.string(), z.array(z.string().min(1).max(240)).min(1)).refine((value) => Object.keys(value).length > 0),
|
|
410
|
+
rationale: z.string().min(1).max(2000),
|
|
411
|
+
compensatingControls: z.array(z.string().min(1).max(500)).min(1).max(40),
|
|
412
|
+
evidence: z.array(z.string().min(1).max(500)).min(1).max(40),
|
|
413
|
+
expiresAt: z.string().datetime(),
|
|
414
|
+
},
|
|
415
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
416
|
+
},
|
|
417
|
+
async (input) => result(recordPolicyExceptionAction(paths.projectRoot, input, { personas: portfolioPersonas() })),
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
server.registerTool(
|
|
421
|
+
'ewai_search_palace',
|
|
422
|
+
{
|
|
423
|
+
title: 'Search the project Mind Palace',
|
|
424
|
+
description: 'Search the full content of project SPECS and return the best matching document sections.',
|
|
425
|
+
inputSchema: {
|
|
426
|
+
query: z.string().min(1),
|
|
427
|
+
limit: z.number().int().min(1).max(100).optional()
|
|
428
|
+
},
|
|
429
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
430
|
+
},
|
|
431
|
+
async ({ query, limit = 25 }) => result(searchPalace(paths.projectRoot, query, { limit }))
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
const evidenceDepthOwnerEvidenceSchema = z.object({
|
|
435
|
+
id: z.string().min(1).max(200),
|
|
436
|
+
dimension: z.enum(['architecture', 'data', 'security', 'product', 'delivery', 'governance', 'operations']),
|
|
437
|
+
authority: z.enum(['declared', 'confirmed']),
|
|
438
|
+
evidenceDigest: z.string().regex(/^sha256:[a-z0-9._-]{3,200}$/i),
|
|
439
|
+
answerCode: z.string().min(1).max(200),
|
|
440
|
+
reasonCode: z.string().min(1).max(200),
|
|
441
|
+
contradiction: z.enum(['none', 'declared-versus-observed', 'observed-versus-observed', 'declared-versus-declared', 'unresolved']).optional(),
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
server.registerTool(
|
|
445
|
+
'ewai_evidence_depth_status',
|
|
446
|
+
{
|
|
447
|
+
title: 'Read reproducible archaeology and discovery depth',
|
|
448
|
+
description: 'Read the seven-dimensional evidence ledger, stable gaps, active personas and named stored runs without returning source, answer or managed persona bodies.',
|
|
449
|
+
inputSchema: {},
|
|
450
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
451
|
+
},
|
|
452
|
+
async () => result(readEvidenceDepthWorkspace(paths.projectRoot, { personas: portfolioPersonas() })),
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
server.registerTool(
|
|
456
|
+
'ewai_evidence_depth_prepare',
|
|
457
|
+
{
|
|
458
|
+
title: 'Prepare a reproducible evidence-depth review',
|
|
459
|
+
description: 'Prepare deterministic recommendations and questions from the fresh Source Map, separate named owner evidence and relevant installed personas. This does not approve depth or grouping.',
|
|
460
|
+
inputSchema: {
|
|
461
|
+
focus: z.string().max(200).optional(),
|
|
462
|
+
ownerEvidence: z.array(evidenceDepthOwnerEvidenceSchema).max(50).optional(),
|
|
463
|
+
},
|
|
464
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
465
|
+
},
|
|
466
|
+
async ({ focus = '', ownerEvidence = [] }) => result(prepareEvidenceDepthWorkspace(
|
|
467
|
+
paths.projectRoot,
|
|
468
|
+
{ focus },
|
|
469
|
+
{ personas: portfolioPersonas(), ownerEvidence },
|
|
470
|
+
)),
|
|
471
|
+
);
|
|
472
|
+
|
|
473
|
+
const evidenceDepthDimensionReviewSchema = z.object({
|
|
474
|
+
id: z.enum(['architecture', 'data', 'security', 'product', 'delivery', 'governance', 'operations']),
|
|
475
|
+
selectedDepth: z.enum(['bounded', 'standard', 'deep']),
|
|
476
|
+
rationale: z.string().max(500).optional(),
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
const evidenceDepthGroupingAssignmentSchema = z.object({
|
|
480
|
+
gapId: z.string().min(1).max(200),
|
|
481
|
+
groupId: z.string().min(1).max(200),
|
|
482
|
+
disposition: z.enum(['owned', 'shared', 'deferred', 'excluded']),
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
server.registerTool(
|
|
486
|
+
'ewai_evidence_depth_record',
|
|
487
|
+
{
|
|
488
|
+
title: 'Record a named evidence-depth review',
|
|
489
|
+
description: 'Record the exact named-human selection for all seven dimensions and every stable gap. This is evidence, not delivery or release approval.',
|
|
490
|
+
inputSchema: {
|
|
491
|
+
schema: z.literal('ewai.evidence-depth-review/v1'),
|
|
492
|
+
expectedPreparationDigest: z.string().regex(/^sha256:[a-z0-9._-]{3,200}$/i),
|
|
493
|
+
reviewedBy: z.string().min(1).max(120),
|
|
494
|
+
dimensions: z.array(evidenceDepthDimensionReviewSchema).length(7),
|
|
495
|
+
grouping: z.object({
|
|
496
|
+
strategy: z.string().min(1).max(200),
|
|
497
|
+
assignments: z.array(evidenceDepthGroupingAssignmentSchema).max(200),
|
|
498
|
+
}),
|
|
499
|
+
},
|
|
500
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
501
|
+
},
|
|
502
|
+
async (input) => result(recordEvidenceDepthWorkspaceRun(paths.projectRoot, input)),
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
server.registerTool(
|
|
506
|
+
'ewai_evidence_depth_compare',
|
|
507
|
+
{
|
|
508
|
+
title: 'Compare two reviewed evidence-depth runs',
|
|
509
|
+
description: 'Compare exact stored run identities in causal order without rescanning the repository or treating comparison as approval.',
|
|
510
|
+
inputSchema: { leftRunId: z.string().min(1).max(200), rightRunId: z.string().min(1).max(200) },
|
|
511
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
512
|
+
},
|
|
513
|
+
async (input) => result(compareEvidenceDepthWorkspaceRuns(paths.projectRoot, input)),
|
|
514
|
+
);
|
|
515
|
+
|
|
516
|
+
const prototypeDigestSchema = z.string().regex(/^sha256:[a-f0-9]{64}$/);
|
|
517
|
+
const prototypeSlugSchema = z.string().regex(/^[a-z0-9][a-z0-9._-]{0,79}$/);
|
|
518
|
+
const prototypeFindingReferenceSchema = z.object({
|
|
519
|
+
personaId: z.string().min(1).max(200),
|
|
520
|
+
concernCode: z.string().min(1).max(200),
|
|
521
|
+
evidenceRefs: z.array(z.string().min(1).max(200)).min(1).max(50),
|
|
522
|
+
});
|
|
523
|
+
const prototypeFindingSchema = prototypeFindingReferenceSchema.extend({
|
|
524
|
+
severity: z.enum(['advisory', 'material', 'critical']),
|
|
525
|
+
observation: z.string().min(1).max(2000),
|
|
526
|
+
recommendation: z.string().min(1).max(2000),
|
|
527
|
+
});
|
|
528
|
+
const prototypeAssessmentSchema = z.object({
|
|
529
|
+
findingId: z.string().min(1).max(200).optional(),
|
|
530
|
+
findingRef: prototypeFindingReferenceSchema.optional(),
|
|
531
|
+
disposition: z.enum(['incorporate', 'incorporate-with-modification', 'defer', 'reject', 'escalate']),
|
|
532
|
+
rationale: z.string().min(1).max(2000),
|
|
533
|
+
modification: z.string().max(2000).optional(),
|
|
534
|
+
owner: z.string().max(160).optional(),
|
|
535
|
+
}).refine((value) => Boolean(value.findingId) !== Boolean(value.findingRef), 'Supply exactly one of findingId or findingRef');
|
|
536
|
+
const prototypeReviewSubmissionSchema = {
|
|
537
|
+
deliverySlug: prototypeSlugSchema,
|
|
538
|
+
schema: z.enum(['ewai.prototype-plan-review-submission/v1', 'ewai.prototype-cycle-review-submission/v1']),
|
|
539
|
+
expectedPreparationDigest: prototypeDigestSchema,
|
|
540
|
+
reviewedBy: z.string().min(1).max(160),
|
|
541
|
+
findings: z.array(prototypeFindingSchema).max(200),
|
|
542
|
+
assessments: z.array(prototypeAssessmentSchema).max(200),
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
server.registerTool(
|
|
546
|
+
'ewai_prototype_review_status',
|
|
547
|
+
{
|
|
548
|
+
title: 'Read persona-guided prototype review status',
|
|
549
|
+
description: 'Read reviewed plan and rendered-design cycles, stage-specific active personas, tier availability, findings, dispositions and the derived next action. Personas advise; people select and approve.',
|
|
550
|
+
inputSchema: { deliverySlug: prototypeSlugSchema },
|
|
551
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
552
|
+
},
|
|
553
|
+
async ({ deliverySlug }) => result(readPrototypeIterationWorkspace(paths.projectRoot, deliverySlug, { personas: portfolioPersonas() })),
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
server.registerTool(
|
|
557
|
+
'ewai_prototype_plan_prepare',
|
|
558
|
+
{
|
|
559
|
+
title: 'Prepare persona review of a prototype plan',
|
|
560
|
+
description: 'Identify relevant installed personas for the proposed screens and journeys, then create a deterministic review preparation. This does not record model findings or select a prototype.',
|
|
561
|
+
inputSchema: {
|
|
562
|
+
deliverySlug: prototypeSlugSchema,
|
|
563
|
+
intentDigest: prototypeDigestSchema,
|
|
564
|
+
designSystem: z.object({ id: z.string().min(1).max(200), effectiveDigest: prototypeDigestSchema }),
|
|
565
|
+
plan: z.object({
|
|
566
|
+
summary: z.string().min(1).max(2000),
|
|
567
|
+
screens: z.array(z.object({ id: z.string(), title: z.string(), purpose: z.string(), userOutcomes: z.array(z.string()), evidenceRefs: z.array(z.string()) })).min(1).max(100),
|
|
568
|
+
journeys: z.array(z.object({ id: z.string(), actor: z.string(), outcome: z.string(), screenRefs: z.array(z.string()) })).min(1).max(100),
|
|
569
|
+
}),
|
|
570
|
+
signals: z.array(z.string().min(1).max(120)).max(50).optional(),
|
|
571
|
+
predecessorDigest: prototypeDigestSchema.optional(),
|
|
572
|
+
},
|
|
573
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
574
|
+
},
|
|
575
|
+
async ({ deliverySlug, ...input }) => result(preparePrototypePlanWorkspace(paths.projectRoot, deliverySlug, input, { personas: portfolioPersonas() })),
|
|
576
|
+
);
|
|
577
|
+
|
|
578
|
+
server.registerTool(
|
|
579
|
+
'ewai_prototype_plan_record',
|
|
580
|
+
{
|
|
581
|
+
title: 'Record assessed persona findings for a prototype plan',
|
|
582
|
+
description: 'Record immutable persona findings and exactly one explicit disposition per finding. Recording is advisory evidence and is not prototype selection or Manual QA.',
|
|
583
|
+
inputSchema: prototypeReviewSubmissionSchema,
|
|
584
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
585
|
+
},
|
|
586
|
+
async ({ deliverySlug, ...input }) => result(recordPrototypePlanWorkspaceReview(paths.projectRoot, deliverySlug, input)),
|
|
587
|
+
);
|
|
588
|
+
|
|
589
|
+
server.registerTool(
|
|
590
|
+
'ewai_prototype_cycle_prepare',
|
|
591
|
+
{
|
|
592
|
+
title: 'Prepare persona review of a rendered prototype cycle',
|
|
593
|
+
description: 'Recompute relevant personas against the actual rendered design and seven separate evidence channels. Review is bounded to one to three configured cycles.',
|
|
594
|
+
inputSchema: {
|
|
595
|
+
deliverySlug: prototypeSlugSchema,
|
|
596
|
+
planReviewDigest: prototypeDigestSchema,
|
|
597
|
+
cycleNumber: z.number().int().min(1).max(3),
|
|
598
|
+
maxCycles: z.number().int().min(1).max(3).optional(),
|
|
599
|
+
predecessorDigest: prototypeDigestSchema.optional(),
|
|
600
|
+
prototype: z.object({ manifestDigest: prototypeDigestSchema, entryPath: z.string().min(1).max(240) }),
|
|
601
|
+
evidenceChannels: z.array(z.object({
|
|
602
|
+
channel: z.enum(['source', 'rendered-viewport', 'interaction', 'assistive-technology', 'user-research', 'manual-qa', 'release']),
|
|
603
|
+
status: z.enum(['available', 'not-collected', 'not-applicable', 'pending-human']),
|
|
604
|
+
evidenceRefs: z.array(z.string().min(1).max(200)).max(100),
|
|
605
|
+
note: z.string().min(1).max(1000),
|
|
606
|
+
})).length(7),
|
|
607
|
+
signals: z.array(z.string().min(1).max(120)).max(50).optional(),
|
|
608
|
+
},
|
|
609
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
610
|
+
},
|
|
611
|
+
async ({ deliverySlug, ...input }) => result(preparePrototypeCycleWorkspace(paths.projectRoot, deliverySlug, input, { personas: portfolioPersonas() })),
|
|
612
|
+
);
|
|
613
|
+
|
|
614
|
+
server.registerTool(
|
|
615
|
+
'ewai_prototype_cycle_record',
|
|
616
|
+
{
|
|
617
|
+
title: 'Record assessed persona findings for a rendered prototype',
|
|
618
|
+
description: 'Record an immutable design-review cycle and derive iterate, ready-for-human-selection or human-decision-required. This cannot approve Manual QA or release.',
|
|
619
|
+
inputSchema: prototypeReviewSubmissionSchema,
|
|
620
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
621
|
+
},
|
|
622
|
+
async ({ deliverySlug, ...input }) => result(recordPrototypeCycleWorkspaceReview(paths.projectRoot, deliverySlug, input)),
|
|
623
|
+
);
|
|
624
|
+
|
|
625
|
+
server.registerTool(
|
|
626
|
+
'ewai_prototype_review_compare',
|
|
627
|
+
{
|
|
628
|
+
title: 'Compare two prototype reviews',
|
|
629
|
+
description: 'Explain review variance in causal order: inputs, personas, findings, assessments and output.',
|
|
630
|
+
inputSchema: { deliverySlug: prototypeSlugSchema, leftDigest: prototypeDigestSchema, rightDigest: prototypeDigestSchema },
|
|
631
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
632
|
+
},
|
|
633
|
+
async ({ deliverySlug, ...input }) => result(comparePrototypeWorkspaceReviews(paths.projectRoot, deliverySlug, input)),
|
|
634
|
+
);
|
|
635
|
+
|
|
636
|
+
server.registerTool(
|
|
637
|
+
'ewai_palace_tidiness',
|
|
638
|
+
{
|
|
639
|
+
title: 'Inspect Mind Palace tidiness',
|
|
640
|
+
description: 'Run deterministic, read-only checks for broken links, duplicate content, orphaned documents, empty documents, and missing titles in SPECS.',
|
|
641
|
+
inputSchema: {},
|
|
642
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
643
|
+
},
|
|
644
|
+
async () => result(palaceTidiness(paths.projectRoot))
|
|
645
|
+
);
|
|
646
|
+
|
|
647
|
+
server.registerTool(
|
|
648
|
+
'ewai_meeting_status',
|
|
649
|
+
{
|
|
650
|
+
title: 'Read meeting evidence status',
|
|
651
|
+
description: 'Read safe registered-source metadata, named review dispositions, evidence receipts and the currently engaged persona ensemble. Raw transcript text and absolute paths are never returned.',
|
|
652
|
+
inputSchema: {
|
|
653
|
+
sourceId: z.string().optional(),
|
|
654
|
+
focus: z.string().max(500).optional(),
|
|
655
|
+
},
|
|
656
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
657
|
+
},
|
|
658
|
+
async ({ sourceId, focus }) => result(readMeetingEvidenceWorkspace(paths.projectRoot, { sourceId, focus })),
|
|
659
|
+
);
|
|
660
|
+
|
|
661
|
+
server.registerTool(
|
|
662
|
+
'ewai_meeting_register',
|
|
663
|
+
{
|
|
664
|
+
title: 'Register a local meeting source',
|
|
665
|
+
description: 'Register a supported local transcript or minutes file after explicit confirmation. The file is not copied into SPECS or the runtime database.',
|
|
666
|
+
inputSchema: {
|
|
667
|
+
file: z.string().min(1),
|
|
668
|
+
confirmed: z.boolean(),
|
|
669
|
+
label: z.string().max(160).optional(),
|
|
670
|
+
classification: z.enum(['public', 'internal', 'confidential', 'restricted']).optional(),
|
|
671
|
+
cloudProcessing: z.enum(['allowed', 'denied', 'unknown']).optional(),
|
|
672
|
+
},
|
|
673
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
674
|
+
},
|
|
675
|
+
async ({ file, ...input }) => result(registerMeetingSource(paths.projectRoot, file, input)),
|
|
676
|
+
);
|
|
677
|
+
|
|
678
|
+
server.registerTool(
|
|
679
|
+
'ewai_meeting_prepare',
|
|
680
|
+
{
|
|
681
|
+
title: 'Prepare meeting evidence extraction',
|
|
682
|
+
description: 'Return the safe source facts, processing route, strict candidate contract and contextual active personas for host-model extraction.',
|
|
683
|
+
inputSchema: { sourceId: z.string().min(1), focus: z.string().max(500).optional() },
|
|
684
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
685
|
+
},
|
|
686
|
+
async ({ sourceId, focus }) => result(prepareMeetingExtraction(paths.projectRoot, sourceId, { focus })),
|
|
687
|
+
);
|
|
688
|
+
|
|
689
|
+
const meetingCandidateSchema = z.object({
|
|
690
|
+
id: z.string(),
|
|
691
|
+
type: z.string(),
|
|
692
|
+
observedStatement: z.string(),
|
|
693
|
+
interpretation: z.string(),
|
|
694
|
+
lineAnchors: z.array(z.object({ start: z.number().int(), end: z.number().int() })),
|
|
695
|
+
confidence: z.enum(['low', 'medium', 'high']),
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
server.registerTool(
|
|
699
|
+
'ewai_meeting_review',
|
|
700
|
+
{
|
|
701
|
+
title: 'Record a named meeting evidence review',
|
|
702
|
+
description: 'Validate a complete candidate bundle and record one named disposition for every candidate. This does not promote evidence.',
|
|
703
|
+
inputSchema: {
|
|
704
|
+
sourceId: z.string().min(1),
|
|
705
|
+
reviewedBy: z.string().min(1).max(160),
|
|
706
|
+
bundle: z.object({
|
|
707
|
+
schema: z.literal('ewai.meeting-candidate-bundle/v1'),
|
|
708
|
+
sourceId: z.string(),
|
|
709
|
+
sourceDigest: z.string(),
|
|
710
|
+
candidates: z.array(meetingCandidateSchema),
|
|
711
|
+
}),
|
|
712
|
+
dispositions: z.array(z.object({
|
|
713
|
+
candidateId: z.string(),
|
|
714
|
+
decision: z.enum(['accepted', 'rejected', 'amended', 'deferred']),
|
|
715
|
+
replacementText: z.string().optional(),
|
|
716
|
+
rationale: z.string().optional(),
|
|
717
|
+
})),
|
|
718
|
+
},
|
|
719
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
720
|
+
},
|
|
721
|
+
async ({ sourceId, ...input }) => result(recordMeetingReview(paths.projectRoot, sourceId, input)),
|
|
722
|
+
);
|
|
723
|
+
|
|
724
|
+
server.registerTool(
|
|
725
|
+
'ewai_meeting_promote',
|
|
726
|
+
{
|
|
727
|
+
title: 'Promote reviewed meeting evidence',
|
|
728
|
+
description: 'After exact confirmation and named approval, persist accepted and amended candidates as paired evidence files only.',
|
|
729
|
+
inputSchema: {
|
|
730
|
+
sourceId: z.string().min(1),
|
|
731
|
+
confirmed: z.boolean(),
|
|
732
|
+
approvedBy: z.string().min(1).max(160),
|
|
733
|
+
},
|
|
734
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
735
|
+
},
|
|
736
|
+
async ({ sourceId, ...input }) => result(promoteMeetingEvidence(paths.projectRoot, sourceId, input)),
|
|
737
|
+
);
|
|
738
|
+
|
|
739
|
+
const knowledgePersonaSchema = z.object({
|
|
740
|
+
id: z.string().min(1).max(160),
|
|
741
|
+
name: z.string().min(1).max(160),
|
|
742
|
+
tier: z.enum(['core', 'premium', 'personal', 'project']),
|
|
743
|
+
category: z.string().max(100).optional(),
|
|
744
|
+
description: z.string().max(240).optional(),
|
|
745
|
+
matchedSignals: z.array(z.string().max(100)).optional(),
|
|
746
|
+
engagementReason: z.string().min(1).max(400),
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
const knowledgeProposalSchema = z.object({
|
|
750
|
+
id: z.string(),
|
|
751
|
+
kind: z.string(),
|
|
752
|
+
title: z.string(),
|
|
753
|
+
destination: z.string(),
|
|
754
|
+
evidenceAnchors: z.array(z.string()),
|
|
755
|
+
rationale: z.string(),
|
|
756
|
+
uncertainty: z.string().optional(),
|
|
757
|
+
relationships: z.array(z.string()).optional(),
|
|
758
|
+
proposedMarkdown: z.string(),
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
const knowledgeBundleSchema = z.object({
|
|
762
|
+
schema: z.literal('ewai.knowledge-proposal-bundle/v1'),
|
|
763
|
+
sourceRef: z.string(),
|
|
764
|
+
sourceDigest: z.string(),
|
|
765
|
+
proposals: z.array(knowledgeProposalSchema),
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
const knowledgeDispositionSchema = z.object({
|
|
769
|
+
proposalId: z.string(),
|
|
770
|
+
decision: z.enum(['accepted', 'rejected', 'amended', 'deferred']),
|
|
771
|
+
rationale: z.string().optional(),
|
|
772
|
+
replacementTitle: z.string().optional(),
|
|
773
|
+
replacementMarkdown: z.string().optional(),
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
server.registerTool(
|
|
777
|
+
'ewai_knowledge_proposal_sources',
|
|
778
|
+
{
|
|
779
|
+
title: 'List eligible knowledge proposal sources',
|
|
780
|
+
description: 'List allowlisted promoted meeting evidence and canonical retrospectives without returning their body or private path.',
|
|
781
|
+
inputSchema: {},
|
|
782
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
783
|
+
},
|
|
784
|
+
async () => result({ schema: 'ewai.knowledge-source-list/v1', sources: listKnowledgeSources(paths.projectRoot), notices: [KNOWLEDGE_PROPOSALS_DISCLAIMER] }),
|
|
785
|
+
);
|
|
786
|
+
|
|
787
|
+
server.registerTool(
|
|
788
|
+
'ewai_knowledge_proposal_status',
|
|
789
|
+
{
|
|
790
|
+
title: 'Read knowledge proposal status',
|
|
791
|
+
description: 'Read the safe proposal, review, materialisation, conflict and active-persona workspace without source bodies or private paths.',
|
|
792
|
+
inputSchema: { bundleId: z.string().optional() },
|
|
793
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
794
|
+
},
|
|
795
|
+
async ({ bundleId }) => result(readKnowledgeProposalWorkspace(paths.projectRoot, { bundleId })),
|
|
796
|
+
);
|
|
797
|
+
|
|
798
|
+
server.registerTool(
|
|
799
|
+
'ewai_knowledge_proposal_prepare',
|
|
800
|
+
{
|
|
801
|
+
title: 'Prepare persona-led knowledge proposals',
|
|
802
|
+
description: 'Return bounded evidence context, the strict proposal contract and actively engaged project, core and optional installed personas for host-model drafting. This writes no project knowledge.',
|
|
803
|
+
inputSchema: { sourceRef: z.string().min(1), focus: z.string().max(500).optional() },
|
|
804
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
805
|
+
},
|
|
806
|
+
async ({ sourceRef, focus }) => result(prepareKnowledgeProposals(paths.projectRoot, sourceRef, { focus })),
|
|
807
|
+
);
|
|
808
|
+
|
|
809
|
+
server.registerTool(
|
|
810
|
+
'ewai_knowledge_proposal_record',
|
|
811
|
+
{
|
|
812
|
+
title: 'Record a validated knowledge proposal bundle',
|
|
813
|
+
description: 'Validate and record evidence-grounded proposals under the proposal evidence area only. This does not write canonical destination knowledge.',
|
|
814
|
+
inputSchema: { sourceRef: z.string().min(1), bundle: knowledgeBundleSchema, activePersonas: z.array(knowledgePersonaSchema).optional() },
|
|
815
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
816
|
+
},
|
|
817
|
+
async ({ sourceRef, bundle, activePersonas }) => result({
|
|
818
|
+
...recordKnowledgeProposalBundle(paths.projectRoot, sourceRef, { bundle, activePersonas }),
|
|
819
|
+
notices: [KNOWLEDGE_PROPOSALS_DISCLAIMER],
|
|
820
|
+
}),
|
|
821
|
+
);
|
|
822
|
+
|
|
823
|
+
server.registerTool(
|
|
824
|
+
'ewai_knowledge_proposal_review',
|
|
825
|
+
{
|
|
826
|
+
title: 'Record a complete named knowledge proposal review',
|
|
827
|
+
description: 'Record one named disposition for every proposal. Review does not grant materialisation authority.',
|
|
828
|
+
inputSchema: { bundleId: z.string().min(1), reviewedBy: z.string().min(1).max(160), dispositions: z.array(knowledgeDispositionSchema) },
|
|
829
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
830
|
+
},
|
|
831
|
+
async ({ bundleId, ...input }) => result({
|
|
832
|
+
...recordKnowledgeProposalReview(paths.projectRoot, bundleId, input),
|
|
833
|
+
notices: [KNOWLEDGE_PROPOSALS_DISCLAIMER],
|
|
834
|
+
}),
|
|
835
|
+
);
|
|
836
|
+
|
|
837
|
+
server.registerTool(
|
|
838
|
+
'ewai_knowledge_proposal_materialise',
|
|
839
|
+
{
|
|
840
|
+
title: 'Additively materialise reviewed knowledge proposals',
|
|
841
|
+
description: 'After separate exact confirmation and named approval, create absent accepted destinations, recognise identical content and preserve differing files as conflicts.',
|
|
842
|
+
inputSchema: { bundleId: z.string().min(1), confirmed: z.boolean(), approvedBy: z.string().min(1).max(160) },
|
|
843
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
844
|
+
},
|
|
845
|
+
async ({ bundleId, ...input }) => result({
|
|
846
|
+
...materialiseKnowledgeProposals(paths.projectRoot, bundleId, input),
|
|
847
|
+
notices: [KNOWLEDGE_PROPOSALS_DISCLAIMER],
|
|
848
|
+
}),
|
|
849
|
+
);
|
|
850
|
+
|
|
851
|
+
server.registerTool(
|
|
852
|
+
'ewai_knowledge_proposal_recover',
|
|
853
|
+
{
|
|
854
|
+
title: 'Recover an interrupted knowledge materialisation',
|
|
855
|
+
description: 'After exact confirmation, remove only transaction-owned incomplete writes or clean a stale journal after an immutable ledger exists.',
|
|
856
|
+
inputSchema: { bundleId: z.string().min(1), confirmed: z.boolean() },
|
|
857
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
858
|
+
},
|
|
859
|
+
async ({ bundleId, confirmed }) => result({
|
|
860
|
+
...recoverKnowledgeMaterialisation(paths.projectRoot, bundleId, { confirmed }),
|
|
861
|
+
notices: [KNOWLEDGE_PROPOSALS_DISCLAIMER],
|
|
862
|
+
}),
|
|
863
|
+
);
|
|
864
|
+
|
|
865
|
+
server.registerTool(
|
|
866
|
+
'ewai_create_intent',
|
|
867
|
+
{
|
|
868
|
+
title: 'Create a project intent',
|
|
869
|
+
description: 'Create a new project-owned intent in SPECS after the user asks to capture a feature or idea.',
|
|
870
|
+
inputSchema: {
|
|
871
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
872
|
+
domain: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).optional(),
|
|
873
|
+
title: z.string().min(1).optional(),
|
|
874
|
+
deliveryShape: deliveryShapeSchema.optional(),
|
|
875
|
+
delivery_shape: deliveryShapeSchema.optional()
|
|
876
|
+
},
|
|
877
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
878
|
+
},
|
|
879
|
+
async ({ slug, domain = 'general', title = '', deliveryShape = null, delivery_shape = null }) => {
|
|
880
|
+
const intent = createIntent(paths.projectRoot, {
|
|
881
|
+
slug,
|
|
882
|
+
domain,
|
|
883
|
+
title,
|
|
884
|
+
personas: [],
|
|
885
|
+
deliveryShape: deliveryShape ?? delivery_shape,
|
|
886
|
+
});
|
|
887
|
+
syncIntentIndex(paths.projectRoot);
|
|
888
|
+
return result({ intent });
|
|
889
|
+
}
|
|
890
|
+
);
|
|
891
|
+
|
|
892
|
+
server.registerTool(
|
|
893
|
+
'ewai_create_intent_map',
|
|
894
|
+
{
|
|
895
|
+
title: 'Create a reviewed map of connected intents',
|
|
896
|
+
description: 'Atomically create an approved product-level intent map and its linked draft intents after a conversational shaping review.',
|
|
897
|
+
inputSchema: {
|
|
898
|
+
confirmed: z.literal(true),
|
|
899
|
+
approvedBy: z.string().min(1).optional(),
|
|
900
|
+
map: z.object({
|
|
901
|
+
schema: z.literal('ewai.intent-map-request/v1').optional(),
|
|
902
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
903
|
+
title: z.string().min(1),
|
|
904
|
+
idea: z.string().min(1),
|
|
905
|
+
desiredOutcome: z.string().min(1),
|
|
906
|
+
users: z.array(z.string()).optional(),
|
|
907
|
+
evidence: z.array(z.string()).optional(),
|
|
908
|
+
boundaries: z.array(z.string()).optional(),
|
|
909
|
+
nonGoals: z.array(z.string()).optional(),
|
|
910
|
+
assumptions: z.array(z.string()).optional(),
|
|
911
|
+
openQuestions: z.array(z.string()).optional(),
|
|
912
|
+
shapingPersonas: z.array(personaAttachmentSchema).optional(),
|
|
913
|
+
intents: z.array(mappedIntentSchema).min(1),
|
|
914
|
+
}),
|
|
915
|
+
},
|
|
916
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
917
|
+
},
|
|
918
|
+
async ({ confirmed, approvedBy = 'Project owner', map }) => result(
|
|
919
|
+
createIntentMap(paths.projectRoot, map, { confirmed, approvedBy }),
|
|
920
|
+
),
|
|
921
|
+
);
|
|
922
|
+
|
|
923
|
+
server.registerTool(
|
|
924
|
+
'ewai_audit_intent_state',
|
|
925
|
+
{
|
|
926
|
+
title: 'Audit durable intent state',
|
|
927
|
+
description: 'Verify agreement among intent Markdown, adjacent intent JSON, delivery-state JSON, and the rebuildable SQLite projection.',
|
|
928
|
+
inputSchema: {},
|
|
929
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
930
|
+
},
|
|
931
|
+
async () => result(auditIntentStateCopies(paths.projectRoot, { repairMissing: true }))
|
|
932
|
+
);
|
|
933
|
+
|
|
934
|
+
server.registerTool(
|
|
935
|
+
'ewai_runtime_status',
|
|
936
|
+
{
|
|
937
|
+
title: 'Show EWAI runtime status',
|
|
938
|
+
description: 'Show the project runtime, dashboard, database, and MCP project binding.',
|
|
939
|
+
inputSchema: {},
|
|
940
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
941
|
+
},
|
|
942
|
+
async () => result({
|
|
943
|
+
project: { name: config.project.name, root: paths.projectRoot },
|
|
944
|
+
database: paths.runtimeRoot ? `${paths.runtimeRoot}/data/pipeline.sqlite` : '',
|
|
945
|
+
dashboard: await dashboardStatus(paths.projectRoot),
|
|
946
|
+
mcp: { transport: 'stdio', pid: process.pid }
|
|
947
|
+
})
|
|
948
|
+
);
|
|
949
|
+
|
|
950
|
+
server.registerTool(
|
|
951
|
+
'ewai_list_dashboard_handoffs',
|
|
952
|
+
{
|
|
953
|
+
title: 'List intent work selected in the dashboard',
|
|
954
|
+
description: 'List pending dashboard selections that should be continued conversationally through the guarded EWAI delivery skill.',
|
|
955
|
+
inputSchema: {},
|
|
956
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
957
|
+
},
|
|
958
|
+
async () => result({ handoffs: listDashboardHandoffs(paths.projectRoot, { status: 'pending' }) }),
|
|
959
|
+
);
|
|
960
|
+
|
|
961
|
+
server.registerTool(
|
|
962
|
+
'ewai_resolve_dashboard_handoff',
|
|
963
|
+
{
|
|
964
|
+
title: 'Resolve an intent dashboard handoff',
|
|
965
|
+
description: 'Mark a dashboard-selected intent as claimed, completed, or cancelled after the conversational companion has acted on it.',
|
|
966
|
+
inputSchema: {
|
|
967
|
+
id: z.string().uuid(),
|
|
968
|
+
status: z.enum(['claimed', 'completed', 'cancelled']),
|
|
969
|
+
resolvedBy: z.string().optional(),
|
|
970
|
+
notes: z.string().optional(),
|
|
971
|
+
},
|
|
972
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
973
|
+
},
|
|
974
|
+
async ({ id, ...input }) => result({ handoff: resolveDashboardHandoff(paths.projectRoot, id, input) }),
|
|
975
|
+
);
|
|
976
|
+
|
|
977
|
+
server.registerTool(
|
|
978
|
+
'ewai_index_status',
|
|
979
|
+
{
|
|
980
|
+
title: 'Show EWAI repository index status',
|
|
981
|
+
description: 'Show the latest project-local Tree-sitter repository index run and coverage counts.',
|
|
982
|
+
inputSchema: {},
|
|
983
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
984
|
+
},
|
|
985
|
+
async () => result(repositoryIndexStatus(paths.projectRoot))
|
|
986
|
+
);
|
|
987
|
+
|
|
988
|
+
server.registerTool(
|
|
989
|
+
'ewai_index_refresh',
|
|
990
|
+
{
|
|
991
|
+
title: 'Refresh EWAI repository index',
|
|
992
|
+
description: 'Rebuild the project-local Tree-sitter repository graph from repositories configured in SPECS/pipeline.yaml.',
|
|
993
|
+
inputSchema: {},
|
|
994
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
995
|
+
},
|
|
996
|
+
async () => result(refreshRepositoryIndex(paths.projectRoot))
|
|
997
|
+
);
|
|
998
|
+
|
|
999
|
+
server.registerTool(
|
|
1000
|
+
'ewai_index_freshness',
|
|
1001
|
+
{
|
|
1002
|
+
title: 'Check EWAI repository index freshness',
|
|
1003
|
+
description: 'Compare the latest indexed hashes with the current configured repositories.',
|
|
1004
|
+
inputSchema: {},
|
|
1005
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1006
|
+
},
|
|
1007
|
+
async () => result(repositoryIndexFreshness(paths.projectRoot))
|
|
1008
|
+
);
|
|
1009
|
+
|
|
1010
|
+
server.registerTool(
|
|
1011
|
+
'ewai_index_search',
|
|
1012
|
+
{
|
|
1013
|
+
title: 'Search EWAI repository index',
|
|
1014
|
+
description: 'Search indexed project files and symbols before making repository-truth claims.',
|
|
1015
|
+
inputSchema: { query: z.string().min(1), limit: z.number().int().min(1).max(200).optional() },
|
|
1016
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1017
|
+
},
|
|
1018
|
+
async ({ query, limit }) => result(searchRepositoryIndex(paths.projectRoot, query, { limit }))
|
|
1019
|
+
);
|
|
1020
|
+
|
|
1021
|
+
server.registerTool(
|
|
1022
|
+
'ewai_source_map_coverage',
|
|
1023
|
+
{
|
|
1024
|
+
title: 'Read EWAI Repository Source Map coverage',
|
|
1025
|
+
description: 'Read bounded file-outcome, analysis-depth, classification and analyser coverage for the latest Source Map run.',
|
|
1026
|
+
inputSchema: {},
|
|
1027
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1028
|
+
},
|
|
1029
|
+
async () => result(repositorySourceMapCoverage(paths.projectRoot))
|
|
1030
|
+
);
|
|
1031
|
+
|
|
1032
|
+
server.registerTool(
|
|
1033
|
+
'ewai_companion_status',
|
|
1034
|
+
{
|
|
1035
|
+
title: 'Read context-aware EWAI delivery guidance',
|
|
1036
|
+
description: 'Read bounded, ranked delivery guidance, active persona provenance and accountable human routes. This tool is advisory and read-only.',
|
|
1037
|
+
inputSchema: { focus: z.string().max(500).optional() },
|
|
1038
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
1039
|
+
},
|
|
1040
|
+
async ({ focus = '' }) => result(readCompanionGuidance(paths.projectRoot, {
|
|
1041
|
+
focus,
|
|
1042
|
+
personas: portfolioPersonas(),
|
|
1043
|
+
})),
|
|
1044
|
+
);
|
|
1045
|
+
|
|
1046
|
+
server.registerTool(
|
|
1047
|
+
'ewai_portfolio_status',
|
|
1048
|
+
{
|
|
1049
|
+
title: 'Read EWAI project and portfolio status',
|
|
1050
|
+
description: 'Read the bounded portfolio hierarchy, declared dependencies, child evidence, attention routes and active persona provenance. This tool is advisory and read-only.',
|
|
1051
|
+
inputSchema: { focus: z.string().max(500).optional() },
|
|
1052
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
1053
|
+
},
|
|
1054
|
+
async ({ focus = '' }) => result(readPortfolioWorkspace(paths.projectRoot, {
|
|
1055
|
+
focus,
|
|
1056
|
+
personas: portfolioPersonas(),
|
|
1057
|
+
})),
|
|
1058
|
+
);
|
|
1059
|
+
|
|
1060
|
+
server.registerTool(
|
|
1061
|
+
'ewai_rollout_status',
|
|
1062
|
+
{
|
|
1063
|
+
title: 'Read EWAI consultancy and network rollout status',
|
|
1064
|
+
description: 'Read the bounded rollout cohorts, exact Blueprint comparison, structural assurance state, accountable routes and active persona provenance. This tool is advisory and read-only.',
|
|
1065
|
+
inputSchema: {
|
|
1066
|
+
focus: z.string().max(500).optional(),
|
|
1067
|
+
projectId: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).max(100).optional(),
|
|
1068
|
+
},
|
|
1069
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
1070
|
+
},
|
|
1071
|
+
async ({ focus = '', projectId }) => result(readRolloutWorkspace(paths.projectRoot, {
|
|
1072
|
+
focus,
|
|
1073
|
+
...(projectId ? { projectId } : {}),
|
|
1074
|
+
personas: portfolioPersonas(),
|
|
1075
|
+
})),
|
|
1076
|
+
);
|
|
1077
|
+
|
|
1078
|
+
server.registerTool(
|
|
1079
|
+
'ewai_source_map_profiles',
|
|
1080
|
+
{
|
|
1081
|
+
title: 'List EWAI Repository Source Map profiles',
|
|
1082
|
+
description: 'List safe profile provenance and activation metadata without installed-pack paths or executable details.',
|
|
1083
|
+
inputSchema: {
|
|
1084
|
+
sourceKind: z.enum(['core', 'technology', 'stack', 'organisation', 'project']).optional(),
|
|
1085
|
+
analyser: z.enum(['inventory-only', 'text-summary', 'structured-keys', 'tree-sitter',
|
|
1086
|
+
'power-platform-metadata', 'salesforce-metadata']).optional(),
|
|
1087
|
+
limit: z.number().int().min(1).max(200).optional()
|
|
1088
|
+
},
|
|
1089
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1090
|
+
},
|
|
1091
|
+
async (input) => result(repositorySourceMapProfiles(paths.projectRoot, input))
|
|
1092
|
+
);
|
|
1093
|
+
|
|
1094
|
+
server.registerTool(
|
|
1095
|
+
'ewai_source_map_files',
|
|
1096
|
+
{
|
|
1097
|
+
title: 'List EWAI Repository Source Map files',
|
|
1098
|
+
description: 'List bounded repository-relative file outcomes without content, values, fingerprints or absolute roots.',
|
|
1099
|
+
inputSchema: {
|
|
1100
|
+
outcome: z.enum(['analysed', 'inventory_only', 'skipped_sensitive', 'skipped_oversized', 'analysis_failed']).optional(),
|
|
1101
|
+
classification: z.string().min(1).max(100).optional(),
|
|
1102
|
+
profileId: z.string().min(1).max(240).optional(),
|
|
1103
|
+
repository: z.string().min(1).max(160).optional(),
|
|
1104
|
+
query: z.string().max(240).optional(),
|
|
1105
|
+
limit: z.number().int().min(1).max(200).optional()
|
|
1106
|
+
},
|
|
1107
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1108
|
+
},
|
|
1109
|
+
async (input) => result(repositorySourceMapFiles(paths.projectRoot, input))
|
|
1110
|
+
);
|
|
1111
|
+
|
|
1112
|
+
server.registerTool(
|
|
1113
|
+
'ewai_index_graph',
|
|
1114
|
+
{
|
|
1115
|
+
title: 'Read EWAI repository graph',
|
|
1116
|
+
description: 'Read indexed imports and relationships for a concrete repo:path or symbol target.',
|
|
1117
|
+
inputSchema: { target: z.string().min(1), limit: z.number().int().min(1).max(200).optional() },
|
|
1118
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1119
|
+
},
|
|
1120
|
+
async ({ target, limit }) => result(repositoryGraph(paths.projectRoot, target, { limit }))
|
|
1121
|
+
);
|
|
1122
|
+
|
|
1123
|
+
server.registerTool(
|
|
1124
|
+
'ewai_index_truth',
|
|
1125
|
+
{
|
|
1126
|
+
title: 'Assemble repository truth for an intent',
|
|
1127
|
+
description: 'Combine indexed files, symbols, similar capabilities, and applicable standards for one intent slug.',
|
|
1128
|
+
inputSchema: { slug: z.string().min(1), limit: z.number().int().min(1).max(200).optional() },
|
|
1129
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1130
|
+
},
|
|
1131
|
+
async ({ slug, limit }) => result(repositoryTruth(paths.projectRoot, slug, { limit }))
|
|
1132
|
+
);
|
|
1133
|
+
|
|
1134
|
+
server.registerTool(
|
|
1135
|
+
'ewai_index_similar',
|
|
1136
|
+
{
|
|
1137
|
+
title: 'Find similar project capabilities',
|
|
1138
|
+
description: 'Compare durable plan fingerprints to find proven neighbouring capabilities.',
|
|
1139
|
+
inputSchema: { slug: z.string().min(1), limit: z.number().int().min(1).max(100).optional() },
|
|
1140
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1141
|
+
},
|
|
1142
|
+
async ({ slug, limit }) => result(similarRepositoryCapabilities(paths.projectRoot, slug, { limit }))
|
|
1143
|
+
);
|
|
1144
|
+
|
|
1145
|
+
server.registerTool(
|
|
1146
|
+
'ewai_index_standards',
|
|
1147
|
+
{
|
|
1148
|
+
title: 'Find standards for a repository target',
|
|
1149
|
+
description: 'Read standards-applicability evidence for a file, symbol, capability, or target.',
|
|
1150
|
+
inputSchema: { target: z.string().min(1) },
|
|
1151
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1152
|
+
},
|
|
1153
|
+
async ({ target }) => result(repositoryStandards(paths.projectRoot, target))
|
|
1154
|
+
);
|
|
1155
|
+
|
|
1156
|
+
server.registerTool(
|
|
1157
|
+
'ewai_standards_coverage',
|
|
1158
|
+
{
|
|
1159
|
+
title: 'Check delivery standards coverage',
|
|
1160
|
+
description: 'Check plan standards evidence, claim-ledger presence, and repository-index freshness for an intent.',
|
|
1161
|
+
inputSchema: { slug: z.string().min(1) },
|
|
1162
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1163
|
+
},
|
|
1164
|
+
async ({ slug }) => result(repositoryStandardsCoverage(paths.projectRoot, slug))
|
|
1165
|
+
);
|
|
1166
|
+
|
|
1167
|
+
server.registerTool(
|
|
1168
|
+
'ewai_list_work_items',
|
|
1169
|
+
{
|
|
1170
|
+
title: 'List EWAI work items',
|
|
1171
|
+
description: 'List the scalable delivery-board projection with groups, sprint state, phases, progress, and linked artefacts.',
|
|
1172
|
+
inputSchema: {
|
|
1173
|
+
query: z.string().optional(),
|
|
1174
|
+
group: z.string().optional(),
|
|
1175
|
+
lane: z.enum(['backlog', 'ready', 'active', 'qa', 'blocked', 'done']).optional(),
|
|
1176
|
+
sprint: z.enum(['current', 'backlog']).optional()
|
|
1177
|
+
},
|
|
1178
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1179
|
+
},
|
|
1180
|
+
async (input) => result({ items: listWorkItems(paths.projectRoot, input) })
|
|
1181
|
+
);
|
|
1182
|
+
|
|
1183
|
+
server.registerTool(
|
|
1184
|
+
'ewai_read_work_item',
|
|
1185
|
+
{
|
|
1186
|
+
title: 'Read an EWAI work item',
|
|
1187
|
+
description: 'Read one intent together with progress, phases, linked materials, and live activity.',
|
|
1188
|
+
inputSchema: { reference: z.string().min(1) },
|
|
1189
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1190
|
+
},
|
|
1191
|
+
async ({ reference }) => result({ view: readWorkItemView(paths.projectRoot, reference) })
|
|
1192
|
+
);
|
|
1193
|
+
|
|
1194
|
+
server.registerTool(
|
|
1195
|
+
'ewai_validation_status',
|
|
1196
|
+
{
|
|
1197
|
+
title: 'Read EWAI validation policy',
|
|
1198
|
+
description: 'Resolve mandatory standards and per-checkpoint external-validation policy for a specified orchestrator.',
|
|
1199
|
+
inputSchema: {
|
|
1200
|
+
orchestrator: z.enum(['manual', 'claude', 'codex', 'antigravity']).optional(),
|
|
1201
|
+
},
|
|
1202
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
1203
|
+
},
|
|
1204
|
+
async ({ orchestrator = 'manual' }) => result(
|
|
1205
|
+
validationStatus(loadProjectConfig(paths.projectRoot).config, orchestrator),
|
|
1206
|
+
)
|
|
1207
|
+
);
|
|
1208
|
+
|
|
1209
|
+
server.registerTool(
|
|
1210
|
+
'ewai_validation_configure_provider',
|
|
1211
|
+
{
|
|
1212
|
+
title: 'Configure an external validation provider',
|
|
1213
|
+
description: 'Record whether a supported CLI is available and enabled for independent project validation.',
|
|
1214
|
+
inputSchema: {
|
|
1215
|
+
provider: z.enum(['claude', 'codex', 'antigravity']),
|
|
1216
|
+
state: z.enum(['available', 'unavailable']),
|
|
1217
|
+
enabled: z.boolean().optional(),
|
|
1218
|
+
},
|
|
1219
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
1220
|
+
},
|
|
1221
|
+
async ({ provider, state, enabled }) => result(
|
|
1222
|
+
configureExternalValidation(paths.projectRoot, provider, state, enabled),
|
|
1223
|
+
)
|
|
1224
|
+
);
|
|
1225
|
+
|
|
1226
|
+
server.registerTool(
|
|
1227
|
+
'ewai_validation_configure_checkpoint',
|
|
1228
|
+
{
|
|
1229
|
+
title: 'Configure an external validation checkpoint',
|
|
1230
|
+
description: 'Set bounded review/fix cycles, selected validators, breadth, depth, and output size for plan, test-plan, or code validation.',
|
|
1231
|
+
inputSchema: {
|
|
1232
|
+
checkpoint: z.enum(['implementation-plan', 'test-plan', 'code']),
|
|
1233
|
+
enabled: z.boolean().optional(),
|
|
1234
|
+
maxCycles: z.number().int().min(1).max(3).optional(),
|
|
1235
|
+
validators: z.union([
|
|
1236
|
+
z.literal('auto'),
|
|
1237
|
+
z.array(z.enum(['claude', 'codex', 'antigravity'])),
|
|
1238
|
+
]).optional(),
|
|
1239
|
+
breadth: z.enum(['targeted', 'change-set', 'capability', 'system']).optional(),
|
|
1240
|
+
depth: z.enum(['issues-only', 'issues-and-fixes', 'analysis-and-recommendations']).optional(),
|
|
1241
|
+
output: z.enum(['small', 'medium', 'large']).optional(),
|
|
1242
|
+
},
|
|
1243
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
1244
|
+
},
|
|
1245
|
+
async ({ checkpoint, enabled, maxCycles, validators, breadth, depth, output }) => {
|
|
1246
|
+
const update = {
|
|
1247
|
+
...(enabled === undefined ? {} : { enabled }),
|
|
1248
|
+
...(maxCycles === undefined ? {} : { max_cycles: maxCycles }),
|
|
1249
|
+
...(validators === undefined ? {} : { validators }),
|
|
1250
|
+
review: Object.fromEntries(
|
|
1251
|
+
Object.entries({ breadth, depth, output }).filter(([, value]) => value !== undefined),
|
|
1252
|
+
),
|
|
1253
|
+
};
|
|
1254
|
+
if (!Object.keys(update.review).length) delete update.review;
|
|
1255
|
+
return result(configureValidationCheckpoint(paths.projectRoot, checkpoint, update));
|
|
1256
|
+
}
|
|
1257
|
+
);
|
|
1258
|
+
|
|
1259
|
+
server.registerTool(
|
|
1260
|
+
'ewai_update_work_item',
|
|
1261
|
+
{
|
|
1262
|
+
title: 'Update EWAI work state',
|
|
1263
|
+
description: 'Update non-phase operational metadata. Delivery phase, status, and completion are controlled only by the guarded EWAI delivery tools.',
|
|
1264
|
+
inputSchema: {
|
|
1265
|
+
reference: z.string().min(1),
|
|
1266
|
+
priority: z.enum(['P0', 'P1', 'P2', 'P3']).optional(),
|
|
1267
|
+
currentSprint: z.boolean().optional(),
|
|
1268
|
+
blockedBy: z.string().optional(),
|
|
1269
|
+
notes: z.string().optional()
|
|
1270
|
+
},
|
|
1271
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false }
|
|
1272
|
+
},
|
|
1273
|
+
async ({ reference, ...input }) => result({ item: updateWorkItem(paths.projectRoot, reference, input) })
|
|
1274
|
+
);
|
|
1275
|
+
|
|
1276
|
+
server.registerTool(
|
|
1277
|
+
'ewai_delivery_begin',
|
|
1278
|
+
{
|
|
1279
|
+
title: 'Begin canonical EWAI delivery',
|
|
1280
|
+
description: 'Create the durable fourteen-stage delivery contract, JSON state, tracker, context packet, SQLite projection, and active run for an existing intent.',
|
|
1281
|
+
inputSchema: {
|
|
1282
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
1283
|
+
tool: z.string().optional(),
|
|
1284
|
+
ideate: z.boolean().optional(),
|
|
1285
|
+
existingCode: z.boolean().optional(),
|
|
1286
|
+
ui: z.boolean().optional(),
|
|
1287
|
+
mode: z.enum(['normal', 'shelf', 'resume', 'dry-run']).optional(),
|
|
1288
|
+
intensity: z.enum(['full', 'scoped', 'targeted']).optional()
|
|
1289
|
+
},
|
|
1290
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
1291
|
+
},
|
|
1292
|
+
async ({ slug, ...input }) => result(beginDelivery(paths.projectRoot, slug, input))
|
|
1293
|
+
);
|
|
1294
|
+
|
|
1295
|
+
server.registerTool(
|
|
1296
|
+
'ewai_delivery_continue',
|
|
1297
|
+
{
|
|
1298
|
+
title: 'Continue canonical EWAI delivery',
|
|
1299
|
+
description: 'Validate all durable copies and completed evidence, then identify the exact next required phase. Never guesses or skips.',
|
|
1300
|
+
inputSchema: { slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/) },
|
|
1301
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1302
|
+
},
|
|
1303
|
+
async ({ slug }) => result(continueDelivery(paths.projectRoot, slug))
|
|
1304
|
+
);
|
|
1305
|
+
|
|
1306
|
+
server.registerTool(
|
|
1307
|
+
'ewai_delivery_status',
|
|
1308
|
+
{
|
|
1309
|
+
title: 'Read canonical EWAI delivery state',
|
|
1310
|
+
description: 'Read the project-owned durable JSON delivery state for an intent.',
|
|
1311
|
+
inputSchema: { slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/) },
|
|
1312
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1313
|
+
},
|
|
1314
|
+
async ({ slug }) => result(readDeliveryState(paths.projectRoot, slug))
|
|
1315
|
+
);
|
|
1316
|
+
|
|
1317
|
+
server.registerTool(
|
|
1318
|
+
'ewai_delivery_resume',
|
|
1319
|
+
{
|
|
1320
|
+
title: 'Resume shelf-ready EWAI delivery',
|
|
1321
|
+
description: 'Resume a deliberately shelved delivery by activating mandatory FitCheck before Build.',
|
|
1322
|
+
inputSchema: {
|
|
1323
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
1324
|
+
tool: z.string().optional()
|
|
1325
|
+
},
|
|
1326
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
1327
|
+
},
|
|
1328
|
+
async ({ slug, tool }) => result(resumeShelvedDelivery(paths.projectRoot, slug, { tool }))
|
|
1329
|
+
);
|
|
1330
|
+
|
|
1331
|
+
server.registerTool(
|
|
1332
|
+
'ewai_delivery_record_gate',
|
|
1333
|
+
{
|
|
1334
|
+
title: 'Record deterministic phase gate evidence',
|
|
1335
|
+
description: 'Write the structured gate ledger used to prove that a phase may complete.',
|
|
1336
|
+
inputSchema: {
|
|
1337
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
1338
|
+
phase: z.string().min(1),
|
|
1339
|
+
status: z.enum(['pass', 'fail', 'blocked', 'escalated']),
|
|
1340
|
+
honestyCheck: z.object({
|
|
1341
|
+
sourceSectionsEdited: z.boolean(),
|
|
1342
|
+
staleTextRemoved: z.boolean(),
|
|
1343
|
+
noAppendOnlyCorrections: z.boolean(),
|
|
1344
|
+
allCodeClaimsCited: z.boolean(),
|
|
1345
|
+
notes: z.string().optional()
|
|
1346
|
+
}),
|
|
1347
|
+
requiredGates: z.array(z.object({
|
|
1348
|
+
id: z.string().min(1),
|
|
1349
|
+
required: z.boolean().optional(),
|
|
1350
|
+
commandOrSkill: z.string().min(1),
|
|
1351
|
+
outputPath: z.string().optional(),
|
|
1352
|
+
exitStatus: z.union([z.number().int(), z.string()]).optional(),
|
|
1353
|
+
status: z.enum(['pass', 'fail', 'blocked', 'not_applicable']),
|
|
1354
|
+
rationale: z.string().optional()
|
|
1355
|
+
})).min(1),
|
|
1356
|
+
deterministicGateFailures: z.array(z.record(z.string(), z.unknown())).optional()
|
|
1357
|
+
},
|
|
1358
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
1359
|
+
},
|
|
1360
|
+
async ({ slug, phase, ...input }) => result(recordPhaseGate(paths.projectRoot, slug, phase, input))
|
|
1361
|
+
);
|
|
1362
|
+
|
|
1363
|
+
server.registerTool(
|
|
1364
|
+
'ewai_delivery_record_validation_cycle',
|
|
1365
|
+
{
|
|
1366
|
+
title: 'Record an external review and fix cycle',
|
|
1367
|
+
description: 'Hash and record one configured external-validation cycle. Issue outcomes require fix evidence; phase completion requires every selected provider to finish on pass.',
|
|
1368
|
+
inputSchema: {
|
|
1369
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
1370
|
+
phase: z.enum([
|
|
1371
|
+
'validate-external-plan',
|
|
1372
|
+
'validate-external-test-plan',
|
|
1373
|
+
'validate-external-code',
|
|
1374
|
+
]),
|
|
1375
|
+
provider: z.enum(['claude', 'codex', 'antigravity']),
|
|
1376
|
+
outcome: z.enum(['pass', 'issues']),
|
|
1377
|
+
responsePath: z.string().optional(),
|
|
1378
|
+
fixPath: z.string().optional(),
|
|
1379
|
+
notes: z.string().optional(),
|
|
1380
|
+
},
|
|
1381
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
1382
|
+
},
|
|
1383
|
+
async ({ slug, phase, ...input }) => result(
|
|
1384
|
+
recordExternalValidationCycle(paths.projectRoot, slug, phase, input),
|
|
1385
|
+
)
|
|
1386
|
+
);
|
|
1387
|
+
|
|
1388
|
+
server.registerTool(
|
|
1389
|
+
'ewai_delivery_gate_template',
|
|
1390
|
+
{
|
|
1391
|
+
title: 'Read the canonical phase gate template',
|
|
1392
|
+
description: 'Return the exact required gate IDs and schema for one EWAI delivery phase.',
|
|
1393
|
+
inputSchema: { slug: z.string().min(1), phase: z.string().min(1) },
|
|
1394
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1395
|
+
},
|
|
1396
|
+
async ({ slug, phase }) => result(phaseGateTemplate(paths.projectRoot, slug, phase))
|
|
1397
|
+
);
|
|
1398
|
+
|
|
1399
|
+
server.registerTool(
|
|
1400
|
+
'ewai_delivery_required_artefacts',
|
|
1401
|
+
{
|
|
1402
|
+
title: 'List canonical phase artefacts',
|
|
1403
|
+
description: 'List the fixed project-owned files that must exist before one phase may complete.',
|
|
1404
|
+
inputSchema: { slug: z.string().min(1), phase: z.string().min(1) },
|
|
1405
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1406
|
+
},
|
|
1407
|
+
async ({ slug, phase }) => {
|
|
1408
|
+
const state = readDeliveryState(paths.projectRoot, slug);
|
|
1409
|
+
const delivery = deliveryPaths(paths.projectRoot, slug);
|
|
1410
|
+
const tracked = [...state.phases, ...state.adjuncts, ...state.humanGates]
|
|
1411
|
+
.find((candidate) => candidate.id === phase);
|
|
1412
|
+
return result({
|
|
1413
|
+
slug,
|
|
1414
|
+
phase,
|
|
1415
|
+
required: requiredPhaseArtefacts(
|
|
1416
|
+
delivery.deliveryRoot,
|
|
1417
|
+
phase,
|
|
1418
|
+
tracked?.validation?.providers ?? state.providers,
|
|
1419
|
+
tracked?.validation?.cycles ?? [],
|
|
1420
|
+
)
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
);
|
|
1424
|
+
|
|
1425
|
+
server.registerTool(
|
|
1426
|
+
'ewai_delivery_runs',
|
|
1427
|
+
{
|
|
1428
|
+
title: 'List durable EWAI delivery runs',
|
|
1429
|
+
description: 'List command-run records projected from project-owned run JSON files.',
|
|
1430
|
+
inputSchema: { slug: z.string().optional() },
|
|
1431
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1432
|
+
},
|
|
1433
|
+
async ({ slug = '' }) => result({ runs: listCommandRuns(paths.projectRoot, slug) })
|
|
1434
|
+
);
|
|
1435
|
+
|
|
1436
|
+
server.registerTool(
|
|
1437
|
+
'ewai_delivery_mark_stale_runs',
|
|
1438
|
+
{
|
|
1439
|
+
title: 'Mark abandoned delivery runs stale',
|
|
1440
|
+
description: 'Mark running records older than a threshold stale in both durable run JSON and SQLite.',
|
|
1441
|
+
inputSchema: { hours: z.number().int().min(1).max(720).optional(), summary: z.string().optional() },
|
|
1442
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
1443
|
+
},
|
|
1444
|
+
async ({ hours, summary }) => result(markStaleCommandRuns(paths.projectRoot, { hours, summary }))
|
|
1445
|
+
);
|
|
1446
|
+
|
|
1447
|
+
server.registerTool(
|
|
1448
|
+
'ewai_delivery_start_phase',
|
|
1449
|
+
{
|
|
1450
|
+
title: 'Start the next required EWAI phase',
|
|
1451
|
+
description: 'Start only the exact next phase after validating state copies and all completed gate evidence. Build additionally requires human approval.',
|
|
1452
|
+
inputSchema: { slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/), phase: z.string().min(1) },
|
|
1453
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false }
|
|
1454
|
+
},
|
|
1455
|
+
async ({ slug, phase }) => result(startDeliveryPhase(paths.projectRoot, slug, phase))
|
|
1456
|
+
);
|
|
1457
|
+
|
|
1458
|
+
server.registerTool(
|
|
1459
|
+
'ewai_delivery_complete_phase',
|
|
1460
|
+
{
|
|
1461
|
+
title: 'Complete a gated EWAI phase',
|
|
1462
|
+
description: 'Complete the running phase only when its deterministic gate ledger and evidence pass freshness checks.',
|
|
1463
|
+
inputSchema: {
|
|
1464
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
1465
|
+
phase: z.string().min(1),
|
|
1466
|
+
artefactPath: z.string().optional()
|
|
1467
|
+
},
|
|
1468
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false }
|
|
1469
|
+
},
|
|
1470
|
+
async ({ slug, phase, artefactPath }) => result(completeDeliveryPhase(paths.projectRoot, slug, phase, { artefactPath }))
|
|
1471
|
+
);
|
|
1472
|
+
|
|
1473
|
+
const errorReportDescriptionSchema = {
|
|
1474
|
+
capability: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
1475
|
+
errorCode: z.string().regex(/^[A-Z][A-Z0-9-]{2,79}$/),
|
|
1476
|
+
command: z.string().regex(/^ewai(?: [a-z0-9][a-z0-9:-]*){0,4}$/),
|
|
1477
|
+
title: z.string().min(1).max(500),
|
|
1478
|
+
expected: z.string().max(4000).optional().default(''),
|
|
1479
|
+
actual: z.string().max(4000).optional().default(''),
|
|
1480
|
+
reproductionSteps: z.array(z.string().min(1).max(1000)).max(50).optional().default([]),
|
|
1481
|
+
};
|
|
1482
|
+
|
|
1483
|
+
server.registerTool(
|
|
1484
|
+
'ewai_error_report_status',
|
|
1485
|
+
{
|
|
1486
|
+
title: 'Read local EWAI error reports',
|
|
1487
|
+
description: 'Read safe project-local draft, package and receipt state. This never transmits a report.',
|
|
1488
|
+
inputSchema: { status: z.enum(['draft', 'finalised', 'archived']).optional() },
|
|
1489
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
1490
|
+
},
|
|
1491
|
+
async ({ status }) => result(listLocalErrorReports(paths.projectRoot, { status })),
|
|
1492
|
+
);
|
|
1493
|
+
|
|
1494
|
+
server.registerTool(
|
|
1495
|
+
'ewai_error_report_create',
|
|
1496
|
+
{
|
|
1497
|
+
title: 'Create a local EWAI error-report draft',
|
|
1498
|
+
description: 'Create a privacy-bounded draft under the project-local operational folder. This never sends or uploads anything.',
|
|
1499
|
+
inputSchema: errorReportDescriptionSchema,
|
|
1500
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
1501
|
+
},
|
|
1502
|
+
async (input) => result(createLocalErrorReport(paths.projectRoot, {
|
|
1503
|
+
...input,
|
|
1504
|
+
ewaiVersion: packageVersion,
|
|
1505
|
+
nodeVersion: process.versions.node,
|
|
1506
|
+
osClass: ['darwin', 'linux', 'win32'].includes(process.platform) ? process.platform : 'other',
|
|
1507
|
+
installationSource: 'npm',
|
|
1508
|
+
})),
|
|
1509
|
+
);
|
|
1510
|
+
|
|
1511
|
+
server.registerTool(
|
|
1512
|
+
'ewai_error_report_show',
|
|
1513
|
+
{
|
|
1514
|
+
title: 'Inspect one local EWAI error report',
|
|
1515
|
+
description: 'Read the safe report projection and its local provider attempt/receipt ledger.',
|
|
1516
|
+
inputSchema: { reportId: z.string().regex(/^report_[a-z0-9_]{3,80}$/) },
|
|
1517
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
1518
|
+
},
|
|
1519
|
+
async ({ reportId }) => result({ report: readLocalErrorReport(paths.projectRoot, reportId), ...listErrorReportReceipts(paths.projectRoot, reportId) }),
|
|
1520
|
+
);
|
|
1521
|
+
|
|
1522
|
+
server.registerTool(
|
|
1523
|
+
'ewai_error_report_update',
|
|
1524
|
+
{
|
|
1525
|
+
title: 'Update a local EWAI error-report draft',
|
|
1526
|
+
description: 'Update human-authored fields. Updating finalised evidence creates a new local draft revision.',
|
|
1527
|
+
inputSchema: {
|
|
1528
|
+
reportId: z.string().regex(/^report_[a-z0-9_]{3,80}$/),
|
|
1529
|
+
title: z.string().min(1).max(500).optional(), expected: z.string().max(4000).optional(),
|
|
1530
|
+
actual: z.string().max(4000).optional(), reproductionSteps: z.array(z.string().min(1).max(1000)).max(50).optional(),
|
|
1531
|
+
},
|
|
1532
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
1533
|
+
},
|
|
1534
|
+
async ({ reportId, ...changes }) => result(updateLocalErrorReport(paths.projectRoot, reportId, changes)),
|
|
1535
|
+
);
|
|
1536
|
+
|
|
1537
|
+
server.registerTool(
|
|
1538
|
+
'ewai_error_report_finalise',
|
|
1539
|
+
{
|
|
1540
|
+
title: 'Finalise a local EWAI error-report package',
|
|
1541
|
+
description: 'Create an immutable deterministic ZIP and digest locally. Finalisation is not transmission.',
|
|
1542
|
+
inputSchema: { reportId: z.string().regex(/^report_[a-z0-9_]{3,80}$/) },
|
|
1543
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
1544
|
+
},
|
|
1545
|
+
async ({ reportId }) => result(finaliseLocalErrorReport(paths.projectRoot, reportId)),
|
|
1546
|
+
);
|
|
1547
|
+
|
|
1548
|
+
server.registerTool(
|
|
1549
|
+
'ewai_error_report_prepare_email',
|
|
1550
|
+
{
|
|
1551
|
+
title: 'Prepare a manual email handoff',
|
|
1552
|
+
description: 'Prepare a mailto link and reveal reference for the exact ZIP. EWAI cannot attach or send the message.',
|
|
1553
|
+
inputSchema: {
|
|
1554
|
+
reportId: z.string().regex(/^report_[a-z0-9_]{3,80}$/),
|
|
1555
|
+
expectedDigest: z.string().regex(/^sha256:[a-f0-9]{64}$/), recipient: z.string().email().optional(),
|
|
1556
|
+
},
|
|
1557
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
1558
|
+
},
|
|
1559
|
+
async ({ reportId, ...input }) => result(prepareErrorReportEmail(paths.projectRoot, reportId, input)),
|
|
1560
|
+
);
|
|
1561
|
+
|
|
1562
|
+
server.registerTool(
|
|
1563
|
+
'ewai_error_report_providers',
|
|
1564
|
+
{
|
|
1565
|
+
title: 'List registered error-report providers',
|
|
1566
|
+
description: 'List safe metadata for explicitly registered provider adapters. EWAI ships no commercial connector.',
|
|
1567
|
+
inputSchema: {}, annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
1568
|
+
},
|
|
1569
|
+
async () => result(listErrorReportProviders(paths.projectRoot)),
|
|
1570
|
+
);
|
|
1571
|
+
|
|
1572
|
+
server.registerTool(
|
|
1573
|
+
'ewai_error_report_receipts',
|
|
1574
|
+
{
|
|
1575
|
+
title: 'Read error-report handoff receipts',
|
|
1576
|
+
description: 'Read digest-bound local attempts and accepted transport receipts without provider credentials.',
|
|
1577
|
+
inputSchema: { reportId: z.string().regex(/^report_[a-z0-9_]{3,80}$/) },
|
|
1578
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
1579
|
+
},
|
|
1580
|
+
async ({ reportId }) => result(listErrorReportReceipts(paths.projectRoot, reportId)),
|
|
1581
|
+
);
|
|
1582
|
+
|
|
1583
|
+
server.registerTool(
|
|
1584
|
+
'ewai_error_report_send_provider',
|
|
1585
|
+
{
|
|
1586
|
+
title: 'Submit one finalised error report to a registered provider',
|
|
1587
|
+
description: 'Deliberately send the exact confirmed ZIP digest through trusted registered local adapter code. Provider acceptance is transport evidence, not issue resolution.',
|
|
1588
|
+
inputSchema: {
|
|
1589
|
+
reportId: z.string().regex(/^report_[a-z0-9_]{3,80}$/), providerId: z.string().regex(/^[a-z][a-z0-9.-]{1,79}$/),
|
|
1590
|
+
expectedDigest: z.string().regex(/^sha256:[a-f0-9]{64}$/), confirmed: z.literal(true),
|
|
1591
|
+
},
|
|
1592
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
|
|
1593
|
+
},
|
|
1594
|
+
async ({ reportId, providerId, expectedDigest }) => result(await submitErrorReportProvider(paths.projectRoot, reportId, providerId, { confirmed: true, expectedDigest })),
|
|
1595
|
+
);
|
|
1596
|
+
|
|
1597
|
+
server.registerTool(
|
|
1598
|
+
'ewai_error_report_archive',
|
|
1599
|
+
{
|
|
1600
|
+
title: 'Archive local error-report material',
|
|
1601
|
+
description: 'Move local report material into the project-local archive. This does not recall external submissions.',
|
|
1602
|
+
inputSchema: { reportId: z.string().regex(/^report_[a-z0-9_]{3,80}$/), confirmed: z.literal(true) },
|
|
1603
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1604
|
+
},
|
|
1605
|
+
async ({ reportId }) => result(archiveErrorReport(paths.projectRoot, reportId, { confirmed: true })),
|
|
1606
|
+
);
|
|
1607
|
+
|
|
1608
|
+
server.registerTool(
|
|
1609
|
+
'ewai_error_report_delete',
|
|
1610
|
+
{
|
|
1611
|
+
title: 'Delete local error-report material',
|
|
1612
|
+
description: 'Delete only local report/package material after explicit confirmation. Provider receipts remain and no external report is recalled.',
|
|
1613
|
+
inputSchema: { reportId: z.string().regex(/^report_[a-z0-9_]{3,80}$/), confirmed: z.literal(true) },
|
|
1614
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1615
|
+
},
|
|
1616
|
+
async ({ reportId }) => result(deleteErrorReport(paths.projectRoot, reportId, { confirmed: true })),
|
|
1617
|
+
);
|
|
1618
|
+
|
|
1619
|
+
server.registerTool(
|
|
1620
|
+
'ewai_error_report_settings',
|
|
1621
|
+
{
|
|
1622
|
+
title: 'Update local error-report preferences',
|
|
1623
|
+
description: 'Opt into automatic local draft capture or set a support address. This preference can never transmit a report.',
|
|
1624
|
+
inputSchema: { automaticLocalDrafts: z.boolean().optional(), supportEmail: z.string().email().or(z.literal('')).optional() },
|
|
1625
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
1626
|
+
},
|
|
1627
|
+
async (input) => result(updateErrorReportSettings(paths.projectRoot, input)),
|
|
1628
|
+
);
|
|
1629
|
+
|
|
1630
|
+
server.registerTool(
|
|
1631
|
+
'ewai_delivery_approve_build',
|
|
1632
|
+
{
|
|
1633
|
+
title: 'Record human Build approval',
|
|
1634
|
+
description: 'Record the explicit human decision required before EWAI may enter Build. Never call without the user approving Build in this conversation.',
|
|
1635
|
+
inputSchema: {
|
|
1636
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
1637
|
+
confirmed: z.literal(true),
|
|
1638
|
+
approvedBy: z.string().min(1),
|
|
1639
|
+
scope: z.string().optional()
|
|
1640
|
+
},
|
|
1641
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false }
|
|
1642
|
+
},
|
|
1643
|
+
async ({ slug, approvedBy, scope }) => result(recordBuildApproval(paths.projectRoot, slug, {
|
|
1644
|
+
decision: 'approved', approvedBy, scope
|
|
1645
|
+
}))
|
|
1646
|
+
);
|
|
1647
|
+
|
|
1648
|
+
server.registerTool(
|
|
1649
|
+
'ewai_delivery_approve_manual_qa',
|
|
1650
|
+
{
|
|
1651
|
+
title: 'Record human Manual QA approval',
|
|
1652
|
+
description: 'Record the explicit human Manual QA decision and evidence required before Retro.',
|
|
1653
|
+
inputSchema: {
|
|
1654
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
1655
|
+
confirmed: z.literal(true),
|
|
1656
|
+
approvedBy: z.string().min(1),
|
|
1657
|
+
evidencePath: z.string().min(1),
|
|
1658
|
+
notes: z.string().optional()
|
|
1659
|
+
},
|
|
1660
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false }
|
|
1661
|
+
},
|
|
1662
|
+
async ({ slug, approvedBy, evidencePath, notes }) => result(recordManualQaApproval(paths.projectRoot, slug, {
|
|
1663
|
+
decision: 'approved', approvedBy, evidencePath, notes
|
|
1664
|
+
}))
|
|
1665
|
+
);
|
|
1666
|
+
|
|
1667
|
+
server.registerTool(
|
|
1668
|
+
'ewai_add_artefact',
|
|
1669
|
+
{
|
|
1670
|
+
title: 'Link EWAI delivery material',
|
|
1671
|
+
description: 'Register a plan, prototype, test report, decision, or other material against an intent.',
|
|
1672
|
+
inputSchema: {
|
|
1673
|
+
reference: z.string().min(1),
|
|
1674
|
+
kind: z.string().min(1),
|
|
1675
|
+
path: z.string().min(1),
|
|
1676
|
+
title: z.string().optional(),
|
|
1677
|
+
status: z.string().optional()
|
|
1678
|
+
},
|
|
1679
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
1680
|
+
},
|
|
1681
|
+
async ({ reference, ...input }) => result({ artefact: addArtefact(paths.projectRoot, reference, input) })
|
|
1682
|
+
);
|
|
1683
|
+
|
|
1684
|
+
server.registerTool(
|
|
1685
|
+
'ewai_list_active_work',
|
|
1686
|
+
{
|
|
1687
|
+
title: 'List live EWAI work',
|
|
1688
|
+
description: 'List active agent delivery sessions and their latest material events.',
|
|
1689
|
+
inputSchema: { includeCompleted: z.boolean().optional().default(false) },
|
|
1690
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
1691
|
+
},
|
|
1692
|
+
async ({ includeCompleted }) => result({ sessions: listActiveSessions(paths.projectRoot, { includeCompleted }) })
|
|
1693
|
+
);
|
|
1694
|
+
|
|
1695
|
+
const activityInput = {
|
|
1696
|
+
reference: z.string().min(1),
|
|
1697
|
+
ownerId: z.string().optional(),
|
|
1698
|
+
tool: z.string().optional(),
|
|
1699
|
+
phaseKey: z.string().optional(),
|
|
1700
|
+
summary: z.string().min(1),
|
|
1701
|
+
details: z.string().optional()
|
|
1702
|
+
};
|
|
1703
|
+
|
|
1704
|
+
server.registerTool(
|
|
1705
|
+
'ewai_active_start',
|
|
1706
|
+
{
|
|
1707
|
+
title: 'Start live EWAI work',
|
|
1708
|
+
description: 'Mark material delivery work as active so it appears in the live dashboard.',
|
|
1709
|
+
inputSchema: activityInput,
|
|
1710
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
1711
|
+
},
|
|
1712
|
+
async ({ reference, ...input }) => result(startActiveSession(paths.projectRoot, reference, input))
|
|
1713
|
+
);
|
|
1714
|
+
|
|
1715
|
+
server.registerTool(
|
|
1716
|
+
'ewai_active_event',
|
|
1717
|
+
{
|
|
1718
|
+
title: 'Record live EWAI progress',
|
|
1719
|
+
description: 'Record a material progress, handoff, decision, review, blocker, or human-question event.',
|
|
1720
|
+
inputSchema: {
|
|
1721
|
+
...activityInput,
|
|
1722
|
+
eventType: z.enum(['progress', 'handoff', 'external-review', 'decision', 'response', 'blocked', 'question', 'question-resolved', 'stale']).optional(),
|
|
1723
|
+
requiresHuman: z.boolean().optional()
|
|
1724
|
+
},
|
|
1725
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
1726
|
+
},
|
|
1727
|
+
async ({ reference, ...input }) => result(addActivityEvent(paths.projectRoot, reference, input))
|
|
1728
|
+
);
|
|
1729
|
+
|
|
1730
|
+
server.registerTool(
|
|
1731
|
+
'ewai_active_finish',
|
|
1732
|
+
{
|
|
1733
|
+
title: 'Finish live EWAI work',
|
|
1734
|
+
description: 'Close an active delivery session with a material outcome summary.',
|
|
1735
|
+
inputSchema: {
|
|
1736
|
+
...activityInput,
|
|
1737
|
+
status: z.enum(['completed', 'blocked', 'failed', 'stale']).optional()
|
|
1738
|
+
},
|
|
1739
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
1740
|
+
},
|
|
1741
|
+
async ({ reference, ...input }) => result(finishActiveSession(paths.projectRoot, reference, input))
|
|
1742
|
+
);
|
|
1743
|
+
|
|
1744
|
+
server.registerTool(
|
|
1745
|
+
'ewai_list_execution_leases',
|
|
1746
|
+
{
|
|
1747
|
+
title: 'List EWAI execution leases',
|
|
1748
|
+
description: 'List active or historical task ownership leases without exposing lease tokens.',
|
|
1749
|
+
inputSchema: {
|
|
1750
|
+
activeOnly: z.boolean().optional().default(true),
|
|
1751
|
+
workItemId: z.string().optional(),
|
|
1752
|
+
},
|
|
1753
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
1754
|
+
},
|
|
1755
|
+
async (input) => result({ leases: listExecutionLeases(paths.projectRoot, input) }),
|
|
1756
|
+
);
|
|
1757
|
+
|
|
1758
|
+
server.registerTool(
|
|
1759
|
+
'ewai_acquire_execution_lease',
|
|
1760
|
+
{
|
|
1761
|
+
title: 'Acquire an EWAI task execution lease',
|
|
1762
|
+
description: 'Atomically reserve one task for an identified agent run. Refuses conflicting active ownership.',
|
|
1763
|
+
inputSchema: {
|
|
1764
|
+
reference: z.string().min(1),
|
|
1765
|
+
taskId: z.string().regex(/^T-\d{3,}$/),
|
|
1766
|
+
ownerId: z.string().min(1),
|
|
1767
|
+
tool: z.string().optional(),
|
|
1768
|
+
runId: z.string().min(1),
|
|
1769
|
+
durationMs: z.number().int().min(1_000).max(86_400_000).optional(),
|
|
1770
|
+
},
|
|
1771
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
1772
|
+
},
|
|
1773
|
+
async ({ reference, ...input }) => result({ lease: acquireExecutionLease(paths.projectRoot, reference, input) }),
|
|
1774
|
+
);
|
|
1775
|
+
|
|
1776
|
+
server.registerTool(
|
|
1777
|
+
'ewai_heartbeat_execution_lease',
|
|
1778
|
+
{
|
|
1779
|
+
title: 'Renew an EWAI task execution lease',
|
|
1780
|
+
description: 'Extend a task lease using its private capability token.',
|
|
1781
|
+
inputSchema: {
|
|
1782
|
+
leaseId: z.string().uuid(),
|
|
1783
|
+
token: z.string().uuid(),
|
|
1784
|
+
durationMs: z.number().int().min(1_000).max(86_400_000).optional(),
|
|
1785
|
+
},
|
|
1786
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
1787
|
+
},
|
|
1788
|
+
async ({ leaseId, ...input }) => result({ lease: heartbeatExecutionLease(paths.projectRoot, leaseId, input) }),
|
|
1789
|
+
);
|
|
1790
|
+
|
|
1791
|
+
server.registerTool(
|
|
1792
|
+
'ewai_release_execution_lease',
|
|
1793
|
+
{
|
|
1794
|
+
title: 'Release an EWAI task execution lease',
|
|
1795
|
+
description: 'Release or hand off a task lease using its private capability token.',
|
|
1796
|
+
inputSchema: {
|
|
1797
|
+
leaseId: z.string().uuid(),
|
|
1798
|
+
token: z.string().uuid(),
|
|
1799
|
+
outcome: z.enum(['completed', 'handoff', 'blocked', 'failed', 'released']).optional(),
|
|
1800
|
+
},
|
|
1801
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
1802
|
+
},
|
|
1803
|
+
async ({ leaseId, ...input }) => result({ lease: releaseExecutionLease(paths.projectRoot, leaseId, input) }),
|
|
1804
|
+
);
|
|
1805
|
+
|
|
1806
|
+
server.registerTool(
|
|
1807
|
+
'ewai_afk_preflight',
|
|
1808
|
+
{
|
|
1809
|
+
title: 'Check unattended Build readiness',
|
|
1810
|
+
description: 'Deterministically verify the Build gate, task graph, simple or multi-repository topology, branch preparation, provider availability, and safe parallelism before AFK execution.',
|
|
1811
|
+
inputSchema: {
|
|
1812
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
1813
|
+
provider: z.enum(['auto', 'claude', 'codex', 'antigravity']).optional().default('auto'),
|
|
1814
|
+
maxParallel: z.number().int().min(1).optional().default(1),
|
|
1815
|
+
},
|
|
1816
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
1817
|
+
},
|
|
1818
|
+
async ({ slug, ...input }) => result(preflightAfkRun(paths.projectRoot, slug, input)),
|
|
1819
|
+
);
|
|
1820
|
+
|
|
1821
|
+
server.registerTool(
|
|
1822
|
+
'ewai_afk_start',
|
|
1823
|
+
{
|
|
1824
|
+
title: 'Start unattended EWAI Build execution',
|
|
1825
|
+
description: 'Start the bounded local conductor for an already approved Build task graph. Creates required integration/task branches in each configured repository, then uses isolated worktrees, execution leases, fresh-context review, orchestrator-owned merges, and post-merge checks.',
|
|
1826
|
+
inputSchema: {
|
|
1827
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
1828
|
+
provider: z.enum(['auto', 'claude', 'codex', 'antigravity']).optional().default('auto'),
|
|
1829
|
+
maxParallel: z.number().int().min(1).optional().default(1),
|
|
1830
|
+
timeoutMinutes: z.number().int().min(1).max(1440).optional().default(45),
|
|
1831
|
+
},
|
|
1832
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
1833
|
+
},
|
|
1834
|
+
async ({ slug, timeoutMinutes, ...input }) => result(startAfkRun(paths.projectRoot, slug, {
|
|
1835
|
+
...input,
|
|
1836
|
+
timeoutMs: timeoutMinutes * 60 * 1000,
|
|
1837
|
+
})),
|
|
1838
|
+
);
|
|
1839
|
+
|
|
1840
|
+
server.registerTool(
|
|
1841
|
+
'ewai_afk_status',
|
|
1842
|
+
{
|
|
1843
|
+
title: 'Read unattended Build status',
|
|
1844
|
+
description: 'Read one durable AFK run or list all runs without exposing private lease tokens.',
|
|
1845
|
+
inputSchema: { runId: z.string().uuid().optional() },
|
|
1846
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
1847
|
+
},
|
|
1848
|
+
async ({ runId }) => result(afkRunStatus(paths.projectRoot, runId)),
|
|
1849
|
+
);
|
|
1850
|
+
|
|
1851
|
+
server.registerTool(
|
|
1852
|
+
'ewai_afk_pause',
|
|
1853
|
+
{
|
|
1854
|
+
title: 'Safely pause unattended Build',
|
|
1855
|
+
description: 'Request a safe pause after the currently active task wave finishes and before another task is leased.',
|
|
1856
|
+
inputSchema: { runId: z.string().uuid() },
|
|
1857
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
1858
|
+
},
|
|
1859
|
+
async ({ runId }) => result(pauseAfkRun(paths.projectRoot, runId)),
|
|
1860
|
+
);
|
|
1861
|
+
|
|
1862
|
+
server.registerTool(
|
|
1863
|
+
'ewai_afk_resume',
|
|
1864
|
+
{
|
|
1865
|
+
title: 'Resume or recover unattended Build',
|
|
1866
|
+
description: 'Resume a paused or blocked local conductor, safely abandoning stale leases from the previous process before revalidation.',
|
|
1867
|
+
inputSchema: { runId: z.string().uuid() },
|
|
1868
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
1869
|
+
},
|
|
1870
|
+
async ({ runId }) => result(resumeAfkRun(paths.projectRoot, runId)),
|
|
1871
|
+
);
|
|
1872
|
+
|
|
1873
|
+
server.registerTool(
|
|
1874
|
+
'ewai_afk_cancel',
|
|
1875
|
+
{
|
|
1876
|
+
title: 'Cancel unattended Build',
|
|
1877
|
+
description: 'Stop active workers, abandon this run’s leases, and preserve its logs and durable state for diagnosis.',
|
|
1878
|
+
inputSchema: { runId: z.string().uuid() },
|
|
1879
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
1880
|
+
},
|
|
1881
|
+
async ({ runId }) => result(cancelAfkRun(paths.projectRoot, runId)),
|
|
1882
|
+
);
|
|
1883
|
+
|
|
1884
|
+
const transport = new StdioServerTransport();
|
|
1885
|
+
await server.connect(transport);
|