@tiinex/core 0.1.1
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/NOTICE +31 -0
- package/README.md +45 -0
- package/package.json +176 -0
- package/src/actions/record.actions.js +312 -0
- package/src/adapters/adapter.contracts.js +143 -0
- package/src/adapters/archive/archive.adapter.js +502 -0
- package/src/adapters/archive/archive.portableChangeset.js +141 -0
- package/src/adapters/archive/archive.transport.js +124 -0
- package/src/artifacts/artifact.localDraft.js +27 -0
- package/src/artifacts/artifact.normalize.js +28 -0
- package/src/artifacts/artifact.parse.js +207 -0
- package/src/artifacts/artifact.record.js +83 -0
- package/src/audit/audit.run.js +103 -0
- package/src/audit/audit.summary.js +7 -0
- package/src/diagnostics/sourceBoundary.report.js +112 -0
- package/src/export/package.apply.js +349 -0
- package/src/export/package.builder.js +366 -0
- package/src/export/package.bytes.js +164 -0
- package/src/export/package.controlIntegrity.js +42 -0
- package/src/export/package.controlTopology.js +97 -0
- package/src/export/package.fileMap.js +174 -0
- package/src/export/package.manifest.js +401 -0
- package/src/export/package.preflight.js +204 -0
- package/src/export/package.sourceReference.js +81 -0
- package/src/export/package.workspaceContext.js +144 -0
- package/src/export/package.zip.js +128 -0
- package/src/export/tree.bundle.js +278 -0
- package/src/governance/governance.boundary.js +196 -0
- package/src/integrity/integrity.c14nV2.js +190 -0
- package/src/integrity/integrity.methodReference.js +73 -0
- package/src/integrity/integrity.validate.js +56 -0
- package/src/lineage/lineage.candidateResolution.js +46 -0
- package/src/lineage/lineage.githubIssueComment.js +106 -0
- package/src/lineage/lineage.githubIssueLocal.js +196 -0
- package/src/lineage/lineage.githubIssueTarget.js +89 -0
- package/src/lineage/lineage.integrity.js +133 -0
- package/src/lineage/lineage.materialPreference.js +26 -0
- package/src/lineage/lineage.model.js +63 -0
- package/src/lineage/lineage.parentAuthority.js +5 -0
- package/src/lineage/lineage.parentBinding.js +104 -0
- package/src/lineage/lineage.pathBasis.js +47 -0
- package/src/lineage/lineage.resolve.js +388 -0
- package/src/lineage/lineage.sourceScope.js +74 -0
- package/src/lineage/lineage.targetKeys.js +80 -0
- package/src/lineage/lineage.traverse.js +132 -0
- package/src/public/applicationProjection.js +236 -0
- package/src/public/companionResources.js +246 -0
- package/src/public/index.js +16 -0
- package/src/public/node.js +2 -0
- package/src/public/schemaAncestry.js +26 -0
- package/src/publication/publication.contract.js +196 -0
- package/src/publication/publication.preflight.js +159 -0
- package/src/publication/publication.targetContract.js +241 -0
- package/src/reingest/reingest.plan.js +162 -0
- package/src/release/plan.mjs +28 -0
- package/src/release/policy.mjs +100 -0
- package/src/release/run.mjs +74 -0
- package/src/schemas/capability.registry.js +226 -0
- package/src/schemas/companion.js +245 -0
- package/src/schemas/contracts.js +6 -0
- package/src/schemas/coordination/handoff/tiinex.handoff.v1.schema.js +14 -0
- package/src/schemas/coordination/handoff/tiinex.handoff.v1.schema.json +23 -0
- package/src/schemas/coordination/handoff/tiinex.handoff.v1.schema.runtime.json +4283 -0
- package/src/schemas/coordination/handoff/tiinex.handoff.v1.schema.source.js +9 -0
- package/src/schemas/coordination/project/tiinex.project.v1.schema.js +26 -0
- package/src/schemas/coordination/project/tiinex.project.v1.schema.json +23 -0
- package/src/schemas/coordination/project/tiinex.project.v1.schema.runtime.json +1985 -0
- package/src/schemas/coordination/project/tiinex.project.v1.schema.source.js +9 -0
- package/src/schemas/core/decision/tiinex.decision.v1.schema.js +14 -0
- package/src/schemas/core/decision/tiinex.decision.v1.schema.json +24 -0
- package/src/schemas/core/decision/tiinex.decision.v1.schema.runtime.json +1700 -0
- package/src/schemas/core/decision/tiinex.decision.v1.schema.source.js +9 -0
- package/src/schemas/core/evidence/tiinex.evidence.v1.capabilities.js +14 -0
- package/src/schemas/core/evidence/tiinex.evidence.v1.en.i18n.json +6 -0
- package/src/schemas/core/evidence/tiinex.evidence.v1.findings.js +9 -0
- package/src/schemas/core/evidence/tiinex.evidence.v1.presenter.js +1 -0
- package/src/schemas/core/evidence/tiinex.evidence.v1.schema.js +32 -0
- package/src/schemas/core/evidence/tiinex.evidence.v1.schema.json +24 -0
- package/src/schemas/core/evidence/tiinex.evidence.v1.schema.runtime.json +2184 -0
- package/src/schemas/core/evidence/tiinex.evidence.v1.schema.source.js +9 -0
- package/src/schemas/core/evidence/tiinex.evidence.v1.sv.i18n.json +6 -0
- package/src/schemas/core/evidence/tiinex.evidence.v1.transitions.js +1 -0
- package/src/schemas/core/evidence/tiinex.evidence.v1.validate.js +10 -0
- package/src/schemas/core/feedback/tiinex.feedback.v1.schema.js +14 -0
- package/src/schemas/core/feedback/tiinex.feedback.v1.schema.json +23 -0
- package/src/schemas/core/feedback/tiinex.feedback.v1.schema.runtime.json +1773 -0
- package/src/schemas/core/feedback/tiinex.feedback.v1.schema.source.js +9 -0
- package/src/schemas/core/interpretation/tiinex.interpretation.v1.capabilities.js +11 -0
- package/src/schemas/core/interpretation/tiinex.interpretation.v1.contract.js +40 -0
- package/src/schemas/core/interpretation/tiinex.interpretation.v1.en.i18n.json +9 -0
- package/src/schemas/core/interpretation/tiinex.interpretation.v1.findings.js +12 -0
- package/src/schemas/core/interpretation/tiinex.interpretation.v1.localMaterialization.js +89 -0
- package/src/schemas/core/interpretation/tiinex.interpretation.v1.presenter.js +8 -0
- package/src/schemas/core/interpretation/tiinex.interpretation.v1.schema.js +34 -0
- package/src/schemas/core/interpretation/tiinex.interpretation.v1.schema.json +23 -0
- package/src/schemas/core/interpretation/tiinex.interpretation.v1.schema.runtime.json +2029 -0
- package/src/schemas/core/interpretation/tiinex.interpretation.v1.schema.source.js +9 -0
- package/src/schemas/core/interpretation/tiinex.interpretation.v1.sv.i18n.json +9 -0
- package/src/schemas/core/interpretation/tiinex.interpretation.v1.transitions.js +1 -0
- package/src/schemas/core/interpretation/tiinex.interpretation.v1.validate.js +25 -0
- package/src/schemas/core/preservation/tiinex.preservation.v1.capabilities.js +14 -0
- package/src/schemas/core/preservation/tiinex.preservation.v1.en.i18n.json +6 -0
- package/src/schemas/core/preservation/tiinex.preservation.v1.findings.js +9 -0
- package/src/schemas/core/preservation/tiinex.preservation.v1.presenter.js +1 -0
- package/src/schemas/core/preservation/tiinex.preservation.v1.schema.js +31 -0
- package/src/schemas/core/preservation/tiinex.preservation.v1.schema.json +23 -0
- package/src/schemas/core/preservation/tiinex.preservation.v1.schema.runtime.json +2033 -0
- package/src/schemas/core/preservation/tiinex.preservation.v1.schema.source.js +9 -0
- package/src/schemas/core/preservation/tiinex.preservation.v1.sv.i18n.json +6 -0
- package/src/schemas/core/preservation/tiinex.preservation.v1.transitions.js +1 -0
- package/src/schemas/core/preservation/tiinex.preservation.v1.validate.js +10 -0
- package/src/schemas/core/relation/tiinex.relation.v1.capabilities.js +7 -0
- package/src/schemas/core/relation/tiinex.relation.v1.contract.js +3 -0
- package/src/schemas/core/relation/tiinex.relation.v1.en.i18n.json +4 -0
- package/src/schemas/core/relation/tiinex.relation.v1.findings.js +9 -0
- package/src/schemas/core/relation/tiinex.relation.v1.localMaterialization.js +153 -0
- package/src/schemas/core/relation/tiinex.relation.v1.presenter.js +3 -0
- package/src/schemas/core/relation/tiinex.relation.v1.schema.js +20 -0
- package/src/schemas/core/relation/tiinex.relation.v1.schema.json +23 -0
- package/src/schemas/core/relation/tiinex.relation.v1.schema.runtime.json +1668 -0
- package/src/schemas/core/relation/tiinex.relation.v1.schema.source.js +9 -0
- package/src/schemas/core/relation/tiinex.relation.v1.sv.i18n.json +4 -0
- package/src/schemas/core/relation/tiinex.relation.v1.transitions.js +1 -0
- package/src/schemas/core/relation/tiinex.relation.v1.validate.js +36 -0
- package/src/schemas/core/relation/workspace/representation/tiinex.workspace.representation.v1.capabilities.js +14 -0
- package/src/schemas/core/relation/workspace/representation/tiinex.workspace.representation.v1.contract.js +57 -0
- package/src/schemas/core/relation/workspace/representation/tiinex.workspace.representation.v1.en.i18n.json +4 -0
- package/src/schemas/core/relation/workspace/representation/tiinex.workspace.representation.v1.findings.js +13 -0
- package/src/schemas/core/relation/workspace/representation/tiinex.workspace.representation.v1.presenter.js +3 -0
- package/src/schemas/core/relation/workspace/representation/tiinex.workspace.representation.v1.schema.js +20 -0
- package/src/schemas/core/relation/workspace/representation/tiinex.workspace.representation.v1.schema.json +24 -0
- package/src/schemas/core/relation/workspace/representation/tiinex.workspace.representation.v1.schema.runtime.json +3315 -0
- package/src/schemas/core/relation/workspace/representation/tiinex.workspace.representation.v1.schema.source.js +9 -0
- package/src/schemas/core/relation/workspace/representation/tiinex.workspace.representation.v1.sv.i18n.json +4 -0
- package/src/schemas/core/relation/workspace/representation/tiinex.workspace.representation.v1.transitions.js +1 -0
- package/src/schemas/core/relation/workspace/representation/tiinex.workspace.representation.v1.validate.js +78 -0
- package/src/schemas/core/signal/tiinex.signal.v1.schema.js +14 -0
- package/src/schemas/core/signal/tiinex.signal.v1.schema.json +23 -0
- package/src/schemas/core/signal/tiinex.signal.v1.schema.runtime.json +1733 -0
- package/src/schemas/core/signal/tiinex.signal.v1.schema.source.js +9 -0
- package/src/schemas/core/task/tiinex.task.v1.capabilities.js +11 -0
- package/src/schemas/core/task/tiinex.task.v1.contract.js +3 -0
- package/src/schemas/core/task/tiinex.task.v1.en.i18n.json +15 -0
- package/src/schemas/core/task/tiinex.task.v1.findings.js +18 -0
- package/src/schemas/core/task/tiinex.task.v1.localMaterialization.js +148 -0
- package/src/schemas/core/task/tiinex.task.v1.presenter.js +8 -0
- package/src/schemas/core/task/tiinex.task.v1.schema.js +35 -0
- package/src/schemas/core/task/tiinex.task.v1.schema.json +23 -0
- package/src/schemas/core/task/tiinex.task.v1.schema.runtime.json +1708 -0
- package/src/schemas/core/task/tiinex.task.v1.schema.source.js +9 -0
- package/src/schemas/core/task/tiinex.task.v1.sv.i18n.json +15 -0
- package/src/schemas/core/task/tiinex.task.v1.transitions.js +3 -0
- package/src/schemas/core/task/tiinex.task.v1.validate.js +41 -0
- package/src/schemas/core/topic/tiinex.topic.v1.capabilities.js +14 -0
- package/src/schemas/core/topic/tiinex.topic.v1.creation.js +46 -0
- package/src/schemas/core/topic/tiinex.topic.v1.en.i18n.json +8 -0
- package/src/schemas/core/topic/tiinex.topic.v1.findings.js +11 -0
- package/src/schemas/core/topic/tiinex.topic.v1.localMaterialization.js +135 -0
- package/src/schemas/core/topic/tiinex.topic.v1.presenter.js +1 -0
- package/src/schemas/core/topic/tiinex.topic.v1.schema.js +34 -0
- package/src/schemas/core/topic/tiinex.topic.v1.schema.json +23 -0
- package/src/schemas/core/topic/tiinex.topic.v1.schema.runtime.json +1699 -0
- package/src/schemas/core/topic/tiinex.topic.v1.schema.source.js +9 -0
- package/src/schemas/core/topic/tiinex.topic.v1.sv.i18n.json +8 -0
- package/src/schemas/core/topic/tiinex.topic.v1.transitions.js +31 -0
- package/src/schemas/core/topic/tiinex.topic.v1.validate.js +11 -0
- package/src/schemas/creation.capability.js +289 -0
- package/src/schemas/creation.contracts.js +334 -0
- package/src/schemas/creation.executionSnapshot.js +79 -0
- package/src/schemas/creation.factoryQualification.js +73 -0
- package/src/schemas/creation.renderer.js +244 -0
- package/src/schemas/creation.representation.js +279 -0
- package/src/schemas/creation.rootMetadata.js +6 -0
- package/src/schemas/creation.schemaReferences.js +65 -0
- package/src/schemas/discovery/finding/tiinex.discovery.finding.v1.schema.js +14 -0
- package/src/schemas/discovery/finding/tiinex.discovery.finding.v1.schema.json +23 -0
- package/src/schemas/discovery/finding/tiinex.discovery.finding.v1.schema.runtime.json +1873 -0
- package/src/schemas/discovery/finding/tiinex.discovery.finding.v1.schema.source.js +9 -0
- package/src/schemas/discovery/tiinex.discovery.v1.schema.js +14 -0
- package/src/schemas/discovery/tiinex.discovery.v1.schema.json +23 -0
- package/src/schemas/discovery/tiinex.discovery.v1.schema.runtime.json +1839 -0
- package/src/schemas/discovery/tiinex.discovery.v1.schema.source.js +9 -0
- package/src/schemas/generic.artifact.module.js +25 -0
- package/src/schemas/party/organization/tiinex.party.organization.v1.schema.js +26 -0
- package/src/schemas/party/organization/tiinex.party.organization.v1.schema.json +23 -0
- package/src/schemas/party/organization/tiinex.party.organization.v1.schema.runtime.json +2249 -0
- package/src/schemas/party/organization/tiinex.party.organization.v1.schema.source.js +9 -0
- package/src/schemas/party/role/tiinex.party.role.v1.schema.js +26 -0
- package/src/schemas/party/role/tiinex.party.role.v1.schema.json +24 -0
- package/src/schemas/party/role/tiinex.party.role.v1.schema.runtime.json +2091 -0
- package/src/schemas/party/role/tiinex.party.role.v1.schema.source.js +9 -0
- package/src/schemas/presentation/surface/tiinex.presentation.surface.v1.capabilities.js +14 -0
- package/src/schemas/presentation/surface/tiinex.presentation.surface.v1.en.i18n.json +4 -0
- package/src/schemas/presentation/surface/tiinex.presentation.surface.v1.findings.js +1 -0
- package/src/schemas/presentation/surface/tiinex.presentation.surface.v1.presenter.js +1 -0
- package/src/schemas/presentation/surface/tiinex.presentation.surface.v1.schema.js +29 -0
- package/src/schemas/presentation/surface/tiinex.presentation.surface.v1.schema.json +21 -0
- package/src/schemas/presentation/surface/tiinex.presentation.surface.v1.schema.runtime.json +2180 -0
- package/src/schemas/presentation/surface/tiinex.presentation.surface.v1.schema.source.js +9 -0
- package/src/schemas/presentation/surface/tiinex.presentation.surface.v1.sv.i18n.json +4 -0
- package/src/schemas/presentation/surface/tiinex.presentation.surface.v1.transitions.js +1 -0
- package/src/schemas/presentation/surface/tiinex.presentation.surface.v1.validate.js +1 -0
- package/src/schemas/reduction/tiinex.reduction.v1.schema.js +26 -0
- package/src/schemas/reduction/tiinex.reduction.v1.schema.json +23 -0
- package/src/schemas/reduction/tiinex.reduction.v1.schema.runtime.json +1733 -0
- package/src/schemas/reduction/tiinex.reduction.v1.schema.source.js +9 -0
- package/src/schemas/reference.shapes.js +33 -0
- package/src/schemas/registry.js +36 -0
- package/src/schemas/resolver.js +13 -0
- package/src/schemas/schema/module/tiinex.schema.module.v1.capabilities.js +14 -0
- package/src/schemas/schema/module/tiinex.schema.module.v1.en.i18n.json +4 -0
- package/src/schemas/schema/module/tiinex.schema.module.v1.findings.js +1 -0
- package/src/schemas/schema/module/tiinex.schema.module.v1.presenter.js +1 -0
- package/src/schemas/schema/module/tiinex.schema.module.v1.schema.js +29 -0
- package/src/schemas/schema/module/tiinex.schema.module.v1.schema.json +21 -0
- package/src/schemas/schema/module/tiinex.schema.module.v1.schema.runtime.json +2093 -0
- package/src/schemas/schema/module/tiinex.schema.module.v1.schema.source.js +9 -0
- package/src/schemas/schema/module/tiinex.schema.module.v1.sv.i18n.json +4 -0
- package/src/schemas/schema/module/tiinex.schema.module.v1.transitions.js +1 -0
- package/src/schemas/schema/module/tiinex.schema.module.v1.validate.js +1 -0
- package/src/schemas/schema.factory.descriptor.js +104 -0
- package/src/schemas/schema.githubSourceTarget.js +131 -0
- package/src/schemas/schema.identity.js +10 -0
- package/src/schemas/schema.reference.js +133 -0
- package/src/schemas/schema.source.js +239 -0
- package/src/schemas/tiinex.root.v1.capabilities.js +14 -0
- package/src/schemas/tiinex.root.v1.classify.js +55 -0
- package/src/schemas/tiinex.root.v1.en.i18n.json +24 -0
- package/src/schemas/tiinex.root.v1.fallback.js +84 -0
- package/src/schemas/tiinex.root.v1.findings.js +19 -0
- package/src/schemas/tiinex.root.v1.presenter.js +5 -0
- package/src/schemas/tiinex.root.v1.schema.js +29 -0
- package/src/schemas/tiinex.root.v1.schema.json +24 -0
- package/src/schemas/tiinex.root.v1.schema.runtime.json +1574 -0
- package/src/schemas/tiinex.root.v1.schema.source.js +9 -0
- package/src/schemas/tiinex.root.v1.sv.i18n.json +24 -0
- package/src/schemas/tiinex.root.v1.transitions.js +1 -0
- package/src/schemas/tiinex.root.v1.validate.js +36 -0
- package/src/schemas/validation/finding/tiinex.validation.finding.v1.schema.js +14 -0
- package/src/schemas/validation/finding/tiinex.validation.finding.v1.schema.json +23 -0
- package/src/schemas/validation/finding/tiinex.validation.finding.v1.schema.runtime.json +2027 -0
- package/src/schemas/validation/finding/tiinex.validation.finding.v1.schema.source.js +9 -0
- package/src/schemas/validation/method/tiinex.validation.method.v1.schema.js +14 -0
- package/src/schemas/validation/method/tiinex.validation.method.v1.schema.json +23 -0
- package/src/schemas/validation/method/tiinex.validation.method.v1.schema.runtime.json +1848 -0
- package/src/schemas/validation/method/tiinex.validation.method.v1.schema.source.js +9 -0
- package/src/schemas/validation/report/tiinex.validation.report.v1.schema.js +14 -0
- package/src/schemas/validation/report/tiinex.validation.report.v1.schema.json +23 -0
- package/src/schemas/validation/report/tiinex.validation.report.v1.schema.runtime.json +2015 -0
- package/src/schemas/validation/report/tiinex.validation.report.v1.schema.source.js +9 -0
- package/src/schemas/workspace/tiinex.workspace.v1.capabilities.js +12 -0
- package/src/schemas/workspace/tiinex.workspace.v1.en.i18n.json +7 -0
- package/src/schemas/workspace/tiinex.workspace.v1.findings.js +5 -0
- package/src/schemas/workspace/tiinex.workspace.v1.presenter.js +27 -0
- package/src/schemas/workspace/tiinex.workspace.v1.schema.js +30 -0
- package/src/schemas/workspace/tiinex.workspace.v1.schema.json +23 -0
- package/src/schemas/workspace/tiinex.workspace.v1.schema.runtime.json +1596 -0
- package/src/schemas/workspace/tiinex.workspace.v1.schema.source.js +9 -0
- package/src/schemas/workspace/tiinex.workspace.v1.sv.i18n.json +7 -0
- package/src/schemas/workspace/tiinex.workspace.v1.transitions.js +10 -0
- package/src/schemas/workspace/tiinex.workspace.v1.validate.js +10 -0
- package/src/sources/github/github.issueTarget.js +127 -0
- package/src/sources/origin.references.js +249 -0
- package/src/sources/source.explicitTargets.js +49 -0
- package/src/sources/transport.levels.js +107 -0
- package/src/tooling/portable/adapters/cli/cli.cold-start-input.js +34 -0
- package/src/tooling/portable/adapters/cli/cli.command-input.js +455 -0
- package/src/tooling/portable/adapters/cli/cli.common-author.js +249 -0
- package/src/tooling/portable/adapters/cli/cli.common-output.js +330 -0
- package/src/tooling/portable/adapters/cli/cli.editor-assistance.js +13 -0
- package/src/tooling/portable/adapters/cli/cli.ground-materialize.js +96 -0
- package/src/tooling/portable/adapters/cli/cli.ground-recovery.js +99 -0
- package/src/tooling/portable/adapters/cli/cli.handoff-manufacture.js +345 -0
- package/src/tooling/portable/adapters/cli/cli.handoff-sibling-allocation.js +31 -0
- package/src/tooling/portable/adapters/cli/cli.help.js +80 -0
- package/src/tooling/portable/adapters/cli/cli.land.js +13 -0
- package/src/tooling/portable/adapters/cli/cli.local-output.js +72 -0
- package/src/tooling/portable/adapters/cli/cli.material-policy.js +6 -0
- package/src/tooling/portable/adapters/cli/cli.operator-bridge.js +18 -0
- package/src/tooling/portable/adapters/cli/cli.reduction-input.js +14 -0
- package/src/tooling/portable/adapters/cli/cli.run.js +434 -0
- package/src/tooling/portable/adapters/llm/llm.entrypoint.js +34 -0
- package/src/tooling/portable/adapters/node/checkpoint.verify.js +267 -0
- package/src/tooling/portable/adapters/node/handoff.manufacture.bootstrap.js +109 -0
- package/src/tooling/portable/adapters/node/handoff.manufacture.enumeration.js +94 -0
- package/src/tooling/portable/adapters/node/handoff.manufacture.js +193 -0
- package/src/tooling/portable/adapters/node/handoff.manufacture.multiRoot.js +49 -0
- package/src/tooling/portable/adapters/node/handoff.manufacture.packageParent.js +130 -0
- package/src/tooling/portable/adapters/node/handoff.manufacture.requirements.js +353 -0
- package/src/tooling/portable/adapters/node/handoff.manufacture.scope.js +147 -0
- package/src/tooling/portable/adapters/node/workspaceCarrier.manufacture.js +62 -0
- package/src/tooling/portable/assets/asset.operations.js +170 -0
- package/src/tooling/portable/audit/audit.capability.js +119 -0
- package/src/tooling/portable/bootstrap/artifact.result.selfverify.mjs +109 -0
- package/src/tooling/portable/bootstrap/bootstrap.case.mjs +43 -0
- package/src/tooling/portable/bootstrap/tiinex.llm.bootstrap.md +814 -0
- package/src/tooling/portable/bootstrap/tiinex.llm.bootstrap.pointer.json +25 -0
- package/src/tooling/portable/checkpoint/portable.checkpoint.js +89 -0
- package/src/tooling/portable/conformance/checkpoint.qualification.js +271 -0
- package/src/tooling/portable/draft/draft.create.js +389 -0
- package/src/tooling/portable/draft/draft.crud.js +175 -0
- package/src/tooling/portable/draft/draft.exact.js +173 -0
- package/src/tooling/portable/draft/draft.operations.js +265 -0
- package/src/tooling/portable/draft/draft.qualification.js +45 -0
- package/src/tooling/portable/draft/draft.set.js +193 -0
- package/src/tooling/portable/draft/draft.validation-context.js +7 -0
- package/src/tooling/portable/editor/authoring.parent.js +37 -0
- package/src/tooling/portable/editor/editor.assistance.js +221 -0
- package/src/tooling/portable/editor/staged.validation.js +96 -0
- package/src/tooling/portable/engine.facade.js +468 -0
- package/src/tooling/portable/findings.js +92 -0
- package/src/tooling/portable/grounding/grounding.capsule.js +128 -0
- package/src/tooling/portable/grounding/grounding.continuity.js +283 -0
- package/src/tooling/portable/grounding/grounding.participantAuthority.js +20 -0
- package/src/tooling/portable/grounding/grounding.planningContext.js +34 -0
- package/src/tooling/portable/grounding/grounding.readiness.authority.js +17 -0
- package/src/tooling/portable/grounding/grounding.readiness.js +316 -0
- package/src/tooling/portable/grounding/grounding.readiness.support.js +245 -0
- package/src/tooling/portable/grounding/grounding.sourceEvidence.js +71 -0
- package/src/tooling/portable/grounding/grounding.workContext.js +72 -0
- package/src/tooling/portable/grounding/grounding.workProvenance.js +153 -0
- package/src/tooling/portable/handoff/carrierLineage.js +214 -0
- package/src/tooling/portable/handoff/carrierProfile.js +54 -0
- package/src/tooling/portable/handoff/carrierProjection.js +193 -0
- package/src/tooling/portable/handoff/carrierProjection.routeQualification.js +228 -0
- package/src/tooling/portable/handoff/carrierProjection.shared.js +7 -0
- package/src/tooling/portable/handoff/carrierProjection.workspaces.js +54 -0
- package/src/tooling/portable/handoff/coldConsumerEntrypoint.js +185 -0
- package/src/tooling/portable/handoff/coldStartQualification.contract.js +184 -0
- package/src/tooling/portable/handoff/coldStartQualification.grounding.js +392 -0
- package/src/tooling/portable/handoff/coldStartQualification.js +22 -0
- package/src/tooling/portable/handoff/coldStartQualification.materials.js +364 -0
- package/src/tooling/portable/handoff/coldStartQualification.observation.js +220 -0
- package/src/tooling/portable/handoff/coldStartQualification.run.js +81 -0
- package/src/tooling/portable/handoff/coldStartQualification.shared.js +57 -0
- package/src/tooling/portable/handoff/coldStartRolePointers.js +39 -0
- package/src/tooling/portable/handoff/contextAudit.js +247 -0
- package/src/tooling/portable/handoff/contracts/tiinex.handoff.package.v1.schema.md +409 -0
- package/src/tooling/portable/handoff/handoffAuthoringPlan.js +35 -0
- package/src/tooling/portable/handoff/handoffEndpointProjection.js +61 -0
- package/src/tooling/portable/handoff/handoffLeafProjection.js +91 -0
- package/src/tooling/portable/handoff/humanOutputPresentation.js +21 -0
- package/src/tooling/portable/handoff/manufacture.js +84 -0
- package/src/tooling/portable/handoff/materialClosure.archiveV2.binding.js +72 -0
- package/src/tooling/portable/handoff/materialClosure.archiveV2.direct.js +160 -0
- package/src/tooling/portable/handoff/materialClosure.archiveV2.indexes.js +36 -0
- package/src/tooling/portable/handoff/materialClosure.archiveV2.js +247 -0
- package/src/tooling/portable/handoff/materialClosure.archiveV2.projectionProvider.js +44 -0
- package/src/tooling/portable/handoff/materialClosure.archiveV2.workspace.js +226 -0
- package/src/tooling/portable/handoff/materialClosure.descriptor.js +169 -0
- package/src/tooling/portable/handoff/materialClosure.inputBinding.js +372 -0
- package/src/tooling/portable/handoff/materialClosure.inputBinding.support.js +62 -0
- package/src/tooling/portable/handoff/materialClosure.materialized.js +143 -0
- package/src/tooling/portable/handoff/materialClosure.materials.js +116 -0
- package/src/tooling/portable/handoff/materialClosure.package.js +181 -0
- package/src/tooling/portable/handoff/materialClosure.plan.js +204 -0
- package/src/tooling/portable/handoff/materialClosure.readiness.js +36 -0
- package/src/tooling/portable/handoff/materialClosure.requirements.js +137 -0
- package/src/tooling/portable/handoff/operatorContextProjection.js +105 -0
- package/src/tooling/portable/handoff/pointerEntrypoint.js +138 -0
- package/src/tooling/portable/handoff/qualifiedHandoffFixture.js +34 -0
- package/src/tooling/portable/handoff/recipientV2.artifactFirst.build.js +321 -0
- package/src/tooling/portable/handoff/recipientV2.artifactFirst.closure.js +126 -0
- package/src/tooling/portable/handoff/recipientV2.artifactFirst.inspect.js +194 -0
- package/src/tooling/portable/handoff/recipientV2.artifactFirst.materials.js +207 -0
- package/src/tooling/portable/handoff/recipientV2.artifactFirst.projection.js +69 -0
- package/src/tooling/portable/handoff/recipientV2.artifactFirst.roles.js +166 -0
- package/src/tooling/portable/handoff/recipientV2.artifactFirst.routes.js +113 -0
- package/src/tooling/portable/handoff/recipientV2.artifactFirst.shared.js +87 -0
- package/src/tooling/portable/handoff/recipientV2.artifactFirst.workspaces.js +160 -0
- package/src/tooling/portable/handoff/recipientV2.artifactFirstPhase1.js +44 -0
- package/src/tooling/portable/handoff/recipientV2.artifactInspection.js +55 -0
- package/src/tooling/portable/handoff/recipientV2.artifacts.js +174 -0
- package/src/tooling/portable/handoff/recipientV2.coldProjection.js +24 -0
- package/src/tooling/portable/handoff/recipientV2.delivery.js +48 -0
- package/src/tooling/portable/handoff/recipientV2.endpointRolePointers.js +179 -0
- package/src/tooling/portable/handoff/recipientV2.entryContract.js +28 -0
- package/src/tooling/portable/handoff/recipientV2.humanOutput.js +78 -0
- package/src/tooling/portable/handoff/recipientV2.inspect.helpers.js +218 -0
- package/src/tooling/portable/handoff/recipientV2.inspect.js +194 -0
- package/src/tooling/portable/handoff/recipientV2.inspect.pathToken.js +9 -0
- package/src/tooling/portable/handoff/recipientV2.inspect.projection.js +58 -0
- package/src/tooling/portable/handoff/recipientV2.inspect.workspaces.js +177 -0
- package/src/tooling/portable/handoff/recipientV2.lineage.js +142 -0
- package/src/tooling/portable/handoff/recipientV2.packageV1.build.js +147 -0
- package/src/tooling/portable/handoff/recipientV2.packageV1.constants.js +4 -0
- package/src/tooling/portable/handoff/recipientV2.packageV1.contract.js +101 -0
- package/src/tooling/portable/handoff/recipientV2.packageV1.inspect.helpers.js +126 -0
- package/src/tooling/portable/handoff/recipientV2.packageV1.inspect.js +185 -0
- package/src/tooling/portable/handoff/recipientV2.packageV1.js +12 -0
- package/src/tooling/portable/handoff/recipientV2.packageV1.shared.js +24 -0
- package/src/tooling/portable/handoff/recipientV2.packageV1.workspaceProjection.js +22 -0
- package/src/tooling/portable/handoff/recipientV2.pointer.js +40 -0
- package/src/tooling/portable/handoff/recipientV2.routeSelection.js +16 -0
- package/src/tooling/portable/handoff/recipientV2.topology.helpers.js +20 -0
- package/src/tooling/portable/handoff/recipientV2.topology.js +320 -0
- package/src/tooling/portable/handoff/recipientV2.topology.materials.js +70 -0
- package/src/tooling/portable/handoff/recipientV2.topology.workspaces.js +193 -0
- package/src/tooling/portable/handoff/recipientV2.transportManifest.js +123 -0
- package/src/tooling/portable/handoff/recipientV2.workspaceRepresentation.js +163 -0
- package/src/tooling/portable/handoff/routeArtifactConformance.js +130 -0
- package/src/tooling/portable/handoff/toolingBootstrap.js +67 -0
- package/src/tooling/portable/handoff/transportCompanion.js +175 -0
- package/src/tooling/portable/handoff/workspaceByteProvider.archive.js +95 -0
- package/src/tooling/portable/handoff/workspaceByteProvider.js +271 -0
- package/src/tooling/portable/handoff/workspaceCarrier.manufacture.js +93 -0
- package/src/tooling/portable/handoff/workspaceLandingPlan.js +142 -0
- package/src/tooling/portable/handoff/workspacePackageSources.js +105 -0
- package/src/tooling/portable/handoff/workspaceQualifiedReference.js +10 -0
- package/src/tooling/portable/handoff/workspaceSourceIdentity.js +52 -0
- package/src/tooling/portable/handoff/workspaceTargetConformance.js +134 -0
- package/src/tooling/portable/host/host.capabilities.js +181 -0
- package/src/tooling/portable/host/tool.bindings.js +357 -0
- package/src/tooling/portable/host/tool.receiptNormalization.js +141 -0
- package/src/tooling/portable/index.js +52 -0
- package/src/tooling/portable/input/node.input.js +184 -0
- package/src/tooling/portable/input/portable.input.js +249 -0
- package/src/tooling/portable/lifecycle/lifecycle.action.js +11 -0
- package/src/tooling/portable/lifecycle/lifecycle.material.js +173 -0
- package/src/tooling/portable/lifecycle/lifecycle.operations.js +34 -0
- package/src/tooling/portable/lifecycle/lifecycle.readiness.js +247 -0
- package/src/tooling/portable/lineage/lineage.integrity.apply.audit.js +22 -0
- package/src/tooling/portable/lineage/lineage.integrity.apply.evidence.js +36 -0
- package/src/tooling/portable/lineage/lineage.integrity.apply.js +306 -0
- package/src/tooling/portable/lineage/lineage.integrity.apply.structure.js +178 -0
- package/src/tooling/portable/lineage/lineage.integrity.plan.js +377 -0
- package/src/tooling/portable/lineage/lineage.integrity.projection.human.js +82 -0
- package/src/tooling/portable/lineage/lineage.integrity.projection.js +349 -0
- package/src/tooling/portable/lineage/lineage.operations.js +32 -0
- package/src/tooling/portable/lineage/lineage.print.js +398 -0
- package/src/tooling/portable/lineage/lineage.print.render.js +88 -0
- package/src/tooling/portable/lineage/lineage.print.utils.js +58 -0
- package/src/tooling/portable/lineage/lineage.publicationProviderReceipts.js +141 -0
- package/src/tooling/portable/lineage/lineage.publicationQualification.js +183 -0
- package/src/tooling/portable/lineage/lineage.search.js +301 -0
- package/src/tooling/portable/live/live.artifact.js +192 -0
- package/src/tooling/portable/live/live.export.js +107 -0
- package/src/tooling/portable/live/live.lineage.closure.js +71 -0
- package/src/tooling/portable/live/live.lineage.js +338 -0
- package/src/tooling/portable/live/live.protocol.js +181 -0
- package/src/tooling/portable/materialization/durable.materialize.js +162 -0
- package/src/tooling/portable/materialization/epistemic.plan.js +239 -0
- package/src/tooling/portable/materialization/loaded.parent.js +54 -0
- package/src/tooling/portable/materialization/materialization.facade.js +30 -0
- package/src/tooling/portable/operation.catalog.js +393 -0
- package/src/tooling/portable/operation.catalog.package.js +183 -0
- package/src/tooling/portable/operation.result.js +25 -0
- package/src/tooling/portable/orchestration/task.prepare.js +191 -0
- package/src/tooling/portable/output/artifact.result.package.js +308 -0
- package/src/tooling/portable/output/deterministic.zip.js +88 -0
- package/src/tooling/portable/output/node.artifact-set.js +223 -0
- package/src/tooling/portable/output/node.draft.js +41 -0
- package/src/tooling/portable/output/node.zip.js +39 -0
- package/src/tooling/portable/output/recipientV2.zip.js +59 -0
- package/src/tooling/portable/overview/blockingCue.js +16 -0
- package/src/tooling/portable/overview/operatingOverview.js +413 -0
- package/src/tooling/portable/package/generation.binding.js +314 -0
- package/src/tooling/portable/package/generation.binding.projection.js +128 -0
- package/src/tooling/portable/package/material.graph.js +236 -0
- package/src/tooling/portable/package/runtime.package.js +321 -0
- package/src/tooling/portable/package/schema.transition.companion.js +196 -0
- package/src/tooling/portable/package/semantic.package.graph.js +272 -0
- package/src/tooling/portable/package/semantic.package.js +203 -0
- package/src/tooling/portable/package/semantic.package.schema-resolution.js +158 -0
- package/src/tooling/portable/package/semantic.package.transition-registry.js +189 -0
- package/src/tooling/portable/package/semantic.package.types.js +18 -0
- package/src/tooling/portable/providers/schema.bootstrap.provenance.js +10 -0
- package/src/tooling/portable/providers/schema.provider.qualification.js +52 -0
- package/src/tooling/portable/providers/schema.providers.js +458 -0
- package/src/tooling/portable/publication/runtime.publication.js +53 -0
- package/src/tooling/portable/qualification.js +150 -0
- package/src/tooling/portable/reduction/reduction.composition.js +229 -0
- package/src/tooling/portable/reduction/reduction.eligibility.helpers.js +258 -0
- package/src/tooling/portable/reduction/reduction.eligibility.js +191 -0
- package/src/tooling/portable/reduction/reduction.operations.js +30 -0
- package/src/tooling/portable/reduction/reduction.preflight.js +85 -0
- package/src/tooling/portable/reduction/reduction.shared.js +173 -0
- package/src/tooling/portable/schema/bootstrap/canonical.pack.js +24 -0
- package/src/tooling/portable/schema/bootstrap/docs-3988951208eb9a8926e84ab42625d4b42fa00c2d/party/role/tiinex.party.role.v1.schema.md +289 -0
- package/src/tooling/portable/schema/bootstrap/docs-3988951208eb9a8926e84ab42625d4b42fa00c2d/validation/report/tiinex.validation.report.v1.schema.md +300 -0
- package/src/tooling/portable/schema/bootstrap/qualified-local-root/tiinex.root.v1.runtime-projection.json +48 -0
- package/src/tooling/portable/schema/bootstrap/qualified-local-root/tiinex.root.v1.schema.md +865 -0
- package/src/tooling/portable/schema/contract.compile.js +406 -0
- package/src/tooling/portable/schema/contract.compile.utils.js +9 -0
- package/src/tooling/portable/schema/contract.constraints.js +117 -0
- package/src/tooling/portable/schema/contract.envelope.validate.js +177 -0
- package/src/tooling/portable/schema/contract.field-domain.compile.js +399 -0
- package/src/tooling/portable/schema/contract.field-domain.js +247 -0
- package/src/tooling/portable/schema/contract.field-shape.compile.js +34 -0
- package/src/tooling/portable/schema/contract.inheritance.inline.js +103 -0
- package/src/tooling/portable/schema/contract.inheritance.js +210 -0
- package/src/tooling/portable/schema/contract.inheritance.record.js +76 -0
- package/src/tooling/portable/schema/contract.machine-shape.js +309 -0
- package/src/tooling/portable/schema/contract.project.js +81 -0
- package/src/tooling/portable/schema/contract.semantic-resolution.js +82 -0
- package/src/tooling/portable/schema/contract.validate.js +0 -0
- package/src/tooling/portable/schema/lexical.shape.v1.js +338 -0
- package/src/tooling/portable/schema/llm.companion.js +108 -0
- package/src/tooling/portable/schema/named.declarations.js +162 -0
- package/src/tooling/portable/schema/ordinary.contract.js +193 -0
- package/src/tooling/portable/schema/ordinary.fields.js +205 -0
- package/src/tooling/portable/schema/qualifiedLocalRoot.projection.js +70 -0
- package/src/tooling/portable/schema/qualifiedLocalRoot.runtime.js +170 -0
- package/src/tooling/portable/schema/schema.contract.js +465 -0
- package/src/tooling/portable/schema/schema.guide.js +326 -0
- package/src/tooling/portable/schema/schema.snapshot.js +119 -0
- package/src/tooling/portable/session/portable.session.js +145 -0
- package/src/tooling/portable/transfer/transfer.plan.js +102 -0
- package/src/transitions/record.transitions.js +484 -0
- package/src/transitions/transition.validate.js +129 -0
- package/src/validation/findings.js +76 -0
- package/src/validation/validateArtifact.js +216 -0
- package/src/workspaces/workspace.entrypointCapability.js +44 -0
- package/src/workspaces/workspace.materialRole.js +242 -0
- package/src/workspaces/workspace.recordPaths.js +426 -0
- package/tools/tiinex-portable.mjs +6 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GITHUB_ISSUE_BODY_TARGET_KIND,
|
|
3
|
+
GITHUB_ISSUE_COMMENT_TARGET_KIND,
|
|
4
|
+
normalizeGithubRepository,
|
|
5
|
+
parseExactGithubIssueTarget,
|
|
6
|
+
sameGithubRepository
|
|
7
|
+
} from '../sources/github/github.issueTarget.js';
|
|
8
|
+
|
|
9
|
+
export const GITHUB_REPO_FILE_TARGET_KIND = 'github.repo.file';
|
|
10
|
+
export { GITHUB_ISSUE_BODY_TARGET_KIND, GITHUB_ISSUE_COMMENT_TARGET_KIND };
|
|
11
|
+
|
|
12
|
+
const REPO_FILE_ALIASES = new Set([GITHUB_REPO_FILE_TARGET_KIND, 'github-repo-file']);
|
|
13
|
+
const ISSUE_BODY_ALIASES = new Set([GITHUB_ISSUE_BODY_TARGET_KIND, 'github-issue-body']);
|
|
14
|
+
const ISSUE_COMMENT_ALIASES = new Set([GITHUB_ISSUE_COMMENT_TARGET_KIND, 'github-issue-comment']);
|
|
15
|
+
|
|
16
|
+
export function normalizePublicationDestination(value = {}) {
|
|
17
|
+
const provider = String(value.provider || value.adapterId || '').trim().toLowerCase();
|
|
18
|
+
const targetKind = canonicalTargetKind(value.targetKind || value.surface || '');
|
|
19
|
+
const exactSocialTarget = provider === 'github' && [GITHUB_ISSUE_BODY_TARGET_KIND, GITHUB_ISSUE_COMMENT_TARGET_KIND].includes(targetKind);
|
|
20
|
+
const externalTarget = rawTargetAlias(value, ['externalTarget', 'inputTarget', 'url']);
|
|
21
|
+
const containerTarget = rawTargetAlias(value, ['containerTarget', 'parentTarget', 'issueTarget']);
|
|
22
|
+
return deepFreeze({
|
|
23
|
+
provider,
|
|
24
|
+
repository: String(value.repository || value.repo || '').trim(),
|
|
25
|
+
ref: String(value.ref || value.branch || '').trim(),
|
|
26
|
+
path: String(value.path || '').trim().replace(/^\/+/, ''),
|
|
27
|
+
externalTarget: exactSocialTarget ? externalTarget : externalTarget.trim(),
|
|
28
|
+
containerTarget: exactSocialTarget ? containerTarget : containerTarget.trim(),
|
|
29
|
+
targetKind,
|
|
30
|
+
declaredTargetKind: String(value.targetKind || value.surface || '').trim()
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function publicationDestinationFindings(destination = {}, mutationPolicy = '') {
|
|
35
|
+
const findings = [];
|
|
36
|
+
if (!destination.provider) findings.push(finding('error', 'publication.plan.destination.provider-missing', 'Publication destination requires explicit provider identity.'));
|
|
37
|
+
if (destination.provider !== 'github') {
|
|
38
|
+
if (!destination.externalTarget && !destination.path) findings.push(finding('error', 'publication.plan.destination.target-missing', 'Publication destination requires an exact provider target/path.'));
|
|
39
|
+
return findings;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!destination.repository) findings.push(finding('error', 'publication.plan.destination.repo-missing', 'GitHub publication destination requires exact repository.'));
|
|
43
|
+
if (!destination.targetKind) {
|
|
44
|
+
findings.push(finding('error', 'publication.plan.destination.target-kind-missing', 'GitHub publication destination requires one exact target kind.'));
|
|
45
|
+
return findings;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (destination.targetKind === GITHUB_REPO_FILE_TARGET_KIND) {
|
|
49
|
+
if (!destination.ref) findings.push(finding('error', 'publication.plan.destination.ref-missing', 'GitHub repo-file publication requires explicit destination ref/branch.'));
|
|
50
|
+
if (!destination.path) findings.push(finding('error', 'publication.plan.destination.path-missing', 'GitHub repo-file publication requires exact repo-relative target path.'));
|
|
51
|
+
return findings;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (destination.targetKind === GITHUB_ISSUE_BODY_TARGET_KIND) {
|
|
55
|
+
if (!['create-new', 'update-known'].includes(mutationPolicy)) findings.push(finding('error', 'publication.plan.mutation-policy.unsupported-for-target', 'GitHub issue-body publication requires create-new or update-known mutation policy.'));
|
|
56
|
+
if (mutationPolicy === 'update-known' && !destination.externalTarget) findings.push(finding('error', 'publication.plan.destination.issue-target-missing', 'Updating a known GitHub issue body requires its exact issue URL in the plan.'));
|
|
57
|
+
if (destination.externalTarget) findings.push(...validateSocialTarget(destination.externalTarget, destination, GITHUB_ISSUE_BODY_TARGET_KIND, 'issue-target'));
|
|
58
|
+
return findings;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (destination.targetKind === GITHUB_ISSUE_COMMENT_TARGET_KIND) {
|
|
62
|
+
if (!['create-comment', 'update-known'].includes(mutationPolicy)) findings.push(finding('error', 'publication.plan.mutation-policy.unsupported-for-target', 'GitHub issue-comment publication requires create-comment or update-known mutation policy.'));
|
|
63
|
+
if (mutationPolicy === 'create-comment' && !destination.containerTarget) findings.push(finding('error', 'publication.plan.destination.container-target-missing', 'Creating a GitHub issue comment requires the exact parent issue URL.'));
|
|
64
|
+
if (mutationPolicy === 'update-known' && !destination.externalTarget) findings.push(finding('error', 'publication.plan.destination.comment-target-missing', 'Updating a known GitHub issue comment requires its exact comment permalink.'));
|
|
65
|
+
if (destination.containerTarget) findings.push(...validateSocialTarget(destination.containerTarget, destination, GITHUB_ISSUE_BODY_TARGET_KIND, 'container-target'));
|
|
66
|
+
if (destination.externalTarget) findings.push(...validateSocialTarget(destination.externalTarget, destination, GITHUB_ISSUE_COMMENT_TARGET_KIND, 'comment-target'));
|
|
67
|
+
const container = parseExactGithubIssueTarget(destination.containerTarget);
|
|
68
|
+
const exactComment = parseExactGithubIssueTarget(destination.externalTarget);
|
|
69
|
+
if (container.ok && exactComment.ok && !sameIssueContainer(exactComment, container)) findings.push(finding('error', 'publication.plan.destination.comment-container-mismatch', 'GitHub comment target belongs to a different issue than the declared publication container.'));
|
|
70
|
+
return findings;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
findings.push(finding('error', 'publication.plan.destination.target-kind-unsupported', 'GitHub publication target kind is not supported by the shared contract.', { targetKind: destination.declaredTargetKind || destination.targetKind }));
|
|
74
|
+
return findings;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function projectExecutedPublicationTarget(plan = {}, execution = {}) {
|
|
78
|
+
const supplied = execution.sourceTarget || execution.remoteTarget || {};
|
|
79
|
+
const destination = plan.destination || {};
|
|
80
|
+
const plannedTargetKind = canonicalTargetKind(destination.targetKind || '');
|
|
81
|
+
const suppliedTargetKind = canonicalTargetKind(supplied.targetKind || '');
|
|
82
|
+
let projection;
|
|
83
|
+
if (destination.provider === 'github' && plannedTargetKind === GITHUB_REPO_FILE_TARGET_KIND) projection = projectRepoFileTarget(plan, execution, supplied);
|
|
84
|
+
else if (destination.provider === 'github' && (plannedTargetKind === GITHUB_ISSUE_BODY_TARGET_KIND || plannedTargetKind === GITHUB_ISSUE_COMMENT_TARGET_KIND)) projection = projectGithubSocialTarget(plan, execution, supplied, plannedTargetKind);
|
|
85
|
+
else projection = projectGenericTarget(plan, execution, supplied, plannedTargetKind);
|
|
86
|
+
const findings = [...(projection.findings || [])];
|
|
87
|
+
if (suppliedTargetKind && suppliedTargetKind !== plannedTargetKind) findings.push(finding('error', 'publication.result.target.kind-mismatch', 'Supplied publication result target kind differs from the planned target kind.'));
|
|
88
|
+
const suppliedAdapter = String(supplied.adapterId || supplied.provider || '').trim().toLowerCase();
|
|
89
|
+
if (suppliedAdapter && destination.provider && suppliedAdapter !== destination.provider) findings.push(finding('error', 'publication.result.target.provider-mismatch', 'Supplied publication result provider differs from the planned destination provider.'));
|
|
90
|
+
return deepFreeze({ target: projection.target, findings, qualified: !hasErrors(findings) && publicationTargetQualified(projection.target) });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function publicationTargetQualified(target = {}) {
|
|
94
|
+
if (!target?.adapterId) return false;
|
|
95
|
+
if (target.adapterId === 'github' && target.targetKind === GITHUB_REPO_FILE_TARGET_KIND) return Boolean(target.repo && target.path && target.materializedCommit && target.immutability === 'immutable-materialized-commit');
|
|
96
|
+
if (target.adapterId === 'github' && [GITHUB_ISSUE_BODY_TARGET_KIND, GITHUB_ISSUE_COMMENT_TARGET_KIND].includes(target.targetKind)) return Boolean(target.repo && target.inputTarget && target.mutability === 'mutable-remote-representation' && target.exactTarget === true);
|
|
97
|
+
return Boolean(target.inputTarget || target.path);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function projectRepoFileTarget(plan, execution, supplied) {
|
|
101
|
+
const destination = plan.destination || {};
|
|
102
|
+
const findings = [];
|
|
103
|
+
const repo = String(supplied.repo || supplied.repository || destination.repository || '').trim();
|
|
104
|
+
const path = String(supplied.path || destination.path || '').trim().replace(/^\/+/, '');
|
|
105
|
+
const materializedCommit = exactCommit(supplied.materializedCommit || supplied.commit || execution.materializedCommit || '');
|
|
106
|
+
if (!sameGithubRepository(repo, destination.repository)) findings.push(finding('error', 'publication.result.target.repo-mismatch', 'Verified GitHub repo-file target repository differs from the planned destination.'));
|
|
107
|
+
if (!path || path !== String(destination.path || '').trim().replace(/^\/+/, '')) findings.push(finding('error', 'publication.result.target.path-mismatch', 'Verified GitHub repo-file target path differs from the planned destination path.'));
|
|
108
|
+
if (!materializedCommit) findings.push(finding('error', 'publication.result.target.commit-missing', 'Verified GitHub repo-file publication requires one exact 40-character materialized commit.'));
|
|
109
|
+
const target = deepFreeze({
|
|
110
|
+
schema: 'tiinex.publication.remote-target.v2',
|
|
111
|
+
adapterId: 'github',
|
|
112
|
+
repo,
|
|
113
|
+
configuredRef: String(destination.ref || supplied.configuredRef || supplied.ref || '').trim(),
|
|
114
|
+
materializedCommit,
|
|
115
|
+
path,
|
|
116
|
+
inputTarget: String(supplied.inputTarget || '').trim(),
|
|
117
|
+
targetKind: GITHUB_REPO_FILE_TARGET_KIND,
|
|
118
|
+
exactTarget: Boolean(repo && path && materializedCommit),
|
|
119
|
+
immutability: materializedCommit ? 'immutable-materialized-commit' : 'degraded',
|
|
120
|
+
mutability: 'immutable-materialized-representation',
|
|
121
|
+
issueNumber: null,
|
|
122
|
+
commentId: '',
|
|
123
|
+
containerTarget: '',
|
|
124
|
+
providerReceiptId: String(execution.providerReceiptId || supplied.providerReceiptId || '')
|
|
125
|
+
});
|
|
126
|
+
return deepFreeze({ target, findings, qualified: !hasErrors(findings) && publicationTargetQualified(target) });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function projectGithubSocialTarget(plan, execution, supplied, targetKind) {
|
|
130
|
+
const destination = plan.destination || {};
|
|
131
|
+
const findings = [];
|
|
132
|
+
const inputTarget = rawTargetAlias(supplied, ['inputTarget', 'externalTarget', 'url']);
|
|
133
|
+
const parsed = parseExactGithubIssueTarget(inputTarget);
|
|
134
|
+
if (!parsed.ok) findings.push(finding('error', 'publication.result.social-target.invalid', 'Verified GitHub social publication requires one exact GitHub issue/comment target URL.'));
|
|
135
|
+
else {
|
|
136
|
+
if (parsed.targetKind !== targetKind) findings.push(finding('error', 'publication.result.social-target.kind-mismatch', 'Verified GitHub social target surface differs from the planned target kind.'));
|
|
137
|
+
if (!sameGithubRepository(parsed.repository, destination.repository)) findings.push(finding('error', 'publication.result.target.repo-mismatch', 'Verified GitHub social target repository differs from the planned destination.'));
|
|
138
|
+
if (targetKind === GITHUB_ISSUE_BODY_TARGET_KIND && destination.externalTarget && plan.mutationPolicy === 'update-known' && !sameExactSocialTarget(parsed, parseExactGithubIssueTarget(destination.externalTarget))) findings.push(finding('error', 'publication.result.social-target.planned-target-mismatch', 'Verified issue target differs from the exact known issue target in the plan.'));
|
|
139
|
+
if (targetKind === GITHUB_ISSUE_COMMENT_TARGET_KIND) {
|
|
140
|
+
const container = parseExactGithubIssueTarget(destination.containerTarget);
|
|
141
|
+
if (container.ok && parsed.ok && !sameIssueContainer(parsed, container)) findings.push(finding('error', 'publication.result.social-target.container-mismatch', 'Verified comment target belongs to a different issue than the declared publication container.'));
|
|
142
|
+
if (destination.externalTarget && plan.mutationPolicy === 'update-known' && !sameExactSocialTarget(parsed, parseExactGithubIssueTarget(destination.externalTarget))) findings.push(finding('error', 'publication.result.social-target.planned-target-mismatch', 'Verified comment target differs from the exact known comment target in the plan.'));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const target = deepFreeze({
|
|
146
|
+
schema: 'tiinex.publication.remote-target.v2',
|
|
147
|
+
adapterId: 'github',
|
|
148
|
+
repo: parsed.ok ? parsed.repository : String(supplied.repo || supplied.repository || destination.repository || '').trim(),
|
|
149
|
+
configuredRef: '',
|
|
150
|
+
materializedCommit: '',
|
|
151
|
+
path: '',
|
|
152
|
+
inputTarget: parsed.ok ? parsed.inputTarget : inputTarget,
|
|
153
|
+
targetKind,
|
|
154
|
+
exactTarget: Boolean(parsed.ok && parsed.targetKind === targetKind),
|
|
155
|
+
immutability: 'mutable-exact-target',
|
|
156
|
+
mutability: 'mutable-remote-representation',
|
|
157
|
+
issueNumber: parsed.ok ? parsed.number : null,
|
|
158
|
+
issueNumberLexeme: parsed.ok ? parsed.issueNumber : '',
|
|
159
|
+
commentId: parsed.ok ? String(parsed.commentId || '') : '',
|
|
160
|
+
containerTarget: parsed.ok ? parsed.issueTarget : String(destination.containerTarget || ''),
|
|
161
|
+
providerReceiptId: String(execution.providerReceiptId || supplied.providerReceiptId || '')
|
|
162
|
+
});
|
|
163
|
+
return deepFreeze({ target, findings, qualified: !hasErrors(findings) && publicationTargetQualified(target) });
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function projectGenericTarget(plan, execution, supplied, targetKind) {
|
|
167
|
+
const destination = plan.destination || {};
|
|
168
|
+
const target = deepFreeze({
|
|
169
|
+
schema: 'tiinex.publication.remote-target.v2',
|
|
170
|
+
adapterId: String(supplied.adapterId || destination.provider || '').trim(),
|
|
171
|
+
repo: String(supplied.repo || supplied.repository || destination.repository || '').trim(),
|
|
172
|
+
configuredRef: String(destination.ref || supplied.configuredRef || supplied.ref || '').trim(),
|
|
173
|
+
materializedCommit: '',
|
|
174
|
+
path: String(supplied.path || destination.path || '').trim().replace(/^\/+/, ''),
|
|
175
|
+
inputTarget: String(supplied.inputTarget || supplied.externalTarget || destination.externalTarget || '').trim(),
|
|
176
|
+
targetKind,
|
|
177
|
+
exactTarget: Boolean(supplied.inputTarget || supplied.externalTarget || supplied.path || destination.externalTarget || destination.path),
|
|
178
|
+
immutability: 'not-claimed',
|
|
179
|
+
mutability: 'provider-defined',
|
|
180
|
+
issueNumber: null,
|
|
181
|
+
commentId: '',
|
|
182
|
+
containerTarget: '',
|
|
183
|
+
providerReceiptId: String(execution.providerReceiptId || supplied.providerReceiptId || '')
|
|
184
|
+
});
|
|
185
|
+
const findings = [];
|
|
186
|
+
if (!publicationTargetQualified(target)) findings.push(finding('error', 'publication.result.verified-target.incomplete', 'Verification claims success but exact source target identity is incomplete.'));
|
|
187
|
+
return deepFreeze({ target, findings, qualified: !hasErrors(findings) && publicationTargetQualified(target) });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function validateSocialTarget(raw, destination, expectedKind, field) {
|
|
191
|
+
const parsed = parseExactGithubIssueTarget(raw);
|
|
192
|
+
if (!parsed.ok) return [finding('error', `publication.plan.destination.${field}.invalid`, 'GitHub social publication target must be one exact supported issue/comment URL.')];
|
|
193
|
+
const findings = [];
|
|
194
|
+
if (parsed.targetKind !== expectedKind) findings.push(finding('error', `publication.plan.destination.${field}.kind-mismatch`, 'GitHub social target URL does not match the declared target kind.'));
|
|
195
|
+
if (destination.repository && !sameGithubRepository(parsed.repository, destination.repository)) findings.push(finding('error', `publication.plan.destination.${field}.repo-mismatch`, 'GitHub social target belongs to a different repository than the declared destination.'));
|
|
196
|
+
return findings;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
function rawTargetAlias(value = {}, keys = []) {
|
|
201
|
+
for (const key of keys) {
|
|
202
|
+
const candidate = value?.[key];
|
|
203
|
+
if (candidate !== undefined && candidate !== null && String(candidate) !== '') return String(candidate);
|
|
204
|
+
}
|
|
205
|
+
return '';
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function canonicalTargetKind(value = '') {
|
|
209
|
+
const clean = String(value || '').trim().toLowerCase();
|
|
210
|
+
if (REPO_FILE_ALIASES.has(clean)) return GITHUB_REPO_FILE_TARGET_KIND;
|
|
211
|
+
if (ISSUE_BODY_ALIASES.has(clean)) return GITHUB_ISSUE_BODY_TARGET_KIND;
|
|
212
|
+
if (ISSUE_COMMENT_ALIASES.has(clean)) return GITHUB_ISSUE_COMMENT_TARGET_KIND;
|
|
213
|
+
return clean;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function sameIssueContainer(a = {}, b = {}) {
|
|
217
|
+
return Boolean(a?.ok && b?.ok && sameGithubRepository(a.repository, b.repository) && exactIssueIdentity(a) === exactIssueIdentity(b));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function exactIssueIdentity(value = {}) {
|
|
221
|
+
return String(value.issueNumber || value.number || '');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function sameExactSocialTarget(a = {}, b = {}) {
|
|
225
|
+
if (!sameIssueContainer(a, b) || a.targetKind !== b.targetKind) return false;
|
|
226
|
+
if (a.targetKind === GITHUB_ISSUE_COMMENT_TARGET_KIND) return String(a.commentId || '') === String(b.commentId || '');
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function exactCommit(value = '') {
|
|
231
|
+
const text = String(value || '').trim();
|
|
232
|
+
return /^[0-9a-f]{40}$/i.test(text) ? text.toLowerCase() : '';
|
|
233
|
+
}
|
|
234
|
+
function hasErrors(findings = []) { return findings.some((item) => item.severity === 'error'); }
|
|
235
|
+
function finding(severity, code, message, extra = {}) { return Object.freeze({ severity, code, message, ...extra }); }
|
|
236
|
+
function deepFreeze(value) {
|
|
237
|
+
if (!value || typeof value !== 'object' || Object.isFrozen(value)) return value;
|
|
238
|
+
if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return value;
|
|
239
|
+
for (const child of Object.values(value)) deepFreeze(child);
|
|
240
|
+
return Object.freeze(value);
|
|
241
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { buildPublicationPreflight } from '../publication/publication.preflight.js';
|
|
2
|
+
import { buildSourceBoundaryReport, isSourceBacked } from '../diagnostics/sourceBoundary.report.js';
|
|
3
|
+
import { projectPackageSourceReference } from '../export/package.sourceReference.js';
|
|
4
|
+
|
|
5
|
+
export const REINGEST_PLAN_SCHEMA_ID = 'tiinex.reingest.plan.v1';
|
|
6
|
+
|
|
7
|
+
export function buildReingestPlan(workspace = {}, input = {}) {
|
|
8
|
+
const records = Array.isArray(input.records) ? input.records : (Array.isArray(workspace.records) ? workspace.records : []);
|
|
9
|
+
const assets = Array.isArray(input.assets) ? input.assets : (Array.isArray(workspace.assets) ? workspace.assets : []);
|
|
10
|
+
const workspaceCandidates = Array.isArray(input.workspaceCandidates) ? input.workspaceCandidates : (Array.isArray(workspace.workspaceMergeCandidates) ? workspace.workspaceMergeCandidates : []);
|
|
11
|
+
const sourceBoundary = input.sourceBoundary || buildSourceBoundaryReport(workspace, { records, assets });
|
|
12
|
+
const publicationPreflight = input.publicationPreflight || buildPublicationPreflight(workspace, { records, assets, workspaceCandidates });
|
|
13
|
+
const findings = [];
|
|
14
|
+
const sourceTargets = records.filter((record) => isSourceBacked(record.source)).map((record) => sourceTargetForRecord(record, findings));
|
|
15
|
+
const localDraftTargets = (publicationPreflight.publishableLocalDrafts || []).map((record) => localDraftTarget(record));
|
|
16
|
+
const blockedLocalTargets = (publicationPreflight.blockedLocalDrafts || []).map((record) => blockedLocalTarget(record));
|
|
17
|
+
const assetTargets = assets.map((asset) => assetTarget(asset, findings));
|
|
18
|
+
const workspaceCandidateTargets = workspaceCandidates.map((candidate) => workspaceCandidateTarget(candidate, findings));
|
|
19
|
+
|
|
20
|
+
for (const finding of sourceBoundary.findings || []) {
|
|
21
|
+
if (finding.severity === 'error' || finding.code?.includes('ref.unpinned') || finding.code?.includes('path.missing') || finding.code?.includes('repo.missing')) {
|
|
22
|
+
findings.push(normalizeFinding('source-boundary', finding));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
for (const finding of publicationPreflight.findings || []) {
|
|
26
|
+
if (finding.severity === 'error' || finding.code?.includes('ref-unpinned') || finding.code?.includes('asset.metadata-only') || finding.code?.includes('workspace-candidate')) {
|
|
27
|
+
findings.push(normalizeFinding('publication-preflight', finding));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const dedupedFindings = dedupeFindings(findings);
|
|
32
|
+
const counts = {
|
|
33
|
+
records: records.length,
|
|
34
|
+
sourceTargets: sourceTargets.length,
|
|
35
|
+
pinnedSourceTargets: sourceTargets.filter((target) => target.status === 'pinned').length,
|
|
36
|
+
exactSourceTargets: sourceTargets.filter((target) => target.status === 'exact').length,
|
|
37
|
+
degradedSourceTargets: sourceTargets.filter((target) => target.status === 'degraded').length,
|
|
38
|
+
localDraftTargets: localDraftTargets.length,
|
|
39
|
+
blockedLocalTargets: blockedLocalTargets.length,
|
|
40
|
+
assets: assetTargets.length,
|
|
41
|
+
metadataOnlyAssets: assetTargets.filter((target) => target.status !== 'content-available').length,
|
|
42
|
+
workspaceCandidates: workspaceCandidateTargets.length,
|
|
43
|
+
errors: dedupedFindings.filter((finding) => finding.severity === 'error').length,
|
|
44
|
+
warnings: dedupedFindings.filter((finding) => finding.severity === 'warning').length,
|
|
45
|
+
findings: dedupedFindings.length
|
|
46
|
+
};
|
|
47
|
+
const status = counts.errors ? 'blocked' : counts.warnings || counts.degradedSourceTargets || counts.metadataOnlyAssets || counts.workspaceCandidates || counts.blockedLocalTargets ? 'degraded' : 'ready';
|
|
48
|
+
|
|
49
|
+
return Object.freeze({
|
|
50
|
+
schema: REINGEST_PLAN_SCHEMA_ID,
|
|
51
|
+
workspaceId: workspace.id || '',
|
|
52
|
+
title: `Re-ingest plan · ${workspace.title || workspace.name || 'workspace'}`,
|
|
53
|
+
status,
|
|
54
|
+
boundary: 'Plan only. Re-ingest may read declared source-backed material and replay local drafts after explicit publication/export; it never guesses missing GitHub provenance.',
|
|
55
|
+
counts: Object.freeze(counts),
|
|
56
|
+
sourceTargets: Object.freeze(sourceTargets),
|
|
57
|
+
localDraftTargets: Object.freeze(localDraftTargets),
|
|
58
|
+
blockedLocalTargets: Object.freeze(blockedLocalTargets),
|
|
59
|
+
assetTargets: Object.freeze(assetTargets),
|
|
60
|
+
workspaceCandidateTargets: Object.freeze(workspaceCandidateTargets),
|
|
61
|
+
findings: Object.freeze(dedupedFindings)
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function sourceTargetForRecord(record = {}, findings = []) {
|
|
66
|
+
const target = projectPackageSourceReference(record);
|
|
67
|
+
const id = record.id || target.path || record.path || record.title || 'record';
|
|
68
|
+
if (target.adapterId === 'github') {
|
|
69
|
+
if (!target.repo) findings.push(finding('error', 'reingest.github.repo-missing', 'GitHub re-ingest target is missing repo.', { recordId: id, path: target.path }));
|
|
70
|
+
if (!target.path && !target.inputTarget) findings.push(finding('error', 'reingest.github.path-missing', 'GitHub re-ingest target is missing exact source artifact target.', { recordId: id, repo: target.repo }));
|
|
71
|
+
if (!target.materializedCommit) findings.push(finding('warning', 'reingest.github.ref-unpinned', 'GitHub re-ingest target lacks exact materialized commit authority; branch/tag refs remain mutable or unqualified.', { recordId: id, repo: target.repo, path: target.path, configuredRef: target.configuredRef }));
|
|
72
|
+
}
|
|
73
|
+
return Object.freeze({
|
|
74
|
+
id,
|
|
75
|
+
title: record.title || 'Source-backed artifact',
|
|
76
|
+
adapterId: target.adapterId,
|
|
77
|
+
repo: target.repo,
|
|
78
|
+
ref: target.ref,
|
|
79
|
+
path: target.path,
|
|
80
|
+
target,
|
|
81
|
+
status: target.status === 'pinned-reference' ? 'pinned' : target.status === 'exact-target-reference' ? 'exact' : 'degraded',
|
|
82
|
+
mode: 'read-existing-source',
|
|
83
|
+
boundary: 'Source-backed material remains reference-only; exact source-target authority is preserved and never inferred from workspace presentation paths.'
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function localDraftTarget(record = {}) {
|
|
88
|
+
return Object.freeze({
|
|
89
|
+
id: record.id || record.path || record.title || '',
|
|
90
|
+
title: record.title || 'Local draft',
|
|
91
|
+
path: record.path || '',
|
|
92
|
+
schemaId: record.schemaId || '',
|
|
93
|
+
status: 'awaiting-publication-or-export',
|
|
94
|
+
mode: 'local-draft-result',
|
|
95
|
+
boundary: 'Local draft can only be re-ingested after explicit publication/export assigns a portable source or package target.'
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function blockedLocalTarget(record = {}) {
|
|
100
|
+
return Object.freeze({
|
|
101
|
+
id: record.id || record.path || record.title || '',
|
|
102
|
+
title: record.title || 'Blocked local material',
|
|
103
|
+
path: record.path || '',
|
|
104
|
+
status: 'blocked',
|
|
105
|
+
reason: record.reason || record.status || 'not-publication-ready',
|
|
106
|
+
mode: 'local-session-only',
|
|
107
|
+
boundary: 'Blocked local material stays local/session and must not be treated as source-backed.'
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function assetTarget(asset = {}, findings = []) {
|
|
112
|
+
const id = asset.id || asset.path || asset.name || 'asset';
|
|
113
|
+
const metadataOnly = asset.previewState === 'omitted-large' || asset.cacheState === 'preview-truncated-for-session-cache' || (!asset.content && !asset.dataUrl && !asset.text);
|
|
114
|
+
if (metadataOnly) findings.push(finding('warning', 'reingest.asset.metadata-only', 'Asset does not have full content available for re-ingest; keep as metadata-only or require local reselection.', { assetId: id, path: asset.path || '' }));
|
|
115
|
+
return Object.freeze({
|
|
116
|
+
id,
|
|
117
|
+
name: asset.name || asset.path || 'asset',
|
|
118
|
+
path: asset.path || '',
|
|
119
|
+
mediaType: asset.type || asset.mimeType || '',
|
|
120
|
+
status: metadataOnly ? 'metadata-only' : 'content-available',
|
|
121
|
+
boundary: asset.source?.boundary || 'Asset boundary follows its intake source; local assets are not source-backed leaves.'
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function workspaceCandidateTarget(candidate = {}, findings = []) {
|
|
126
|
+
findings.push(finding('info', 'reingest.workspace-candidate.explicit-open-merge-required', 'Workspace candidate must be explicitly opened or merged before it participates in re-ingest.', { workspaceCandidateId: candidate.id || '', path: candidate.path || '' }));
|
|
127
|
+
return Object.freeze({
|
|
128
|
+
id: candidate.id || candidate.path || '',
|
|
129
|
+
title: candidate.title || candidate.path || 'Workspace candidate',
|
|
130
|
+
path: candidate.path || '',
|
|
131
|
+
status: 'open-or-merge-required',
|
|
132
|
+
boundary: 'Workspace files are context candidates, not leaves to publish or re-ingest as artifacts.'
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function normalizeFinding(source, item = {}) {
|
|
137
|
+
return finding(item.severity || 'info', item.code || 'finding', item.message || String(item.code || 'Finding'), Object.assign({ source }, item.recordId ? { recordId: item.recordId } : {}, item.path ? { path: item.path } : {}, item.repo ? { repo: item.repo } : {}));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function dedupeFindings(items = []) {
|
|
141
|
+
const seen = new Set();
|
|
142
|
+
const deduped = [];
|
|
143
|
+
for (const item of items) {
|
|
144
|
+
const key = [item.severity, item.code, item.recordId || item.assetId || item.workspaceCandidateId || '', item.path || '', item.repo || ''].join('\u0000');
|
|
145
|
+
if (seen.has(key)) continue;
|
|
146
|
+
seen.add(key);
|
|
147
|
+
deduped.push(item);
|
|
148
|
+
}
|
|
149
|
+
return deduped;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function finding(severity, code, message, extra = {}) {
|
|
153
|
+
return Object.freeze(Object.assign({ severity, code, message }, extra));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function explicitRepo(source = {}) {
|
|
157
|
+
return String(source.repo || source.repository || source.config?.repo || '').trim();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function explicitRef(source = {}) {
|
|
161
|
+
return String(source.ref || source.config?.ref || source.resolvedRef || source.commit || '').trim();
|
|
162
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {parseSemver, stableVersion, bumpVersion, recommendRelease} from './policy.mjs';
|
|
2
|
+
export const RELEASE_POLICY = 'tiinex.master-npm-release.v1';
|
|
3
|
+
export function compareVersion(a,b){const x=parseSemver(a),y=parseSemver(b);return x.major-y.major||x.minor-y.minor||x.patch-y.patch;}
|
|
4
|
+
export function releasePlan({pkg,metadata,sourceCommit,messages=[],previousPackage=null}) {
|
|
5
|
+
if(!/^@tiinex\/[a-z0-9-]+$/.test(pkg.name)||pkg.private===true)throw Error('release.package.invalid');
|
|
6
|
+
if(!/^[a-f0-9]{40,64}$/.test(sourceCommit))throw Error('release.source-commit.required');
|
|
7
|
+
const versions=Object.values(metadata?.versions||{});
|
|
8
|
+
const done=versions.find(v=>(v.tiinexRelease?.sourceCommit||v.gitHead)===sourceCommit && !parseSemver(v.version).prerelease);
|
|
9
|
+
if(done)return {policy:RELEASE_POLICY,action:'skip',reason:'source-already-published',version:done.version,sourceCommit};
|
|
10
|
+
const stable=versions.filter(v=>!parseSemver(v.version).prerelease).sort((a,b)=>compareVersion(a.version,b.version));
|
|
11
|
+
const last=stable.at(-1);const floor=stableVersion(pkg.version);
|
|
12
|
+
let decision;
|
|
13
|
+
if(!last)decision={bump:'bootstrap',rawSeverity:'bootstrap',targetVersion:floor,reasons:['First stable version: explicit source package floor.']};
|
|
14
|
+
else decision=recommendRelease({currentVersion:last.version,previousVersion:last.version,previousPackage:previousPackage||last,currentPackage:pkg,commitMessages:messages});
|
|
15
|
+
if(compareVersion(floor,decision.targetVersion)>0){decision={...decision,targetVersion:floor,reasons:[...decision.reasons,'Source package version explicitly raises the minimum release version.']};}
|
|
16
|
+
if(metadata?.versions?.[decision.targetVersion])throw Error('release.version.collision');
|
|
17
|
+
return {policy:RELEASE_POLICY,action:'publish',name:pkg.name,version:decision.targetVersion,previousVersion:last?.version||null,previousCommit:last?.tiinexRelease?.sourceCommit||last?.gitHead||null,sourceCommit,decision};
|
|
18
|
+
}
|
|
19
|
+
export function assertPublishContext(env,repository) {
|
|
20
|
+
if(env.GITHUB_ACTIONS!=='true'||!['push','workflow_dispatch'].includes(env.GITHUB_EVENT_NAME)||env.GITHUB_REF!=='refs/heads/master'||env.GITHUB_REPOSITORY!==repository)throw Error('release.master-only: publishing requires this repository on refs/heads/master');
|
|
21
|
+
if(env.TIINEX_ENABLE_NPM_PUBLISH!=='true')throw Error('release.not-enabled');
|
|
22
|
+
}
|
|
23
|
+
export async function readRegistry(name,{fetcher=globalThis.fetch}={}) {
|
|
24
|
+
const response=await fetcher(`https://registry.npmjs.org/${encodeURIComponent(name)}`,{headers:{Accept:'application/json'},signal:AbortSignal.timeout(30000)});
|
|
25
|
+
if(response.status===404)return {name,versions:{}};
|
|
26
|
+
if(!response.ok)throw Error(`release.registry.failure:${response.status}`);
|
|
27
|
+
const data=await response.json();if(data.name!==name||!data.versions||typeof data.versions!=='object')throw Error('release.registry.invalid-response');return data;
|
|
28
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
const RELEASE_MARKER = /(?:\[release:(major|minor|patch)\]|\brelease(?:-intent)?\s*:\s*(major|minor|patch)\b)/ig;
|
|
2
|
+
const BREAKING_MARKER = /(?:^|\n)\s*BREAKING(?: CHANGE|-CHANGE)?\s*:|^[a-z]+(?:\([^\n)]*\))?!:/im;
|
|
3
|
+
const FEATURE_MARKER = /(?:^|\n)\s*feat(?:\([^\n)]*\))?\s*:|\[(?:feature|feat)\]/im;
|
|
4
|
+
|
|
5
|
+
export function parseSemver(value) {
|
|
6
|
+
const match = String(value ?? '').trim().match(/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/);
|
|
7
|
+
if (!match) throw new Error(`Invalid semantic version: ${value}`);
|
|
8
|
+
return {major:Number(match[1]),minor:Number(match[2]),patch:Number(match[3]),prerelease:match[4] ?? ''};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function stableVersion(value) {
|
|
12
|
+
const parsed=parseSemver(value);
|
|
13
|
+
return `${parsed.major}.${parsed.minor}.${parsed.patch}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function bumpVersion(value, bump) {
|
|
17
|
+
const parsed=parseSemver(stableVersion(value));
|
|
18
|
+
if (bump==='major') return `${parsed.major+1}.0.0`;
|
|
19
|
+
if (bump==='minor') return `${parsed.major}.${parsed.minor+1}.0`;
|
|
20
|
+
if (bump==='patch') return `${parsed.major}.${parsed.minor}.${parsed.patch+1}`;
|
|
21
|
+
throw new Error(`Unsupported bump: ${bump}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function strongest(values) {
|
|
25
|
+
const order={patch:1,minor:2,major:3};
|
|
26
|
+
return values.reduce((best,value)=>order[value]>order[best] ? value : best,'patch');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function explicitMarkers(messages) {
|
|
30
|
+
const found=[];
|
|
31
|
+
for (const message of messages) {
|
|
32
|
+
RELEASE_MARKER.lastIndex=0;
|
|
33
|
+
let match;
|
|
34
|
+
while ((match=RELEASE_MARKER.exec(String(message)))) found.push((match[1]??match[2]).toLowerCase());
|
|
35
|
+
}
|
|
36
|
+
return found;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function stableObject(value) {
|
|
40
|
+
if (value===undefined) return null;
|
|
41
|
+
if (Array.isArray(value)) return value.map(stableObject);
|
|
42
|
+
if (value && typeof value==='object') return Object.fromEntries(Object.keys(value).sort().map(key=>[key,stableObject(value[key])]));
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function same(a,b){return JSON.stringify(stableObject(a))===JSON.stringify(stableObject(b));}
|
|
47
|
+
|
|
48
|
+
export function comparePackageSurface(previousPackage,currentPackage) {
|
|
49
|
+
if (!previousPackage) return {severity:'patch',reasons:[]};
|
|
50
|
+
const reasons=[]; const severities=[];
|
|
51
|
+
if (previousPackage.name!==currentPackage.name) { severities.push('major'); reasons.push(`package name changed from ${previousPackage.name} to ${currentPackage.name}`); }
|
|
52
|
+
if (previousPackage.type!==currentPackage.type) { severities.push('major'); reasons.push(`package module type changed from ${previousPackage.type} to ${currentPackage.type}`); }
|
|
53
|
+
if (!same(previousPackage.engines?.node,currentPackage.engines?.node)) { severities.push('major'); reasons.push('supported Node engine declaration changed'); }
|
|
54
|
+
const before=previousPackage.exports??{}; const after=currentPackage.exports??{};
|
|
55
|
+
for (const key of Object.keys(before)) {
|
|
56
|
+
if (!(key in after)) { severities.push('major'); reasons.push(`public export removed: ${key}`); }
|
|
57
|
+
else if (!same(before[key],after[key])) { severities.push('major'); reasons.push(`public export target changed: ${key}`); }
|
|
58
|
+
}
|
|
59
|
+
for (const key of Object.keys(after)) if (!(key in before)) { severities.push('minor'); reasons.push(`public export added: ${key}`); }
|
|
60
|
+
const beforeFiles=Array.isArray(previousPackage.files)?previousPackage.files:[];
|
|
61
|
+
const afterFiles=Array.isArray(currentPackage.files)?currentPackage.files:[];
|
|
62
|
+
for (const pattern of beforeFiles) if (!afterFiles.includes(pattern)) { severities.push('major'); reasons.push(`published file pattern removed: ${pattern}`); }
|
|
63
|
+
for (const pattern of afterFiles) if (!beforeFiles.includes(pattern)) { severities.push('minor'); reasons.push(`published file pattern added: ${pattern}`); }
|
|
64
|
+
return {severity:severities.length?strongest(severities):'patch',reasons};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function recommendRelease({currentVersion,previousVersion=null,previousPackage=null,currentPackage,commitMessages=[],override=null}) {
|
|
68
|
+
const current=parseSemver(currentVersion);
|
|
69
|
+
if (!previousVersion) {
|
|
70
|
+
const target=stableVersion(currentVersion);
|
|
71
|
+
return {bump:'bootstrap',rawSeverity:'bootstrap',targetVersion:target,reasons:[`first stable release from ${currentVersion}`],explicit:false};
|
|
72
|
+
}
|
|
73
|
+
const base=stableVersion(previousVersion);
|
|
74
|
+
const baseParsed=parseSemver(base);
|
|
75
|
+
if (stableVersion(currentVersion)!==base) throw new Error(`package.json version ${currentVersion} does not share the latest release base ${base}`);
|
|
76
|
+
if (current.prerelease) throw new Error(`package.json must stay on released stable version ${base} after the first release; found ${currentVersion}`);
|
|
77
|
+
if (override) {
|
|
78
|
+
if (!['major','minor','patch'].includes(override)) throw new Error(`Invalid release override: ${override}`);
|
|
79
|
+
return {bump:override,rawSeverity:override,targetVersion:bumpVersion(base,override),reasons:[`manual --bump ${override} override`],explicit:true};
|
|
80
|
+
}
|
|
81
|
+
const markers=explicitMarkers(commitMessages);
|
|
82
|
+
const explicit=markers.length?strongest(markers):null;
|
|
83
|
+
const packageChange=comparePackageSurface(previousPackage,currentPackage);
|
|
84
|
+
const breaking=commitMessages.some(message=>BREAKING_MARKER.test(String(message)));
|
|
85
|
+
const feature=commitMessages.some(message=>FEATURE_MARKER.test(String(message)));
|
|
86
|
+
const candidates=[packageChange.severity];
|
|
87
|
+
const reasons=[...packageChange.reasons];
|
|
88
|
+
if (breaking) { candidates.push('major'); reasons.push('breaking-change commit marker detected'); }
|
|
89
|
+
if (feature) { candidates.push('minor'); reasons.push('feature commit marker detected'); }
|
|
90
|
+
if (explicit) { candidates.push(explicit); reasons.push(`explicit release marker requested ${explicit}`); }
|
|
91
|
+
let rawSeverity=strongest(candidates);
|
|
92
|
+
let bump=rawSeverity;
|
|
93
|
+
const explicitMajor=markers.includes('major');
|
|
94
|
+
if (baseParsed.major===0 && rawSeverity==='major' && !explicitMajor) {
|
|
95
|
+
bump='minor';
|
|
96
|
+
reasons.push('pre-1.0 safety: automatic breaking changes advance the minor version; use [release:major] or --bump major to opt into 1.0.0');
|
|
97
|
+
}
|
|
98
|
+
if (!reasons.length) reasons.push('no public-surface or release-intent signal detected; defaulting to patch');
|
|
99
|
+
return {bump,rawSeverity,targetVersion:bumpVersion(base,bump),reasons,explicit:Boolean(explicit)};
|
|
100
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {readFile,writeFile,mkdir,rm,cp,realpath,stat} from 'node:fs/promises';
|
|
2
|
+
import {spawnSync} from 'node:child_process';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import {createHash} from 'node:crypto';
|
|
5
|
+
import {assertPublishContext,readRegistry,releasePlan,compareVersion} from './plan.mjs';
|
|
6
|
+
import {parseSemver} from './policy.mjs';
|
|
7
|
+
const npm=process.platform==='win32'?'npm.cmd':'npm';
|
|
8
|
+
function run(command,args,cwd,{allowFailure=false}={}) {const r=spawnSync(command,args,{cwd,encoding:'utf8',timeout:180000,maxBuffer:32*1024*1024,shell:process.platform==='win32'&&command===npm});if(r.error||(!allowFailure&&r.status!==0))throw Error(`${command} ${args[0]} failed: ${r.error?.message||r.stderr||r.stdout}`);return r;}
|
|
9
|
+
/** Release state is registry metadata, not mutable package.json commits or movable tags.
|
|
10
|
+
* Staging changes only version metadata. The tested source commit is recorded in the tarball.
|
|
11
|
+
* Caller may invoke prepare for preview; publish independently rechecks master and digest.
|
|
12
|
+
*/
|
|
13
|
+
export async function runRelease({cwd=process.cwd(),argv=process.argv.slice(2),env=process.env}={}) {
|
|
14
|
+
cwd=await realpath(cwd);const command=argv[0]||'preview';
|
|
15
|
+
if(!['preview','prepare','publish','bootstrap'].includes(command))throw Error('Use preview, prepare, publish or bootstrap.');
|
|
16
|
+
const pkg=JSON.parse(await readFile(path.join(cwd,'package.json'),'utf8'));
|
|
17
|
+
const policy=JSON.parse(await readFile(path.join(cwd,'.github/release-policy.json'),'utf8'));
|
|
18
|
+
const repository=policy.repository;
|
|
19
|
+
if(pkg.repository?.url!==`git+https://github.com/${repository}.git`||!repository.startsWith('Tiinex/'))throw Error('release.repository.mismatch');
|
|
20
|
+
const git=(args,opts)=>run('git',args,cwd,opts);
|
|
21
|
+
const head=git(['rev-parse','HEAD']).stdout.trim();
|
|
22
|
+
if(command==='publish') {
|
|
23
|
+
assertPublishContext(env,repository);
|
|
24
|
+
const p=JSON.parse(await readFile(path.join(cwd,'.release/plan.json'),'utf8'));
|
|
25
|
+
if(p.sourceCommit!==head||env.GITHUB_SHA!==head)throw Error('release.commit-changed');
|
|
26
|
+
if(p.action==='skip'){console.log(JSON.stringify(p));return p;}
|
|
27
|
+
const file=path.resolve(cwd,p.file);if(path.dirname(file)!==path.join(cwd,'.release'))throw Error('release.archive-path');
|
|
28
|
+
const bytes=await readFile(file);if(createHash('sha512').update(bytes).digest('base64')!==p.integrity.slice(7))throw Error('release.archive-tampered');
|
|
29
|
+
const meta=await readRegistry(pkg.name);const existing=meta.versions[p.version];
|
|
30
|
+
if(existing){if(existing.dist?.integrity!==p.integrity)throw Error('release.version.collision');console.log('Already published exact archive');return p;}
|
|
31
|
+
const latest=Object.values(meta.versions).filter(v=>!parseSemver(v.version).prerelease).sort((a,b)=>compareVersion(a.version,b.version)).at(-1);
|
|
32
|
+
if(latest&&compareVersion(latest.version,p.version)>=0)throw Error('release.newer-version-already-published');
|
|
33
|
+
const result=run(npm,['publish',file,'--ignore-scripts','--access','public','--tag','latest','--provenance'],cwd,{allowFailure:true});
|
|
34
|
+
if(result.status!==0){const check=await readRegistry(pkg.name);if(check.versions[p.version]?.dist?.integrity!==p.integrity)throw Error('release.publish.failed: '+result.stderr);}
|
|
35
|
+
console.log(JSON.stringify({...p,published:true}));return p;
|
|
36
|
+
}
|
|
37
|
+
if(command==='prepare') {assertPublishContext(env,repository);if(env.GITHUB_SHA!==head)throw Error('release.checkout-is-not-event-commit');}
|
|
38
|
+
if(command==='bootstrap' && git(['branch','--show-current']).stdout.trim()!=='master')throw Error('release.bootstrap.master-only');
|
|
39
|
+
if(git(['status','--porcelain','--untracked-files=no']).stdout.trim())throw Error('release.dirty-source');
|
|
40
|
+
const metadata=await readRegistry(pkg.name);
|
|
41
|
+
if(command==='bootstrap'&&Object.keys(metadata.versions).length)throw Error('Package exists: configure OIDC and use the master workflow, not bootstrap.');
|
|
42
|
+
if(command==='bootstrap') { const check=pkg.scripts?.validate?'validate':pkg.scripts?.check?'check':'test'; run(npm,['run',check],cwd); }
|
|
43
|
+
const previous=Object.values(metadata.versions).filter(v=>!parseSemver(v.version).prerelease).sort((a,b)=>compareVersion(a.version,b.version)).at(-1);
|
|
44
|
+
let messages=[], previousCommit=previous?.tiinexRelease?.sourceCommit||previous?.gitHead;
|
|
45
|
+
if(previous) {
|
|
46
|
+
if(!previousCommit||!/^[a-f0-9]{40,64}$/.test(previousCommit))throw Error('release.previous-source-unavailable: migrate registry/git baseline explicitly');
|
|
47
|
+
const ancestor=git(['merge-base','--is-ancestor',previousCommit,head],{allowFailure:true});
|
|
48
|
+
if(ancestor.status!==0){
|
|
49
|
+
const superseded=git(['merge-base','--is-ancestor',head,previousCommit],{allowFailure:true});
|
|
50
|
+
if(superseded.status===0){const skipped={action:'skip',reason:'superseded-master-commit',sourceCommit:head,version:previous.version};await mkdir(path.join(cwd,'.release'),{recursive:true});await writeFile(path.join(cwd,'.release/plan.json'),JSON.stringify(skipped,null,2));return skipped;}
|
|
51
|
+
throw Error('release.divergent-or-shallow-history: full history containing registry source is required');
|
|
52
|
+
}
|
|
53
|
+
messages=git(['log','--format=%B%x00',`${previousCommit}..${head}`]).stdout.split('\0').filter(Boolean);
|
|
54
|
+
} else messages=git(['log','-1','--format=%B']).stdout.split('\0');
|
|
55
|
+
const plan=releasePlan({pkg,metadata,sourceCommit:head,messages});
|
|
56
|
+
if(command==='preview'){console.log(JSON.stringify(plan,null,2));return plan;}
|
|
57
|
+
const dir=path.join(cwd,'.release');await rm(dir,{recursive:true,force:true});await mkdir(dir);
|
|
58
|
+
if(plan.action==='skip'){await writeFile(path.join(dir,'plan.json'),JSON.stringify(plan,null,2));console.log(JSON.stringify(plan));return plan;}
|
|
59
|
+
const stage=path.join(dir,'stage');await mkdir(stage);
|
|
60
|
+
// Excludes ignored/untracked work by definition, and never uses a dirty worktree.
|
|
61
|
+
const files=git(['ls-files','-z']).stdout.split('\0').filter(Boolean);
|
|
62
|
+
for(const rel of files){if(rel.startsWith('.release/')||rel.startsWith('node_modules/')||rel.startsWith('.git/'))continue;const from=path.resolve(cwd,rel),to=path.resolve(stage,rel);if(!to.startsWith(stage+path.sep))throw Error('release.path-escape');await mkdir(path.dirname(to),{recursive:true});await cp(from,to,{dereference:false});}
|
|
63
|
+
const staged={...pkg,version:plan.version,gitHead:head,tiinexRelease:{policy:plan.policy,sourceCommit:head,sourceTree:git(['rev-parse','HEAD^{tree}']).stdout.trim(),repository,previousVersion:plan.previousVersion}};
|
|
64
|
+
await writeFile(path.join(stage,'package.json'),JSON.stringify(staged,null,2)+'\n');
|
|
65
|
+
const lockPath=path.join(stage,'package-lock.json');try{const lock=JSON.parse(await readFile(lockPath,'utf8'));lock.version=plan.version;if(lock.packages?.[''])lock.packages[''].version=plan.version;await writeFile(lockPath,JSON.stringify(lock,null,2)+'\n');}catch(e){if(e.code!=='ENOENT')throw e;}
|
|
66
|
+
const packed=JSON.parse(run(npm,['pack','--ignore-scripts','--json','--pack-destination',dir],stage).stdout)[0];
|
|
67
|
+
const receipt={...plan,file:'.release/'+packed.filename,integrity:packed.integrity,bytes:packed.size};
|
|
68
|
+
await writeFile(path.join(dir,'plan.json'),JSON.stringify(receipt,null,2)+'\n');await rm(stage,{recursive:true,force:true});
|
|
69
|
+
if(command==='bootstrap') {
|
|
70
|
+
console.log('One-time manual publication under latest dist-tag; requires npm login and 2FA.');
|
|
71
|
+
const r=spawnSync(npm,['publish',path.join(cwd,receipt.file),'--ignore-scripts','--access','public','--tag','latest','--provenance=false'],{cwd,stdio:'inherit',shell:process.platform==='win32'});if(r.status!==0)throw Error('release.bootstrap.publish-failed');
|
|
72
|
+
}
|
|
73
|
+
console.log(JSON.stringify(receipt,null,2));return receipt;
|
|
74
|
+
}
|