@mnstry/atelier 0.2.0-alpha.6 → 0.2.0-alpha.8
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/CHANGELOG.md +176 -0
- package/README.md +59 -15
- package/SECURITY.md +6 -1
- package/contracts/atelier-adoption-policy.v1.schema.json +49 -0
- package/contracts/atelier-coauthor.v1.schema.json +163 -0
- package/contracts/atelier-decision-request.v1.schema.json +476 -0
- package/contracts/atelier-decision-result.v1.schema.json +500 -0
- package/contracts/atelier-guide.v1.schema.json +227 -0
- package/contracts/atelier-intake.v1.schema.json +151 -0
- package/contracts/atelier-migration.v2.schema.json +61 -0
- package/contracts/atelier-obsidian-acceptance-receipt.v1.schema.json +211 -0
- package/contracts/atelier-obsidian-apply-policy.v1.schema.json +298 -0
- package/contracts/atelier-obsidian-corpus-profile.v1.schema.json +98 -0
- package/contracts/atelier-obsidian-edit-operation.v1.schema.json +138 -0
- package/contracts/atelier-obsidian-ext-settings.v1.schema.json +287 -0
- package/contracts/atelier-obsidian-generation-manifest.v1.schema.json +353 -0
- package/contracts/atelier-obsidian-proposal-receipt.v1.schema.json +110 -0
- package/contracts/atelier-obsidian-publication-journal.v1.schema.json +167 -0
- package/contracts/atelier-obsidian-scope.v1.schema.json +264 -0
- package/contracts/atelier-obsidian-service-state.v1.schema.json +149 -0
- package/contracts/atelier-obsidian-source-snapshot.v1.schema.json +179 -0
- package/contracts/atelier-pane-presentation.v1.schema.json +76 -0
- package/contracts/atelier-presentation.v1.schema.json +1293 -0
- package/contracts/atelier-review.v1.schema.json +1601 -0
- package/contracts/atelier-skill-steward.v1.schema.json +692 -0
- package/contracts/atelier-upgrade-plan.v2.schema.json +398 -0
- package/contracts/atelier-upgrade-receipt.v1.schema.json +99 -0
- package/contracts/atelier-vault-publication.v1.schema.json +58 -0
- package/docs/assurance-controls.md +9 -1
- package/docs/atelier-sync.md +5 -4
- package/docs/blocks/claims.md +15 -10
- package/docs/blocks/will-not-do.md +4 -1
- package/docs/coauthor-session.md +57 -0
- package/docs/connected-composition.md +75 -0
- package/docs/decisions.md +167 -0
- package/docs/exact-upgrades.md +159 -0
- package/docs/extension-pack-lifecycle.md +33 -0
- package/docs/guided-upgrades.md +99 -0
- package/docs/install.md +65 -9
- package/docs/intake-and-guides.md +65 -0
- package/docs/integration-and-review-plan.md +409 -0
- package/docs/integration-contract-decisions.md +22 -0
- package/docs/local-review.md +84 -0
- package/docs/local-services.md +227 -0
- package/docs/local-state.md +107 -0
- package/docs/obsidian-contract.md +687 -0
- package/docs/obsidian.md +387 -0
- package/docs/portable-presentation.md +328 -0
- package/docs/presentation-consumer-boundaries.md +75 -0
- package/docs/presentation-review-disposition.md +47 -0
- package/docs/project-command-inventory.md +38 -0
- package/docs/project-options.md +53 -0
- package/docs/release-engineering.md +88 -0
- package/docs/review-portability.md +55 -0
- package/docs/skill-steward.md +156 -0
- package/docs/upgrade.md +55 -2
- package/docs/vault-service.md +292 -0
- package/fixtures/atelier-coauthor/invalid/authority.v1.json +5 -0
- package/fixtures/atelier-coauthor/valid/config.v1.json +12 -0
- package/fixtures/atelier-guide/invalid/authority.v1.json +11 -0
- package/fixtures/atelier-guide/valid/capability.v1.json +10 -0
- package/fixtures/atelier-guide/valid/consent.v1.json +11 -0
- package/fixtures/atelier-guide/valid/engagement.v1.json +7 -0
- package/fixtures/atelier-guide/valid/offer.v1.json +10 -0
- package/fixtures/atelier-intake/invalid/authority.v1.json +9 -0
- package/fixtures/atelier-intake/valid/attempt.v1.json +8 -0
- package/fixtures/atelier-intake/valid/completion.v1.json +9 -0
- package/fixtures/atelier-intake/valid/source.v1.json +7 -0
- package/fixtures/atelier-review/invalid/authenticated-identity.v1.json +22 -0
- package/fixtures/atelier-review/valid/bound.v1.json +229 -0
- package/fixtures/atelier-review/valid/bundle.v1.json +267 -0
- package/fixtures/atelier-review/valid/contribution.v1.json +22 -0
- package/fixtures/atelier-review/valid/lifecycle.v1.json +14 -0
- package/fixtures/atelier-skill-steward/audit/invalid/source-mutation.v1.json +26 -0
- package/fixtures/atelier-skill-steward/audit/valid/clean.v1.json +26 -0
- package/fixtures/atelier-skill-steward/candidates/invalid/workflow-key.v1.json +37 -0
- package/fixtures/atelier-skill-steward/candidates/valid/create.v1.json +37 -0
- package/fixtures/atelier-skill-steward/lock/invalid/bad-digest.v1.json +18 -0
- package/fixtures/atelier-skill-steward/lock/valid/installed.v1.json +23 -0
- package/fixtures/atelier-skill-steward/plan/invalid/delete-action.v1.json +33 -0
- package/fixtures/atelier-skill-steward/plan/valid/add.v1.json +33 -0
- package/fixtures/atelier-upgrade-transaction/adoption-policy/invalid/example.json +12 -0
- package/fixtures/atelier-upgrade-transaction/adoption-policy/valid/example.json +11 -0
- package/fixtures/atelier-upgrade-transaction/migration/invalid/example.json +20 -0
- package/fixtures/atelier-upgrade-transaction/migration/valid/example.json +19 -0
- package/fixtures/atelier-upgrade-transaction/upgrade-plan/invalid/example.json +58 -0
- package/fixtures/atelier-upgrade-transaction/upgrade-plan/valid/example.json +57 -0
- package/fixtures/atelier-upgrade-transaction/upgrade-receipt/invalid/example.json +15 -0
- package/fixtures/atelier-upgrade-transaction/upgrade-receipt/valid/example.json +14 -0
- package/fixtures/atelier-vault-publication/invalid/publication.json +5 -0
- package/fixtures/atelier-vault-publication/valid/publication.json +11 -0
- package/fixtures/decisions/request/invalid/unknown-authority.v1.json +61 -0
- package/fixtures/decisions/request/valid/triage.v1.json +60 -0
- package/fixtures/decisions/result/invalid/execution-authority.v1.json +50 -0
- package/fixtures/decisions/result/valid/abstained.v1.json +23 -0
- package/fixtures/decisions/result/valid/assessed.v1.json +50 -0
- package/fixtures/obsidian/acceptance/ap05-extra-notes.json +14 -0
- package/fixtures/obsidian/acceptance/receipts/G07.valid.v1.json +63 -0
- package/fixtures/obsidian/acceptance/receipts/G13.valid.v1.json +69 -0
- package/fixtures/obsidian/acceptance/receipts/G14.valid.v1.json +62 -0
- package/fixtures/obsidian/acceptance/receipts/G15.valid.v1.json +56 -0
- package/fixtures/obsidian/acceptance/receipts/G16.valid.v1.json +73 -0
- package/fixtures/obsidian/acceptance/receipts/G17.valid.v1.json +75 -0
- package/fixtures/obsidian/acceptance/receipts/G18.valid.v1.json +64 -0
- package/fixtures/obsidian/acceptance/service-sentinels.json +10 -0
- package/fixtures/obsidian/contracts/acceptance-receipt/invalid/duplicate-evidence-name.v1.json +39 -0
- package/fixtures/obsidian/contracts/acceptance-receipt/invalid/evidence-by-absolute-path.v1.json +34 -0
- package/fixtures/obsidian/contracts/acceptance-receipt/invalid/missing-candidate-tree.v1.json +33 -0
- package/fixtures/obsidian/contracts/acceptance-receipt/invalid/no-evidence.v1.json +28 -0
- package/fixtures/obsidian/contracts/acceptance-receipt/invalid/unknown-outcome.v1.json +34 -0
- package/fixtures/obsidian/contracts/acceptance-receipt/invalid/unknown-top-level-field.v1.json +35 -0
- package/fixtures/obsidian/contracts/acceptance-receipt/valid/node-gate.v1.json +34 -0
- package/fixtures/obsidian/contracts/apply-policy/invalid/automatic-without-edit-class.v1.json +27 -0
- package/fixtures/obsidian/contracts/apply-policy/invalid/conflict-overwrite.v1.json +29 -0
- package/fixtures/obsidian/contracts/apply-policy/invalid/missing-policy-digest.v1.json +28 -0
- package/fixtures/obsidian/contracts/apply-policy/invalid/unbounded-batch.v1.json +29 -0
- package/fixtures/obsidian/contracts/apply-policy/invalid/unimplemented-edit-class.v1.json +30 -0
- package/fixtures/obsidian/contracts/apply-policy/invalid/unknown-mode.v1.json +29 -0
- package/fixtures/obsidian/contracts/apply-policy/invalid/unknown-selector-operator.v1.json +22 -0
- package/fixtures/obsidian/contracts/apply-policy/invalid/unknown-top-level-field.v1.json +30 -0
- package/fixtures/obsidian/contracts/apply-policy/valid/automatic-scoped.v1.json +29 -0
- package/fixtures/obsidian/contracts/apply-policy/valid/manual-default.v1.json +20 -0
- package/fixtures/obsidian/contracts/corpus-profile/invalid/absolute-path-in-ext.v1.json +30 -0
- package/fixtures/obsidian/contracts/corpus-profile/invalid/absolute-repository-root.v1.json +27 -0
- package/fixtures/obsidian/contracts/corpus-profile/invalid/duplicate-repository-id.v1.json +27 -0
- package/fixtures/obsidian/contracts/corpus-profile/invalid/overlapping-managed-roots.v1.json +27 -0
- package/fixtures/obsidian/contracts/corpus-profile/invalid/unknown-enrollment.v1.json +27 -0
- package/fixtures/obsidian/contracts/corpus-profile/invalid/unknown-top-level-field.v1.json +28 -0
- package/fixtures/obsidian/contracts/corpus-profile/valid/three-repositories.v1.json +27 -0
- package/fixtures/obsidian/contracts/edit-operation/invalid/absolute-recovery-ref.v1.json +21 -0
- package/fixtures/obsidian/contracts/edit-operation/invalid/inline-observed-bytes.v1.json +22 -0
- package/fixtures/obsidian/contracts/edit-operation/invalid/missing-base-digest.v1.json +20 -0
- package/fixtures/obsidian/contracts/edit-operation/invalid/short-idempotency-key.v1.json +21 -0
- package/fixtures/obsidian/contracts/edit-operation/invalid/unknown-kind.v1.json +21 -0
- package/fixtures/obsidian/contracts/edit-operation/valid/pending-body-replacement.v1.json +21 -0
- package/fixtures/obsidian/contracts/ext-settings/invalid/absolute-path-prefix.v1.json +28 -0
- package/fixtures/obsidian/contracts/ext-settings/invalid/apply-policy-in-portable-settings.v1.json +30 -0
- package/fixtures/obsidian/contracts/ext-settings/invalid/duplicate-scope-id.v1.json +27 -0
- package/fixtures/obsidian/contracts/ext-settings/invalid/machine-local-vault-path.v1.json +28 -0
- package/fixtures/obsidian/contracts/ext-settings/invalid/service-port-in-portable-settings.v1.json +28 -0
- package/fixtures/obsidian/contracts/ext-settings/invalid/unknown-default-scope.v1.json +27 -0
- package/fixtures/obsidian/contracts/ext-settings/valid/disabled.v1.json +5 -0
- package/fixtures/obsidian/contracts/ext-settings/valid/enabled-with-scopes.v1.json +27 -0
- package/fixtures/obsidian/contracts/generation-manifest/invalid/absolute-note-path.v1.json +114 -0
- package/fixtures/obsidian/contracts/generation-manifest/invalid/complete-with-unwritten-notes.v1.json +114 -0
- package/fixtures/obsidian/contracts/generation-manifest/invalid/derived-link-claimed-declared.v1.json +114 -0
- package/fixtures/obsidian/contracts/generation-manifest/invalid/duplicate-note-identity.v1.json +114 -0
- package/fixtures/obsidian/contracts/generation-manifest/invalid/in-scope-endpoint-missing.v1.json +114 -0
- package/fixtures/obsidian/contracts/generation-manifest/invalid/title-only-note-path.v1.json +114 -0
- package/fixtures/obsidian/contracts/generation-manifest/invalid/unknown-note-field.v1.json +115 -0
- package/fixtures/obsidian/contracts/generation-manifest/invalid/unknown-relation-type.v1.json +114 -0
- package/fixtures/obsidian/contracts/generation-manifest/invalid/withheld-endpoint.v1.json +114 -0
- package/fixtures/obsidian/contracts/generation-manifest/valid/two-notes.v1.json +114 -0
- package/fixtures/obsidian/contracts/oracles/scope-cases.json +412 -0
- package/fixtures/obsidian/contracts/proposal-receipt/invalid/accepted-without-proposal-id.v1.json +12 -0
- package/fixtures/obsidian/contracts/proposal-receipt/invalid/missing-adapter-operation-id.v1.json +11 -0
- package/fixtures/obsidian/contracts/proposal-receipt/invalid/unknown-backpressure-outcome.v1.json +12 -0
- package/fixtures/obsidian/contracts/proposal-receipt/invalid/unknown-top-level-field.v1.json +13 -0
- package/fixtures/obsidian/contracts/proposal-receipt/valid/accepted-new.v1.json +12 -0
- package/fixtures/obsidian/contracts/proposal-receipt/valid/deferred.v1.json +12 -0
- package/fixtures/obsidian/contracts/publication-journal/invalid/absolute-recovery-ref.v1.json +47 -0
- package/fixtures/obsidian/contracts/publication-journal/invalid/duplicate-sequence.v1.json +47 -0
- package/fixtures/obsidian/contracts/publication-journal/invalid/empty-protocol-id.v1.json +47 -0
- package/fixtures/obsidian/contracts/publication-journal/invalid/missing-protocol-id.v1.json +46 -0
- package/fixtures/obsidian/contracts/publication-journal/invalid/unknown-entry-field.v1.json +48 -0
- package/fixtures/obsidian/contracts/publication-journal/invalid/unknown-state.v1.json +47 -0
- package/fixtures/obsidian/contracts/publication-journal/valid/committed.v1.json +47 -0
- package/fixtures/obsidian/contracts/publication-journal/valid/updating-after-restart.v1.json +22 -0
- package/fixtures/obsidian/contracts/scope/invalid/absolute-path-prefix.v1.json +15 -0
- package/fixtures/obsidian/contracts/scope/invalid/duplicate-ids.v1.json +18 -0
- package/fixtures/obsidian/contracts/scope/invalid/expansion-without-node-budget.v1.json +40 -0
- package/fixtures/obsidian/contracts/scope/invalid/full-mode-with-subset.v1.json +8 -0
- package/fixtures/obsidian/contracts/scope/invalid/unknown-mode.v1.json +41 -0
- package/fixtures/obsidian/contracts/scope/invalid/unknown-selector-key.v1.json +15 -0
- package/fixtures/obsidian/contracts/scope/invalid/unknown-selector-operator.v1.json +14 -0
- package/fixtures/obsidian/contracts/scope/invalid/unknown-top-level-field.v1.json +42 -0
- package/fixtures/obsidian/contracts/scope/valid/explicit-empty.v1.json +8 -0
- package/fixtures/obsidian/contracts/scope/valid/focus.v1.json +11 -0
- package/fixtures/obsidian/contracts/scope/valid/full.v1.json +8 -0
- package/fixtures/obsidian/contracts/scope/valid/scoped-set-expression.v1.json +41 -0
- package/fixtures/obsidian/contracts/service-state/invalid/hostname-instead-of-literal-loopback.v1.json +23 -0
- package/fixtures/obsidian/contracts/service-state/invalid/missing-consent.v1.json +18 -0
- package/fixtures/obsidian/contracts/service-state/invalid/privileged-port.v1.json +23 -0
- package/fixtures/obsidian/contracts/service-state/invalid/unknown-top-level-field.v1.json +24 -0
- package/fixtures/obsidian/contracts/service-state/invalid/wildcard-bind.v1.json +23 -0
- package/fixtures/obsidian/contracts/service-state/valid/healthy.v1.json +23 -0
- package/fixtures/obsidian/contracts/source-snapshot/invalid/absolute-file-path.v1.json +48 -0
- package/fixtures/obsidian/contracts/source-snapshot/invalid/duplicate-repository-id.v1.json +48 -0
- package/fixtures/obsidian/contracts/source-snapshot/invalid/mixed-read.v1.json +48 -0
- package/fixtures/obsidian/contracts/source-snapshot/invalid/parent-traversal-path.v1.json +48 -0
- package/fixtures/obsidian/contracts/source-snapshot/invalid/unknown-file-field.v1.json +49 -0
- package/fixtures/obsidian/contracts/source-snapshot/valid/two-repositories.v1.json +48 -0
- package/fixtures/obsidian/edits/workspace.json +65 -0
- package/fixtures/obsidian/materialization/expected-full.json +99 -0
- package/fixtures/obsidian/materialization/expected-scoped.json +39 -0
- package/fixtures/obsidian/materialization/workspace.json +54 -0
- package/fixtures/obsidian/proposals/expected-shapes.json +11 -0
- package/fixtures/ui/presentation/pane.v1.json +7 -0
- package/fixtures/ui/presentation/reference.v1.json +293 -0
- package/package.json +57 -6
- package/skills/claude/atelier-guided-coauthor/SKILL.md +49 -0
- package/skills/claude/atelier-guided-upgrade/SKILL.md +97 -0
- package/skills/claude/atelier-open/SKILL.md +5 -0
- package/skills/claude/atelier-skill-steward/SKILL.md +62 -0
- package/skills/claude/mnstry-readiness/SKILL.md +5 -0
- package/skills/codex/atelier-guided-coauthor/SKILL.md +49 -0
- package/skills/codex/atelier-guided-upgrade/SKILL.md +97 -0
- package/skills/codex/atelier-open/SKILL.md +5 -0
- package/skills/codex/atelier-skill-steward/SKILL.md +62 -0
- package/skills/codex/mnstry-readiness/SKILL.md +5 -0
- package/src/access/preview-enforcer.mjs +84 -0
- package/src/boundary/policy.mjs +57 -25
- package/src/cli/project-options.mjs +58 -0
- package/src/cli/run.mjs +43 -3
- package/src/coauthor/session.mjs +161 -0
- package/src/coauthor/store.mjs +173 -0
- package/src/collaboration/event-ledger.mjs +16 -33
- package/src/collaboration/inspection-bundle.mjs +223 -0
- package/src/collaboration/review-contracts.mjs +25 -0
- package/src/collaboration/review-store.mjs +305 -0
- package/src/commands/coauthor.mjs +26 -0
- package/src/commands/config.mjs +6 -1
- package/src/commands/extension-pack.mjs +15 -8
- package/src/commands/init.mjs +44 -5
- package/src/commands/obsidian.mjs +368 -0
- package/src/commands/review.mjs +147 -0
- package/src/commands/setup.mjs +51 -14
- package/src/commands/skills.mjs +199 -0
- package/src/commands/sync.mjs +8 -1
- package/src/composition/registry.mjs +27 -0
- package/src/composition/wire.mjs +122 -0
- package/src/contracts/corpus.mjs +29 -0
- package/src/decisions/contracts.d.mts +96 -0
- package/src/decisions/contracts.mjs +321 -0
- package/src/disclosure/content-scan.mjs +13 -0
- package/src/export/atelier-export-contract.mjs +16 -1
- package/src/extension-packs/lifecycle.mjs +154 -0
- package/src/graph/graph.mjs +64 -2
- package/src/graph/knowledge-graph.mjs +548 -24
- package/src/guides/contracts.mjs +54 -0
- package/src/intake/store.mjs +119 -0
- package/src/preview/channel.mjs +89 -0
- package/src/project/config.mjs +26 -27
- package/src/project/durable-state.mjs +161 -0
- package/src/project/file-class.mjs +166 -0
- package/src/project/private-state.mjs +11 -1
- package/src/projection/obsidian/contracts.mjs +571 -0
- package/src/projection/obsidian/edits/align.mjs +169 -0
- package/src/projection/obsidian/edits/apply.mjs +889 -0
- package/src/projection/obsidian/edits/arbitrate.mjs +414 -0
- package/src/projection/obsidian/edits/contribution.mjs +108 -0
- package/src/projection/obsidian/edits/index.mjs +19 -0
- package/src/projection/obsidian/edits/object-identity.mjs +61 -0
- package/src/projection/obsidian/edits/object-store.mjs +517 -0
- package/src/projection/obsidian/edits/observe.mjs +123 -0
- package/src/projection/obsidian/edits/policy.mjs +123 -0
- package/src/projection/obsidian/edits/regions.mjs +648 -0
- package/src/projection/obsidian/materialize/byte-lens.mjs +98 -0
- package/src/projection/obsidian/materialize/index.mjs +7 -0
- package/src/projection/obsidian/materialize/path-registry.mjs +105 -0
- package/src/projection/obsidian/materialize/prepare-view.mjs +746 -0
- package/src/projection/obsidian/materialize/settings.mjs +57 -0
- package/src/projection/obsidian/materialize/stage.mjs +27 -0
- package/src/projection/obsidian/proposals/adapter.mjs +572 -0
- package/src/projection/obsidian/proposals/backpressure.mjs +113 -0
- package/src/projection/obsidian/proposals/contribution.mjs +55 -0
- package/src/projection/obsidian/proposals/index.mjs +23 -0
- package/src/projection/obsidian/proposals/observation.mjs +216 -0
- package/src/projection/obsidian/proposals/queue.mjs +277 -0
- package/src/projection/obsidian/proposals/router.mjs +168 -0
- package/src/projection/obsidian/publication/bridge-script.mjs +266 -0
- package/src/projection/obsidian/publication/exchange.mjs +117 -0
- package/src/projection/obsidian/publication/index.mjs +5 -0
- package/src/projection/obsidian/publication/publisher.mjs +588 -0
- package/src/projection/obsidian/publication/test-seam.mjs +16 -0
- package/src/projection/obsidian/publication/transport.mjs +139 -0
- package/src/projection/obsidian/recovery/index.mjs +6 -0
- package/src/projection/obsidian/recovery/journal.mjs +134 -0
- package/src/projection/obsidian/recovery/late-writer.mjs +46 -0
- package/src/projection/obsidian/recovery/restart.mjs +316 -0
- package/src/projection/obsidian/recovery/store.mjs +234 -0
- package/src/projection/obsidian/selection-ui/conflict-view.mjs +91 -0
- package/src/projection/obsidian/selection-ui/contribution.mjs +141 -0
- package/src/projection/obsidian/selection-ui/focus.mjs +82 -0
- package/src/projection/obsidian/selection-ui/index.mjs +12 -0
- package/src/projection/obsidian/selection-ui/policy-setup.mjs +107 -0
- package/src/projection/obsidian/selection-ui/receipt.mjs +173 -0
- package/src/projection/obsidian/selection-ui/selection-state.mjs +122 -0
- package/src/projection/obsidian/selection-ui/selection.mjs +109 -0
- package/src/projection/project.mjs +28 -19
- package/src/readiness-protocols/evidence.mjs +282 -0
- package/src/readiness-protocols/runtime.mjs +4 -3
- package/src/readiness-protocols/source-read.mjs +39 -0
- package/src/runtime/obsidian/app-capability.mjs +110 -0
- package/src/runtime/obsidian/app-production-seams.mjs +96 -0
- package/src/runtime/obsidian/contributions/proposal-adapter.mjs +4 -0
- package/src/runtime/obsidian/contributions/selection-ui.mjs +4 -0
- package/src/runtime/obsidian/contributions/source-apply.mjs +4 -0
- package/src/runtime/obsidian/contributions.mjs +27 -0
- package/src/runtime/obsidian/documents.mjs +37 -0
- package/src/runtime/obsidian/enablement.mjs +53 -0
- package/src/runtime/obsidian/engine.mjs +532 -0
- package/src/runtime/obsidian/errors.mjs +14 -0
- package/src/runtime/obsidian/extension-points.mjs +103 -0
- package/src/runtime/obsidian/index.mjs +34 -0
- package/src/runtime/obsidian/lifecycle.mjs +258 -0
- package/src/runtime/obsidian/machine-settings.mjs +260 -0
- package/src/runtime/obsidian/observation.mjs +158 -0
- package/src/runtime/obsidian/opening.mjs +243 -0
- package/src/runtime/obsidian/pending-edits.mjs +141 -0
- package/src/runtime/obsidian/pipeline.mjs +122 -0
- package/src/runtime/obsidian/private-lock.mjs +156 -0
- package/src/runtime/obsidian/process-identity.mjs +58 -0
- package/src/runtime/obsidian/service-client.mjs +66 -0
- package/src/runtime/obsidian/service-main.mjs +89 -0
- package/src/runtime/obsidian/service-record.mjs +169 -0
- package/src/runtime/obsidian/service-server.mjs +121 -0
- package/src/runtime/obsidian/service.mjs +216 -0
- package/src/runtime/obsidian/startup-adapters.mjs +87 -0
- package/src/runtime/obsidian/state-store.mjs +180 -0
- package/src/runtime/obsidian/sync-notice.mjs +33 -0
- package/src/runtime/obsidian/tick-loop.mjs +84 -0
- package/src/runtime/obsidian/watchers.mjs +36 -0
- package/src/runtime/supervisor.mjs +16 -1
- package/src/server/local-sidecar.mjs +44 -0
- package/src/server/server.mjs +1 -0
- package/src/skills/steward.mjs +780 -0
- package/src/ui/presentation/browser.mjs +278 -0
- package/src/ui/presentation/contract.mjs +116 -0
- package/src/ui/presentation/index.mjs +7 -0
- package/src/ui/presentation/native.mjs +153 -0
- package/src/ui/presentation/proof.mjs +57 -0
- package/src/ui/presentation/schema-check.mjs +30 -0
- package/src/ui/presentation/schema.generated.mjs +1371 -0
- package/src/ui/presentation/state.mjs +43 -0
- package/src/ui/presentation/styles.mjs +67 -0
- package/src/ui/presentation/tokens.mjs +74 -0
- package/src/ui/presentation/web.mjs +85 -0
- package/src/ui/review-page.mjs +32 -0
- package/src/upgrade/explanation.mjs +33 -0
- package/src/upgrade/provenance.mjs +338 -0
- package/src/upgrade/transaction-files.mjs +103 -0
- package/src/upgrade/transaction.mjs +475 -0
- package/src/upgrade/upgrade.mjs +63 -28
- package/src/vault/hosts.mjs +21 -0
- package/src/vault/identity.mjs +19 -0
- package/src/vault/index.mjs +7 -0
- package/src/vault/interface.mjs +11 -0
- package/src/vault/metadata.mjs +31 -0
- package/src/vault/privacy.mjs +148 -0
- package/src/vault/probe.mjs +89 -0
- package/src/vault/service.mjs +131 -0
- package/src/vault/source.mjs +45 -0
- package/src/vault/storage.mjs +23 -0
- package/templates/distribution-workspace/.claude/launch.json +6 -2
- package/templates/distribution-workspace/gitignore +1 -0
- package/templates/distribution-workspace/project/README.md +2 -2
- package/templates/external-project-workspace/README.md +45 -0
- package/templates/external-project-workspace/answers.example.json +4 -0
- package/templates/external-project-workspace/atelier.project.json +40 -0
- package/templates/external-project-workspace/boundary-policy.v1.json +60 -0
- package/templates/external-project-workspace/gitignore +8 -0
- package/templates/external-project-workspace/pack-lifecycle.json +14 -0
- package/templates/external-project-workspace/packs/protocols/contract-gate.v1.json +109 -0
- package/templates/external-project-workspace/packs/sample-pack.v1.json +48 -0
- package/templates/external-project-workspace/repo-access.v1.json +9 -0
- package/templates/external-project-workspace/source/README.md +11 -0
- package/templates/launch.json +6 -2
- package/templates/private-domain-workspace/.claude/launch.json +6 -2
- package/templates/private-domain-workspace/domain/README.md +2 -2
- package/templates/private-domain-workspace/gitignore +1 -0
- package/templates/shared-project-workspace/.claude/launch.json +6 -2
- package/templates/shared-project-workspace/gitignore +1 -0
- package/templates/shared-project-workspace/project/README.md +2 -2
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
1
3
|
import { basenameOf, matchesPathPattern, normalizeRelPath } from './path-match.mjs'
|
|
2
4
|
|
|
3
5
|
export const FILE_CLASS_SCHEMA = 'mnstry.atelier-file-classes@v1'
|
|
@@ -6,8 +8,13 @@ export const SOURCE = 'source'
|
|
|
6
8
|
export const GENERATED_PROJECTION = 'generated-projection'
|
|
7
9
|
export const DISTRIBUTED_RUNTIME_COPY = 'distributed-runtime-copy'
|
|
8
10
|
|
|
11
|
+
// Declarable classes for tracked files. The kit manifest schema closes this set.
|
|
9
12
|
export const FILE_CLASSES = Object.freeze([SOURCE, GENERATED_PROJECTION, DISTRIBUTED_RUNTIME_COPY])
|
|
10
13
|
|
|
14
|
+
// A machine-local file that git never tracks. It is not declarable: nothing
|
|
15
|
+
// tracked can be ignored-local, so it stays out of FILE_CLASSES.
|
|
16
|
+
export const IGNORED_LOCAL = 'ignored-local'
|
|
17
|
+
|
|
11
18
|
// What each class means for automated handling. Sync loops, merge policies, upgrade
|
|
12
19
|
// tooling, and CI guards all read this instead of each keeping a list of filenames
|
|
13
20
|
// that drifts out of step with the others.
|
|
@@ -15,8 +22,17 @@ export const FILE_CLASS_HANDLING = Object.freeze({
|
|
|
15
22
|
[SOURCE]: Object.freeze({ rederivable: false, discardable: false, conflictsNeedHuman: true }),
|
|
16
23
|
[GENERATED_PROJECTION]: Object.freeze({ rederivable: true, discardable: true, conflictsNeedHuman: false }),
|
|
17
24
|
[DISTRIBUTED_RUNTIME_COPY]: Object.freeze({ rederivable: true, discardable: true, conflictsNeedHuman: false }),
|
|
25
|
+
// Holds this machine's only reference to external editable state. Never
|
|
26
|
+
// swept, never synced, never a merge conflict.
|
|
27
|
+
[IGNORED_LOCAL]: Object.freeze({ rederivable: false, discardable: false, conflictsNeedHuman: false }),
|
|
18
28
|
})
|
|
19
29
|
|
|
30
|
+
// The one repo-local file the Obsidian view leaves in a repository or
|
|
31
|
+
// workspace: a pointer to the external data directory and its local settings.
|
|
32
|
+
// It lives under the existing ignored local-state directory.
|
|
33
|
+
export const OBSIDIAN_LOCAL_POINTER = '.atelier-local/obsidian.json'
|
|
34
|
+
export const IGNORED_LOCAL_PATTERNS = Object.freeze([`**/${OBSIDIAN_LOCAL_POINTER}`])
|
|
35
|
+
|
|
20
36
|
// The kit's own declaration — the single place these paths are classified. A
|
|
21
37
|
// distributed-runtime-copy is canonical in exactly one repo role and rederivable
|
|
22
38
|
// everywhere else; that is why the class carries `canonicalRepoRole` rather than
|
|
@@ -75,6 +91,12 @@ export function validateFileClasses(entries, { label = 'fileClasses' } = {}) {
|
|
|
75
91
|
*/
|
|
76
92
|
export function classifyPath(filePath, { repoRole = null, fileClasses = KIT_FILE_CLASSES } = {}) {
|
|
77
93
|
const rel = normalizeRelPath(filePath)
|
|
94
|
+
// Not overridable: a declaration cannot turn a local pointer into something
|
|
95
|
+
// a sync loop may discard or commit.
|
|
96
|
+
const localPattern = IGNORED_LOCAL_PATTERNS.find((pattern) => matchesPathPattern(pattern, rel))
|
|
97
|
+
if (localPattern) {
|
|
98
|
+
return { path: rel, class: IGNORED_LOCAL, pattern: localPattern, canonicalRepoRole: null, canonicalHere: true, declared: false, handling: FILE_CLASS_HANDLING[IGNORED_LOCAL] }
|
|
99
|
+
}
|
|
78
100
|
let matched = null
|
|
79
101
|
for (const entry of fileClasses) {
|
|
80
102
|
if (matchesPathPattern(entry.pattern, rel)) matched = entry
|
|
@@ -125,3 +147,147 @@ export function generatedProjectionDirectoryBasenames(fileClasses = KIT_FILE_CLA
|
|
|
125
147
|
}
|
|
126
148
|
return names
|
|
127
149
|
}
|
|
150
|
+
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// External managed data root: <data>/obsidian/<workspace-id>/
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
|
|
155
|
+
export const EDITABLE_VAULT = 'editable-vault'
|
|
156
|
+
export const TRUSTED_STATE = 'trusted-state'
|
|
157
|
+
export const RECOVERY_RECORD = 'recovery-record'
|
|
158
|
+
export const DISPOSABLE_STAGING = 'disposable-staging'
|
|
159
|
+
export const UNKNOWN_MANAGED = 'unknown-managed'
|
|
160
|
+
|
|
161
|
+
// Only staging is discardable. A vault holds a person's edits and recovery
|
|
162
|
+
// holds the only other copy of them, so neither is ever generated output, and
|
|
163
|
+
// anything unrecognized is kept.
|
|
164
|
+
export const MANAGED_AREA_HANDLING = Object.freeze({
|
|
165
|
+
[EDITABLE_VAULT]: Object.freeze({ rederivable: false, discardable: false, conflictsNeedHuman: true }),
|
|
166
|
+
[TRUSTED_STATE]: Object.freeze({ rederivable: false, discardable: false, conflictsNeedHuman: true }),
|
|
167
|
+
[RECOVERY_RECORD]: Object.freeze({ rederivable: false, discardable: false, conflictsNeedHuman: true }),
|
|
168
|
+
[DISPOSABLE_STAGING]: Object.freeze({ rederivable: true, discardable: true, conflictsNeedHuman: false }),
|
|
169
|
+
[UNKNOWN_MANAGED]: Object.freeze({ rederivable: false, discardable: false, conflictsNeedHuman: true }),
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
const MANAGED_AREAS = Object.freeze({ vaults: EDITABLE_VAULT, state: TRUSTED_STATE, recovery: RECOVERY_RECORD, staging: DISPOSABLE_STAGING })
|
|
173
|
+
|
|
174
|
+
// Classify a path relative to one workspace's managed data root. Matching is
|
|
175
|
+
// exact and case-sensitive, and a path that climbs, is absolute or names only
|
|
176
|
+
// the area directory itself is never discardable.
|
|
177
|
+
export function classifyManagedPath(relativePath) {
|
|
178
|
+
const rel = normalizeRelPath(relativePath).replace(/\/+$/, '')
|
|
179
|
+
const segments = rel.split('/')
|
|
180
|
+
const contained = rel !== '' && !rel.startsWith('/') && !/^[A-Za-z]:/.test(rel) && !segments.some((part) => part === '..' || part === '.' || part === '')
|
|
181
|
+
const area = contained && segments.length > 1 && Object.hasOwn(MANAGED_AREAS, segments[0]) ? segments[0] : null
|
|
182
|
+
const resolved = area ? MANAGED_AREAS[area] : UNKNOWN_MANAGED
|
|
183
|
+
return { path: rel, area, class: resolved, handling: MANAGED_AREA_HANDLING[resolved] }
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// The real path of a target that may not exist yet: the deepest existing
|
|
187
|
+
// ancestor is resolved and the missing tail is appended. Only "does not exist"
|
|
188
|
+
// moves up a level. Any other failure (a directory that cannot be searched,
|
|
189
|
+
// a link loop) is thrown: a lexical path standing in for a real one would
|
|
190
|
+
// weaken the alias check exactly where it matters.
|
|
191
|
+
function realLocation(target, realpath) {
|
|
192
|
+
const missing = []
|
|
193
|
+
let current = path.resolve(target)
|
|
194
|
+
for (;;) {
|
|
195
|
+
try {
|
|
196
|
+
return path.join(realpath(current), ...missing.reverse())
|
|
197
|
+
} catch (error) {
|
|
198
|
+
if (error?.code !== 'ENOENT' && error?.code !== 'ENOTDIR') throw error
|
|
199
|
+
const parent = path.dirname(current)
|
|
200
|
+
if (parent === current) return path.resolve(target)
|
|
201
|
+
missing.push(path.basename(current))
|
|
202
|
+
current = parent
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const containsPath = (outer, inner) => inner === outer || inner.startsWith(outer.endsWith(path.sep) ? outer : `${outer}${path.sep}`)
|
|
208
|
+
|
|
209
|
+
function isSymbolicLink(target, lstat) {
|
|
210
|
+
try {
|
|
211
|
+
return lstat(target).isSymbolicLink()
|
|
212
|
+
} catch {
|
|
213
|
+
return false
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// True when the path or any of its ancestors is a symbolic link.
|
|
218
|
+
function crossesSymbolicLink(target, lstat) {
|
|
219
|
+
for (let current = path.resolve(target); ; current = path.dirname(current)) {
|
|
220
|
+
if (isSymbolicLink(current, lstat)) return true
|
|
221
|
+
if (path.dirname(current) === current) return false
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Refuse a managed root that overlaps an enrolled repository in either
|
|
226
|
+
// direction, under lexical or real paths. `realpath` and `lstat` are the only
|
|
227
|
+
// filesystem reads, and both can be supplied; nothing is created or changed.
|
|
228
|
+
// A real path that cannot be established refuses; it is never replaced by the
|
|
229
|
+
// lexical path.
|
|
230
|
+
export function checkManagedRoots({ managedRoots = [], repositoryRoots = [], realpath = fs.realpathSync.native, lstat = fs.lstatSync } = {}) {
|
|
231
|
+
const refusals = []
|
|
232
|
+
const refuse = (code, managedRoot, repositoryRoot, message) => refusals.push({ code, managedRoot, repositoryRoot, message })
|
|
233
|
+
const locate = (root) => {
|
|
234
|
+
try {
|
|
235
|
+
return { given: root, lexical: path.resolve(root), real: realLocation(root, realpath) }
|
|
236
|
+
} catch (error) {
|
|
237
|
+
return { given: root, lexical: path.resolve(root), real: null, errorCode: error?.code ?? 'unknown' }
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const repositories = repositoryRoots.map(locate)
|
|
241
|
+
|
|
242
|
+
for (const managedRoot of managedRoots) {
|
|
243
|
+
if (typeof managedRoot !== 'string' || !path.isAbsolute(managedRoot)) {
|
|
244
|
+
refuse('managed-root-not-absolute', managedRoot, null, 'a managed root must be an absolute path')
|
|
245
|
+
continue
|
|
246
|
+
}
|
|
247
|
+
const managed = locate(managedRoot)
|
|
248
|
+
if (managed.real === null) {
|
|
249
|
+
refuse('managed-root-realpath-failed', managedRoot, null, `the real path of a managed root cannot be established (${managed.errorCode})`)
|
|
250
|
+
continue
|
|
251
|
+
}
|
|
252
|
+
if (isSymbolicLink(managed.lexical, lstat)) {
|
|
253
|
+
refuse('managed-root-symlink-alias', managedRoot, null, 'a managed root must not be a symbolic link')
|
|
254
|
+
}
|
|
255
|
+
for (const repository of repositories) {
|
|
256
|
+
const inside = (kind) => containsPath(repository[kind], managed[kind])
|
|
257
|
+
const around = (kind) => containsPath(managed[kind], repository[kind])
|
|
258
|
+
if (inside('lexical')) refuse('managed-root-inside-repository', managedRoot, repository.given, 'a managed root must sit outside every enrolled repository')
|
|
259
|
+
else if (around('lexical')) refuse('repository-inside-managed-root', managedRoot, repository.given, 'an enrolled repository must not sit inside a managed root')
|
|
260
|
+
else if (repository.real === null) {
|
|
261
|
+
refuse('managed-root-realpath-failed', managedRoot, repository.given, `the real path of an enrolled repository cannot be established (${repository.errorCode})`)
|
|
262
|
+
} else if (inside('real') || around('real')) {
|
|
263
|
+
// Name the cause that is actually there. Folding letter case and
|
|
264
|
+
// Unicode normalization alone may explain the overlap; otherwise a
|
|
265
|
+
// symbolic link on either path does; otherwise something else presents
|
|
266
|
+
// one location under two names (a mount, for example).
|
|
267
|
+
const folded = (value) => value.normalize('NFC').toLowerCase()
|
|
268
|
+
const byFolding = containsPath(folded(repository.lexical), folded(managed.lexical)) || containsPath(folded(managed.lexical), folded(repository.lexical))
|
|
269
|
+
if (!byFolding && (crossesSymbolicLink(managed.lexical, lstat) || crossesSymbolicLink(repository.lexical, lstat))) {
|
|
270
|
+
refuse('managed-root-symlink-alias', managedRoot, repository.given, 'a symbolic link makes the managed root and an enrolled repository overlap')
|
|
271
|
+
} else {
|
|
272
|
+
refuse('managed-root-realpath-overlap', managedRoot, repository.given,
|
|
273
|
+
'the managed root and an enrolled repository are written differently but name overlapping locations, and no symbolic link explains it: look for a difference in letter case or Unicode normalization on a filesystem that folds them, or a mount that presents one location under two names')
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return { ok: refusals.length === 0, refusals }
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// The same guard at enrolment time: a repository that would contain, sit
|
|
282
|
+
// inside or alias an existing managed root cannot be enrolled.
|
|
283
|
+
export function checkRepositoryEnrollment({ repositoryRoot, managedRoots = [], realpath, lstat } = {}) {
|
|
284
|
+
const { refusals } = checkManagedRoots({ managedRoots, repositoryRoots: [repositoryRoot], ...(realpath ? { realpath } : {}), ...(lstat ? { lstat } : {}) })
|
|
285
|
+
const codes = {
|
|
286
|
+
'managed-root-inside-repository': 'enrollment-contains-managed-root',
|
|
287
|
+
'repository-inside-managed-root': 'enrollment-inside-managed-root',
|
|
288
|
+
'managed-root-symlink-alias': 'enrollment-aliases-managed-root',
|
|
289
|
+
'managed-root-realpath-overlap': 'enrollment-realpath-overlaps-managed-root',
|
|
290
|
+
}
|
|
291
|
+
const blocking = refusals.filter((item) => item.repositoryRoot !== null).map((item) => ({ ...item, code: codes[item.code] ?? item.code }))
|
|
292
|
+
return { ok: blocking.length === 0, refusals: blocking }
|
|
293
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
|
+
import { randomUUID } from 'node:crypto'
|
|
3
4
|
|
|
4
5
|
function escapes(root, candidate) {
|
|
5
6
|
const relative = path.relative(root, candidate)
|
|
@@ -79,12 +80,20 @@ export function readRegularTextNoFollow(file) {
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
export function syncPrivateDirectory(directory) {
|
|
84
|
+
let fd;
|
|
85
|
+
try { fd = fs.openSync(directory, fs.constants.O_RDONLY); fs.fsyncSync(fd); }
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (process.platform !== 'win32' || !['EPERM', 'EACCES', 'EINVAL', 'EISDIR'].includes(error.code)) throw error;
|
|
88
|
+
} finally { if (fd !== undefined) fs.closeSync(fd); }
|
|
89
|
+
}
|
|
90
|
+
|
|
82
91
|
export function atomicReplacePrivateText(file, text, mode = 0o600) {
|
|
83
92
|
const existing = lstatIfPresent(file)
|
|
84
93
|
if (existing && (existing.isSymbolicLink() || !existing.isFile())) {
|
|
85
94
|
throw new Error('state leaf is not a regular file')
|
|
86
95
|
}
|
|
87
|
-
const tmp = `${file}.${
|
|
96
|
+
const tmp = `${file}.${randomUUID()}.tmp`
|
|
88
97
|
let descriptor
|
|
89
98
|
try {
|
|
90
99
|
descriptor = openRegularFileNoFollow(
|
|
@@ -98,6 +107,7 @@ export function atomicReplacePrivateText(file, text, mode = 0o600) {
|
|
|
98
107
|
fs.closeSync(descriptor)
|
|
99
108
|
descriptor = null
|
|
100
109
|
fs.renameSync(tmp, file)
|
|
110
|
+
syncPrivateDirectory(path.dirname(file))
|
|
101
111
|
} catch (error) {
|
|
102
112
|
if (descriptor != null) fs.closeSync(descriptor)
|
|
103
113
|
try {
|