agentera 3.0.0-dev.8 → 3.0.0-dev.80
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/LICENSE +201 -0
- package/README.md +252 -22
- package/bundle/.agentera-build-source.json +8 -0
- package/bundle/CHANGELOG.md +1387 -0
- package/bundle/DESIGN.md +229 -0
- package/bundle/LICENSE +201 -0
- package/bundle/README.md +143 -0
- package/bundle/UPGRADE.md +271 -0
- package/bundle/extract-corpus-parity.json +2 -4
- package/bundle/fixtures/routing/hybrid-corpus.yaml +154 -0
- package/bundle/references/adapters/package-publication.json +484 -0
- package/bundle/references/adapters/package-registry.yaml +443 -188
- package/bundle/references/adapters/package-surface-characterization.md +68 -34
- package/bundle/references/adapters/product-v1-reset.yaml +101 -0
- package/bundle/references/adapters/runtime-lifecycle-adapters.yaml +74 -0
- package/bundle/references/adapters/runtime-lifecycle-authority.yaml +62 -0
- package/bundle/references/adapters/runtime-lifecycle-operation-contract.yaml +84 -0
- package/bundle/references/adapters/runtime-retired-resources.yaml +333 -0
- package/bundle/references/analysis/evidence-tier-authority.yaml +559 -0
- package/bundle/references/analysis/personal-glossary-evaluation-authority.yaml +175 -0
- package/bundle/references/analysis/personal-glossary-evaluation-corpus.yaml +291 -0
- package/bundle/references/analysis/personal-glossary-holdout.yaml +192 -0
- package/bundle/references/analysis/verification-policy.yaml +261 -0
- package/bundle/references/artifacts/artifact-registry-interface-model.yaml +17 -8
- package/bundle/references/artifacts/glossary-entry-contract.yaml +2906 -0
- package/bundle/references/artifacts/state-storage-authority.yaml +3065 -0
- package/bundle/references/artifacts/verbosity-budget-authority.yaml +42 -0
- package/bundle/references/cli/app-lifecycle-vocabulary.yaml +3 -4
- package/bundle/references/cli/capability-instruction-contract.yaml +11 -14
- package/bundle/references/cli/hybrid-route-contract.yaml +438 -0
- package/bundle/references/cli/routing-model.md +152 -93
- package/bundle/references/cli/trigger-schema-enrichment.md +57 -46
- package/bundle/references/cli/update-channels.yaml +7 -5
- package/bundle/references/cli/vocabulary-index.yaml +7 -9
- package/bundle/references/cli/vocabulary.md +54 -97
- package/bundle/references/meta/retained-reference-authority.yaml +171 -0
- package/bundle/skills/agentera/SKILL.md +183 -63
- package/bundle/skills/agentera/capabilities/audit/schemas/artifacts.yaml +27 -19
- package/bundle/skills/agentera/capabilities/audit/schemas/exit.yaml +2 -2
- package/bundle/skills/agentera/capabilities/audit/schemas/triggers.yaml +13 -35
- package/bundle/skills/agentera/capabilities/audit/schemas/validation.yaml +30 -11
- package/bundle/skills/agentera/capabilities/build/schemas/artifacts.yaml +44 -21
- package/bundle/skills/agentera/capabilities/build/schemas/exit.yaml +8 -6
- package/bundle/skills/agentera/capabilities/build/schemas/triggers.yaml +14 -36
- package/bundle/skills/agentera/capabilities/build/schemas/validation.yaml +95 -21
- package/bundle/skills/agentera/capabilities/design/schemas/artifacts.yaml +6 -6
- package/bundle/skills/agentera/capabilities/design/schemas/exit.yaml +5 -5
- package/bundle/skills/agentera/capabilities/design/schemas/triggers.yaml +5 -34
- package/bundle/skills/agentera/capabilities/design/schemas/validation.yaml +2 -2
- package/bundle/skills/agentera/capabilities/discuss/schemas/artifacts.yaml +17 -13
- package/bundle/skills/agentera/capabilities/discuss/schemas/exit.yaml +2 -2
- package/bundle/skills/agentera/capabilities/discuss/schemas/triggers.yaml +6 -40
- package/bundle/skills/agentera/capabilities/discuss/schemas/validation.yaml +72 -5
- package/bundle/skills/agentera/capabilities/document/schemas/artifacts.yaml +24 -17
- package/bundle/skills/agentera/capabilities/document/schemas/triggers.yaml +5 -35
- package/bundle/skills/agentera/capabilities/document/schemas/validation.yaml +13 -13
- package/bundle/skills/agentera/capabilities/optimize/schemas/artifacts.yaml +10 -10
- package/bundle/skills/agentera/capabilities/optimize/schemas/exit.yaml +2 -2
- package/bundle/skills/agentera/capabilities/optimize/schemas/triggers.yaml +4 -35
- package/bundle/skills/agentera/capabilities/optimize/schemas/validation.yaml +3 -3
- package/bundle/skills/agentera/capabilities/orchestrate/schemas/artifacts.yaml +34 -22
- package/bundle/skills/agentera/capabilities/orchestrate/schemas/exit.yaml +9 -7
- package/bundle/skills/agentera/capabilities/orchestrate/schemas/triggers.yaml +5 -37
- package/bundle/skills/agentera/capabilities/orchestrate/schemas/validation.yaml +38 -37
- package/bundle/skills/agentera/capabilities/plan/schemas/artifacts.yaml +20 -16
- package/bundle/skills/agentera/capabilities/plan/schemas/triggers.yaml +8 -31
- package/bundle/skills/agentera/capabilities/plan/schemas/validation.yaml +66 -6
- package/bundle/skills/agentera/capabilities/profile/schemas/artifacts.yaml +13 -4
- package/bundle/skills/agentera/capabilities/profile/schemas/exit.yaml +8 -5
- package/bundle/skills/agentera/capabilities/profile/schemas/triggers.yaml +8 -37
- package/bundle/skills/agentera/capabilities/profile/schemas/validation.yaml +67 -3
- package/bundle/skills/agentera/capabilities/research/schemas/artifacts.yaml +6 -6
- package/bundle/skills/agentera/capabilities/research/schemas/triggers.yaml +5 -29
- package/bundle/skills/agentera/capabilities/status/schemas/artifacts.yaml +13 -12
- package/bundle/skills/agentera/capabilities/status/schemas/triggers.yaml +7 -49
- package/bundle/skills/agentera/capabilities/vision/schemas/artifacts.yaml +8 -8
- package/bundle/skills/agentera/capabilities/vision/schemas/exit.yaml +7 -6
- package/bundle/skills/agentera/capabilities/vision/schemas/triggers.yaml +7 -39
- package/bundle/skills/agentera/capabilities/vision/schemas/validation.yaml +14 -16
- package/bundle/skills/agentera/capability_schema_contract.yaml +32 -32
- package/bundle/skills/agentera/protocol.yaml +4 -4
- package/bundle/skills/agentera/route-phrases.yaml +81 -0
- package/bundle/skills/agentera/schemas/artifacts/changelog.yaml +1 -0
- package/bundle/skills/agentera/schemas/artifacts/decisions.yaml +29 -30
- package/bundle/skills/agentera/schemas/artifacts/design.yaml +1 -0
- package/bundle/skills/agentera/schemas/artifacts/docs.yaml +7 -43
- package/bundle/skills/agentera/schemas/artifacts/experiments.yaml +140 -34
- package/bundle/skills/agentera/schemas/artifacts/glossary.yaml +87 -0
- package/bundle/skills/agentera/schemas/artifacts/health.yaml +53 -51
- package/bundle/skills/agentera/schemas/artifacts/objective.yaml +18 -35
- package/bundle/skills/agentera/schemas/artifacts/plan.yaml +453 -55
- package/bundle/skills/agentera/schemas/artifacts/progress.yaml +128 -39
- package/bundle/skills/agentera/schemas/artifacts/todo.yaml +305 -7
- package/bundle/skills/agentera/schemas/artifacts/vision.yaml +0 -19
- package/dist/.agentera-build-source.json +8 -0
- package/dist/analytics/extractCorpus/cli.js +52 -11
- package/dist/analytics/extractCorpus/copilotSessions.js +19 -8
- package/dist/analytics/extractCorpus/core.js +262 -14
- package/dist/analytics/extractCorpus/corpus.js +57 -18
- package/dist/analytics/extractCorpus/coverageAudit.js +44 -45
- package/dist/analytics/extractCorpus/cursorSessions.js +28 -8
- package/dist/analytics/extractCorpus/evidenceTiers.js +709 -0
- package/dist/analytics/extractCorpus/extractCorpusParity.js +4 -4
- package/dist/analytics/extractCorpus/filesystemSources.js +5 -5
- package/dist/analytics/extractCorpus/index.js +4 -2
- package/dist/analytics/extractCorpus/jsonlSessions.js +76 -8
- package/dist/analytics/extractCorpus/sqliteCaps.js +0 -1
- package/dist/analytics/extractCorpus/sqliteSessions.js +12 -4
- package/dist/analytics/extractCorpus/tierReader.js +108 -0
- package/dist/analytics/extractCorpus.js +0 -1
- package/dist/analytics/glossaryAdviceResolution.js +166 -0
- package/dist/analytics/glossaryInputAcquisition.js +319 -0
- package/dist/analytics/personalGlossaryAdmission.js +113 -0
- package/dist/analytics/personalGlossaryCandidateProjection.js +788 -0
- package/dist/analytics/personalGlossaryCandidateProjectionExcerpts.js +144 -0
- package/dist/analytics/personalGlossaryCandidateProjectionModel.js +1 -0
- package/dist/analytics/personalGlossaryCandidateReadView.js +23 -0
- package/dist/analytics/personalGlossaryCurrentGeneration.js +25 -0
- package/dist/analytics/personalGlossaryDecision.js +203 -0
- package/dist/analytics/personalGlossaryExplicit.js +788 -0
- package/dist/analytics/personalGlossaryExplicitMining.js +285 -0
- package/dist/analytics/personalGlossaryExplicitScope.js +41 -0
- package/dist/analytics/personalGlossaryExplicitSegments.js +418 -0
- package/dist/analytics/personalGlossaryExplicitTypes.js +26 -0
- package/dist/analytics/personalGlossaryLexicalClassifier.js +175 -0
- package/dist/analytics/personalGlossaryProfile.js +229 -0
- package/dist/analytics/personalGlossaryRecurrence.js +618 -0
- package/dist/analytics/personalGlossaryRefreshProjection.js +351 -0
- package/dist/analytics/personalGlossaryReviewRecordStorage.js +428 -0
- package/dist/analytics/personalGlossaryReviewRecords.js +332 -0
- package/dist/analytics/profileSignals.js +211 -0
- package/dist/analytics/usageStats.js +150 -23
- package/dist/audit/terminologyDrift.js +281 -0
- package/dist/bin/agentera.js +3 -2
- package/dist/capabilities/audit/instructions.js +16 -6
- package/dist/capabilities/build/instructions.js +59 -6
- package/dist/capabilities/design/instructions.js +3 -4
- package/dist/capabilities/discuss/instructions.js +29 -6
- package/dist/capabilities/document/instructions.js +11 -6
- package/dist/capabilities/index.js +20 -14
- package/dist/capabilities/optimize/instructions.js +14 -6
- package/dist/capabilities/orchestrate/instructions.js +42 -6
- package/dist/capabilities/plan/instructions.js +30 -3
- package/dist/capabilities/profile/instructions.js +104 -5
- package/dist/capabilities/research/instructions.js +4 -5
- package/dist/capabilities/status/instructions.js +15 -6
- package/dist/capabilities/status/startupInstructions.js +34 -0
- package/dist/capabilities/vision/instructions.js +3 -5
- package/dist/cli/appContext.js +14 -7
- package/dist/cli/argvalidate.js +0 -1
- package/dist/cli/capabilityContext/benchmark.js +5 -4
- package/dist/cli/capabilityContext/bespoke.js +14 -6
- package/dist/cli/capabilityContext/build.js +116 -42
- package/dist/cli/capabilityContext/closeout.js +30 -27
- package/dist/cli/capabilityContext/contract.js +18 -27
- package/dist/cli/capabilityContext/evidence.js +84 -77
- package/dist/cli/capabilityContext/index.js +0 -1
- package/dist/cli/capabilityContext/orchestration.js +42 -18
- package/dist/cli/capabilityContext/planState.js +89 -96
- package/dist/cli/capabilityContext/progress.js +52 -12
- package/dist/cli/capabilityContext/projectVerification.js +409 -0
- package/dist/cli/capabilityContext/shared.js +9 -20
- package/dist/cli/capabilityContext/slim.js +52 -8
- package/dist/cli/capabilityContext/startup.js +51 -114
- package/dist/cli/capabilityContext/startupAggregation.js +68 -0
- package/dist/cli/capabilityContext/types.js +26 -10
- package/dist/cli/capabilityContext.js +0 -1
- package/dist/cli/commands/appHome.js +0 -1
- package/dist/cli/commands/capability.js +2 -2
- package/dist/cli/commands/compact.js +163 -13
- package/dist/cli/commands/doctor.js +118 -11
- package/dist/cli/commands/durability.js +81 -0
- package/dist/cli/commands/glossaryAdvice.js +138 -0
- package/dist/cli/commands/lint.js +22 -8
- package/dist/cli/commands/personalGlossaryCandidateReads.js +755 -0
- package/dist/cli/commands/personalGlossaryDecision.js +349 -0
- package/dist/cli/commands/personalGlossaryPublish.js +484 -0
- package/dist/cli/commands/personalGlossaryReviewRecordReads.js +209 -0
- package/dist/cli/commands/personalGlossaryReviewRecords.js +623 -0
- package/dist/cli/commands/prime/briefOrientation.js +845 -0
- package/dist/cli/commands/prime/buildExecutionRequest.js +165 -0
- package/dist/cli/commands/prime/bundleStatus.js +54 -4
- package/dist/cli/commands/prime/collectEntityOrientation.js +338 -0
- package/dist/cli/commands/prime/collectOrientationState.js +124 -68
- package/dist/cli/commands/prime/orientationOutput.js +271 -59
- package/dist/cli/commands/prime/types.js +0 -1
- package/dist/cli/commands/prime.js +89 -11
- package/dist/cli/commands/profileGrounding.js +55 -0
- package/dist/cli/commands/query.js +74 -52
- package/dist/cli/commands/report.js +187 -27
- package/dist/cli/commands/route.js +142 -0
- package/dist/cli/commands/schema.js +436 -138
- package/dist/cli/commands/state/decisions.js +40 -56
- package/dist/cli/commands/state/docs.js +58 -85
- package/dist/cli/commands/state/experimentRecords.js +151 -0
- package/dist/cli/commands/state/experiments.js +11 -65
- package/dist/cli/commands/state/get.js +129 -0
- package/dist/cli/commands/state/health.js +11 -113
- package/dist/cli/commands/state/index.js +6 -41
- package/dist/cli/commands/state/list.js +194 -0
- package/dist/cli/commands/state/objective.js +21 -65
- package/dist/cli/commands/state/plan.js +11 -170
- package/dist/cli/commands/state/planTasks.js +154 -0
- package/dist/cli/commands/state/plans.js +154 -0
- package/dist/cli/commands/state/progress.js +11 -45
- package/dist/cli/commands/state/shared.js +0 -1
- package/dist/cli/commands/state/todo.js +28 -107
- package/dist/cli/commands/state/write.js +459 -0
- package/dist/cli/commands/upgrade.js +176 -5
- package/dist/cli/commands/upgradeVerify.js +118 -0
- package/dist/cli/commands/validate.js +235 -136
- package/dist/cli/commands/verify.js +73 -16
- package/dist/cli/contracts/bundleStatus.js +0 -1
- package/dist/cli/contracts/orientationState.js +0 -1
- package/dist/cli/dispatch/argvParser.js +0 -1
- package/dist/cli/dispatch/check.js +84 -40
- package/dist/cli/dispatch/commands.js +3 -3
- package/dist/cli/dispatch/index.js +84 -52
- package/dist/cli/dispatch/lifecycle.js +182 -62
- package/dist/cli/dispatch/prime.js +37 -2
- package/dist/cli/dispatch/projections.js +17 -0
- package/dist/cli/dispatch/shared.js +1 -2
- package/dist/cli/dispatch/state.js +62 -66
- package/dist/cli/dispatch.js +0 -1
- package/dist/cli/errors.js +16 -17
- package/dist/cli/help.js +419 -41
- package/dist/cli/migrationRequired.js +125 -0
- package/dist/cli/orientation/attention.js +19 -22
- package/dist/cli/orientation/corpusCoverage.js +32 -1
- package/dist/cli/orientation.js +346 -129
- package/dist/cli/planArtifacts.js +350 -0
- package/dist/cli/planEvidence.js +157 -0
- package/dist/cli/planLifecycleState.js +36 -0
- package/dist/cli/planTaskIndex.js +11 -0
- package/dist/cli/preCutoverCommand.js +32 -0
- package/dist/cli/prime-blob.js +71 -3
- package/dist/cli/productV1Eol.js +55 -0
- package/dist/cli/profileAcquisition.js +167 -0
- package/dist/cli/startupCompletenessContract.js +11 -9
- package/dist/cli/stateQuery.js +47 -12
- package/dist/cli/structured.js +0 -1
- package/dist/cli/todoMarkdown.js +25 -12
- package/dist/cli/todoReadinessSelection.js +192 -0
- package/dist/cli/todoSeverity.js +0 -1
- package/dist/core/atomicWriter.js +23 -0
- package/dist/core/developmentChannel.js +1 -0
- package/dist/core/developmentInvocation.js +377 -0
- package/dist/core/difflib.js +0 -1
- package/dist/core/envPaths.js +0 -1
- package/dist/core/jsonValue.js +0 -1
- package/dist/core/paths.js +0 -1
- package/dist/core/pyjson.js +0 -1
- package/dist/core/shell.js +4 -0
- package/dist/core/skillIdentity.js +23 -0
- package/dist/core/sourceRoot.js +9 -12
- package/dist/core/text.js +10 -0
- package/dist/core/toml.js +0 -1
- package/dist/core/yaml.js +61 -2
- package/dist/eval/evalSkills.js +13 -14
- package/dist/eval/glossaryEvaluation.js +751 -0
- package/dist/eval/glossaryEvaluationProcess.js +29 -0
- package/dist/eval/glossaryEvaluationRunner.js +571 -0
- package/dist/eval/glossaryEvaluationSuccessReport.js +297 -0
- package/dist/eval/hybridRouteEvaluation.js +155 -0
- package/dist/eval/semanticEval.js +0 -1
- package/dist/eval/semanticFixtures.js +0 -1
- package/dist/hooks/common.js +3 -56
- package/dist/hooks/compaction/apply.js +224 -47
- package/dist/hooks/compaction/dryRun.js +2 -1
- package/dist/hooks/compaction/index.js +5 -6
- package/dist/hooks/compaction/parse.js +73 -6
- package/dist/hooks/compaction/retention.js +28 -25
- package/dist/hooks/compaction/status.js +145 -26
- package/dist/hooks/compaction/types.js +0 -1
- package/dist/hooks/validateArtifact/agentFacing.js +0 -1
- package/dist/hooks/validateArtifact/index.js +6 -65
- package/dist/hooks/validateArtifact/markdown.js +9 -10
- package/dist/hooks/validateArtifact/schema.js +96 -9
- package/dist/hooks/validateArtifact/traversal.js +12 -11
- package/dist/hooks/validateArtifact/violations.js +5 -3
- package/dist/migrate/v2HandoffManifest.js +8 -3
- package/dist/registries/activationContract.js +2 -0
- package/dist/registries/activationTuples.js +145 -0
- package/dist/registries/artifactProtocolIds.js +2 -1
- package/dist/registries/artifactRegistry.js +207 -60
- package/dist/registries/artifactSchemaProjection.js +45 -0
- package/dist/registries/capabilityContract.js +5 -21
- package/dist/registries/evaluatorHandoffContract.js +0 -1
- package/dist/registries/evidenceTierContract.js +375 -0
- package/dist/registries/explicitSegmentGrammarContract.js +619 -0
- package/dist/registries/glossaryAdviceContract.js +79 -0
- package/dist/registries/glossaryCandidateContractPaths.js +6 -0
- package/dist/registries/glossaryCandidateContracts.js +820 -0
- package/dist/registries/glossaryCandidateDecisionAuthority.js +119 -0
- package/dist/registries/glossaryCandidateDecisionContract.js +62 -0
- package/dist/registries/glossaryCandidateProjectionAuthority.js +345 -0
- package/dist/registries/glossaryCandidateProjectionContract.js +108 -0
- package/dist/registries/glossaryCaveatContract.js +67 -0
- package/dist/registries/glossaryConsumerContractValidation.js +787 -0
- package/dist/registries/glossaryEntryContract.js +759 -0
- package/dist/registries/glossaryEntryTemporal.js +12 -0
- package/dist/registries/glossaryMiningAuthority.js +764 -0
- package/dist/registries/glossaryProfileFullContract.js +24 -0
- package/dist/registries/glossaryReviewRecordsAuthority.js +426 -0
- package/dist/registries/glossaryReviewRecordsContract.js +129 -0
- package/dist/registries/glossaryTermIdentity.js +139 -0
- package/dist/registries/glossaryTermOccurrence.js +20 -0
- package/dist/registries/hybridRoute.js +274 -0
- package/dist/registries/hybridRouteReceipt.js +221 -0
- package/dist/registries/packagePublication.js +273 -0
- package/dist/registries/packageRegistry.js +184 -209
- package/dist/registries/personalGlossaryContracts.js +1 -0
- package/dist/registries/todoReadinessContract.js +448 -0
- package/dist/registries/triggerLoader.js +7 -44
- package/dist/registries/verbosityBudgetContract.js +205 -0
- package/dist/release/releaseMetadata.js +168 -11
- package/dist/runtime/lifecycleAdapterContract.js +457 -0
- package/dist/runtime/lifecycleAdapters.js +777 -0
- package/dist/runtime/lifecycleAuthority.js +453 -0
- package/dist/runtime/lifecycleOperationContract.js +123 -0
- package/dist/runtime/lifecycleOperations.js +634 -0
- package/dist/runtime/lifecycleOwnershipJournal.js +622 -0
- package/dist/runtime/lifecyclePublication.js +415 -0
- package/dist/runtime/lifecycleSnapshot.js +438 -0
- package/dist/runtime/nativeResourceCleanup.js +503 -0
- package/dist/setup/opencode.js +20 -13
- package/dist/setup/opencodeConstants.js +1 -0
- package/dist/setup/sharedSkill.js +45 -0
- package/dist/setup/smokeChecks.js +14 -75
- package/dist/state/archiveDiscovery.js +580 -0
- package/dist/state/archivePublication.js +225 -0
- package/dist/state/archiveRecovery.js +237 -0
- package/dist/state/archiveReplay.js +53 -0
- package/dist/state/canonicalMigrationRecord.js +36 -0
- package/dist/state/changelog.js +221 -0
- package/dist/state/decisionEntities.js +367 -0
- package/dist/state/decisionLegacyValidation.js +215 -0
- package/dist/state/decisionMigrationProvenance.js +199 -0
- package/dist/state/decisionOverlay.js +254 -0
- package/dist/state/decisionRevision.js +256 -0
- package/dist/state/decisionRevisionMigration.js +89 -0
- package/dist/state/directRetrieval.js +323 -0
- package/dist/state/durability.js +324 -0
- package/dist/state/entityCutover.js +459 -0
- package/dist/state/entityCutoverGit.js +127 -0
- package/dist/state/entityGlossaryAuthority.js +13 -0
- package/dist/state/entityListProjection.js +187 -0
- package/dist/state/entityListRuntimeRegistry.js +85 -0
- package/dist/state/entityMigrationCausality.js +97 -0
- package/dist/state/entityMigrationIdentity.js +5 -0
- package/dist/state/entityMigrationPreview.js +840 -0
- package/dist/state/entityMigrationTodo.js +133 -0
- package/dist/state/entityPublicationContext.js +859 -0
- package/dist/state/entityRetrievalHelp.js +506 -0
- package/dist/state/entityStorage.js +899 -0
- package/dist/state/exactReplacementRecovery.js +18 -0
- package/dist/state/experimentArchive.js +63 -0
- package/dist/state/experimentIdentity.js +202 -0
- package/dist/state/healthEntities.js +262 -0
- package/dist/state/healthEntityValidation.js +18 -0
- package/dist/state/healthRepair.js +69 -0
- package/dist/state/installRoot.js +15 -7
- package/dist/state/legacyEntityCutoverEvidence.js +65 -0
- package/dist/state/legacyIdentity.js +47 -0
- package/dist/state/legacySummaryRecord.js +6 -0
- package/dist/state/listAccounting.js +54 -0
- package/dist/state/listClassification.js +17 -0
- package/dist/state/listCursor.js +42 -0
- package/dist/state/listRetrieval.js +781 -0
- package/dist/state/migrationSourceBinding.js +30 -0
- package/dist/state/objectiveExperimentEntities.js +322 -0
- package/dist/state/planEntities.js +1027 -0
- package/dist/state/planIdentity.js +47 -0
- package/dist/state/planLineageValidation.js +52 -0
- package/dist/state/planReplacementTransaction.js +475 -0
- package/dist/state/planRetrieval.js +313 -0
- package/dist/state/planTaskRetrieval.js +294 -0
- package/dist/state/progressEntities.js +512 -0
- package/dist/state/progressGlossaryCaveat.js +168 -0
- package/dist/state/progressPublicationOrder.js +19 -0
- package/dist/state/progressWritePolicy.js +33 -0
- package/dist/state/projectRoot.js +62 -0
- package/dist/state/projectionPolicy.js +190 -0
- package/dist/state/retrievalAuthority.js +156 -0
- package/dist/state/safeProjectFile.js +155 -0
- package/dist/state/startupAnalysis/benchmark.js +70 -9
- package/dist/state/startupAnalysis/contract.js +44 -10
- package/dist/state/startupAnalysis/helpers.js +1 -2
- package/dist/state/startupAnalysis/index.js +0 -1
- package/dist/state/startupAnalysis/metrics.js +0 -1
- package/dist/state/startupAnalysis/records.js +0 -1
- package/dist/state/startupAnalysis/report.js +0 -1
- package/dist/state/startupAnalysis/threshold.js +13 -1
- package/dist/state/startupAnalysis.js +0 -1
- package/dist/state/startupProjection.js +499 -0
- package/dist/state/stateMode.js +222 -0
- package/dist/state/stateStorageAuthority.js +47 -0
- package/dist/state/summaryEntityRead.js +25 -0
- package/dist/state/summaryMigrationProvenance.js +66 -0
- package/dist/state/summarySourceRowAuthority.js +36 -0
- package/dist/state/todoActivationSafety.js +58 -0
- package/dist/state/todoCreateBatch.js +69 -0
- package/dist/state/todoDocsEntities.js +1339 -0
- package/dist/state/todoDocsEntityValidation.js +158 -0
- package/dist/state/todoMarkdownProjection.js +63 -0
- package/dist/state/todoReconciliationActivation.js +182 -0
- package/dist/state/todoReconciliationInspection.js +184 -0
- package/dist/state/todoReconciliationRepair.js +320 -0
- package/dist/state/todoReconciliationTransaction.js +628 -0
- package/dist/state/todoSeverityHeadings.js +71 -0
- package/dist/state/todoTransitionBatch.js +65 -0
- package/dist/state/todoUpdateBatch.js +50 -0
- package/dist/state/write/assign.js +20 -0
- package/dist/state/write/candidateMutation.js +269 -0
- package/dist/state/write/errors.js +11 -0
- package/dist/state/write/experimentPublication.js +192 -0
- package/dist/state/write/explain.js +380 -0
- package/dist/state/write/fields.js +61 -0
- package/dist/state/write/glossaryPublication.js +263 -0
- package/dist/state/write/grammar.js +285 -0
- package/dist/state/write/helpers.js +29 -0
- package/dist/state/write/index.js +12 -0
- package/dist/state/write/input.js +391 -0
- package/dist/state/write/lock.js +837 -0
- package/dist/state/write/mutation.js +234 -0
- package/dist/state/write/operations.js +170 -0
- package/dist/state/write/planEvaluation.js +128 -0
- package/dist/state/write/planPublication.js +179 -0
- package/dist/state/write/runtimeOperations.js +146 -0
- package/dist/state/write/serialize.js +1 -0
- package/dist/state/write/transaction.js +57 -0
- package/dist/state/write/validate.js +7 -0
- package/dist/upgrade/appContentRefresh.js +77 -36
- package/dist/upgrade/appModel.js +0 -1
- package/dist/upgrade/atomicWriter.js +1 -0
- package/dist/upgrade/bundleEvidence.js +0 -1
- package/dist/upgrade/channels.js +6 -9
- package/dist/upgrade/compatibility.js +43 -17
- package/dist/upgrade/doctor.js +55 -32
- package/dist/upgrade/doctorClassifier.js +11 -1
- package/dist/upgrade/installedHooksRetirement.js +46 -40
- package/dist/upgrade/legacyAgentCleanup.js +133 -34
- package/dist/upgrade/lifecycleUpgrade.js +113 -0
- package/dist/upgrade/migrateArtifactsV2ToV3.js +325 -82
- package/dist/upgrade/migrationPublication.js +122 -0
- package/dist/upgrade/nextMajorDoctor.js +0 -22
- package/dist/upgrade/npxPlatformStatus.js +2 -2
- package/dist/upgrade/productV1Reset.js +515 -0
- package/dist/upgrade/productV1ResetAuthority.js +139 -0
- package/dist/upgrade/projectIntegration.js +126 -134
- package/dist/upgrade/projectIntegrationDecision.js +21 -13
- package/dist/upgrade/retiredResourceDiagnostics.js +117 -0
- package/dist/upgrade/runtimeMigration.js +210 -430
- package/dist/upgrade/upgradeCommands.js +14 -1
- package/dist/upgrade/upgradeLock.js +85 -0
- package/dist/upgrade/upgradeOrchestrator.js +253 -48
- package/dist/upgrade/v3CapabilitySurface.js +2 -3
- package/dist/upgrade/versionResolution.js +0 -1
- package/dist/validate/activationArtifactEvidence.js +866 -0
- package/dist/validate/activationArtifactEvidenceTypes.js +12 -0
- package/dist/validate/activationConjunction.js +816 -0
- package/dist/validate/activationEvidenceManifest.js +610 -0
- package/dist/validate/activationPackageSemantics.js +29 -0
- package/dist/validate/appHomeContract.js +1 -7
- package/dist/validate/bootstrapAuthority.js +44 -0
- package/dist/validate/capability.js +11 -3
- package/dist/validate/crossCapability.js +14 -9
- package/dist/validate/glossaryVariantGuard.js +96 -0
- package/dist/validate/retainedReferenceAuthority.js +879 -0
- package/dist/validate/selfAudit.js +39 -45
- package/dist/validate/vocabularyAuthority.js +8 -8
- package/package.json +39 -13
- package/bundle/references/adapters/cursor.md +0 -214
- package/bundle/references/adapters/opencode.md +0 -530
- package/bundle/references/adapters/package-manifest-interface-model.yaml +0 -337
- package/bundle/references/adapters/runtime-adapter-characterization.md +0 -79
- package/bundle/references/adapters/runtime-adapter-interface-model.yaml +0 -200
- package/bundle/references/adapters/runtime-adapter-registry.yaml +0 -554
- package/bundle/references/adapters/runtime-feature-parity.md +0 -189
- package/bundle/references/analysis/benchmark.md +0 -267
- package/bundle/references/analysis/startup-measurement-contract.yaml +0 -424
- package/bundle/references/cli/agent-ready-state-contract.yaml +0 -953
- package/bundle/references/cli/audience-namespace-cli-migration.yaml +0 -369
- package/bundle/references/cli/bundle-skill-vocabulary.yaml +0 -250
- package/bundle/references/cli/capability-tool-classification.yaml +0 -53
- package/bundle/references/cli/coexistence-probe.yaml +0 -13
- package/bundle/references/cli/parity-expected-actual-template.md +0 -30
- package/bundle/references/cli/routing-execution-vocabulary.yaml +0 -281
- package/bundle/references/cli/single-name-protocol.yaml +0 -42
- package/bundle/references/cli/upgrade-repair-wording.md +0 -45
- package/bundle/references/cli/v3-handoff-manifest.schema.yaml +0 -98
- package/bundle/references/meta/documentation-inventory.md +0 -49
- package/bundle/skills/agentera/.claude-plugin/plugin.json +0 -27
- package/bundle/skills/agentera/agents/audit.toml +0 -6
- package/bundle/skills/agentera/agents/build.toml +0 -6
- package/bundle/skills/agentera/agents/design.toml +0 -6
- package/bundle/skills/agentera/agents/discuss.toml +0 -6
- package/bundle/skills/agentera/agents/document.toml +0 -6
- package/bundle/skills/agentera/agents/optimize.toml +0 -6
- package/bundle/skills/agentera/agents/orchestrate.toml +0 -6
- package/bundle/skills/agentera/agents/plan.toml +0 -6
- package/bundle/skills/agentera/agents/profile.toml +0 -6
- package/bundle/skills/agentera/agents/research.toml +0 -6
- package/bundle/skills/agentera/agents/status.toml +0 -6
- package/bundle/skills/agentera/agents/vision.toml +0 -6
- package/bundle/skills/agentera/references/contract.md +0 -1048
- package/dist/analytics/extractCorpus/cli.js.map +0 -1
- package/dist/analytics/extractCorpus/copilotSessions.js.map +0 -1
- package/dist/analytics/extractCorpus/core.js.map +0 -1
- package/dist/analytics/extractCorpus/corpus.js.map +0 -1
- package/dist/analytics/extractCorpus/coverageAudit.js.map +0 -1
- package/dist/analytics/extractCorpus/cursorSessions.js.map +0 -1
- package/dist/analytics/extractCorpus/extractCorpusParity.js.map +0 -1
- package/dist/analytics/extractCorpus/filesystemSources.js.map +0 -1
- package/dist/analytics/extractCorpus/index.js.map +0 -1
- package/dist/analytics/extractCorpus/jsonlSessions.js.map +0 -1
- package/dist/analytics/extractCorpus/sqliteCaps.js.map +0 -1
- package/dist/analytics/extractCorpus/sqliteSessions.js.map +0 -1
- package/dist/analytics/extractCorpus.js.map +0 -1
- package/dist/analytics/usageStats.js.map +0 -1
- package/dist/bin/agentera.js.map +0 -1
- package/dist/capabilities/audit/instructions.js.map +0 -1
- package/dist/capabilities/build/instructions.js.map +0 -1
- package/dist/capabilities/design/instructions.js.map +0 -1
- package/dist/capabilities/discuss/instructions.js.map +0 -1
- package/dist/capabilities/document/instructions.js.map +0 -1
- package/dist/capabilities/index.js.map +0 -1
- package/dist/capabilities/optimize/instructions.js.map +0 -1
- package/dist/capabilities/orchestrate/instructions.js.map +0 -1
- package/dist/capabilities/plan/instructions.js.map +0 -1
- package/dist/capabilities/profile/instructions.js.map +0 -1
- package/dist/capabilities/research/instructions.js.map +0 -1
- package/dist/capabilities/status/instructions.js.map +0 -1
- package/dist/capabilities/vision/instructions.js.map +0 -1
- package/dist/cli/appContext.js.map +0 -1
- package/dist/cli/argvalidate.js.map +0 -1
- package/dist/cli/capabilityContext/benchmark.js.map +0 -1
- package/dist/cli/capabilityContext/bespoke.js.map +0 -1
- package/dist/cli/capabilityContext/build.js.map +0 -1
- package/dist/cli/capabilityContext/closeout.js.map +0 -1
- package/dist/cli/capabilityContext/contract.js.map +0 -1
- package/dist/cli/capabilityContext/evidence.js.map +0 -1
- package/dist/cli/capabilityContext/index.js.map +0 -1
- package/dist/cli/capabilityContext/orchestration.js.map +0 -1
- package/dist/cli/capabilityContext/planState.js.map +0 -1
- package/dist/cli/capabilityContext/progress.js.map +0 -1
- package/dist/cli/capabilityContext/shared.js.map +0 -1
- package/dist/cli/capabilityContext/slim.js.map +0 -1
- package/dist/cli/capabilityContext/startup.js.map +0 -1
- package/dist/cli/capabilityContext/types.js.map +0 -1
- package/dist/cli/capabilityContext.js.map +0 -1
- package/dist/cli/commands/appHome.js.map +0 -1
- package/dist/cli/commands/capability.js.map +0 -1
- package/dist/cli/commands/compact.js.map +0 -1
- package/dist/cli/commands/doctor.js.map +0 -1
- package/dist/cli/commands/lint.js.map +0 -1
- package/dist/cli/commands/prime/bundleStatus.js.map +0 -1
- package/dist/cli/commands/prime/collectOrientationState.js.map +0 -1
- package/dist/cli/commands/prime/orientationOutput.js.map +0 -1
- package/dist/cli/commands/prime/types.js.map +0 -1
- package/dist/cli/commands/prime/v1Migration.js +0 -39
- package/dist/cli/commands/prime/v1Migration.js.map +0 -1
- package/dist/cli/commands/prime.js.map +0 -1
- package/dist/cli/commands/query.js.map +0 -1
- package/dist/cli/commands/report.js.map +0 -1
- package/dist/cli/commands/schema.js.map +0 -1
- package/dist/cli/commands/state/decisions.js.map +0 -1
- package/dist/cli/commands/state/docs.js.map +0 -1
- package/dist/cli/commands/state/experiments.js.map +0 -1
- package/dist/cli/commands/state/health.js.map +0 -1
- package/dist/cli/commands/state/index.js.map +0 -1
- package/dist/cli/commands/state/objective.js.map +0 -1
- package/dist/cli/commands/state/plan.js.map +0 -1
- package/dist/cli/commands/state/progress.js.map +0 -1
- package/dist/cli/commands/state/shared.js.map +0 -1
- package/dist/cli/commands/state/todo.js.map +0 -1
- package/dist/cli/commands/upgrade.js.map +0 -1
- package/dist/cli/commands/validate.js.map +0 -1
- package/dist/cli/commands/verify.js.map +0 -1
- package/dist/cli/contracts/bundleStatus.js.map +0 -1
- package/dist/cli/contracts/orientationState.js.map +0 -1
- package/dist/cli/dispatch/argvParser.js.map +0 -1
- package/dist/cli/dispatch/check.js.map +0 -1
- package/dist/cli/dispatch/commands.js.map +0 -1
- package/dist/cli/dispatch/index.js.map +0 -1
- package/dist/cli/dispatch/lifecycle.js.map +0 -1
- package/dist/cli/dispatch/prime.js.map +0 -1
- package/dist/cli/dispatch/shared.js.map +0 -1
- package/dist/cli/dispatch/state.js.map +0 -1
- package/dist/cli/dispatch.js.map +0 -1
- package/dist/cli/errors.js.map +0 -1
- package/dist/cli/help.js.map +0 -1
- package/dist/cli/orientation/attention.js.map +0 -1
- package/dist/cli/orientation/corpusCoverage.js.map +0 -1
- package/dist/cli/orientation.js.map +0 -1
- package/dist/cli/prime-blob.js.map +0 -1
- package/dist/cli/startupCompletenessContract.js.map +0 -1
- package/dist/cli/stateQuery.js.map +0 -1
- package/dist/cli/structured.js.map +0 -1
- package/dist/cli/todoMarkdown.js.map +0 -1
- package/dist/cli/todoSeverity.js.map +0 -1
- package/dist/core/difflib.js.map +0 -1
- package/dist/core/envPaths.js.map +0 -1
- package/dist/core/jsonValue.js.map +0 -1
- package/dist/core/paths.js.map +0 -1
- package/dist/core/pyjson.js.map +0 -1
- package/dist/core/sourceRoot.js.map +0 -1
- package/dist/core/toml.js.map +0 -1
- package/dist/core/yaml.js.map +0 -1
- package/dist/eval/evalSkills.js.map +0 -1
- package/dist/eval/semanticEval.js.map +0 -1
- package/dist/eval/semanticFixtures.js.map +0 -1
- package/dist/hooks/common.js.map +0 -1
- package/dist/hooks/compaction/apply.js.map +0 -1
- package/dist/hooks/compaction/dryRun.js.map +0 -1
- package/dist/hooks/compaction/index.js.map +0 -1
- package/dist/hooks/compaction/parse.js.map +0 -1
- package/dist/hooks/compaction/retention.js.map +0 -1
- package/dist/hooks/compaction/status.js.map +0 -1
- package/dist/hooks/compaction/types.js.map +0 -1
- package/dist/hooks/cursorPreToolUse.js +0 -19
- package/dist/hooks/cursorPreToolUse.js.map +0 -1
- package/dist/hooks/cursorSessionStart.js +0 -79
- package/dist/hooks/cursorSessionStart.js.map +0 -1
- package/dist/hooks/sessionStart.js +0 -216
- package/dist/hooks/sessionStart.js.map +0 -1
- package/dist/hooks/sessionStop.js +0 -206
- package/dist/hooks/sessionStop.js.map +0 -1
- package/dist/hooks/validateArtifact/agentFacing.js.map +0 -1
- package/dist/hooks/validateArtifact/index.js.map +0 -1
- package/dist/hooks/validateArtifact/markdown.js.map +0 -1
- package/dist/hooks/validateArtifact/runtime.js +0 -86
- package/dist/hooks/validateArtifact/runtime.js.map +0 -1
- package/dist/hooks/validateArtifact/schema.js.map +0 -1
- package/dist/hooks/validateArtifact/traversal.js.map +0 -1
- package/dist/hooks/validateArtifact/violations.js.map +0 -1
- package/dist/migrate/v2HandoffManifest.js.map +0 -1
- package/dist/registries/artifactProtocolIds.js.map +0 -1
- package/dist/registries/artifactRegistry.js.map +0 -1
- package/dist/registries/capabilityContract.js.map +0 -1
- package/dist/registries/evaluatorHandoffContract.js.map +0 -1
- package/dist/registries/packageRegistry.js.map +0 -1
- package/dist/registries/runtimeAdapterRegistry.js +0 -316
- package/dist/registries/runtimeAdapterRegistry.js.map +0 -1
- package/dist/registries/triggerLoader.js.map +0 -1
- package/dist/release/releaseMetadata.js.map +0 -1
- package/dist/setup/codex/agents.js +0 -96
- package/dist/setup/codex/agents.js.map +0 -1
- package/dist/setup/codex/cli.js +0 -161
- package/dist/setup/codex/cli.js.map +0 -1
- package/dist/setup/codex/configToml.js +0 -639
- package/dist/setup/codex/configToml.js.map +0 -1
- package/dist/setup/codex/constants.js +0 -29
- package/dist/setup/codex/constants.js.map +0 -1
- package/dist/setup/codex/installRoot.js +0 -64
- package/dist/setup/codex/installRoot.js.map +0 -1
- package/dist/setup/codex/state.js +0 -270
- package/dist/setup/codex/state.js.map +0 -1
- package/dist/setup/codex.js +0 -12
- package/dist/setup/codex.js.map +0 -1
- package/dist/setup/copilot.js +0 -227
- package/dist/setup/copilot.js.map +0 -1
- package/dist/setup/cursor.js +0 -129
- package/dist/setup/cursor.js.map +0 -1
- package/dist/setup/cursorSurfaces.js +0 -67
- package/dist/setup/cursorSurfaces.js.map +0 -1
- package/dist/setup/doctor/core.js +0 -300
- package/dist/setup/doctor/core.js.map +0 -1
- package/dist/setup/doctor/diagnostics.js +0 -240
- package/dist/setup/doctor/diagnostics.js.map +0 -1
- package/dist/setup/doctor/opencode.js +0 -313
- package/dist/setup/doctor/opencode.js.map +0 -1
- package/dist/setup/doctor/report.js +0 -425
- package/dist/setup/doctor/report.js.map +0 -1
- package/dist/setup/doctor.js +0 -10
- package/dist/setup/doctor.js.map +0 -1
- package/dist/setup/opencode.js.map +0 -1
- package/dist/setup/smokeChecks.js.map +0 -1
- package/dist/state/installRoot.js.map +0 -1
- package/dist/state/startupAnalysis/benchmark.js.map +0 -1
- package/dist/state/startupAnalysis/contract.js.map +0 -1
- package/dist/state/startupAnalysis/helpers.js.map +0 -1
- package/dist/state/startupAnalysis/index.js.map +0 -1
- package/dist/state/startupAnalysis/metrics.js.map +0 -1
- package/dist/state/startupAnalysis/records.js.map +0 -1
- package/dist/state/startupAnalysis/report.js.map +0 -1
- package/dist/state/startupAnalysis/threshold.js.map +0 -1
- package/dist/state/startupAnalysis.js.map +0 -1
- package/dist/upgrade/appContentRefresh.js.map +0 -1
- package/dist/upgrade/appModel.js.map +0 -1
- package/dist/upgrade/bundleEvidence.js.map +0 -1
- package/dist/upgrade/channels.js.map +0 -1
- package/dist/upgrade/coexistenceProbe.js +0 -107
- package/dist/upgrade/coexistenceProbe.js.map +0 -1
- package/dist/upgrade/compatibility.js.map +0 -1
- package/dist/upgrade/doctor.js.map +0 -1
- package/dist/upgrade/doctorClassifier.js.map +0 -1
- package/dist/upgrade/installedHooksRetirement.js.map +0 -1
- package/dist/upgrade/legacyAgentCleanup.js.map +0 -1
- package/dist/upgrade/migrateArtifactsV1ToV2.js +0 -570
- package/dist/upgrade/migrateArtifactsV1ToV2.js.map +0 -1
- package/dist/upgrade/migrateArtifactsV2ToV3.js.map +0 -1
- package/dist/upgrade/nextMajorDoctor.js.map +0 -1
- package/dist/upgrade/npxPlatformStatus.js.map +0 -1
- package/dist/upgrade/projectIntegration.js.map +0 -1
- package/dist/upgrade/projectIntegrationDecision.js.map +0 -1
- package/dist/upgrade/runtimeMigration.js.map +0 -1
- package/dist/upgrade/upgradeCommands.js.map +0 -1
- package/dist/upgrade/upgradeOrchestrator.js.map +0 -1
- package/dist/upgrade/v3CapabilitySurface.js.map +0 -1
- package/dist/upgrade/versionResolution.js.map +0 -1
- package/dist/validate/appHomeContract.js.map +0 -1
- package/dist/validate/capability.js.map +0 -1
- package/dist/validate/crossCapability.js.map +0 -1
- package/dist/validate/lifecycleAdapters/legacyPythonParity.js +0 -93
- package/dist/validate/lifecycleAdapters/legacyPythonParity.js.map +0 -1
- package/dist/validate/lifecycleAdapters/nodeFormChecks.js +0 -488
- package/dist/validate/lifecycleAdapters/nodeFormChecks.js.map +0 -1
- package/dist/validate/lifecycleAdapters/shared.js +0 -198
- package/dist/validate/lifecycleAdapters/shared.js.map +0 -1
- package/dist/validate/lifecycleAdapters.js +0 -62
- package/dist/validate/lifecycleAdapters.js.map +0 -1
- package/dist/validate/selfAudit.js.map +0 -1
- package/dist/validate/vocabularyAuthority.js.map +0 -1
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { dumpYamlMapping, loadYamlMapping } from "../core/yaml.js";
|
|
5
|
+
import { canonicalRecordJson } from "./archiveDiscovery.js";
|
|
6
|
+
import { verifyEntityCutoverGitSource } from "./entityCutoverGit.js";
|
|
7
|
+
import { canonicalEntityEnvelope, canonicalEntityEnvelopeBytes, validateEntityState } from "./entityStorage.js";
|
|
8
|
+
import { planEntityMigration, validateEntityMigrationTargets } from "./entityMigrationPreview.js";
|
|
9
|
+
import { loadLegacyEntityCutoverTargets } from "./legacyEntityCutoverEvidence.js";
|
|
10
|
+
import { validateRealProjectRoot } from "./projectRoot.js";
|
|
11
|
+
import { readProjectFileSnapshot } from "./safeProjectFile.js";
|
|
12
|
+
import { acquireWriterLock } from "./write/lock.js";
|
|
13
|
+
import { EntityPublicationContext } from "./entityPublicationContext.js";
|
|
14
|
+
import { todoReconciliationBinding } from "./todoDocsEntities.js";
|
|
15
|
+
import { todoCutoverPublicProjectionViolations } from "./todoReconciliationInspection.js";
|
|
16
|
+
import { TODO_RECONCILIATION_ACTIVATION_PATH, todoReconciliationActivationBytes } from "./todoReconciliationActivation.js";
|
|
17
|
+
import { inspectTodoReconciliation, publishTodoReconciliation, recoverTodoReconciliation } from "./todoReconciliationTransaction.js";
|
|
18
|
+
export const MIGRATION_ROOT = ".agentera/migrations/entities";
|
|
19
|
+
export const FORWARD_MANIFEST = `${MIGRATION_ROOT}/forward.yaml`;
|
|
20
|
+
export const ENTITY_MODE_MARKER = ".agentera/state-mode.yaml";
|
|
21
|
+
const MANIFEST_SCHEMA = "agentera.entityCutoverManifest.v1";
|
|
22
|
+
const SHA256 = /^[a-f0-9]{64}$/;
|
|
23
|
+
export class EntityCutoverError extends Error {
|
|
24
|
+
constructor(message) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = "EntityCutoverError";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function hash(bytes) {
|
|
30
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
31
|
+
}
|
|
32
|
+
function mapping(value) {
|
|
33
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
34
|
+
}
|
|
35
|
+
function exactKeys(value, expected) {
|
|
36
|
+
return canonicalRecordJson(Object.keys(value).sort()) === canonicalRecordJson([...expected].sort());
|
|
37
|
+
}
|
|
38
|
+
function safeTarget(value) {
|
|
39
|
+
return value.startsWith(".agentera/entities/")
|
|
40
|
+
&& !path.isAbsolute(value)
|
|
41
|
+
&& !value.includes("\\")
|
|
42
|
+
&& value.split("/").every((part) => part !== "" && part !== "." && part !== "..");
|
|
43
|
+
}
|
|
44
|
+
function markerSnapshot(project) {
|
|
45
|
+
return readProjectFileSnapshot(validateRealProjectRoot(project), ENTITY_MODE_MARKER);
|
|
46
|
+
}
|
|
47
|
+
function parseHistoricalForwardManifest(bytes) {
|
|
48
|
+
const value = loadYamlMapping(bytes.toString("utf8"));
|
|
49
|
+
if (!exactKeys(value, ["schemaVersion", "phase", "source", "targets", "marker"])
|
|
50
|
+
|| value.schemaVersion !== MANIFEST_SCHEMA
|
|
51
|
+
|| value.phase !== "entities_published"
|
|
52
|
+
|| !mapping(value.marker)
|
|
53
|
+
|| value.marker.path !== ENTITY_MODE_MARKER
|
|
54
|
+
|| typeof value.marker.sha256 !== "string"
|
|
55
|
+
|| !SHA256.test(value.marker.sha256)
|
|
56
|
+
|| !Array.isArray(value.targets)) {
|
|
57
|
+
throw new EntityCutoverError(`historical cutover manifest '${FORWARD_MANIFEST}' is invalid`);
|
|
58
|
+
}
|
|
59
|
+
const targets = value.targets.map((raw) => {
|
|
60
|
+
if (!mapping(raw) || !exactKeys(raw, ["path", "sha256"]) || typeof raw.path !== "string" || !safeTarget(raw.path) || typeof raw.sha256 !== "string" || !SHA256.test(raw.sha256)) {
|
|
61
|
+
throw new EntityCutoverError(`historical cutover manifest '${FORWARD_MANIFEST}' has an invalid target`);
|
|
62
|
+
}
|
|
63
|
+
return { path: raw.path, sha256: raw.sha256 };
|
|
64
|
+
});
|
|
65
|
+
return { schemaVersion: MANIFEST_SCHEMA, phase: "entities_published", targets, marker: value.marker };
|
|
66
|
+
}
|
|
67
|
+
function loadHistoricalForwardManifest(project) {
|
|
68
|
+
const observed = readProjectFileSnapshot(validateRealProjectRoot(project), FORWARD_MANIFEST);
|
|
69
|
+
if (observed.kind === "missing")
|
|
70
|
+
return null;
|
|
71
|
+
if (observed.kind !== "file")
|
|
72
|
+
throw new EntityCutoverError(`historical cutover manifest '${FORWARD_MANIFEST}' is unsafe`);
|
|
73
|
+
return parseHistoricalForwardManifest(observed.bytes);
|
|
74
|
+
}
|
|
75
|
+
function targetsForPlan(plan) {
|
|
76
|
+
const targets = plan.entries.map((entry) => {
|
|
77
|
+
const target = entry.proposed_target;
|
|
78
|
+
if (!target || typeof target.id !== "string" || typeof entry.artifact !== "string" || !safeTarget(target.path))
|
|
79
|
+
throw new EntityCutoverError(`first unresolved path '${entry.source_paths[0] ?? ".agentera"}': source has no safe canonical target`);
|
|
80
|
+
const bytes = canonicalEntityEnvelopeBytes({ id: target.id, artifact: entry.artifact, record: entry.record, migrationProvenance: entry.canonical_migration_provenance });
|
|
81
|
+
if (entry.target_sha256 !== hash(bytes))
|
|
82
|
+
throw new EntityCutoverError(`first unresolved path '${target.path}': converted entity bytes are not deterministic`);
|
|
83
|
+
return { path: target.path, sha256: hash(bytes) };
|
|
84
|
+
}).sort((a, b) => a.path.localeCompare(b.path));
|
|
85
|
+
if (new Set(targets.map(({ path: target }) => target)).size !== targets.length)
|
|
86
|
+
throw new EntityCutoverError("first unresolved path '.agentera/entities': converted target paths are not unique");
|
|
87
|
+
return targets;
|
|
88
|
+
}
|
|
89
|
+
function assertPlanReady(plan, sourceRoot) {
|
|
90
|
+
const blocker = plan.diagnostics[0];
|
|
91
|
+
if (plan.counts.blockers > 0)
|
|
92
|
+
throw new EntityCutoverError(`first unresolved path '${blocker?.path ?? ".agentera"}': ${blocker?.message ?? `${plan.counts.blockers} migration blocker(s)`}`);
|
|
93
|
+
const invalid = validateEntityMigrationTargets(plan.project, plan.entries, sourceRoot)[0];
|
|
94
|
+
if (invalid)
|
|
95
|
+
throw new EntityCutoverError(`first unresolved path '${invalid.path}': ${invalid.message}`);
|
|
96
|
+
}
|
|
97
|
+
function listFiles(project, relativeRoot) {
|
|
98
|
+
const absoluteRoot = path.join(project, relativeRoot);
|
|
99
|
+
if (!fs.existsSync(absoluteRoot))
|
|
100
|
+
return [];
|
|
101
|
+
const found = [];
|
|
102
|
+
const visit = (directory) => {
|
|
103
|
+
const stat = fs.lstatSync(directory);
|
|
104
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || fs.realpathSync(directory) !== directory)
|
|
105
|
+
throw new EntityCutoverError(`first unresolved path '${path.relative(project, directory)}': expected a real project directory`);
|
|
106
|
+
for (const entry of fs.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
107
|
+
const absolute = path.join(directory, entry.name);
|
|
108
|
+
const relative = path.relative(project, absolute).split(path.sep).join("/");
|
|
109
|
+
if (entry.isSymbolicLink())
|
|
110
|
+
throw new EntityCutoverError(`first unresolved path '${relative}': symbolic links are not import targets`);
|
|
111
|
+
if (entry.isDirectory())
|
|
112
|
+
visit(absolute);
|
|
113
|
+
else if (entry.isFile())
|
|
114
|
+
found.push(relative);
|
|
115
|
+
else
|
|
116
|
+
throw new EntityCutoverError(`first unresolved path '${relative}': expected a regular file`);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
visit(absoluteRoot);
|
|
120
|
+
return found.sort();
|
|
121
|
+
}
|
|
122
|
+
function validateExistingTargets(project, targets, mutableTodoTargets = new Set()) {
|
|
123
|
+
const expected = new Map(targets.map((target) => [target.path, target]));
|
|
124
|
+
for (const relative of listFiles(project, ".agentera/entities")) {
|
|
125
|
+
if (!expected.has(relative))
|
|
126
|
+
throw new EntityCutoverError(`first unresolved path '${relative}': entity is not part of the converted v2 input`);
|
|
127
|
+
}
|
|
128
|
+
for (const target of targets) {
|
|
129
|
+
const observed = readProjectFileSnapshot(validateRealProjectRoot(project), target.path);
|
|
130
|
+
if (observed.kind === "missing")
|
|
131
|
+
continue;
|
|
132
|
+
if (observed.kind !== "file" || hash(observed.bytes) !== target.sha256) {
|
|
133
|
+
if (observed.kind === "file" && mutableTodoTargets.has(target.path))
|
|
134
|
+
continue;
|
|
135
|
+
throw new EntityCutoverError(`first unresolved path '${target.path}': existing target is not an exact converted match`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function validateActiveEntityCutover(project, markerBytes, sourceRoot) {
|
|
140
|
+
const result = validateEntityState(project, sourceRoot);
|
|
141
|
+
if (!result.valid || result.entityCount === 0)
|
|
142
|
+
throw new EntityCutoverError(`active entity state is invalid: ${result.entityCount === 0 ? "no canonical entities were published" : result.issues.map(({ message }) => message).join("; ")}`);
|
|
143
|
+
const targets = loadEntityCutoverTargetsForMarker(project, markerBytes);
|
|
144
|
+
const byPath = new Map(result.entities.map((entity) => [entity.relativePath, entity]));
|
|
145
|
+
for (const target of targets) {
|
|
146
|
+
const entity = byPath.get(target.path);
|
|
147
|
+
if (!entity || entity.classification !== "valid" || (target.id && entity.id !== target.id) || (target.artifact && entity.artifact !== target.artifact))
|
|
148
|
+
throw new EntityCutoverError(`active entity target '${target.path}' is missing or invalid`);
|
|
149
|
+
}
|
|
150
|
+
return result.entityCount;
|
|
151
|
+
}
|
|
152
|
+
export function loadEntityCutoverTargetsForMarker(projectRoot, bytes) {
|
|
153
|
+
const project = validateRealProjectRoot(projectRoot).path;
|
|
154
|
+
const marker = loadYamlMapping(bytes.toString("utf8"));
|
|
155
|
+
if (marker.schemaVersion !== "agentera.stateMode.v1" || marker.mode !== "entities")
|
|
156
|
+
throw new EntityCutoverError("state marker is not valid entity authority");
|
|
157
|
+
if (marker.cutover === undefined && marker.migration_id === undefined)
|
|
158
|
+
return [];
|
|
159
|
+
if (marker.cutover === "one_way_git") {
|
|
160
|
+
const manifest = loadHistoricalForwardManifest(project);
|
|
161
|
+
if (!manifest || manifest.marker.sha256 !== hash(bytes))
|
|
162
|
+
throw new EntityCutoverError("historical one-way entity marker has no matching completed manifest");
|
|
163
|
+
return manifest.targets;
|
|
164
|
+
}
|
|
165
|
+
if (typeof marker.migration_id === "string")
|
|
166
|
+
return loadLegacyEntityCutoverTargets(project, bytes);
|
|
167
|
+
throw new EntityCutoverError("entity marker has no supported cutover binding");
|
|
168
|
+
}
|
|
169
|
+
function inspect(projectRoot, sourceRoot, requireGit, writerLockHeld = false, activeUpgradeLockPaths = []) {
|
|
170
|
+
const project = validateRealProjectRoot(projectRoot).path;
|
|
171
|
+
const marker = markerSnapshot(project);
|
|
172
|
+
if (marker.kind === "file")
|
|
173
|
+
return { inspection: { phase: "active", entityCount: validateActiveEntityCutover(project, marker.bytes, sourceRoot), todoReconciliation: false } };
|
|
174
|
+
if (marker.kind !== "missing")
|
|
175
|
+
throw new EntityCutoverError(`first unresolved path '${ENTITY_MODE_MARKER}': marker path is unsafe`);
|
|
176
|
+
const binding = todoReconciliationBinding(project, sourceRoot);
|
|
177
|
+
if (inspectTodoReconciliation(project, binding).length > 0) {
|
|
178
|
+
return { inspection: { phase: "ready", entityCount: 1, todoReconciliation: true } };
|
|
179
|
+
}
|
|
180
|
+
const plan = planEntityMigration(project, sourceRoot);
|
|
181
|
+
assertPlanReady(plan, sourceRoot);
|
|
182
|
+
const targets = targetsForPlan(plan);
|
|
183
|
+
const mutableTodoTargets = new Set(plan.todo_reconciliation ? plan.entries.filter(({ boundary }) => boundary === "todo_item").map((entry) => entry.proposed_target.path) : []);
|
|
184
|
+
validateExistingTargets(project, targets, mutableTodoTargets);
|
|
185
|
+
let head;
|
|
186
|
+
if (requireGit) {
|
|
187
|
+
const allowedPaths = new Set([FORWARD_MANIFEST, ENTITY_MODE_MARKER, ...targets.map(({ path: target }) => target)]);
|
|
188
|
+
for (const activeLockPath of activeUpgradeLockPaths) {
|
|
189
|
+
const relative = path.relative(project, path.resolve(activeLockPath));
|
|
190
|
+
if (relative !== "" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))
|
|
191
|
+
allowedPaths.add(relative.split(path.sep).join("/"));
|
|
192
|
+
}
|
|
193
|
+
const binding = verifyEntityCutoverGitSource(project, plan, { paths: allowedPaths, prefixes: writerLockHeld ? [".agentera/.writer.lock"] : [] });
|
|
194
|
+
head = binding.head;
|
|
195
|
+
}
|
|
196
|
+
return { inspection: { phase: "ready", entityCount: targets.length, todoReconciliation: Boolean(plan.todo_reconciliation) }, plan, ...(head ? { head } : {}) };
|
|
197
|
+
}
|
|
198
|
+
export function inspectEntityCutoverForUpgrade(projectRoot, sourceRoot, requireGit = false, activeUpgradeLockPaths = []) {
|
|
199
|
+
return inspect(projectRoot, sourceRoot, requireGit, false, activeUpgradeLockPaths).inspection;
|
|
200
|
+
}
|
|
201
|
+
export function prepareEntityCutoverForUpgrade(projectRoot, sourceRoot, activeUpgradeLockPaths = []) {
|
|
202
|
+
const current = inspect(projectRoot, sourceRoot, true, false, activeUpgradeLockPaths);
|
|
203
|
+
if (current.inspection.phase === "ready" && !current.plan)
|
|
204
|
+
return { project: validateRealProjectRoot(projectRoot).path, sourceRoot, head: "", sourceFingerprint: "", previewDigest: "", recovery: true };
|
|
205
|
+
if (current.inspection.phase === "active" || !current.plan || !current.head)
|
|
206
|
+
throw new EntityCutoverError("entity authority is already active; no cutover preparation is available");
|
|
207
|
+
return { project: current.plan.project, sourceRoot, head: current.head, sourceFingerprint: current.plan.source_fingerprint, previewDigest: current.plan.preview_digest };
|
|
208
|
+
}
|
|
209
|
+
function ensureDirectory(project, relativeDirectory) {
|
|
210
|
+
let current = project;
|
|
211
|
+
for (const segment of relativeDirectory.split("/").filter(Boolean)) {
|
|
212
|
+
current = path.join(current, segment);
|
|
213
|
+
if (!fs.existsSync(current))
|
|
214
|
+
fs.mkdirSync(current, { mode: 0o700 });
|
|
215
|
+
const stat = fs.lstatSync(current);
|
|
216
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || fs.realpathSync(current) !== current)
|
|
217
|
+
throw new EntityCutoverError(`first unresolved path '${path.relative(project, current)}': target directory is unsafe`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function writeDurable(file, bytes) {
|
|
221
|
+
const fd = fs.openSync(file, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL | (fs.constants.O_NOFOLLOW ?? 0), 0o600);
|
|
222
|
+
try {
|
|
223
|
+
fs.writeFileSync(fd, bytes);
|
|
224
|
+
fs.fsyncSync(fd);
|
|
225
|
+
}
|
|
226
|
+
finally {
|
|
227
|
+
fs.closeSync(fd);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function fault(phase) {
|
|
231
|
+
if (process.env.NODE_ENV === "test" && process.env.AGENTERA_FAULT_INJECT_ENTITY_MIGRATION_AFTER_PHASE === phase)
|
|
232
|
+
throw new EntityCutoverError(`simulated entity import interruption after ${phase}`);
|
|
233
|
+
}
|
|
234
|
+
function publishTargets(project, plan) {
|
|
235
|
+
for (const entry of plan.entries.slice().sort((a, b) => a.proposed_target.path.localeCompare(b.proposed_target.path))) {
|
|
236
|
+
const target = entry.proposed_target;
|
|
237
|
+
const bytes = canonicalEntityEnvelopeBytes({ id: target.id, artifact: entry.artifact, record: entry.record, migrationProvenance: entry.canonical_migration_provenance });
|
|
238
|
+
const observed = readProjectFileSnapshot(validateRealProjectRoot(project), target.path);
|
|
239
|
+
if (observed.kind === "file") {
|
|
240
|
+
if (hash(observed.bytes) !== hash(bytes)) {
|
|
241
|
+
if (plan.todo_reconciliation && entry.boundary === "todo_item")
|
|
242
|
+
continue;
|
|
243
|
+
throw new EntityCutoverError(`first unresolved path '${target.path}': existing target is not an exact converted match`);
|
|
244
|
+
}
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (observed.kind !== "missing")
|
|
248
|
+
throw new EntityCutoverError(`first unresolved path '${target.path}': target is unsafe`);
|
|
249
|
+
ensureDirectory(project, path.relative(project, path.dirname(path.join(project, target.path))).split(path.sep).join("/"));
|
|
250
|
+
try {
|
|
251
|
+
writeDurable(path.join(project, target.path), bytes);
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
throw new EntityCutoverError(`first unresolved path '${target.path}': ${error.message}`);
|
|
255
|
+
}
|
|
256
|
+
fault("entity_published");
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function upgradePublicationContext(project, activeUpgradeLockPaths) {
|
|
260
|
+
const lockPath = activeUpgradeLockPaths.find((candidate) => path.dirname(candidate) === path.join(project, ".agentera"));
|
|
261
|
+
if (!lockPath || !fs.existsSync(lockPath))
|
|
262
|
+
throw new EntityCutoverError("active project upgrade lock is unavailable for recoverable TODO cutover");
|
|
263
|
+
const relative = path.relative(project, lockPath).split(path.sep).join("/");
|
|
264
|
+
return EntityPublicationContext.open(validateRealProjectRoot(project), relative, fs.readFileSync(lockPath));
|
|
265
|
+
}
|
|
266
|
+
function validatePendingEntityCutoverTargets(project, sourceRoot, binding, targets) {
|
|
267
|
+
const entityTargets = new Map();
|
|
268
|
+
let activation;
|
|
269
|
+
let publicTarget;
|
|
270
|
+
let marker;
|
|
271
|
+
for (const target of targets) {
|
|
272
|
+
const match = /^\.agentera\/entities\/([a-z][a-z0-9_]*)\/([a-z][a-z0-9_]*)\/([a-z]{10})\.yaml$/.exec(target.path);
|
|
273
|
+
if (match) {
|
|
274
|
+
entityTargets.set(target.path, { artifact: match[1], boundary: match[2], id: match[3], target });
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (target.path === TODO_RECONCILIATION_ACTIVATION_PATH && !activation)
|
|
278
|
+
activation = target;
|
|
279
|
+
else if (target.path === binding.publicPath && !publicTarget)
|
|
280
|
+
publicTarget = target;
|
|
281
|
+
else if (target.path === ENTITY_MODE_MARKER && !marker)
|
|
282
|
+
marker = target;
|
|
283
|
+
else
|
|
284
|
+
throw new EntityCutoverError(`first unresolved path '${target.path}': pending TODO cutover journal has an unexpected target`);
|
|
285
|
+
}
|
|
286
|
+
if (!activation || !publicTarget || !marker || targets.length !== entityTargets.size + 3) {
|
|
287
|
+
throw new EntityCutoverError("first unresolved path '.agentera/.todo-reconciliation': pending TODO cutover journal target set is incomplete");
|
|
288
|
+
}
|
|
289
|
+
if (activation.before !== null || !activation.after.equals(Buffer.from(todoReconciliationActivationBytes([])))) {
|
|
290
|
+
throw new EntityCutoverError(`first unresolved path '${TODO_RECONCILIATION_ACTIVATION_PATH}': pending TODO cutover activation target is invalid`);
|
|
291
|
+
}
|
|
292
|
+
if (publicTarget.before === null || marker.before !== null) {
|
|
293
|
+
throw new EntityCutoverError("first unresolved path '.agentera/.todo-reconciliation': pending TODO cutover baselines are invalid");
|
|
294
|
+
}
|
|
295
|
+
const currentEntityPaths = listFiles(project, ".agentera/entities");
|
|
296
|
+
const expectedEntityPaths = [...entityTargets.keys()].sort();
|
|
297
|
+
if (canonicalRecordJson(currentEntityPaths) !== canonicalRecordJson(expectedEntityPaths)) {
|
|
298
|
+
const unexpected = currentEntityPaths.find((target) => !entityTargets.has(target));
|
|
299
|
+
const missing = expectedEntityPaths.find((target) => !currentEntityPaths.includes(target));
|
|
300
|
+
const unresolved = unexpected ?? missing ?? ".agentera/entities";
|
|
301
|
+
throw new EntityCutoverError(`first unresolved path '${unresolved}': canonical entity is not part of the pending journal's complete validated target set`);
|
|
302
|
+
}
|
|
303
|
+
for (const target of targets) {
|
|
304
|
+
const observed = readProjectFileSnapshot(validateRealProjectRoot(project), target.path);
|
|
305
|
+
if (observed.kind === "missing" && target.before === null)
|
|
306
|
+
continue;
|
|
307
|
+
if (observed.kind === "file" && (observed.bytes.equals(target.after) || target.before?.equals(observed.bytes)))
|
|
308
|
+
continue;
|
|
309
|
+
throw new EntityCutoverError(`first unresolved path '${target.path}': pending TODO cutover target changed outside its journal baseline`);
|
|
310
|
+
}
|
|
311
|
+
const finalEntities = [...entityTargets.values()].sort((left, right) => left.target.path.localeCompare(right.target.path)).map(({ artifact, boundary, id, target }) => {
|
|
312
|
+
let envelope;
|
|
313
|
+
try {
|
|
314
|
+
envelope = canonicalEntityEnvelope(target.after.toString("utf8"), { id, artifact, boundary }, sourceRoot, { kind: "migration_preview", projectRoot: project });
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
throw new EntityCutoverError(`first unresolved path '${target.path}': pending cutover final entity is invalid: ${error.message}`);
|
|
318
|
+
}
|
|
319
|
+
return { artifact, boundary, id, record: envelope.record };
|
|
320
|
+
});
|
|
321
|
+
const projectionIssue = todoCutoverPublicProjectionViolations(publicTarget.after.toString("utf8"), finalEntities.filter(({ artifact, boundary }) => artifact === "todo" && boundary === "todo_item"))[0];
|
|
322
|
+
if (projectionIssue)
|
|
323
|
+
throw new EntityCutoverError(`first unresolved path '${binding.publicPath}': ${projectionIssue}`);
|
|
324
|
+
const markerValue = loadYamlMapping(marker.after.toString("utf8"));
|
|
325
|
+
if (!exactKeys(markerValue, ["schemaVersion", "mode", "source_fingerprint", "preview_digest"])
|
|
326
|
+
|| markerValue.schemaVersion !== "agentera.stateMode.v1"
|
|
327
|
+
|| markerValue.mode !== "entities"
|
|
328
|
+
|| typeof markerValue.source_fingerprint !== "string"
|
|
329
|
+
|| typeof markerValue.preview_digest !== "string"
|
|
330
|
+
|| !SHA256.test(markerValue.source_fingerprint)
|
|
331
|
+
|| !SHA256.test(markerValue.preview_digest)) {
|
|
332
|
+
throw new EntityCutoverError(`first unresolved path '${ENTITY_MODE_MARKER}': pending TODO cutover authority target is invalid`);
|
|
333
|
+
}
|
|
334
|
+
const validation = validateEntityState(project, sourceRoot, { kind: "migration_preview", projectRoot: project });
|
|
335
|
+
if (!validation.valid || validation.entityCount !== entityTargets.size) {
|
|
336
|
+
const issue = validation.issues[0];
|
|
337
|
+
throw new EntityCutoverError(`first unresolved path '${issue?.path ?? ".agentera/entities"}': TODO cutover entity graph is invalid (${validation.entityCount}/${entityTargets.size})${issue ? `: ${issue.message}` : ""}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function recoverPendingTodoCutover(project, sourceRoot, activeUpgradeLockPaths) {
|
|
341
|
+
const binding = todoReconciliationBinding(project, sourceRoot);
|
|
342
|
+
if (!inspectTodoReconciliation(project, binding).length)
|
|
343
|
+
return null;
|
|
344
|
+
const context = upgradePublicationContext(project, activeUpgradeLockPaths);
|
|
345
|
+
let journalTargets;
|
|
346
|
+
try {
|
|
347
|
+
recoverTodoReconciliation(context, sourceRoot, binding, {
|
|
348
|
+
beforeRecovery: (targets) => {
|
|
349
|
+
validatePendingEntityCutoverTargets(project, sourceRoot, binding, targets);
|
|
350
|
+
journalTargets = targets;
|
|
351
|
+
},
|
|
352
|
+
beforeActivation: () => {
|
|
353
|
+
if (!journalTargets)
|
|
354
|
+
throw new EntityCutoverError("pending TODO cutover targets were not validated before recovery");
|
|
355
|
+
validatePendingEntityCutoverTargets(project, sourceRoot, binding, journalTargets);
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
finally {
|
|
360
|
+
context.close();
|
|
361
|
+
}
|
|
362
|
+
const marker = markerSnapshot(project);
|
|
363
|
+
if (marker.kind !== "file")
|
|
364
|
+
throw new EntityCutoverError(`first unresolved path '${ENTITY_MODE_MARKER}': recovered cutover did not publish its authority marker`);
|
|
365
|
+
return { status: "complete", phase: "active", idempotent: false, mutation_performed: true, entity_count: validateActiveEntityCutover(project, marker.bytes, sourceRoot) };
|
|
366
|
+
}
|
|
367
|
+
function publishTodoCutover(project, sourceRoot, plan, activeUpgradeLockPaths) {
|
|
368
|
+
const reconciliation = plan.todo_reconciliation;
|
|
369
|
+
if (!reconciliation) {
|
|
370
|
+
publishMarker(project, plan);
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
const markerBytes = dumpYamlMapping({ schemaVersion: "agentera.stateMode.v1", mode: "entities", source_fingerprint: plan.source_fingerprint, preview_digest: plan.preview_digest });
|
|
374
|
+
const targets = plan.entries.map((entry) => {
|
|
375
|
+
const target = entry.proposed_target;
|
|
376
|
+
const before = readProjectFileSnapshot(validateRealProjectRoot(project), target.path);
|
|
377
|
+
if (before.kind !== "file")
|
|
378
|
+
throw new EntityCutoverError(`first unresolved path '${target.path}': cutover target was not published before reconciliation`);
|
|
379
|
+
return { path: target.path, before: before.bytes, after: canonicalEntityEnvelopeBytes({ id: target.id, artifact: entry.artifact, record: entry.record, migrationProvenance: entry.canonical_migration_provenance }) };
|
|
380
|
+
});
|
|
381
|
+
targets.push({ path: TODO_RECONCILIATION_ACTIVATION_PATH, before: null, after: reconciliation.activation_after }, { path: reconciliation.public_path, before: Buffer.from(reconciliation.markdown_before_base64, "base64"), after: reconciliation.markdown_after }, { path: ENTITY_MODE_MARKER, before: null, after: markerBytes });
|
|
382
|
+
const validatedTargets = targets.map((target) => ({ path: target.path, before: target.before, after: Buffer.from(target.after) }));
|
|
383
|
+
const context = upgradePublicationContext(project, activeUpgradeLockPaths);
|
|
384
|
+
try {
|
|
385
|
+
publishTodoReconciliation(context, sourceRoot, { publicPath: reconciliation.public_path, mappingSha256: reconciliation.mapping_sha256 }, targets, {
|
|
386
|
+
retainUnchangedTargets: true,
|
|
387
|
+
interruptAfterTarget: process.env.NODE_ENV === "test" && process.env.AGENTERA_FAULT_INJECT_TODO_CUTOVER_AFTER_TARGET ? Number(process.env.AGENTERA_FAULT_INJECT_TODO_CUTOVER_AFTER_TARGET) : undefined,
|
|
388
|
+
beforeActivation: () => validatePendingEntityCutoverTargets(project, sourceRoot, { publicPath: reconciliation.public_path, mappingSha256: reconciliation.mapping_sha256 }, validatedTargets),
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
finally {
|
|
392
|
+
context.close();
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
function publishMarker(project, plan) {
|
|
396
|
+
const markerBytes = dumpYamlMapping({ schemaVersion: "agentera.stateMode.v1", mode: "entities", source_fingerprint: plan.source_fingerprint, preview_digest: plan.preview_digest });
|
|
397
|
+
const existing = markerSnapshot(project);
|
|
398
|
+
if (existing.kind === "file") {
|
|
399
|
+
if (!existing.bytes.equals(Buffer.from(markerBytes)))
|
|
400
|
+
throw new EntityCutoverError(`first unresolved path '${ENTITY_MODE_MARKER}': marker has unexpected bytes`);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
if (existing.kind !== "missing")
|
|
404
|
+
throw new EntityCutoverError(`first unresolved path '${ENTITY_MODE_MARKER}': marker path is unsafe`);
|
|
405
|
+
ensureDirectory(project, ".agentera");
|
|
406
|
+
const temporary = path.join(project, `.agentera/.state-mode-${randomUUID()}.tmp`);
|
|
407
|
+
try {
|
|
408
|
+
writeDurable(temporary, markerBytes);
|
|
409
|
+
fault("before_marker");
|
|
410
|
+
if (fs.existsSync(path.join(project, ENTITY_MODE_MARKER)))
|
|
411
|
+
throw new EntityCutoverError(`first unresolved path '${ENTITY_MODE_MARKER}': marker appeared during publication`);
|
|
412
|
+
fs.renameSync(temporary, path.join(project, ENTITY_MODE_MARKER));
|
|
413
|
+
}
|
|
414
|
+
finally {
|
|
415
|
+
fs.rmSync(temporary, { force: true });
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
export function applyPreparedEntityCutover(prepared, activeUpgradeLockPaths = []) {
|
|
419
|
+
if (prepared.recovery) {
|
|
420
|
+
const lock = acquireWriterLock(prepared.project, 2000);
|
|
421
|
+
try {
|
|
422
|
+
const recovered = recoverPendingTodoCutover(prepared.project, prepared.sourceRoot, activeUpgradeLockPaths);
|
|
423
|
+
if (!recovered)
|
|
424
|
+
throw new EntityCutoverError("prepared TODO cutover recovery journal is missing");
|
|
425
|
+
return recovered;
|
|
426
|
+
}
|
|
427
|
+
finally {
|
|
428
|
+
lock.release();
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
const before = inspect(prepared.project, prepared.sourceRoot, true, false, activeUpgradeLockPaths);
|
|
432
|
+
if (before.inspection.phase === "active")
|
|
433
|
+
return { status: "complete", phase: "active", idempotent: true, mutation_performed: false, entity_count: before.inspection.entityCount };
|
|
434
|
+
if (!before.plan || before.head !== prepared.head || before.plan.source_fingerprint !== prepared.sourceFingerprint || before.plan.preview_digest !== prepared.previewDigest)
|
|
435
|
+
throw new EntityCutoverError("first unresolved path '.agentera': converted input changed before apply");
|
|
436
|
+
const lock = acquireWriterLock(prepared.project, 2000);
|
|
437
|
+
try {
|
|
438
|
+
const current = inspect(prepared.project, prepared.sourceRoot, true, true, activeUpgradeLockPaths);
|
|
439
|
+
if (current.inspection.phase === "active")
|
|
440
|
+
return { status: "complete", phase: "active", idempotent: true, mutation_performed: false, entity_count: current.inspection.entityCount };
|
|
441
|
+
const plan = current.plan;
|
|
442
|
+
if (current.head !== prepared.head || plan.source_fingerprint !== prepared.sourceFingerprint || plan.preview_digest !== prepared.previewDigest)
|
|
443
|
+
throw new EntityCutoverError("first unresolved path '.agentera': converted input changed before its first effect");
|
|
444
|
+
publishTargets(prepared.project, plan);
|
|
445
|
+
const validation = validateEntityState(prepared.project, prepared.sourceRoot, { kind: "migration_preview", projectRoot: prepared.project });
|
|
446
|
+
if (!validation.valid || validation.entityCount !== plan.entries.length) {
|
|
447
|
+
const issue = validation.issues[0];
|
|
448
|
+
throw new EntityCutoverError(`first unresolved path '${issue?.path ?? ".agentera/entities"}': converted entity graph is invalid (${validation.entityCount}/${plan.entries.length})${issue ? `: ${issue.message}` : ""}`);
|
|
449
|
+
}
|
|
450
|
+
publishTodoCutover(prepared.project, prepared.sourceRoot, plan, activeUpgradeLockPaths);
|
|
451
|
+
const marker = markerSnapshot(prepared.project);
|
|
452
|
+
if (marker.kind !== "file")
|
|
453
|
+
throw new EntityCutoverError(`first unresolved path '${ENTITY_MODE_MARKER}': marker was not published`);
|
|
454
|
+
return { status: "complete", phase: "active", idempotent: false, mutation_performed: true, entity_count: validateActiveEntityCutover(prepared.project, marker.bytes, prepared.sourceRoot) };
|
|
455
|
+
}
|
|
456
|
+
finally {
|
|
457
|
+
lock.release();
|
|
458
|
+
}
|
|
459
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { validateRealProjectRoot } from "./projectRoot.js";
|
|
6
|
+
import { readProjectFileSnapshot } from "./safeProjectFile.js";
|
|
7
|
+
export class EntityCutoverGitError extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "EntityCutoverGitError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function hash(bytes) {
|
|
14
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
15
|
+
}
|
|
16
|
+
function gitEnvironment() {
|
|
17
|
+
const env = { ...process.env };
|
|
18
|
+
for (const name of ["GIT_INDEX_FILE", "GIT_DIR", "GIT_WORK_TREE", "GIT_COMMON_DIR"])
|
|
19
|
+
delete env[name];
|
|
20
|
+
return env;
|
|
21
|
+
}
|
|
22
|
+
function git(project, args, encoding = "utf8") {
|
|
23
|
+
const result = spawnSync("git", args, { cwd: project, env: gitEnvironment(), encoding: encoding ?? "buffer" });
|
|
24
|
+
if (result.error)
|
|
25
|
+
throw new EntityCutoverGitError(`Git preflight failed: ${result.error.message}`);
|
|
26
|
+
return { status: result.status ?? 2, stdout: result.stdout ?? (encoding === null ? Buffer.alloc(0) : "") };
|
|
27
|
+
}
|
|
28
|
+
function gitText(project, args) {
|
|
29
|
+
const result = git(project, args);
|
|
30
|
+
if (result.status !== 0)
|
|
31
|
+
throw new EntityCutoverGitError(`Git preflight command failed: git ${args.join(" ")}`);
|
|
32
|
+
return String(result.stdout).trim();
|
|
33
|
+
}
|
|
34
|
+
function safeRelative(value) {
|
|
35
|
+
return value.length > 0
|
|
36
|
+
&& !value.includes("\0")
|
|
37
|
+
&& !value.includes("\\")
|
|
38
|
+
&& !path.isAbsolute(value)
|
|
39
|
+
&& value.split("/").every((part) => part !== "" && part !== "." && part !== "..");
|
|
40
|
+
}
|
|
41
|
+
function assertCleanTrackedState(project) {
|
|
42
|
+
const working = git(project, ["diff", "--quiet", "--no-ext-diff", "--"]);
|
|
43
|
+
if (working.status === 1)
|
|
44
|
+
throw new EntityCutoverGitError("Git worktree has modified or renamed tracked paths; commit or restore them before v2-to-v3 upgrade");
|
|
45
|
+
if (working.status !== 0)
|
|
46
|
+
throw new EntityCutoverGitError("Git could not verify the working tree before v2-to-v3 upgrade");
|
|
47
|
+
const staged = git(project, ["diff", "--cached", "--quiet", "--no-ext-diff", "HEAD", "--"]);
|
|
48
|
+
if (staged.status === 1)
|
|
49
|
+
throw new EntityCutoverGitError("Git index has staged or renamed paths; commit or restore them before v2-to-v3 upgrade");
|
|
50
|
+
if (staged.status !== 0)
|
|
51
|
+
throw new EntityCutoverGitError("Git could not verify the index before v2-to-v3 upgrade");
|
|
52
|
+
}
|
|
53
|
+
function assertNoUnapprovedUntracked(project, allowlist) {
|
|
54
|
+
const result = git(project, ["ls-files", "--others", "--exclude-standard", "-z"]);
|
|
55
|
+
if (result.status !== 0)
|
|
56
|
+
throw new EntityCutoverGitError("Git could not inventory untracked paths before v2-to-v3 upgrade");
|
|
57
|
+
const paths = new Set(allowlist.paths ?? []);
|
|
58
|
+
const prefixes = [...(allowlist.prefixes ?? [])].map((prefix) => prefix.endsWith("/") ? prefix : `${prefix}/`);
|
|
59
|
+
const unexpected = String(result.stdout).split("\0").filter(Boolean).find((candidate) => !paths.has(candidate) && !prefixes.some((prefix) => candidate.startsWith(prefix)));
|
|
60
|
+
if (unexpected)
|
|
61
|
+
throw new EntityCutoverGitError(`Git worktree has untracked path '${unexpected}'; commit, ignore, or remove it before v2-to-v3 upgrade`);
|
|
62
|
+
}
|
|
63
|
+
function headEntry(project, relativePath) {
|
|
64
|
+
const result = git(project, ["ls-tree", "-z", "HEAD", "--", relativePath]);
|
|
65
|
+
if (result.status !== 0)
|
|
66
|
+
throw new EntityCutoverGitError(`Git could not inspect HEAD path '${relativePath}'`);
|
|
67
|
+
const records = String(result.stdout).split("\0").filter(Boolean);
|
|
68
|
+
if (records.length === 0)
|
|
69
|
+
return null;
|
|
70
|
+
if (records.length !== 1)
|
|
71
|
+
throw new EntityCutoverGitError(`Git HEAD path '${relativePath}' is ambiguous`);
|
|
72
|
+
const match = /^([0-7]{6}) (blob|commit) ([a-f0-9]+)\t(.+)$/.exec(records[0]);
|
|
73
|
+
if (!match || match[4] !== relativePath || match[2] !== "blob" || !["100644", "100755"].includes(match[1])) {
|
|
74
|
+
throw new EntityCutoverGitError(`migration input '${relativePath}' must be a regular tracked file in HEAD`);
|
|
75
|
+
}
|
|
76
|
+
return { mode: match[1], oid: match[3] };
|
|
77
|
+
}
|
|
78
|
+
function assertSourceMatchesHead(project, source) {
|
|
79
|
+
const lookupPath = source.path.endsWith("/") ? source.path.slice(0, -1) : source.path;
|
|
80
|
+
if (!safeRelative(lookupPath))
|
|
81
|
+
throw new EntityCutoverGitError(`migration input path '${source.path}' is unsafe`);
|
|
82
|
+
if (source.presence === "missing") {
|
|
83
|
+
const tracked = source.path.endsWith("/")
|
|
84
|
+
? gitText(project, ["ls-tree", "-r", "--name-only", "HEAD", "--", `${lookupPath}/`]) !== ""
|
|
85
|
+
: headEntry(project, lookupPath) !== null;
|
|
86
|
+
if (tracked)
|
|
87
|
+
throw new EntityCutoverGitError(`migration input '${source.path}' is tracked in HEAD but absent from the worktree`);
|
|
88
|
+
const observed = readProjectFileSnapshot(validateRealProjectRoot(project), lookupPath);
|
|
89
|
+
if (observed.kind !== "missing")
|
|
90
|
+
throw new EntityCutoverGitError(`migration input '${source.path}' is absent from HEAD but present or unsafe in the worktree`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const tracked = headEntry(project, lookupPath);
|
|
94
|
+
if (!tracked)
|
|
95
|
+
throw new EntityCutoverGitError(`migration input '${source.path}' is ignored or untracked; v2-to-v3 upgrade consumes only HEAD`);
|
|
96
|
+
const observed = readProjectFileSnapshot(validateRealProjectRoot(project), lookupPath);
|
|
97
|
+
if (observed.kind !== "file")
|
|
98
|
+
throw new EntityCutoverGitError(`migration input '${source.path}' must be a safe regular tracked file`);
|
|
99
|
+
const blob = git(project, ["cat-file", "blob", tracked.oid], null);
|
|
100
|
+
if (blob.status !== 0 || !Buffer.isBuffer(blob.stdout))
|
|
101
|
+
throw new EntityCutoverGitError(`Git could not read HEAD bytes for migration input '${source.path}'`);
|
|
102
|
+
const executable = (observed.mode & 0o111) !== 0;
|
|
103
|
+
const expectedMode = executable ? "100755" : "100644";
|
|
104
|
+
if (tracked.mode !== expectedMode
|
|
105
|
+
|| source.mode !== observed.mode
|
|
106
|
+
|| source.type !== "file"
|
|
107
|
+
|| source.sha256 !== hash(observed.bytes)
|
|
108
|
+
|| !observed.bytes.equals(blob.stdout)) {
|
|
109
|
+
throw new EntityCutoverGitError(`migration input '${source.path}' differs from HEAD in bytes, type, mode, or symlink form`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
export function verifyEntityCutoverGitSource(projectRoot, plan, allowlist = {}) {
|
|
113
|
+
const project = validateRealProjectRoot(projectRoot).path;
|
|
114
|
+
const top = fs.realpathSync(gitText(project, ["rev-parse", "--show-toplevel"]));
|
|
115
|
+
if (top !== project)
|
|
116
|
+
throw new EntityCutoverGitError(`project '${project}' must be the Git worktree root for v2-to-v3 upgrade`);
|
|
117
|
+
const head = gitText(project, ["rev-parse", "--verify", "HEAD^{commit}"]);
|
|
118
|
+
if (!/^[a-f0-9]{40,64}$/.test(head))
|
|
119
|
+
throw new EntityCutoverGitError("Git HEAD is missing or invalid; commit the v2 project before upgrade");
|
|
120
|
+
assertCleanTrackedState(project);
|
|
121
|
+
assertNoUnapprovedUntracked(project, allowlist);
|
|
122
|
+
for (const source of plan.sources)
|
|
123
|
+
assertSourceMatchesHead(project, source);
|
|
124
|
+
if (gitText(project, ["rev-parse", "--verify", "HEAD^{commit}"]) !== head)
|
|
125
|
+
throw new EntityCutoverGitError("Git HEAD changed during v2-to-v3 preflight");
|
|
126
|
+
return { head };
|
|
127
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { glossaryCaveatContractFromDocument, } from "../registries/glossaryCaveatContract.js";
|
|
3
|
+
import { loadYamlMapping } from "../core/yaml.js";
|
|
4
|
+
let cache;
|
|
5
|
+
/** Read every request and reuse one derived contract only for exact matching bytes. */
|
|
6
|
+
export function loadEntityGlossaryAuthority(path) {
|
|
7
|
+
const bytes = fs.readFileSync(path);
|
|
8
|
+
if (cache?.path === path && cache.bytes.equals(bytes))
|
|
9
|
+
return cache.contract;
|
|
10
|
+
const contract = glossaryCaveatContractFromDocument(loadYamlMapping(bytes.toString("utf8")));
|
|
11
|
+
cache = { path, bytes, contract };
|
|
12
|
+
return contract;
|
|
13
|
+
}
|