@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
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atelier-guided-coauthor
|
|
3
|
+
description: Guide an author through a selected packet in Codex, retaining private source-bound draft answers and resuming through the local Atelier coauthor CLI.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Guided coauthor
|
|
7
|
+
|
|
8
|
+
Use the installed `atelier coauthor` command, not a browser conversation service.
|
|
9
|
+
The author chooses the packet and may read it normally without this workflow.
|
|
10
|
+
|
|
11
|
+
Check the repository's instructions and local package first. Run
|
|
12
|
+
`./node_modules/.bin/atelier coauthor --help` from the intended repository.
|
|
13
|
+
Do not download another package if the command is unavailable. Explain that the
|
|
14
|
+
installed version needs the coauthor capability and preserve ordinary packet review.
|
|
15
|
+
|
|
16
|
+
## Start or resume
|
|
17
|
+
|
|
18
|
+
- Require an existing Git workspace with ignored, untracked `.atelier-local/`.
|
|
19
|
+
Do not change global skills, sibling repositories, credentials or remote access.
|
|
20
|
+
- Read the selected packet. Use consumer-owned field ids and workspace-relative
|
|
21
|
+
source references. Compute SHA-256 over each source file's exact UTF-8 bytes.
|
|
22
|
+
Send a `start` request containing `config: {id, fields}`; each field has
|
|
23
|
+
`id` and `source: {ref, digest}`. Packet structure stays in the consumer.
|
|
24
|
+
- Requests are JSON on stdin; responses are JSON. Use an ignored request file
|
|
25
|
+
when needed, not shell interpolation of the author's text. Read the returned
|
|
26
|
+
state and revision. `read` takes `sessionId` and resumes retained history.
|
|
27
|
+
- Ask one useful question at a time. Record the author's exact answer with an
|
|
28
|
+
`answer` event; events carry a unique `id`, `expectedRevision` and `type`.
|
|
29
|
+
Do not infer an answer or approval from silence.
|
|
30
|
+
- If proposing edited wording, use `propose` and show the change. Wait for the
|
|
31
|
+
author's explicit confirmation before `confirm`. `reject` restores the
|
|
32
|
+
original. Even apparently stylistic rewrites need confirmation.
|
|
33
|
+
- Send `save` only for the agreed draft. Say “saved as a private draft” only
|
|
34
|
+
after the command returns a saved receipt. The source packet is never edited.
|
|
35
|
+
`continueAfterSave: true` on an answer retains the author's advance intent;
|
|
36
|
+
otherwise `advance` is explicit.
|
|
37
|
+
- `pause` and `resume` preserve the current phase. On restart, a `saving`
|
|
38
|
+
state may use `recover` to reconcile the pending private write. A
|
|
39
|
+
`recovery` state requires explicit `retry`, with one retry available.
|
|
40
|
+
Stop retrying when exhausted and retain all artifacts for inspection.
|
|
41
|
+
|
|
42
|
+
## Boundaries
|
|
43
|
+
|
|
44
|
+
Never submit store-owned receipt/failure events or fabricate persistence evidence.
|
|
45
|
+
A stale source or revision is a visible conflict, not permission to overwrite it.
|
|
46
|
+
Keep the old history and obtain a newly bound session for revised sources.
|
|
47
|
+
Saved answers are proposals for later owner review, not publication, canonical
|
|
48
|
+
acceptance, guide access, or a completed packet. No saved-answer undo is provided;
|
|
49
|
+
do not erase history to simulate it. Summarize unresolved questions for the meeting.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atelier-guided-upgrade
|
|
3
|
+
description: Prepare and explain an Atelier package upgrade in an isolated candidate, retain the owner decision, and apply only the approved effects. Use for owners asking to update an existing Atelier.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Guided Atelier upgrade
|
|
7
|
+
|
|
8
|
+
The default outcome is a reviewable candidate and an owner decision. Preserve the
|
|
9
|
+
owner's actual request and existing scoped authority; no per-command approval
|
|
10
|
+
loop is needed for actions already authorized. Preparation alone never authorizes
|
|
11
|
+
changing the working installation, merging, publishing or restarting a service.
|
|
12
|
+
|
|
13
|
+
## Establish the source and workspace
|
|
14
|
+
|
|
15
|
+
Read the selected repository's instructions and upgrade procedure. Identify its
|
|
16
|
+
actual installed scoped package, package-manager lock, Atelier lock, Git state,
|
|
17
|
+
project roots, packs, overlays and running-service ownership. Resolve the package
|
|
18
|
+
from that workspace (including a parent install); never use global Atelier,
|
|
19
|
+
unscoped registry fallback or the first sibling checkout found on disk.
|
|
20
|
+
Read `docs/guided-upgrades.md` and `docs/exact-upgrades.md` from the selected
|
|
21
|
+
installed package when present. If an old install lacks this skill or commands,
|
|
22
|
+
use the owner-selected new package's documentation only after verifying its
|
|
23
|
+
source. Repository instructions and owner authority still govern.
|
|
24
|
+
|
|
25
|
+
Select an exact release through a source already trusted by the owner. Record
|
|
26
|
+
version, source commit when verified, artifact URL/integrity and the dependency
|
|
27
|
+
lock. Mutable dist-tags are discovery hints, not final pins. A declaration in a
|
|
28
|
+
lock or a digest supplied beside a download does not authenticate a publisher.
|
|
29
|
+
An unpublished candidate must be labeled as such; use it only in an expressly
|
|
30
|
+
selected rehearsal. Never invent a release or replace a pinned install with main.
|
|
31
|
+
|
|
32
|
+
## Prepare without disturbing authoring
|
|
33
|
+
|
|
34
|
+
Use a separate candidate with an identified base. Preserve dirty source and
|
|
35
|
+
private answers; do not stash, reset, clean, stop services or commit another
|
|
36
|
+
writer's edits to create eligibility. If using a snapshot of current edits,
|
|
37
|
+
record and recheck its exact manifest; it is a snapshot, not an adopted commit.
|
|
38
|
+
Ignored answers, browser storage and runtime credentials are not in a Git clone.
|
|
39
|
+
Record that gap without importing them into a public report or projection.
|
|
40
|
+
|
|
41
|
+
Stage the selected package using the owner's package manager and lock procedure,
|
|
42
|
+
with lifecycle scripts disabled; investigate any required scripts before execution.
|
|
43
|
+
Verify the resolved identity and inventory before running its commands. Inspect
|
|
44
|
+
migration/compatibility effects before rewriting the old Atelier lock. Retain the
|
|
45
|
+
old lock and all lineage. Keep installation changes distinct from generated files.
|
|
46
|
+
|
|
47
|
+
Check exact-plan eligibility: Linux/macOS, one managed repository at `.`, config
|
|
48
|
+
and workspace at its root, linked candidate worktree, clean state and supported
|
|
49
|
+
Git settings. Packs, overlays and other unsupported participants require the
|
|
50
|
+
repository's explicit operator procedure. Do not broaden graph roots, remove
|
|
51
|
+
policies or disable filters/hooks to force eligibility. Never silently fall back
|
|
52
|
+
to legacy `upgrade --apply`; it has different guarantees.
|
|
53
|
+
|
|
54
|
+
For an eligible candidate, prepare `upgrade plan --save`, then use
|
|
55
|
+
`upgrade explain --plan SAVED_PLAN_PATH` (JSON) and `--format markdown` (owner
|
|
56
|
+
view). Invoke the verified installed binary with the explicit project path.
|
|
57
|
+
Inspect `bindingsCurrent` and blockers even when the explanation exits zero.
|
|
58
|
+
Keep source/pin/policy installation commits and the saved projection plan separate.
|
|
59
|
+
For an operator procedure, retain an exact before/after file manifest and named
|
|
60
|
+
commands instead; do not call it an exact-plan transaction or invent its digest.
|
|
61
|
+
|
|
62
|
+
## Explain and retain consent
|
|
63
|
+
|
|
64
|
+
Present the local benefit, exact target, changed files, preserved customizations,
|
|
65
|
+
checks, known limits, recovery coverage and proposed effects. Show installation,
|
|
66
|
+
local commit, merge, publication and activation separately. Ask one concrete
|
|
67
|
+
question covering the effects that still need authority. A permission to prepare
|
|
68
|
+
or a generic earlier “go” does not approve a newly introduced material effect.
|
|
69
|
+
A prior explicit approval of this same current plan and effects remains valid.
|
|
70
|
+
|
|
71
|
+
Retain a new decision record in ignored, untracked
|
|
72
|
+
`.atelier-local/guided-upgrades/` (or a private sibling evidence directory):
|
|
73
|
+
`kind: owner-decision`, report and plan/manifest SHA-256, candidate base, target
|
|
74
|
+
identity, exact owner words, conversation reference, observation time, decision
|
|
75
|
+
(approve/defer/decline), allowed effects, and
|
|
76
|
+
`humanApprovalAuthenticated: false`, `recordedBy: agent`.
|
|
77
|
+
Do not invent identity, words, references or approvals; missing provenance is a
|
|
78
|
+
reported gap. This is an agent-attested record, not an authenticated signature or
|
|
79
|
+
an execution grant. Keep existing records immutable. Silence conveys no consent.
|
|
80
|
+
|
|
81
|
+
## Apply, validate and close
|
|
82
|
+
|
|
83
|
+
After actual approval, use the saved path and exact confirmation digest literally.
|
|
84
|
+
Recheck bindings; changed or expired plans require a fresh explanation and any
|
|
85
|
+
newly necessary decision. A consumed plan is inspected, never replayed.
|
|
86
|
+
Run the repository's documented acceptance checks and inspect the actual diff.
|
|
87
|
+
Only a verified terminal transaction receipt means a candidate commit completed.
|
|
88
|
+
Honor existing hooks and keep source/answer files within their ownership boundary.
|
|
89
|
+
An operator procedure has its own validation evidence, not a transaction receipt.
|
|
90
|
+
|
|
91
|
+
Continue authorized merge/activation steps only when included in the owner's
|
|
92
|
+
scope. Report prepared, installed-in-candidate, committed, merged and running as
|
|
93
|
+
separate observed states. A local preview passing is not recipient acceptance.
|
|
94
|
+
On failure, preserve the candidate, backups and receipts; explain what changed
|
|
95
|
+
and the next safe action. Recovery inspection does not automatically restore
|
|
96
|
+
files or reset Git. Do not publish source, restart an existing service or advance
|
|
97
|
+
an author's workflow phase merely because upgrade checks passed.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atelier-skill-steward
|
|
3
|
+
description: Audit, create, improve, reconcile, retire, or update an Atelier-backed agent skill catalog using evidence thresholds, behavioral checks, and reversible managed projections.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Atelier skill steward
|
|
7
|
+
|
|
8
|
+
Use this skill when a repository should maintain its agent skills as a coherent,
|
|
9
|
+
self-improving catalog. Do not use it to turn a one-off preference into a skill,
|
|
10
|
+
capture prompts or transcripts, or grant a skill new authority implicitly.
|
|
11
|
+
|
|
12
|
+
## Route the work
|
|
13
|
+
|
|
14
|
+
- Audit the current catalog with `atelier skills audit --json`.
|
|
15
|
+
- Record only a content-free signal with `atelier skills observe`; use a stable
|
|
16
|
+
workflow key, enumerated signal, optional skill name, and outcome. Never put a
|
|
17
|
+
summary, prompt, source excerpt, person, client, or private method in the key.
|
|
18
|
+
- Find evidence-thresholded work with `atelier skills candidates --json`.
|
|
19
|
+
- Create or improve an authored skill only when the candidate evidence and the
|
|
20
|
+
current task establish a repeatable input, workflow, and success condition.
|
|
21
|
+
- Update a repo-scoped deployed catalog with `atelier skills sync`. Review the
|
|
22
|
+
plan, then repeat its exact digest with `--apply --confirm`. Never manufacture
|
|
23
|
+
confirmation before inspecting blockers and actions.
|
|
24
|
+
|
|
25
|
+
## Authoring boundary
|
|
26
|
+
|
|
27
|
+
Keep each skill focused. Give `SKILL.md` lowercase kebab-case `name` and a
|
|
28
|
+
discriminating `description`; put only decision-changing guidance in the body.
|
|
29
|
+
Add scripts or references only when deterministic reuse or progressive
|
|
30
|
+
disclosure justifies them. Test direct triggers, indirect triggers, incomplete
|
|
31
|
+
inputs, non-triggers, and risky edge cases.
|
|
32
|
+
|
|
33
|
+
In the public Atelier repository, read `AGENTS.md`, `CONTRIBUTING.md`, and
|
|
34
|
+
`docs/release-engineering.md` before editing. Re-derive private lessons as
|
|
35
|
+
generic invariants with invented fixtures. Keep Codex and Claude bundles
|
|
36
|
+
byte-identical and run the repository disclosure and release gates required by
|
|
37
|
+
those documents.
|
|
38
|
+
|
|
39
|
+
## Promotion policy
|
|
40
|
+
|
|
41
|
+
An instruction-only change that retains the same tools, data boundary, and
|
|
42
|
+
external authority may advance after its behavioral checks and catalog audit
|
|
43
|
+
pass. New scripts, tool dependencies, network access, filesystem scope,
|
|
44
|
+
external messages, spending, destructive operations, credential handling, or
|
|
45
|
+
audience changes require explicit human authorization immediately before that
|
|
46
|
+
authority is introduced.
|
|
47
|
+
|
|
48
|
+
Do not treat an audit pass as proof of behavioral quality. Compare the candidate
|
|
49
|
+
against representative positive and negative requests. Reject it when it only
|
|
50
|
+
memorizes one incident, broadens its trigger, weakens a refusal, or cannot name
|
|
51
|
+
observable improvement.
|
|
52
|
+
|
|
53
|
+
## Retirement and updates
|
|
54
|
+
|
|
55
|
+
Remove obsolete skills from active discovery only after checking dependents and
|
|
56
|
+
supersession. Preserve recovery through Git or the sync quarantine; never
|
|
57
|
+
permanently delete a managed deployed bundle during sync. A locally drifted or
|
|
58
|
+
unmanaged target is a blocker, not permission to overwrite it.
|
|
59
|
+
|
|
60
|
+
The steward has no model provider, telemetry, send path, browser apply endpoint,
|
|
61
|
+
or hidden source-mutation authority. Scheduling may invoke this workflow, but a
|
|
62
|
+
schedule does not widen its permissions or lower its evidence gates.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { parseRequest, parseBoundedJSON, need, isRef, isDigest, canonical, deepFreeze, MODES } from '../composition/wire.mjs';
|
|
2
|
+
import { digestBytes } from '../composition/registry.mjs';
|
|
3
|
+
|
|
4
|
+
const messages = Object.freeze({ loading: 'Checking access.', ready: 'Preview ready.', unauthenticated: 'Sign in to preview.',
|
|
5
|
+
forbidden: 'Preview is not permitted.', expired: 'Session expired.', unavailable: 'Preview unavailable.', stale: 'Preview changed. Refresh to continue.' });
|
|
6
|
+
export class PreviewRefusal extends Error {
|
|
7
|
+
constructor(state) { super('Preview refused'); need(Object.hasOwn(messages, state) && !['ready', 'loading'].includes(state)); this.state = state; }
|
|
8
|
+
}
|
|
9
|
+
function principal(p) { need(p && isRef(p.issuer) && isRef(p.subject) && ['human', 'agent', 'service', 'local-owner'].includes(p.kind)); }
|
|
10
|
+
function sessionCheck(s, now) {
|
|
11
|
+
need(s && Number.isSafeInteger(s.generation) && s.generation >= 0 && Number.isFinite(s.expiresAt));
|
|
12
|
+
for (const k of ['sessionRef', 'workspaceRef', 'audienceRef', 'policyRevision']) need(isRef(s[k]));
|
|
13
|
+
need(s.tenantRef === null || isRef(s.tenantRef));
|
|
14
|
+
// This prototype deliberately cannot admit production or implicit public access.
|
|
15
|
+
need(s.plane === 'preview');
|
|
16
|
+
if (!s.principal) throw new PreviewRefusal('unauthenticated');
|
|
17
|
+
principal(s.principal); principal(s.representedPrincipal);
|
|
18
|
+
if (s.expiresAt <= now) throw new PreviewRefusal('expired');
|
|
19
|
+
}
|
|
20
|
+
function checkDelegation(s, request, target, now) {
|
|
21
|
+
const d = s.delegation;
|
|
22
|
+
if (!d) {
|
|
23
|
+
need(s.principal.kind !== 'agent' && canonical(s.principal) === canonical(s.representedPrincipal)); return;
|
|
24
|
+
}
|
|
25
|
+
need(s.principal.kind === 'agent' && d.active === true && d.redelegationAllowed === false && isRef(d.ref) && isRef(d.revision));
|
|
26
|
+
need(Number.isFinite(d.expiresAt) && d.expiresAt > now && d.expiresAt <= s.expiresAt);
|
|
27
|
+
need(canonical(d.actor) === canonical(s.principal) && canonical(d.representedPrincipal) === canonical(s.representedPrincipal));
|
|
28
|
+
for (const key of ['sessionRef', 'generation', 'tenantRef', 'workspaceRef', 'audienceRef', 'plane']) need(d[key] === s[key]);
|
|
29
|
+
for (const key of ['modes', 'operationRefs', 'resourceRefs']) need(Array.isArray(d[key]) && d[key].length <= 64 && new Set(d[key]).size === d[key].length);
|
|
30
|
+
need(d.modes.every(m => MODES.includes(m)) && d.operationRefs.every(isRef) && d.resourceRefs.every(isRef));
|
|
31
|
+
if (!d.modes.includes(request.mode) || !d.operationRefs.includes(target.operationRef) || !d.resourceRefs.includes(target.resourceRef)) throw new PreviewRefusal('forbidden');
|
|
32
|
+
}
|
|
33
|
+
export function createPreviewEnforcer(ports, { now = Date.now } = {}) {
|
|
34
|
+
for (const key of ['authenticate', 'resolveTarget', 'authorize', 'revalidate', 'perform', 'projectResult', 'audit']) need(typeof ports?.[key] === 'function');
|
|
35
|
+
return Object.freeze({ async handle(channel, bytes, signal) {
|
|
36
|
+
let request, binding, phase = 'parse', performed = false;
|
|
37
|
+
const generation = Number.isSafeInteger(channel?.generation) && channel.generation >= 0 ? channel.generation : 0;
|
|
38
|
+
const state = (name, projectedData) => deepFreeze({ state: {
|
|
39
|
+
schema: 'atelier-preview-state/proposal-v1', requestId: request?.requestId || 'invalid', placementId: request?.placementId || 'invalid',
|
|
40
|
+
sourceDigest: request?.sourceDigest || '0'.repeat(64), mode: request?.mode || 'synthetic', state: name,
|
|
41
|
+
sessionGeneration: generation, publicMessage: messages[name],
|
|
42
|
+
}, ...(name === 'ready' ? { projectedData } : {}) });
|
|
43
|
+
const live = () => { if (signal?.aborted) throw new PreviewRefusal('stale'); if (binding && binding.expiresAt <= now()) throw new PreviewRefusal('expired'); };
|
|
44
|
+
const fresh = async () => { live(); if (await ports.revalidate(binding, signal) !== true) throw new PreviewRefusal('stale'); live(); };
|
|
45
|
+
const audit = (stage, outcome) => ports.audit(deepFreeze({ binding, phase: stage, outcome }));
|
|
46
|
+
try {
|
|
47
|
+
request = deepFreeze(parseRequest(bytes)); live(); phase = 'authenticate';
|
|
48
|
+
const s = deepFreeze(structuredClone(await ports.authenticate(channel, signal)));
|
|
49
|
+
sessionCheck(s, now()); live(); phase = 'resolve';
|
|
50
|
+
const t = deepFreeze(structuredClone(await ports.resolveTarget(s, request, signal)));
|
|
51
|
+
for (const key of ['resourceRef', 'operationRef', 'serviceRef', 'sourceRef', 'placementRef', 'registryRevision']) need(isRef(t?.[key]));
|
|
52
|
+
for (const key of ['sourceDigest', 'descriptorDigest', 'rendererDigest']) need(isDigest(t[key]));
|
|
53
|
+
need(t.sourceDigest === request.sourceDigest && t.placementRef === request.placementId);
|
|
54
|
+
checkDelegation(s, request, t, now());
|
|
55
|
+
binding = deepFreeze({ sessionRef: s.sessionRef, generation: s.generation, principal: s.principal, representedPrincipal: s.representedPrincipal,
|
|
56
|
+
delegationRef: s.delegation?.ref || null, delegationRevision: s.delegation?.revision || null,
|
|
57
|
+
tenantRef: s.tenantRef, workspaceRef: s.workspaceRef, plane: s.plane, mode: request.mode, audienceRef: s.audienceRef,
|
|
58
|
+
target: t, requestRef: request.requestId, requestDigest: digestBytes(canonical(request)), policyRevision: s.policyRevision,
|
|
59
|
+
expiresAt: Math.min(s.expiresAt, s.delegation?.expiresAt ?? Infinity) });
|
|
60
|
+
phase = 'authorize'; live(); await audit('requested', 'pending');
|
|
61
|
+
const decision = deepFreeze(structuredClone(await ports.authorize(binding, signal))); live();
|
|
62
|
+
need(canonical(decision?.binding) === canonical(binding));
|
|
63
|
+
if (decision.outcome !== 'allow') throw new PreviewRefusal(decision.outcome === 'deny' ? 'forbidden' : decision.outcome === 'reauth-required' ? 'expired' : 'unavailable');
|
|
64
|
+
await audit('authorized', 'allowed'); await fresh(); phase = 'perform'; performed = true;
|
|
65
|
+
const raw = await ports.perform(s, request, decision, signal);
|
|
66
|
+
await fresh(); phase = 'project';
|
|
67
|
+
const projected = await ports.projectResult(binding, raw, signal);
|
|
68
|
+
// Trusted projector owns the field allowlist. Root still enforces JSON,
|
|
69
|
+
// byte/depth bounds and cannot accidentally serialize result metadata.
|
|
70
|
+
const data = parseBoundedJSON(JSON.stringify(projected));
|
|
71
|
+
// Preparation is not a browser delivery acknowledgement. Keep the last
|
|
72
|
+
// asynchronous audit inside the revalidation boundary before returning.
|
|
73
|
+
await fresh(); await audit('settled', 'prepared'); await fresh();
|
|
74
|
+
return state('ready', data);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
const name = error instanceof PreviewRefusal ? error.state : 'unavailable';
|
|
77
|
+
if (binding) {
|
|
78
|
+
try { await audit('settled', performed ? 'uncertain' : name === 'stale' ? 'stale' : phase === 'authorize' ? 'denied' : 'failed'); }
|
|
79
|
+
catch { /* No output or automatic effect retry if audit storage fails. */ }
|
|
80
|
+
}
|
|
81
|
+
return state(name);
|
|
82
|
+
}
|
|
83
|
+
} });
|
|
84
|
+
}
|
package/src/boundary/policy.mjs
CHANGED
|
@@ -146,7 +146,7 @@ export function validateBoundaryPolicy(policy, project = null) {
|
|
|
146
146
|
const declaredRepos = isObject(repos) ? repos : {}
|
|
147
147
|
for (const [index, exception] of policy.contentRuleExceptions.entries()) {
|
|
148
148
|
const name = firstString(exception?.repo)
|
|
149
|
-
if (name && Object.keys(declaredRepos).length && !declaredRepos
|
|
149
|
+
if (name && Object.keys(declaredRepos).length && !Object.hasOwn(declaredRepos, name)) {
|
|
150
150
|
errors.push(`contentRuleExceptions[${index}].repo ${name} is not declared in repos`)
|
|
151
151
|
}
|
|
152
152
|
}
|
|
@@ -163,7 +163,7 @@ export function validateBoundaryPolicy(policy, project = null) {
|
|
|
163
163
|
}
|
|
164
164
|
if (!firstString(actor.privateDomainRepo)) errors.push(`actors.${actorId}.privateDomainRepo is required`)
|
|
165
165
|
if (firstString(actor.privateDomainRepo) && isObject(repos)) {
|
|
166
|
-
const privateRepo = repos[actor.privateDomainRepo]
|
|
166
|
+
const privateRepo = Object.hasOwn(repos, actor.privateDomainRepo) ? repos[actor.privateDomainRepo] : null
|
|
167
167
|
if (!privateRepo) {
|
|
168
168
|
errors.push(`actors.${actorId}.privateDomainRepo ${actor.privateDomainRepo} is not declared in repos`)
|
|
169
169
|
} else if (privateRepo.kind !== 'private_domain') {
|
|
@@ -188,7 +188,7 @@ export function validateBoundaryPolicy(policy, project = null) {
|
|
|
188
188
|
errors.push(...validAudienceList(repo.forbiddenAudiences, `repos.${repoName}.forbiddenAudiences`))
|
|
189
189
|
if (repo.kind === 'private_domain') {
|
|
190
190
|
if (!firstString(repo.ownerActor)) errors.push(`repos.${repoName}.ownerActor is required for private_domain repos`)
|
|
191
|
-
if (repo.ownerActor && isObject(actors) && !actors
|
|
191
|
+
if (repo.ownerActor && isObject(actors) && !Object.hasOwn(actors, repo.ownerActor)) errors.push(`repos.${repoName}.ownerActor ${repo.ownerActor} is not declared`)
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
|
|
@@ -197,35 +197,61 @@ export function validateBoundaryPolicy(policy, project = null) {
|
|
|
197
197
|
if (repo.external) {
|
|
198
198
|
// Declaring a boundary for a repo nobody manages is the confusion the
|
|
199
199
|
// external kind exists to remove.
|
|
200
|
-
if (repos
|
|
200
|
+
if (Object.hasOwn(repos, repo.name)) errors.push(`policy repos.${repo.name} must not be declared; it is an external (unmanaged) repo`)
|
|
201
201
|
continue
|
|
202
202
|
}
|
|
203
|
-
if (!repos
|
|
203
|
+
if (!Object.hasOwn(repos, repo.name)) errors.push(`policy repos.${repo.name} must be declared`)
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
return errors
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
|
|
210
|
+
function resolveExplicitActor({ policy, actor, env }) {
|
|
211
211
|
const actors = policy?.actors ?? {}
|
|
212
|
-
const explicit = actor || env.MNSTRY_ATELIER_ACTOR
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const actorEmails = new Set(asArray(info.gitEmails).map((email) => email.toLowerCase()))
|
|
217
|
-
if (gitEmails.some((email) => actorEmails.has(email.toLowerCase()))) return { actorId, source: 'git-email', gitEmails }
|
|
212
|
+
const explicit = actor || env.MNSTRY_ATELIER_ACTOR
|
|
213
|
+
const unverified = (reason) => ({ actorId: null, source: 'unverified', reason })
|
|
214
|
+
if (actor && env.MNSTRY_ATELIER_ACTOR && actor !== env.MNSTRY_ATELIER_ACTOR) {
|
|
215
|
+
return unverified('conflicting-explicit-actors')
|
|
218
216
|
}
|
|
219
|
-
|
|
217
|
+
if (explicit && !Object.hasOwn(actors, explicit)) return unverified('unknown-explicit-actor')
|
|
218
|
+
return explicit ? { actorId: explicit, source: 'explicit' } : null
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function resolveCurrentActor({ policy, project, actor = null, env = process.env, gitExecutable = 'git', allowNetworkActorResolution = true, allowHistoryActorResolution = false } = {}) {
|
|
222
|
+
const actors = policy?.actors ?? {}
|
|
223
|
+
const explicit = resolveExplicitActor({ policy, actor, env })
|
|
224
|
+
if (explicit) return explicit
|
|
225
|
+
const unverified = (reason) => ({ actorId: null, source: 'unverified', reason })
|
|
226
|
+
// Without an explicit local selector, a platform login precedes Git metadata.
|
|
227
|
+
// It is platform attribution only; this function cannot authenticate its env.
|
|
228
|
+
const platformLogin = env.GITHUB_ACTOR
|
|
229
|
+
if (platformLogin) {
|
|
230
|
+
const matches = Object.entries(actors).filter(([, info]) =>
|
|
231
|
+
!String(info.githubLogin || '').endsWith('_GITHUB_LOGIN_PLACEHOLDER') &&
|
|
232
|
+
String(info.githubLogin || '').toLowerCase() === String(platformLogin).toLowerCase())
|
|
233
|
+
if (matches.length !== 1) return unverified(matches.length ? 'ambiguous-platform-actor' : 'unknown-platform-actor')
|
|
234
|
+
return { actorId: matches[0][0], source: 'github-login', githubLogin: platformLogin }
|
|
235
|
+
}
|
|
236
|
+
// Keep the legacy option accepted by the API, but history is never evidence
|
|
237
|
+
// of the person currently operating a checkout.
|
|
238
|
+
const gitEmails = gitEmailsForProject(project, { gitExecutable, env, allowHistoryActorResolution: false })
|
|
239
|
+
const matches = Object.entries(actors).filter(([, info]) => {
|
|
240
|
+
const actorEmails = new Set(asArray(info.gitEmails).map((email) => email.toLowerCase()))
|
|
241
|
+
return gitEmails.some((email) => actorEmails.has(email.toLowerCase()))
|
|
242
|
+
})
|
|
243
|
+
if (matches.length > 1) return unverified('ambiguous-git-actor')
|
|
244
|
+
if (matches.length === 1) return { actorId: matches[0][0], source: 'git-email', gitEmails }
|
|
245
|
+
const login = allowNetworkActorResolution ? ghLogin() : null
|
|
220
246
|
if (login) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
247
|
+
const matches = Object.entries(actors).filter(([, info]) => !String(info.githubLogin || '').endsWith('_GITHUB_LOGIN_PLACEHOLDER') && String(info.githubLogin || '').toLowerCase() === String(login).toLowerCase())
|
|
248
|
+
if (matches.length !== 1) return unverified(matches.length ? 'ambiguous-platform-actor' : 'unknown-platform-actor')
|
|
249
|
+
return { actorId: matches[0][0], source: 'github-login', githubLogin: login }
|
|
224
250
|
}
|
|
225
|
-
return { actorId: null, source: 'unverified', gitEmails, githubLogin:
|
|
251
|
+
return { actorId: null, source: 'unverified', gitEmails, githubLogin: null }
|
|
226
252
|
}
|
|
227
253
|
|
|
228
|
-
function gitEmailsForProject(project, { gitExecutable = 'git', env = process.env, allowHistoryActorResolution =
|
|
254
|
+
function gitEmailsForProject(project, { gitExecutable = 'git', env = process.env, allowHistoryActorResolution = false } = {}) {
|
|
229
255
|
const roots = unique([project?.repoOpsRoot, project?.workspaceRoot, ...managedRepos(project).map((repo) => repo.path)])
|
|
230
256
|
const emails = []
|
|
231
257
|
for (const root of roots) {
|
|
@@ -249,7 +275,7 @@ function ghLogin() {
|
|
|
249
275
|
}
|
|
250
276
|
|
|
251
277
|
function repoPolicy(policy, repoName) {
|
|
252
|
-
return policy?.repos
|
|
278
|
+
return policy?.repos && Object.hasOwn(policy.repos, repoName) ? policy.repos[repoName] : null
|
|
253
279
|
}
|
|
254
280
|
|
|
255
281
|
function finding({ severity = 'error', code, message, repo = null, path: itemPath = null, node = null, details = {} }) {
|
|
@@ -282,13 +308,19 @@ function nodePlacementFindings({ node, policy }) {
|
|
|
282
308
|
|
|
283
309
|
function actorFindings({ policy, project, actor, gitExecutable, allowNetworkActorResolution, allowHistoryActorResolution, forceActorErrors }) {
|
|
284
310
|
const findings = []
|
|
285
|
-
const
|
|
311
|
+
const operatedRepos = new Set(managedRepos(project).map((repo) => repo.name))
|
|
312
|
+
const ownedRepos = Object.entries(policy.repos ?? {}).filter(([name, repo]) =>
|
|
313
|
+
operatedRepos.has(name) && repo?.kind === 'private_domain' && repo.ownerActor)
|
|
314
|
+
const explicit = resolveExplicitActor({ policy, actor, env: process.env })
|
|
315
|
+
if (explicit?.reason) return [finding({ severity: 'error', code: 'actor-resolution-refused', message: explicit.reason })]
|
|
316
|
+
// Shared-only work needs no derived identity and must not invoke Git or gh.
|
|
317
|
+
if (!ownedRepos.length) return findings
|
|
318
|
+
const current = explicit || resolveCurrentActor({ policy, project, actor, gitExecutable, allowNetworkActorResolution, allowHistoryActorResolution })
|
|
286
319
|
const severity = forceActorErrors ? 'error' : severityFor(policy)
|
|
287
|
-
for (const [repoName, repo] of
|
|
288
|
-
if (repo.kind !== 'private_domain') continue
|
|
289
|
-
if (!repo.ownerActor) continue
|
|
320
|
+
for (const [repoName, repo] of ownedRepos) {
|
|
290
321
|
if (!current.actorId) {
|
|
291
|
-
findings.push(finding({ severity, code: 'private-domain-actor-unverified', repo: repoName,
|
|
322
|
+
findings.push(finding({ severity, code: 'private-domain-actor-unverified', repo: repoName,
|
|
323
|
+
message: `${repoName}: could not verify local actor for private domain repo owned by ${repo.ownerActor}${current.reason ? ` (${current.reason})` : ''}` }))
|
|
292
324
|
} else if (current.actorId !== repo.ownerActor) {
|
|
293
325
|
findings.push(finding({ severity, code: 'private-domain-actor-mismatch', repo: repoName, message: `${repoName}: private domain repo is owned by ${repo.ownerActor}, but current actor is ${current.actorId}` }))
|
|
294
326
|
}
|
|
@@ -603,7 +635,7 @@ function promotionFindings({ policy, project, graph }) {
|
|
|
603
635
|
return findings
|
|
604
636
|
}
|
|
605
637
|
|
|
606
|
-
export function checkBoundaryPolicy({ project, policy, staged = false, stagedOnly = false, actor = null, gitExecutable = 'git', allowNetworkActorResolution = true, allowHistoryActorResolution =
|
|
638
|
+
export function checkBoundaryPolicy({ project, policy, staged = false, stagedOnly = false, actor = null, gitExecutable = 'git', allowNetworkActorResolution = true, allowHistoryActorResolution = false, forceActorErrors = false } = {}) {
|
|
607
639
|
const validationErrors = validateBoundaryPolicy(policy, project)
|
|
608
640
|
let graph = null
|
|
609
641
|
const findings = validationErrors.map((message) => finding({ severity: 'error', code: 'boundary-policy-invalid', message }))
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Shared project-location syntax. Command-specific arguments remain owned by
|
|
2
|
+
// their command; this parser does not make unknown options globally valid.
|
|
3
|
+
export const PROJECT_OPTION_SPEC = Object.freeze({
|
|
4
|
+
project: 'value',
|
|
5
|
+
'project-config': 'value',
|
|
6
|
+
'repo-path': 'value',
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
function invalid(message) {
|
|
10
|
+
const error = new Error(message)
|
|
11
|
+
error.code = 'project-option-invalid'
|
|
12
|
+
error.exitCode = 2
|
|
13
|
+
throw error
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function projectOptionAt(argv, index, configArgPrefix = '--project-config=') {
|
|
17
|
+
const arg = argv[index]
|
|
18
|
+
if (typeof arg !== 'string' || !arg.startsWith('--')) return null
|
|
19
|
+
const name = arg.slice(2).split('=')[0]
|
|
20
|
+
const custom = configArgPrefix !== '--project-config=' && arg.startsWith(configArgPrefix)
|
|
21
|
+
if (!custom && !Object.hasOwn(PROJECT_OPTION_SPEC, name)) return null
|
|
22
|
+
const inline = custom || arg.includes('=')
|
|
23
|
+
const value = custom ? arg.slice(configArgPrefix.length) : inline ? arg.slice(arg.indexOf('=') + 1) : argv[index + 1]
|
|
24
|
+
if (typeof value !== 'string' || !value.trim() || value.startsWith('--')) {
|
|
25
|
+
invalid(`--${custom ? 'project-config' : name} requires a non-empty value`)
|
|
26
|
+
}
|
|
27
|
+
const option = custom ? 'project-config' : name
|
|
28
|
+
if (option === 'repo-path') {
|
|
29
|
+
const separator = value.indexOf('=')
|
|
30
|
+
if (separator < 1 || !value.slice(0, separator).trim() || !value.slice(separator + 1).trim()) {
|
|
31
|
+
invalid('--repo-path requires NAME=PATH')
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return { name: option, value, nextIndex: index + (inline ? 1 : 2) }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function parseProjectOptions(argv = [], configArgPrefix = '--project-config=') {
|
|
38
|
+
let project = null
|
|
39
|
+
const repoPaths = new Map()
|
|
40
|
+
const remaining = []
|
|
41
|
+
for (let index = 0; index < argv.length;) {
|
|
42
|
+
const option = projectOptionAt(argv, index, configArgPrefix)
|
|
43
|
+
if (!option) {
|
|
44
|
+
remaining.push(argv[index++])
|
|
45
|
+
continue
|
|
46
|
+
}
|
|
47
|
+
if (option.name === 'repo-path') {
|
|
48
|
+
const separator = option.value.indexOf('=')
|
|
49
|
+
repoPaths.set(option.value.slice(0, separator).trim(), option.value.slice(separator + 1))
|
|
50
|
+
} else if (project === null) {
|
|
51
|
+
// Preserve the resolver's first project selection and last named repo
|
|
52
|
+
// override behavior, including aliases in the same invocation.
|
|
53
|
+
project = option.value.trim()
|
|
54
|
+
}
|
|
55
|
+
index = option.nextIndex
|
|
56
|
+
}
|
|
57
|
+
return { project, repoPaths, remaining }
|
|
58
|
+
}
|
package/src/cli/run.mjs
CHANGED
|
@@ -59,6 +59,10 @@ export const commandMap = new Map([
|
|
|
59
59
|
['announcements', ['src/commands/announcements.mjs']],
|
|
60
60
|
['announcements:list', ['src/commands/announcements.mjs', 'list']],
|
|
61
61
|
['sync', ['src/commands/sync.mjs']],
|
|
62
|
+
['review', ['src/commands/review.mjs']],
|
|
63
|
+
['coauthor', ['src/commands/coauthor.mjs']],
|
|
64
|
+
['skills', ['src/commands/skills.mjs']],
|
|
65
|
+
['obsidian', ['src/commands/obsidian.mjs']],
|
|
62
66
|
])
|
|
63
67
|
|
|
64
68
|
function isDefaultBrand(brand) {
|
|
@@ -122,14 +126,24 @@ Core commands:
|
|
|
122
126
|
sync plan Prepare one bounded, reviewable commit plan.
|
|
123
127
|
sync commit Execute an exactly confirmed commit plan.
|
|
124
128
|
sync run --once Run one full-state supervisor cycle.
|
|
129
|
+
obsidian status|open|apply Maintain and open Obsidian views of the corpus; apply edits made in them.
|
|
125
130
|
egress check Check extracted Atelier paths for forbidden egress.
|
|
126
131
|
boundary check Enforce private/shared repo placement rules.
|
|
127
132
|
boundary audit Report content-rule matches tree-wide without blocking.
|
|
128
133
|
boundary install-hooks Install staged/private-domain Git guards.
|
|
129
134
|
promote Record a git.promote disclosure event.
|
|
130
|
-
upgrade --
|
|
135
|
+
upgrade plan --save Save an exact local candidate plan.
|
|
136
|
+
upgrade explain --plan Explain saved changes and consent without writes.
|
|
137
|
+
upgrade apply --plan --confirm Apply the selected plan through commit hooks.
|
|
138
|
+
upgrade status|recover Inspect receipts or preview recovery.
|
|
139
|
+
upgrade --dry-run Plan a legacy package/template upgrade.
|
|
131
140
|
upgrade --apply Apply a branch-based reviewable upgrade.
|
|
132
141
|
lock check|write Verify or create atelier.lock.json.
|
|
142
|
+
lock provenance Inspect actual installed package identity.
|
|
143
|
+
review run|history|handoff Evidence-bound local human review.
|
|
144
|
+
review export|inspect|packs Preview inspection bundles and pack lifecycle.
|
|
145
|
+
coauthor start|read|event|recover Save and resume private authoring drafts.
|
|
146
|
+
skills audit|observe|candidates|sync Audit and manage local skill projections.
|
|
133
147
|
config check Validate project config.
|
|
134
148
|
extension-pack validate Validate declared extension packs.
|
|
135
149
|
extension-pack list List declared extension packs.
|
|
@@ -145,6 +159,9 @@ Attestation commands:
|
|
|
145
159
|
Commands whose usage names --project accept --project=PATH or --project PATH.
|
|
146
160
|
The project resolver also accepts --project-config=PATH and
|
|
147
161
|
MNSTRY_ATELIER_PROJECT_CONFIG=PATH; each command's own help is authoritative.
|
|
162
|
+
Project-aware commands accept repeated --repo-path NAME=PATH or
|
|
163
|
+
--repo-path=NAME=PATH. Overrides change location, never declared read authority.
|
|
164
|
+
Run config check --explain for path-free resolution sources.
|
|
148
165
|
Machine-local repo paths belong in
|
|
149
166
|
.atelier-local/, atelier.local.json, or atelier.workspace.local.json.`
|
|
150
167
|
}
|
|
@@ -152,7 +169,14 @@ Machine-local repo paths belong in
|
|
|
152
169
|
export function buildCommandHelpText(command, brand = DEFAULT_BRAND) {
|
|
153
170
|
const c = brand.command
|
|
154
171
|
const help = {
|
|
155
|
-
|
|
172
|
+
skills: `Usage: ${c} skills audit|observe|candidates|sync
|
|
173
|
+
Audit bundled skills or --root DIR [--peer DIR].
|
|
174
|
+
Sync previews by default; applying requires --apply --confirm PLAN_DIGEST.
|
|
175
|
+
Observations are local metadata, never automatic telemetry.`,
|
|
176
|
+
coauthor: `Usage: ${c} coauthor start|read|event|recover
|
|
177
|
+
|
|
178
|
+
Read one JSON request from stdin (maximum 1 MiB). Start takes {"config":{"id":"SESSION","fields":[{"id":"FIELD","source":{"ref":"packet.md","digest":"SHA256"}}]}}. Read/recover take {"sessionId":"SESSION"}. Event takes {"sessionId":"SESSION","event":{"id":"UNIQUE","expectedRevision":0,"type":"answer","text":"ANSWER"}}. Run from the intended Git workspace with ignored .atelier-local/. Saves are private drafts, never canonical source edits.`,
|
|
179
|
+
init: `Usage: ${c} init [--template private-domain|shared-project|sample-workspace|distribution|external-project] [--target DIR] [--actor ID]
|
|
156
180
|
|
|
157
181
|
Creates tracked starter files and an Atelier lockfile. It does not install hooks unless asked separately. An unrecognized --template exits 1 and writes nothing; omit --template for the blank scaffold.`,
|
|
158
182
|
adopt: `Usage: ${c} adopt [--profile single-repo|private-domain|shared-project|multi-repo|monorepo|control-workspace] [--target DIR] [--yes]
|
|
@@ -183,7 +207,7 @@ Runs the bundled MNSTRY readiness pack claim-first. Protocol state and packet dr
|
|
|
183
207
|
${c} extension-pack validate [--json] [--project ./atelier.project.json]
|
|
184
208
|
${c} extension-pack list [--json] [--project ./atelier.project.json]
|
|
185
209
|
|
|
186
|
-
Loads every extension pack declared under ext["mnstry.atelier"].extensionPacks in the tracked project config and reports one line per pack. Packs load additively alongside the bundled MNSTRY protocols and can never replace them. list is the default subcommand.`,
|
|
210
|
+
Loads every extension pack declared under ext["mnstry.atelier"].extensionPacks in the tracked project config and reports one line per pack. Packs load additively alongside the bundled MNSTRY protocols and can never replace them. list is the default subcommand. Shared --project-config and repeated --repo-path NAME=PATH options are supported in both space and equals forms.`,
|
|
187
211
|
distribution: `Usage: ${c} distribution check [--target DIR] [--pack DIR]
|
|
188
212
|
|
|
189
213
|
Checks a distribution package for the required MNSTRY attribution markers. Blocking: the distribution README.md byte check, and a CLI probe that EXECUTES the target's declared bin with --version (spawned with the current Node, cwd set to the target — only run this against distributions you trust) and requires the attribution in its output; a target that looks like a distribution but declares no probe-able bin, or ships a malformed package.json, is also blocking. The extension-pack manifest attribution key is advisory and reported only. The normative wording lives in TRADEMARKS.md under "Required attribution"; see also docs/attestation.md and docs/distributions.md.`,
|
|
@@ -205,6 +229,22 @@ Assembles a local feedback report under ignored .atelier-local/feedback/ (mode 0
|
|
|
205
229
|
announcements: `Usage: ${c} announcements list [--dir DIR] [--public-key FILE] | verify <file> [--public-key FILE] [--json] | show <file> [--public-key FILE]
|
|
206
230
|
|
|
207
231
|
MNSTRY announcements are a pull-only channel: signed JSON documents under announcements/ in the repository. The trust anchor is always the committed MNSTRY key, or one you pass explicitly with --public-key; --dir changes only where documents are read from and never which key verifies them. Every run names the key and keyId it used. The kit never fetches anything — receiving announcements is the git pull you chose to run, and show refuses to print a body whose signature does not verify.`,
|
|
232
|
+
obsidian: `Usage: ${c} obsidian status|scope|audience|mode|policy|service|open|apply|conflicts|apply-policy|selection|proposals [--project atelier.project.json] [--data-root DIR] [--json]
|
|
233
|
+
|
|
234
|
+
${c} obsidian status
|
|
235
|
+
${c} obsidian scope list | scope show ID
|
|
236
|
+
${c} obsidian audience show | set A,B | clear
|
|
237
|
+
${c} obsidian mode show | set manual|automatic
|
|
238
|
+
${c} obsidian policy show | install FILE | revoke
|
|
239
|
+
${c} obsidian service start [--consent-actor ID] --adapter=obsidian-cli | status | stop | unit --print --adapter=obsidian-cli
|
|
240
|
+
${c} obsidian open [--scope ID] [--consent-actor ID] [--allow-stale] --adapter=obsidian-cli
|
|
241
|
+
${c} obsidian apply list | show EDIT | run EDIT [--actor ID] | recover
|
|
242
|
+
${c} obsidian conflicts [ID]
|
|
243
|
+
${c} obsidian apply-policy create FILE | show | revoke
|
|
244
|
+
${c} obsidian selection resolve ID | persist ID [allow-empty] | show ID | list
|
|
245
|
+
${c} obsidian proposals list | show OPERATION
|
|
246
|
+
|
|
247
|
+
Noninteractive. With --json exactly one JSON document is printed, for a refusal too. status, scope, audience show, mode show, policy show and service status are read-only. open reports current only when the owned maintenance service ticked after the request, the view's trusted generation is the prepared one and reads back byte for byte, and the installed Obsidian meets the minimum version and answers for that vault; every other outcome is typed and exits 3. Reaching the installed app is never a default: open, service start and service unit need --adapter=obsidian-cli. Audiences, mode and the apply policy are private machine settings, never project configuration and never a note. apply, conflicts, apply-policy, selection and proposals are contributed operations registered from modules shipped under src/runtime/obsidian/contributions/; the built-in names cannot be replaced. While no apply operation is registered every apply reports apply-unavailable. Exit codes: 0 done, 1 internal error, 2 refusal or usage, 3 ran and the answer is not success.`,
|
|
208
248
|
sync: `Usage:
|
|
209
249
|
${c} sync enroll --repo DIR [--project atelier.project.json] [--git ABSOLUTE_PATH]
|
|
210
250
|
${c} sync status --repo DIR
|