@mnstry/atelier 0.2.0-alpha.11 → 0.2.0-alpha.13
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 +1005 -0
- package/README.md +149 -9
- package/contracts/atelier-adoption-policy.v2.schema.json +55 -0
- package/contracts/atelier-architecture.v1.schema.json +258 -0
- package/contracts/atelier-boundary-delegations.v1.schema.json +161 -0
- package/contracts/atelier-boundary-owner-keys.v1.schema.json +98 -0
- package/contracts/atelier-build.v1.schema.json +1076 -0
- package/contracts/atelier-capability.v1.schema.json +1252 -0
- package/contracts/atelier-coordination.v1.schema.json +1050 -0
- package/contracts/atelier-evidence-navigation.v1.schema.json +603 -0
- package/contracts/atelier-harness.v1.schema.json +234 -0
- package/contracts/atelier-ingestion.v1.schema.json +806 -0
- package/contracts/atelier-inquiry.v1.schema.json +1772 -0
- package/contracts/atelier-instruction-adoption.v1.schema.json +490 -0
- package/contracts/atelier-interaction.v1.schema.json +553 -0
- package/contracts/atelier-judgment.v1.schema.json +690 -0
- package/contracts/atelier-knowledge.v1.schema.json +1512 -0
- package/contracts/atelier-learning.v1.schema.json +1095 -0
- package/contracts/atelier-migration.v3.schema.json +64 -0
- package/contracts/atelier-obsidian-generation-manifest.v2.schema.json +372 -0
- package/contracts/atelier-personal-workspace-manifest.v1.schema.json +87 -0
- package/contracts/atelier-personal-workspace-overlay.v1.schema.json +299 -0
- package/contracts/atelier-template-adoption.v1.schema.json +223 -0
- package/contracts/atelier-template-profile.v1.schema.json +1168 -0
- package/contracts/atelier-trackable.v1.schema.json +781 -0
- package/contracts/atelier-upgrade-plan.v3.schema.json +532 -0
- package/contracts/compat-baseline.json +1 -1
- package/docs/architecture.md +89 -0
- package/docs/assurance-controls.md +4 -3
- package/docs/blocks/capability-stewardship.md +17 -0
- package/docs/blocks/claims.md +16 -3
- package/docs/blocks/inquiry-harnesses.md +19 -0
- package/docs/blocks/learning-harnesses.md +17 -0
- package/docs/capability-stewardship.md +269 -0
- package/docs/coordination.md +51 -0
- package/docs/decision-practices.md +111 -0
- package/docs/decisions.md +29 -0
- package/docs/evidence-navigation.md +237 -0
- package/docs/exact-upgrades.md +3 -2
- package/docs/ingestion.md +181 -0
- package/docs/inquiry-harnesses.md +211 -0
- package/docs/install.md +80 -3
- package/docs/intake-and-guides.md +5 -0
- package/docs/integration-contract-decisions.md +24 -2
- package/docs/interaction-and-reflection.md +72 -0
- package/docs/knowledge-graph.md +20 -0
- package/docs/knowledge-health/api.md +30 -0
- package/docs/knowledge-health/assessment/api.md +96 -0
- package/docs/knowledge-health/assessment/capabilities.md +40 -0
- package/docs/knowledge-health/assessment/evaluation.md +27 -0
- package/docs/knowledge-health/assessment/facilitator.md +30 -0
- package/docs/knowledge-health/assessment/quickstart.md +61 -0
- package/docs/knowledge-health/assessment/troubleshooting.md +23 -0
- package/docs/knowledge-health/devday/facilitator.md +16 -0
- package/docs/knowledge-health/devday/participant-response.md +22 -0
- package/docs/knowledge-health/devday/public-default.md +107 -0
- package/docs/knowledge-health/devday/quickstart.md +18 -0
- package/docs/knowledge-health/devday/support.md +22 -0
- package/docs/knowledge-health/exercise.md +17 -0
- package/docs/knowledge-health/facilitator.md +20 -0
- package/docs/knowledge-health/quickstart.md +94 -0
- package/docs/knowledge-health/readme.md +15 -0
- package/docs/knowledge-health/support.md +34 -0
- package/docs/knowledge-setup.md +248 -0
- package/docs/knowledge-workspace.md +264 -0
- package/docs/learning-harnesses.md +238 -0
- package/docs/learning.md +215 -0
- package/docs/local-services.md +242 -26
- package/docs/obsidian-contract.md +878 -36
- package/docs/obsidian-plugin.md +619 -0
- package/docs/obsidian.md +809 -64
- package/docs/optional-ingestion.md +83 -0
- package/docs/personal-workspace.md +257 -0
- package/docs/practical-judgment.md +92 -0
- package/docs/progressive-ingestion-acceptance.md +89 -0
- package/docs/progressive-ingestion.md +235 -0
- package/docs/project-command-inventory.md +1 -0
- package/docs/release-engineering.md +56 -1
- package/docs/repo-boundary-guard.md +94 -0
- package/docs/research-starter-quickstart.md +66 -0
- package/docs/research-starter.md +114 -0
- package/docs/semantic-ingestion.md +198 -0
- package/docs/semantic-operation.md +317 -0
- package/docs/skill-steward.md +6 -0
- package/docs/template-profile.md +164 -0
- package/docs/template-upgrades.md +114 -0
- package/docs/trackables.md +111 -0
- package/docs/upgrade.md +68 -3
- package/fixtures/atelier-architecture/binding/invalid/document.json +19 -0
- package/fixtures/atelier-architecture/binding/valid/document.json +19 -0
- package/fixtures/atelier-architecture/catalog/invalid/document.json +290 -0
- package/fixtures/atelier-architecture/catalog/valid/document.json +343 -0
- package/fixtures/atelier-build-contract/attempt/invalid/document.json +20 -0
- package/fixtures/atelier-build-contract/attempt/valid/document.json +19 -0
- package/fixtures/atelier-build-contract/candidate/invalid/document.json +24 -0
- package/fixtures/atelier-build-contract/candidate/valid/document.json +23 -0
- package/fixtures/atelier-build-contract/decision/invalid/document.json +31 -0
- package/fixtures/atelier-build-contract/decision/valid/document.json +30 -0
- package/fixtures/atelier-build-contract/delivery/invalid/document.json +18 -0
- package/fixtures/atelier-build-contract/delivery/valid/document.json +17 -0
- package/fixtures/atelier-build-contract/gate/invalid/document.json +22 -0
- package/fixtures/atelier-build-contract/gate/valid/document.json +21 -0
- package/fixtures/atelier-build-contract/ledger/invalid/document.json +270 -0
- package/fixtures/atelier-build-contract/ledger/valid/document.json +269 -0
- package/fixtures/atelier-build-contract/objective/invalid/document.json +73 -0
- package/fixtures/atelier-build-contract/objective/valid/document.json +72 -0
- package/fixtures/atelier-build-contract/progress/invalid/document.json +18 -0
- package/fixtures/atelier-build-contract/progress/valid/document.json +17 -0
- package/fixtures/atelier-capability-contract/adoption/invalid/document.json +71 -0
- package/fixtures/atelier-capability-contract/adoption/valid/document.json +70 -0
- package/fixtures/atelier-capability-contract/event/invalid/document.json +18 -0
- package/fixtures/atelier-capability-contract/event/valid/document.json +17 -0
- package/fixtures/atelier-capability-contract/journal/invalid/document.json +382 -0
- package/fixtures/atelier-capability-contract/journal/valid/document.json +381 -0
- package/fixtures/atelier-capability-contract/notice/invalid/document.json +8 -0
- package/fixtures/atelier-capability-contract/notice/valid/document.json +7 -0
- package/fixtures/atelier-capability-contract/package/invalid/document.json +59 -0
- package/fixtures/atelier-capability-contract/package/valid/document.json +58 -0
- package/fixtures/atelier-capability-contract/plan/invalid/document.json +107 -0
- package/fixtures/atelier-capability-contract/plan/valid/document.json +106 -0
- package/fixtures/atelier-capability-contract/release/invalid/document.json +85 -0
- package/fixtures/atelier-capability-contract/release/valid/document.json +84 -0
- package/fixtures/atelier-capability-contract/state/invalid/document.json +316 -0
- package/fixtures/atelier-capability-contract/state/valid/document.json +315 -0
- package/fixtures/atelier-coordination/dependency/invalid/document.json +37 -0
- package/fixtures/atelier-coordination/dependency/valid/document.json +36 -0
- package/fixtures/atelier-coordination/directive/invalid/document.json +25 -0
- package/fixtures/atelier-coordination/directive/valid/document.json +24 -0
- package/fixtures/atelier-coordination/disposition/invalid/document.json +34 -0
- package/fixtures/atelier-coordination/disposition/valid/document.json +33 -0
- package/fixtures/atelier-coordination/outcome/invalid/document.json +39 -0
- package/fixtures/atelier-coordination/outcome/valid/document.json +38 -0
- package/fixtures/atelier-coordination/recovery/invalid/document.json +34 -0
- package/fixtures/atelier-coordination/recovery/valid/document.json +33 -0
- package/fixtures/atelier-harness-contract/handoff/invalid/document.json +25 -0
- package/fixtures/atelier-harness-contract/handoff/valid/document.json +24 -0
- package/fixtures/atelier-ingestion/invalid/authority.json +19 -0
- package/fixtures/atelier-ingestion/semantic-baseline.json +26 -0
- package/fixtures/atelier-ingestion/semantic-operation.json +75 -0
- package/fixtures/atelier-ingestion/valid/plan-input.json +18 -0
- package/fixtures/atelier-inquiry-contract/assessment/invalid/document.json +41 -0
- package/fixtures/atelier-inquiry-contract/assessment/valid/document.json +40 -0
- package/fixtures/atelier-inquiry-contract/bundle/invalid/document.json +51 -0
- package/fixtures/atelier-inquiry-contract/bundle/valid/document.json +50 -0
- package/fixtures/atelier-inquiry-contract/campaign/invalid/document.json +17 -0
- package/fixtures/atelier-inquiry-contract/campaign/valid/document.json +16 -0
- package/fixtures/atelier-inquiry-contract/decision/invalid/document.json +22 -0
- package/fixtures/atelier-inquiry-contract/decision/valid/document.json +21 -0
- package/fixtures/atelier-inquiry-contract/feedback/invalid/document.json +19 -0
- package/fixtures/atelier-inquiry-contract/feedback/valid/document.json +18 -0
- package/fixtures/atelier-inquiry-contract/handoff/invalid/document.json +92 -0
- package/fixtures/atelier-inquiry-contract/handoff/valid/document.json +91 -0
- package/fixtures/atelier-inquiry-contract/hypothesis/invalid/document.json +20 -0
- package/fixtures/atelier-inquiry-contract/hypothesis/valid/document.json +19 -0
- package/fixtures/atelier-inquiry-contract/ledger/invalid/document.json +680 -0
- package/fixtures/atelier-inquiry-contract/ledger/valid/document.json +679 -0
- package/fixtures/atelier-inquiry-contract/legacy-assessment/invalid/document.json +19 -0
- package/fixtures/atelier-inquiry-contract/legacy-assessment/valid/document.json +18 -0
- package/fixtures/atelier-inquiry-contract/request/invalid/document.json +50 -0
- package/fixtures/atelier-inquiry-contract/request/valid/document.json +49 -0
- package/fixtures/atelier-inquiry-contract/source/invalid/document.json +18 -0
- package/fixtures/atelier-inquiry-contract/source/valid/document.json +17 -0
- package/fixtures/atelier-inquiry-contract/withdrawal/invalid/document.json +16 -0
- package/fixtures/atelier-inquiry-contract/withdrawal/valid/document.json +15 -0
- package/fixtures/atelier-instruction-adoption/context-receipt/invalid/document.json +18 -0
- package/fixtures/atelier-instruction-adoption/context-receipt/valid/document.json +17 -0
- package/fixtures/atelier-instruction-adoption/plan/invalid/document.json +63 -0
- package/fixtures/atelier-instruction-adoption/plan/valid/document.json +62 -0
- package/fixtures/atelier-instruction-adoption/receipt/invalid/document.json +22 -0
- package/fixtures/atelier-instruction-adoption/receipt/valid/document.json +21 -0
- package/fixtures/atelier-instruction-adoption/state/invalid/document.json +30 -0
- package/fixtures/atelier-instruction-adoption/state/valid/document.json +29 -0
- package/fixtures/atelier-interaction/act/invalid/document.json +25 -0
- package/fixtures/atelier-interaction/act/valid/document.json +24 -0
- package/fixtures/atelier-interaction/assessment/invalid/document.json +32 -0
- package/fixtures/atelier-interaction/assessment/valid/document.json +31 -0
- package/fixtures/atelier-interaction/observation/invalid/document.json +22 -0
- package/fixtures/atelier-interaction/observation/valid/document.json +21 -0
- package/fixtures/atelier-interaction/policy/invalid/document.json +20 -0
- package/fixtures/atelier-interaction/policy/valid/document.json +19 -0
- package/fixtures/atelier-judgment/case/invalid/document.json +76 -0
- package/fixtures/atelier-judgment/case/valid/document.json +75 -0
- package/fixtures/atelier-judgment/decision/invalid/document.json +38 -0
- package/fixtures/atelier-judgment/decision/valid/document.json +37 -0
- package/fixtures/atelier-judgment/native-decision.md +3 -0
- package/fixtures/atelier-judgment/practice-reconsideration/definition.json +92 -0
- package/fixtures/atelier-judgment/practice-reconsideration/scenario.json +435 -0
- package/fixtures/atelier-knowledge-contract/activation/invalid/document.json +26 -0
- package/fixtures/atelier-knowledge-contract/activation/valid/document.json +25 -0
- package/fixtures/atelier-knowledge-contract/contribution/invalid/document.json +34 -0
- package/fixtures/atelier-knowledge-contract/contribution/valid/document.json +33 -0
- package/fixtures/atelier-knowledge-contract/domain/invalid/document.json +41 -0
- package/fixtures/atelier-knowledge-contract/domain/valid/document.json +40 -0
- package/fixtures/atelier-knowledge-contract/domain-revision/invalid/document.json +46 -0
- package/fixtures/atelier-knowledge-contract/domain-revision/valid/document.json +45 -0
- package/fixtures/atelier-knowledge-contract/evaluation/invalid/document.json +21 -0
- package/fixtures/atelier-knowledge-contract/evaluation/valid/document.json +20 -0
- package/fixtures/atelier-knowledge-contract/ledger/invalid/document.json +318 -0
- package/fixtures/atelier-knowledge-contract/ledger/valid/document.json +317 -0
- package/fixtures/atelier-knowledge-contract/relation/invalid/document.json +25 -0
- package/fixtures/atelier-knowledge-contract/relation/valid/document.json +24 -0
- package/fixtures/atelier-knowledge-contract/review/invalid/document.json +18 -0
- package/fixtures/atelier-knowledge-contract/review/valid/document.json +17 -0
- package/fixtures/atelier-knowledge-contract/withdrawal/invalid/document.json +16 -0
- package/fixtures/atelier-knowledge-contract/withdrawal/valid/document.json +15 -0
- package/fixtures/atelier-learning/invalid/authority.json +14 -0
- package/fixtures/atelier-learning/valid/capture.json +13 -0
- package/fixtures/atelier-personal-workspace-contract/manifest/invalid/authority-key.json +17 -0
- package/fixtures/atelier-personal-workspace-contract/manifest/invalid/nonempty-ext.json +25 -0
- package/fixtures/atelier-personal-workspace-contract/manifest/invalid/wrong-schema.json +22 -0
- package/fixtures/atelier-personal-workspace-contract/manifest/valid/manifest.json +22 -0
- package/fixtures/atelier-personal-workspace-contract/overlay/invalid/authority-key.json +25 -0
- package/fixtures/atelier-personal-workspace-contract/overlay/invalid/unknown-top-level-field.json +27 -0
- package/fixtures/atelier-personal-workspace-contract/overlay/invalid/wrong-schema.json +24 -0
- package/fixtures/atelier-trackable/definition/invalid/document.json +15 -0
- package/fixtures/atelier-trackable/definition/valid/document.json +14 -0
- package/fixtures/atelier-trackable/request/invalid/document.json +23 -0
- package/fixtures/atelier-trackable/request/valid/document.json +22 -0
- package/fixtures/boundary-delegations/invalid/authority-key.v1.json +30 -0
- package/fixtures/boundary-delegations/invalid/push-operation.v1.json +28 -0
- package/fixtures/boundary-delegations/invalid/unsigned.v1.json +25 -0
- package/fixtures/boundary-delegations/valid/empty.v1.json +4 -0
- package/fixtures/boundary-delegations/valid/signed-operator.v1.json +30 -0
- package/fixtures/boundary-owner-keys/invalid/wrong-algorithm.v1.json +15 -0
- package/fixtures/boundary-owner-keys/invalid/wrong-curve.v1.json +15 -0
- package/fixtures/boundary-owner-keys/valid/one-owner.v1.json +17 -0
- package/fixtures/capability-packages/adoption.example.json +70 -0
- package/fixtures/capability-packages/evidence-review/capability-package.json +58 -0
- package/fixtures/capability-packages/evidence-review/capability-release.json +84 -0
- package/fixtures/capability-packages/evidence-review/evaluation.md +15 -0
- package/fixtures/capability-packages/evidence-review/skills/evidence-review/SKILL.md +22 -0
- package/fixtures/capability-packages/evidence-review/skills/evidence-review/references/ledger.md +7 -0
- package/fixtures/capability-packages/research/capability-package.json +88 -0
- package/fixtures/capability-packages/research/capability-release.json +134 -0
- package/fixtures/capability-packages/research/evaluation.md +15 -0
- package/fixtures/capability-packages/research/skills/research-integrate/SKILL.md +29 -0
- package/fixtures/capability-packages/research/skills/research-integrate/references/integration.md +10 -0
- package/fixtures/capability-packages/research/skills/research-plan/SKILL.md +27 -0
- package/fixtures/capability-packages/research/skills/research-plan/references/inquiries.md +26 -0
- package/fixtures/capability-packages/research/skills/research-synthesize/SKILL.md +23 -0
- package/fixtures/capability-packages/research/skills/research-synthesize/references/synthesis.md +12 -0
- package/fixtures/evidence-navigation/invalid/duplicate-operation.json +16 -0
- package/fixtures/evidence-navigation/invalid/instruction-kind.json +36 -0
- package/fixtures/evidence-navigation/invalid/invalid-digest.json +36 -0
- package/fixtures/evidence-navigation/invalid/invalid-time.json +36 -0
- package/fixtures/evidence-navigation/invalid/missing-attribution.json +35 -0
- package/fixtures/evidence-navigation/invalid/reserved-extension.json +19 -0
- package/fixtures/evidence-navigation/invalid/unattributed-acceptance.json +36 -0
- package/fixtures/evidence-navigation/invalid/uncoerced-version.json +16 -0
- package/fixtures/evidence-navigation/invalid/unknown-currency.json +17 -0
- package/fixtures/evidence-navigation/invalid/unknown-selector-field.json +37 -0
- package/fixtures/evidence-navigation/invalid/unsupported-operation.json +15 -0
- package/fixtures/evidence-navigation/valid/claim.json +36 -0
- package/fixtures/evidence-navigation/valid/host.json +16 -0
- package/fixtures/evidence-navigation/valid/profile.json +16 -0
- package/fixtures/evidence-navigation/valid/snapshot.json +17 -0
- package/fixtures/harness-packages/build-harness/capability-package.json +61 -0
- package/fixtures/harness-packages/build-harness/capability-release.json +82 -0
- package/fixtures/harness-packages/build-harness/evaluation.md +3 -0
- package/fixtures/harness-packages/build-harness/skills/atelier-build-harness/SKILL.md +59 -0
- package/fixtures/harness-packages/knowledge-harness/capability-package.json +61 -0
- package/fixtures/harness-packages/knowledge-harness/capability-release.json +82 -0
- package/fixtures/harness-packages/knowledge-harness/evaluation.md +3 -0
- package/fixtures/harness-packages/knowledge-harness/skills/atelier-knowledge-harness/SKILL.md +60 -0
- package/fixtures/harnesses/learning-cycle.json +780 -0
- package/fixtures/inquiry/workshop.json +675 -0
- package/fixtures/inquiry-packages/discovery-harness/capability-package.json +61 -0
- package/fixtures/inquiry-packages/discovery-harness/capability-release.json +82 -0
- package/fixtures/inquiry-packages/discovery-harness/evaluation.md +3 -0
- package/fixtures/inquiry-packages/discovery-harness/skills/atelier-discovery-harness/SKILL.md +48 -0
- package/fixtures/inquiry-packages/research-harness/capability-package.json +61 -0
- package/fixtures/inquiry-packages/research-harness/capability-release.json +82 -0
- package/fixtures/inquiry-packages/research-harness/evaluation.md +3 -0
- package/fixtures/inquiry-packages/research-harness/skills/atelier-research-harness/SKILL.md +43 -0
- package/fixtures/knowledge-health/calibration-suite.json +26 -0
- package/fixtures/knowledge-health/calibration-trial.json +37 -0
- package/fixtures/knowledge-health/corrected/checklist.md +18 -0
- package/fixtures/knowledge-health/devday/participant-record.json +19 -0
- package/fixtures/knowledge-health/expected-summary.json +27 -0
- package/fixtures/knowledge-health/workshop/README.md +20 -0
- package/fixtures/knowledge-health/workshop/atelier.project.json +7 -0
- package/fixtures/knowledge-health/workshop/knowledge-plan.json +65 -0
- package/fixtures/knowledge-health/workshop/records/checklist.md +18 -0
- package/fixtures/knowledge-health/workshop/records/workshop.md +18 -0
- package/fixtures/knowledge-health/workshop/repo-access.v1.json +5 -0
- package/fixtures/knowledge-health/workspace/atelier.project.json +18 -0
- package/fixtures/knowledge-health/workspace/knowledge-plan.json +74 -0
- package/fixtures/knowledge-health/workspace/records/checklist.md +18 -0
- package/fixtures/knowledge-health/workspace/records/pilot.md +16 -0
- package/fixtures/knowledge-health/workspace/repo-access.v1.json +9 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/case-only-collision.v2.json +160 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/flat-note-path.v2.json +160 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/hidden-folder.v2.json +160 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/identity-in-the-body.v2.json +160 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/link-breaking-name.v2.json +160 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/missing-identity-region.v2.json +156 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/missing-layout-version.v2.json +159 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/note-named-like-a-folder.v2.json +160 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/unknown-region-kind.v2.json +160 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/invalid/v1-contract-version.v2.json +161 -0
- package/fixtures/obsidian/contracts/generation-manifest-v2/valid/three-notes.v2.json +160 -0
- package/fixtures/obsidian/edits/workspace.json +1 -1
- package/fixtures/obsidian/materialization/expected-full.json +21 -21
- package/fixtures/obsidian/materialization/expected-full.layout-1.json +99 -0
- package/fixtures/obsidian/materialization/expected-scoped.json +7 -7
- package/fixtures/obsidian/materialization/expected-scoped.layout-1.json +39 -0
- package/fixtures/personal-workspace/overlay.json +24 -0
- package/fixtures/templates/local-library.v1.json +75 -0
- package/fixtures/templates/upgrade-contracts/adoption-policy.v2/invalid.json +16 -0
- package/fixtures/templates/upgrade-contracts/adoption-policy.v2/valid.json +13 -0
- package/fixtures/templates/upgrade-contracts/migration.v3/invalid.json +24 -0
- package/fixtures/templates/upgrade-contracts/migration.v3/valid.json +21 -0
- package/fixtures/templates/upgrade-contracts/template-adoption.v1/invalid.json +60 -0
- package/fixtures/templates/upgrade-contracts/template-adoption.v1/valid.json +57 -0
- package/fixtures/templates/upgrade-contracts/upgrade-plan.v3/invalid.json +85 -0
- package/fixtures/templates/upgrade-contracts/upgrade-plan.v3/valid.json +82 -0
- package/package.json +64 -6
- package/plugins/obsidian/main.js +444 -0
- package/plugins/obsidian/manifest.json +9 -0
- package/plugins/obsidian/styles.css +22 -0
- package/skills/claude/atelier-build-harness/SKILL.md +59 -0
- package/skills/claude/atelier-coordination/SKILL.md +32 -0
- package/skills/claude/atelier-discovery-harness/SKILL.md +48 -0
- package/skills/claude/atelier-guided-upgrade/SKILL.md +29 -0
- package/skills/claude/atelier-interaction/SKILL.md +34 -0
- package/skills/claude/atelier-knowledge-harness/SKILL.md +60 -0
- package/skills/claude/atelier-knowledge-setup/SKILL.md +72 -0
- package/skills/claude/atelier-practical-judgment/SKILL.md +64 -0
- package/skills/claude/atelier-research-harness/SKILL.md +43 -0
- package/skills/claude/atelier-skill-steward/SKILL.md +53 -0
- package/skills/claude/atelier-trackables/SKILL.md +40 -0
- package/skills/codex/atelier-build-harness/SKILL.md +59 -0
- package/skills/codex/atelier-coordination/SKILL.md +32 -0
- package/skills/codex/atelier-discovery-harness/SKILL.md +48 -0
- package/skills/codex/atelier-guided-upgrade/SKILL.md +29 -0
- package/skills/codex/atelier-interaction/SKILL.md +34 -0
- package/skills/codex/atelier-knowledge-harness/SKILL.md +60 -0
- package/skills/codex/atelier-knowledge-setup/SKILL.md +72 -0
- package/skills/codex/atelier-practical-judgment/SKILL.md +64 -0
- package/skills/codex/atelier-research-harness/SKILL.md +43 -0
- package/skills/codex/atelier-skill-steward/SKILL.md +53 -0
- package/skills/codex/atelier-trackables/SKILL.md +40 -0
- package/src/architecture/catalog.mjs +355 -0
- package/src/architecture/index.mjs +93 -0
- package/src/boundary/content-rules.mjs +4 -2
- package/src/boundary/delegation-command.mjs +158 -0
- package/src/boundary/delegation.mjs +396 -0
- package/src/boundary/policy.mjs +52 -10
- package/src/build/git.mjs +18 -0
- package/src/build/index.mjs +3 -0
- package/src/build/ledger.mjs +88 -0
- package/src/capabilities/adoption.mjs +381 -0
- package/src/capabilities/evidence.mjs +140 -0
- package/src/capabilities/files.mjs +124 -0
- package/src/capabilities/index.mjs +4 -0
- package/src/capabilities/instructions.mjs +250 -0
- package/src/capabilities/package.mjs +136 -0
- package/src/cli/command-failure.mjs +36 -0
- package/src/cli/execute-command.mjs +16 -2
- package/src/cli/run.mjs +65 -9
- package/src/coauthor/store.mjs +43 -2
- package/src/collaboration/proposals.mjs +189 -0
- package/src/commands/architecture.mjs +27 -0
- package/src/commands/boundary.mjs +3 -0
- package/src/commands/capability.mjs +73 -0
- package/src/commands/enroll.mjs +3 -0
- package/src/commands/harness.mjs +79 -0
- package/src/commands/ingest.mjs +39 -0
- package/src/commands/init.mjs +4 -1
- package/src/commands/inquiry.mjs +66 -0
- package/src/commands/knowledge-semantic.mjs +128 -0
- package/src/commands/knowledge.mjs +119 -0
- package/src/commands/learn.mjs +61 -0
- package/src/commands/obsidian.mjs +832 -62
- package/src/commands/practice.mjs +24 -0
- package/src/commands/setup.mjs +22 -2
- package/src/commands/trackable.mjs +19 -0
- package/src/contracts/corpus.mjs +36 -0
- package/src/coordination/index.mjs +110 -0
- package/src/egress/forbidden-egress.mjs +2 -0
- package/src/evidence-navigation/contracts.mjs +60 -0
- package/src/evidence-navigation/evaluate.mjs +69 -0
- package/src/evidence-navigation/generation.mjs +22 -0
- package/src/evidence-navigation/index.mjs +2 -0
- package/src/evidence-navigation/local.mjs +167 -0
- package/src/evidence-navigation/schema.generated.mjs +604 -0
- package/src/evidence-navigation/types.mjs +12 -0
- package/src/export/atelier-export-contract.mjs +35 -8
- package/src/graph/enroll.mjs +248 -0
- package/src/graph/graph.mjs +17 -1
- package/src/graph/knowledge-graph.mjs +58 -8
- package/src/harnesses/contracts.mjs +41 -0
- package/src/harnesses/exchange.mjs +154 -0
- package/src/harnesses/feedback.mjs +16 -0
- package/src/harnesses/history.mjs +37 -0
- package/src/harnesses/index.mjs +4 -0
- package/src/harnesses/store.mjs +29 -0
- package/src/ingestion/contracts.mjs +41 -0
- package/src/ingestion/evaluation.mjs +119 -0
- package/src/ingestion/optional/composition/index.mjs +171 -0
- package/src/ingestion/optional/evaluation/index.mjs +219 -0
- package/src/ingestion/optional/graphify/composition-binding.mjs +60 -0
- package/src/ingestion/optional/graphify/composition_receiving.py +185 -0
- package/src/ingestion/optional/graphify/graphify_supplier.py +933 -0
- package/src/ingestion/optional/graphify/json_bridge.py +163 -0
- package/src/ingestion/optional/graphify/query_receiving.py +209 -0
- package/src/ingestion/optional/index.mjs +9 -0
- package/src/ingestion/optional/jev/bridge.mjs +166 -0
- package/src/ingestion/optional/jev/composition-binding.mjs +116 -0
- package/src/ingestion/optional/jev/judgments.mjs +174 -0
- package/src/ingestion/optional/jev/native-translation.mjs +32 -0
- package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/__init__.py +7 -0
- package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/adapter.py +966 -0
- package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/artifacts.py +101 -0
- package/src/ingestion/optional/lightrag/atelier_lightrag_supplier/projection.py +146 -0
- package/src/ingestion/optional/lightrag/composition-binding.mjs +67 -0
- package/src/ingestion/optional/vanilla/composition-binding.mjs +102 -0
- package/src/ingestion/optional/vanilla/index.mjs +218 -0
- package/src/ingestion/optional/vanilla/native-normalization.mjs +187 -0
- package/src/ingestion/processors.mjs +218 -0
- package/src/ingestion/semantic.mjs +203 -0
- package/src/ingestion/store.mjs +372 -0
- package/src/inquiry/beliefs.mjs +32 -0
- package/src/inquiry/contracts.mjs +23 -0
- package/src/inquiry/index.mjs +5 -0
- package/src/inquiry/ledger.mjs +135 -0
- package/src/inquiry/lenses.mjs +15 -0
- package/src/inquiry/projection.mjs +77 -0
- package/src/inquiry/store.mjs +35 -0
- package/src/intake/read-scope.mjs +12 -0
- package/src/intake/store.mjs +69 -6
- package/src/interaction/index.mjs +91 -0
- package/src/judgment/index.mjs +82 -0
- package/src/judgment/practice-evaluation.mjs +70 -0
- package/src/judgment/practice.mjs +144 -0
- package/src/knowledge/context.mjs +217 -0
- package/src/knowledge/index.mjs +5 -0
- package/src/knowledge/ingestion.mjs +79 -0
- package/src/knowledge/intake.mjs +33 -0
- package/src/knowledge/ledger.mjs +110 -0
- package/src/knowledge/participatory/guidance.mjs +36 -0
- package/src/knowledge/participatory/guided-contribution.mjs +44 -0
- package/src/knowledge/participatory/index.mjs +2 -0
- package/src/knowledge/participatory/installed-workshop.mjs +108 -0
- package/src/knowledge/plan.mjs +67 -0
- package/src/knowledge/projection.mjs +43 -0
- package/src/knowledge/semantic-operation.mjs +567 -0
- package/src/knowledge/sessions.mjs +467 -0
- package/src/knowledge/workspace.mjs +295 -0
- package/src/knowledge-health/assessment.mjs +165 -0
- package/src/knowledge-health/capabilities.mjs +350 -0
- package/src/knowledge-health/context.mjs +62 -0
- package/src/knowledge-health/example.mjs +47 -0
- package/src/knowledge-health/index.mjs +10 -0
- package/src/knowledge-health/owner-join.mjs +88 -0
- package/src/knowledge-health/proof/common.mjs +24 -0
- package/src/knowledge-health/proof/installed-check.mjs +100 -0
- package/src/knowledge-health/proof/native-readback.mjs +37 -0
- package/src/knowledge-health/proof/rehearse.mjs +68 -0
- package/src/knowledge-health/proof/validate-participant.mjs +17 -0
- package/src/knowledge-health/proof/verify-native-capture.mjs +14 -0
- package/src/knowledge-health/proof/workshop-check.mjs +36 -0
- package/src/knowledge-health/rule-identity.mjs +44 -0
- package/src/knowledge-health/workshop-composition.mjs +19 -0
- package/src/knowledge-health/workshop-profile.mjs +176 -0
- package/src/knowledge-health/workshop.mjs +99 -0
- package/src/learning/adapters.mjs +68 -0
- package/src/learning/assistance.mjs +127 -0
- package/src/learning/contracts.mjs +65 -0
- package/src/learning/store.mjs +272 -0
- package/src/personal-workspace/index.mjs +391 -0
- package/src/personal-workspace/selection.mjs +385 -0
- package/src/project/config.mjs +8 -0
- package/src/project/durable-state.mjs +3 -1
- package/src/project/file-class.mjs +1 -1
- package/src/project/private-state.mjs +10 -1
- package/src/projection/obsidian/contracts.mjs +224 -18
- package/src/projection/obsidian/edits/apply.mjs +63 -19
- package/src/projection/obsidian/edits/regions.mjs +137 -42
- package/src/projection/obsidian/materialize/index.mjs +6 -3
- package/src/projection/obsidian/materialize/path-registry.mjs +443 -57
- package/src/projection/obsidian/materialize/prepare-view.mjs +382 -131
- package/src/projection/obsidian/materialize/redaction.mjs +327 -0
- package/src/projection/obsidian/materialize/settings.mjs +113 -34
- package/src/projection/obsidian/personal-workspace.mjs +436 -0
- package/src/projection/obsidian/plugin-bridge/bundle.mjs +50 -0
- package/src/projection/obsidian/plugin-bridge/channel.mjs +174 -0
- package/src/projection/obsidian/plugin-bridge/index.mjs +10 -0
- package/src/projection/obsidian/proposals/adapter.mjs +47 -8
- package/src/projection/obsidian/proposals/observation.mjs +20 -7
- package/src/projection/obsidian/publication/bridge-script.mjs +11 -5
- package/src/projection/obsidian/publication/index.mjs +2 -1
- package/src/projection/obsidian/publication/publisher.mjs +312 -36
- package/src/projection/obsidian/publication/transport.mjs +63 -8
- package/src/projection/obsidian/publication/vault-list.mjs +200 -0
- package/src/projection/obsidian/recovery/index.mjs +4 -1
- package/src/projection/obsidian/recovery/restart.mjs +3 -1
- package/src/projection/obsidian/recovery/store.mjs +168 -8
- package/src/projection/obsidian/selection-ui/contribution.mjs +6 -5
- package/src/projection/obsidian/selection-ui/focus.mjs +14 -7
- package/src/projection/obsidian/selection-ui/selection-state.mjs +2 -2
- package/src/projection/obsidian/selection-ui/selection.mjs +8 -3
- package/src/readiness/readiness.mjs +10 -3
- package/src/reflection/index.mjs +56 -0
- package/src/runtime/obsidian/app-capability.mjs +104 -12
- package/src/runtime/obsidian/app-production-seams.mjs +161 -42
- package/src/runtime/obsidian/app-registration.mjs +313 -0
- package/src/runtime/obsidian/app-restart.mjs +154 -0
- package/src/runtime/obsidian/engine.mjs +288 -29
- package/src/runtime/obsidian/extension-points.mjs +1 -1
- package/src/runtime/obsidian/index.mjs +15 -8
- package/src/runtime/obsidian/launch-plan.mjs +91 -0
- package/src/runtime/obsidian/lifecycle.mjs +193 -22
- package/src/runtime/obsidian/login-item.mjs +332 -0
- package/src/runtime/obsidian/machine-settings.mjs +119 -12
- package/src/runtime/obsidian/opening.mjs +369 -63
- package/src/runtime/obsidian/pending-edits.mjs +10 -0
- package/src/runtime/obsidian/pipeline.mjs +71 -3
- package/src/runtime/obsidian/plugin-channel.mjs +289 -0
- package/src/runtime/obsidian/plugin-choice.mjs +182 -0
- package/src/runtime/obsidian/plugin-drift.mjs +124 -0
- package/src/runtime/obsidian/plugin-presence.mjs +61 -0
- package/src/runtime/obsidian/process-identity.mjs +20 -10
- package/src/runtime/obsidian/project-views.mjs +282 -0
- package/src/runtime/obsidian/questions.mjs +48 -0
- package/src/runtime/obsidian/release-watch.mjs +56 -0
- package/src/runtime/obsidian/service-main.mjs +113 -17
- package/src/runtime/obsidian/service-manager-production.mjs +61 -0
- package/src/runtime/obsidian/service-managers.mjs +275 -0
- package/src/runtime/obsidian/service-record.mjs +105 -5
- package/src/runtime/obsidian/service-server.mjs +50 -12
- package/src/runtime/obsidian/service.mjs +134 -7
- package/src/runtime/obsidian/startup-adapters.mjs +59 -21
- package/src/runtime/obsidian/state-store.mjs +13 -1
- package/src/runtime/obsidian/unheld-evidence.mjs +84 -0
- package/src/runtime/obsidian/vault-location.mjs +300 -0
- package/src/runtime/obsidian/view-counts.mjs +34 -0
- package/src/server/local-sidecar.mjs +193 -7
- package/src/server/server.mjs +45 -6
- package/src/template-bindings/project.mjs +92 -0
- package/src/templates/profile.mjs +225 -0
- package/src/trackables/domain.mjs +175 -0
- package/src/trackables/store.mjs +114 -0
- package/src/ui/knowledge-page.mjs +1388 -0
- package/src/upgrade/explanation.mjs +1 -1
- package/src/upgrade/template-participant.mjs +171 -0
- package/src/upgrade/transaction.mjs +72 -25
- package/src/upgrade/upgrade.mjs +2 -1
- package/templates/external-project-workspace/pack-lifecycle.json +6 -1
- package/templates/knowledge-workspace/.gitattributes +2 -0
- package/templates/knowledge-workspace/AGENTS.md +27 -0
- package/templates/knowledge-workspace/README.md +44 -0
- package/templates/knowledge-workspace/atelier.project.json +22 -0
- package/templates/knowledge-workspace/gitignore +6 -0
- package/templates/knowledge-workspace/knowledge-plan.json +111 -0
- package/templates/knowledge-workspace/knowledge-plan.schema.json +281 -0
- package/templates/knowledge-workspace/records/forecast.md +22 -0
- package/templates/knowledge-workspace/records/inspection.md +25 -0
- package/templates/knowledge-workspace/records/telescope.md +24 -0
- package/templates/knowledge-workspace/repo-access.v1.json +9 -0
package/docs/obsidian.md
CHANGED
|
@@ -72,13 +72,18 @@ A focus keeps the full vault on disk and filters the native Graph view. The
|
|
|
72
72
|
query is
|
|
73
73
|
|
|
74
74
|
```
|
|
75
|
-
path
|
|
75
|
+
path:/^<note path>$/ OR path:/^<note path>$/ ...
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
in the order of the selected set (canonical-id order).
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
in the order of the selected set (canonical-id order). Each term is a regular
|
|
79
|
+
expression anchored at both ends, so it matches exactly one note: a plain
|
|
80
|
+
`path:` term matches any path that contains it, and with titles as names one
|
|
81
|
+
note's path can lie inside another's. In the term every regular-expression
|
|
82
|
+
character and the `/` delimiter is escaped with a backslash, and a space and
|
|
83
|
+
a double quote are written as `\x20` and `\x22`, so a path that itself
|
|
84
|
+
contains search operators (`tag:`, `-`, `OR`, parentheses) stays text. Paths
|
|
85
|
+
are NFC-normalized first. A persisted focus of the earlier query version
|
|
86
|
+
(`obsidian-graph-search-paths/v1`, quoted substring terms) is still read. A
|
|
82
87
|
path that carries a control character, a C1 control, or the U+2028 or U+2029
|
|
83
88
|
line separator cannot be a search term and refuses with
|
|
84
89
|
`focus-path-unrepresentable`; so does an absolute path, a backslash path or a
|
|
@@ -256,7 +261,7 @@ nothing under `scripts/obsidian/` ships.
|
|
|
256
261
|
| --- | --- |
|
|
257
262
|
| `@mnstry/atelier/obsidian` | `src/runtime/obsidian/index.mjs`: enablement, machine settings, engine, service lifecycle, production seams, app qualification |
|
|
258
263
|
| `@mnstry/atelier/obsidian/contracts` | `src/projection/obsidian/contracts.mjs`: contract validation, `selectScope`, note paths |
|
|
259
|
-
| `@mnstry/atelier/obsidian/materialize` | `prepareView`, settings, path registry |
|
|
264
|
+
| `@mnstry/atelier/obsidian/materialize` | `prepareView`, settings (including the plugin's files and entry), path registry |
|
|
260
265
|
| `@mnstry/atelier/obsidian/publication` | `publishView`, editor adapters, the exchange |
|
|
261
266
|
| `@mnstry/atelier/obsidian/recovery` | recovery store, journals, late-writer recheck |
|
|
262
267
|
| `@mnstry/atelier/obsidian/edits` | edit observation, arbitration, apply policy, source apply |
|
|
@@ -272,22 +277,35 @@ What the tarball must and must not carry, and the package proof, are in
|
|
|
272
277
|
|
|
273
278
|
## First vault: what to expect
|
|
274
279
|
|
|
275
|
-
This is the path an adopter walks on one machine
|
|
276
|
-
|
|
277
|
-
|
|
280
|
+
This is the path an adopter walks on one machine. Every operation and flag
|
|
281
|
+
below is the shipped `atelier obsidian` usage text; `atelier obsidian --help`
|
|
282
|
+
prints it. There are three steps, and none of them is done by hand in
|
|
283
|
+
Obsidian.
|
|
278
284
|
|
|
279
|
-
1.
|
|
280
|
-
`
|
|
285
|
+
1. Declare a view in the project configuration:
|
|
286
|
+
`atelier obsidian view add everything --all`. It adds a view of every note
|
|
287
|
+
the machine may show to `atelier.project.json`, shows the change as a diff
|
|
288
|
+
and how many notes the view would show, and makes it the default view. You
|
|
289
|
+
commit the file; Atelier commits nothing. See
|
|
290
|
+
[Adding a view](#adding-a-view). The member it writes,
|
|
291
|
+
`ext["mnstry.atelier.obsidian"]`, is an `atelier-obsidian-ext-settings/v1`
|
|
281
292
|
document: `enabled: true`, `scopes` (each with a `scopeId`, a `mode` of
|
|
282
293
|
`full`, `scoped` or `focus`, a `selector`, and for an expansion an explicit
|
|
283
|
-
`depth` and `maxNodes`), and optionally `defaultScopeId`.
|
|
284
|
-
|
|
285
|
-
`
|
|
294
|
+
`depth` and `maxNodes`), and optionally `defaultScopeId`. It can also be
|
|
295
|
+
written by hand. A project without this member is
|
|
296
|
+
`disabled (not-configured)` and nothing is published.
|
|
297
|
+
`atelier obsidian view list` (or `scope list`) shows what was declared.
|
|
286
298
|
2. Set the private machine settings. They live outside every repository and
|
|
287
299
|
are never committed:
|
|
288
|
-
- `atelier obsidian audience set
|
|
289
|
-
|
|
290
|
-
|
|
300
|
+
- `atelier obsidian audience set me` lets "only you" into a view: every
|
|
301
|
+
audience of a note but `sensitive`, and the notes that carry no
|
|
302
|
+
classification, which only a vault that is yours alone shows.
|
|
303
|
+
`audience set A,B` names the audiences instead, and never shows notes
|
|
304
|
+
without a classification; `sensitive` is added by name
|
|
305
|
+
(`audience set me,sensitive`, which is such a list). No audience is
|
|
306
|
+
admitted by default, so a view is empty until one is set;
|
|
307
|
+
`audience clear` empties it again. See
|
|
308
|
+
[Notes without a classification](#notes-without-a-classification).
|
|
291
309
|
- `atelier obsidian mode set manual` keeps every queued edit waiting for a
|
|
292
310
|
person. `mode set automatic` is refused until an active automatic policy
|
|
293
311
|
is installed.
|
|
@@ -295,19 +313,248 @@ usage text; `atelier obsidian --help` prints it.
|
|
|
295
313
|
has to carry; `policy install FILE` installs it and leaves the mode
|
|
296
314
|
unchanged; `policy revoke` returns the mode to `manual` and stops every
|
|
297
315
|
later apply.
|
|
298
|
-
3.
|
|
299
|
-
`atelier obsidian
|
|
300
|
-
Reaching the installed app is never a default, so
|
|
301
|
-
is
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
316
|
+
3. Open a view:
|
|
317
|
+
`atelier obsidian open --scope ID --adapter=obsidian-cli`.
|
|
318
|
+
That's it. Reaching the installed app is never a default, so
|
|
319
|
+
`--adapter=obsidian-cli` is needed the first time; the workspace remembers
|
|
320
|
+
it, and later runs need no flag. The first open of a workspace records who
|
|
321
|
+
allowed the maintenance service to run: for a person at a terminal, the
|
|
322
|
+
account's name; for a program, `--consent-actor ID`, which it must pass.
|
|
323
|
+
Later opens reconnect and need neither. `atelier obsidian settings` shows
|
|
324
|
+
what was remembered and how to change it. `open` starts or
|
|
325
|
+
reconnects maintenance and asks it for a tick, makes Obsidian (version
|
|
326
|
+
1.13.7 or later) know the view's vault as one of its vaults, opens it,
|
|
327
|
+
publishes the view, verifies the vault by reading it back, and waits until
|
|
328
|
+
the app answers for exactly that vault. It does this in whatever state
|
|
329
|
+
Obsidian is in; see
|
|
330
|
+
[What `open` does in each state of Obsidian](#what-open-does-in-each-state-of-obsidian).
|
|
331
|
+
|
|
332
|
+
The maintenance service can also be managed on its own:
|
|
333
|
+
`atelier obsidian service start [--consent-actor ID] [--adapter=obsidian-cli]`,
|
|
334
|
+
`service status` and `service stop`; `service unit --print` prints the login
|
|
335
|
+
item that `service unit --install` would write, and installs nothing (see
|
|
336
|
+
[Start at login](#start-at-login)). The flags are needed only until the
|
|
337
|
+
workspace remembers them, as for `open`.
|
|
338
|
+
|
|
339
|
+
### Adding a view
|
|
340
|
+
|
|
341
|
+
```sh
|
|
342
|
+
atelier obsidian view add ID (--all | --folder PATH [--folder PATH ...] [--repo R] | --tag T) [--expand DEPTH:MAX] [--default] [--allow-empty] [--yes]
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
- `--all` is a view of every note (`full`). `--folder` takes the notes under a
|
|
346
|
+
folder of a repository, written from the repository's root (`docs/notes`),
|
|
347
|
+
and can be given as often as needed; `--repo R` names the repository when
|
|
348
|
+
the project has more than one. `--tag T` takes the notes with a tag. Each of
|
|
349
|
+
these is a `scoped` view, and `--expand DEPTH:MAX` adds the notes they link
|
|
350
|
+
to, following links up to DEPTH steps and adding at most MAX notes.
|
|
351
|
+
- The first view declared is the default; `--default` makes a later one the
|
|
352
|
+
default.
|
|
353
|
+
- Before writing, the command counts the notes the view would show on this
|
|
354
|
+
machine, as the machine decided who may see (as "only you", with the notes
|
|
355
|
+
without a classification it shows, while nobody decided), and names how
|
|
356
|
+
many of the notes it selects are withheld: those without a classification
|
|
357
|
+
(a `kg` block) that the decision does not show, and those whose audience is
|
|
358
|
+
not admitted. A view that would show no note is refused with
|
|
359
|
+
`view-would-be-empty` and the counts; `--allow-empty` declares it anyway.
|
|
360
|
+
When the machine admits no audience at all (`audience clear`), the refusal
|
|
361
|
+
says so and names `atelier obsidian audience set me`.
|
|
362
|
+
- While nobody decided who may see, the maintenance service publishes no
|
|
363
|
+
note, whatever the counts say: the next step `view add` names is then
|
|
364
|
+
`atelier obsidian audience set me`, before `atelier obsidian open` (`next`
|
|
365
|
+
under `--json`, in order).
|
|
366
|
+
- A person at a terminal sees the change and the counts and is asked
|
|
367
|
+
`Write this change? [Y/n]`; `--yes` answers beforehand, and no answer within
|
|
368
|
+
10 minutes writes nothing (`unanswered`). For anyone else the command is the
|
|
369
|
+
consent: the change is made, and printed (`diff` under `--json`).
|
|
370
|
+
- The file is rewritten only when it is in the form Atelier writes JSON in
|
|
371
|
+
(two-space indentation, LF or CRLF line ends, with or without a final one),
|
|
372
|
+
so the change is the new view and nothing else. A file in another form is
|
|
373
|
+
refused with `project-config-format-unknown`, and the member to add by hand
|
|
374
|
+
is in the refusal's `detail`. The file is replaced atomically, keeps its
|
|
375
|
+
mode, and only while it holds the bytes the change was made from
|
|
376
|
+
(`project-config-changed` otherwise). A link is not followed
|
|
377
|
+
(`project-file-not-regular`).
|
|
378
|
+
- The workspace pointer is only ever written into an ignored `.atelier-local/`.
|
|
379
|
+
When that folder is not ignored, the same change adds `.atelier-local/` to
|
|
380
|
+
the project's `.gitignore`, and shows it.
|
|
381
|
+
- A name that is taken is refused with `view-exists`. Removing a view is done
|
|
382
|
+
by hand for now.
|
|
383
|
+
- The contract's `type` selector matches a note's file type (`markdown`,
|
|
384
|
+
`html`), not its `kg.type`, so `view add` does not offer it; a view by
|
|
385
|
+
`kg.type` needs a contract change.
|
|
386
|
+
|
|
387
|
+
### Notes without a classification
|
|
388
|
+
|
|
389
|
+
A note whose front matter carries no `kg` block (or that has no front matter)
|
|
390
|
+
is unclassified: the knowledge graph gives it the `private` audience, and by
|
|
391
|
+
default no view shows it. A vault that is only yours shows it: the audience
|
|
392
|
+
decision `only-you` with `unclassified: shown`, which `audience set me`
|
|
393
|
+
records. A list of audiences never shows one, even a list that names every
|
|
394
|
+
audience "only you" stands for, so a vault for anyone else can never carry
|
|
395
|
+
them.
|
|
396
|
+
|
|
397
|
+
A note whose labels cannot be known is never shown, in any vault: front matter
|
|
398
|
+
Atelier cannot read (a block scalar such as `description: |`, a value wrapped
|
|
399
|
+
onto a second line), front matter that is not plain `key: value` lines at its
|
|
400
|
+
top level (a quoted key such as `"kg":`, a one-line flow or JSON mapping, a
|
|
401
|
+
complex key), or any top-level `kg` key that is not a block. Such a note may
|
|
402
|
+
say `sensitive`, which "only you" leaves out. Only a note with no front
|
|
403
|
+
matter, or with front matter of plain top-level keys at the start of the line,
|
|
404
|
+
none of which is `kg`, counts as one without a classification. A plain key is
|
|
405
|
+
written with ASCII letters, digits, `_` and `-`, starting with a letter or
|
|
406
|
+
`_`: a note whose front matter uses a key with a space (`due date:`), other
|
|
407
|
+
letters (`título:`), a dot or a leading digit, or a quoted key, stays withheld
|
|
408
|
+
even when it holds nothing sensitive. Give it a `kg` block to show it.
|
|
409
|
+
|
|
410
|
+
In an "only you" vault such a note is shown only when its bytes read as a note
|
|
411
|
+
the way the emitter reads every note, so one file that cannot be published
|
|
412
|
+
(front matter that opens and never closes, closes at once, or carries a
|
|
413
|
+
trailing space on its first line; bytes that are not UTF-8) never stops the
|
|
414
|
+
vault: it stays withheld, as does a file that cannot be read. A shown note is
|
|
415
|
+
part of the view in every respect: links to it are links inside the view,
|
|
416
|
+
generated text may name it, the selection operation resolves it, and an edit
|
|
417
|
+
to it is applied to its source like any other.
|
|
418
|
+
|
|
419
|
+
A decision recorded before this release, "only you" with those notes
|
|
420
|
+
withheld, keeps them withheld until `audience set me` is run again. Changing
|
|
421
|
+
the decision rebuilds every view at the next tick (the eligibility revision
|
|
422
|
+
changes).
|
|
423
|
+
|
|
424
|
+
### What this machine remembers
|
|
425
|
+
|
|
426
|
+
A workspace's machine settings (`atelier-obsidian-machine-settings/v2`, owner
|
|
427
|
+
only, under the private data root, never in a repository) hold what a person
|
|
428
|
+
decided once, so no later run asks again or has to be told again. Each
|
|
429
|
+
decision is null until it is made, and otherwise records what was decided,
|
|
430
|
+
when, by whom when that is known (an actor identifier), and how: answered at
|
|
431
|
+
a terminal (`question`), given on the command line (`command`), taken as the
|
|
432
|
+
defaults (`defaults`), or carried over from an earlier release (`v1`).
|
|
433
|
+
|
|
434
|
+
| Decision | Holds | Made today by |
|
|
435
|
+
| --- | --- | --- |
|
|
436
|
+
| `audience` | `only-you` or `custom`, and whether notes that carry no classification are `shown` or `withheld`. Only `only-you` may show them; a list of audiences always withholds them. The admitted list stays in `audienceAllow`, the engine's audience input | `audience set me` (only you, shown) or `audience set A,B` / `audience clear` (withheld) |
|
|
437
|
+
| `location` | the absolute folder that holds this workspace's vaults | `location set DIR` |
|
|
438
|
+
| `loginItem` | `on` or `off` | `service unit --install` (on); `service unit --remove` and `uninstall` (off) |
|
|
439
|
+
| `adapter` | `obsidian-cli` | `--adapter=obsidian-cli` given to `open`, `service start` or `service unit --install` |
|
|
440
|
+
|
|
441
|
+
Who allowed the maintenance service is not a second copy here: it stays the
|
|
442
|
+
consent the service reads from its own settings. `atelier obsidian settings`
|
|
443
|
+
shows all of it, and how each answer is changed.
|
|
444
|
+
|
|
445
|
+
Releases up to 0.2.0-alpha.12 wrote `atelier-obsidian-machine-settings/v1`.
|
|
446
|
+
Such a file is read as the v2 document it stands for, an audience list set
|
|
447
|
+
with it becoming that person's decision, and stays v1 on disk until the next
|
|
448
|
+
write, which writes v2. A release that knows only v1 refuses a v2 file as
|
|
449
|
+
`invalid-machine-settings`: after an upgrade, a maintenance service that
|
|
450
|
+
still runs the earlier release fails its ticks until it is replaced, which
|
|
451
|
+
`atelier obsidian open` and `atelier obsidian service start` do.
|
|
452
|
+
|
|
453
|
+
### Start at login
|
|
454
|
+
|
|
455
|
+
Without a login item the vault is complete after a restart, but nothing keeps
|
|
456
|
+
it fresh until the next `open`. A login item starts the maintenance service
|
|
457
|
+
when you log in:
|
|
458
|
+
|
|
459
|
+
```sh
|
|
460
|
+
atelier obsidian service unit --install [--consent-actor ID] [--adapter=obsidian-cli]
|
|
461
|
+
atelier obsidian service unit --print # what --install writes; writes nothing
|
|
462
|
+
atelier obsidian service unit --remove
|
|
463
|
+
atelier obsidian uninstall
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
- On macOS it is a launchd agent,
|
|
467
|
+
`~/Library/LaunchAgents/ai.mnstry.atelier.<project>.<workspace-id>.plist`.
|
|
468
|
+
macOS says "Background Items Added" and lists it as "node" under System
|
|
469
|
+
Settings → General → Login Items & Extensions, because there is no app to
|
|
470
|
+
name it after. Switched off there, it stays off: `status` reports
|
|
471
|
+
`installed, switched off in System Settings`, and `open` starts the service
|
|
472
|
+
for that session only.
|
|
473
|
+
- On Linux it is a systemd user unit,
|
|
474
|
+
`~/.config/systemd/user/atelier-obsidian-<workspace-id>.service`
|
|
475
|
+
(`$XDG_CONFIG_HOME` when set), enabled with `systemctl --user`. Disabled
|
|
476
|
+
with `systemctl --user disable`, it stays disabled: `status` reports
|
|
477
|
+
`installed, disabled`, and `open` starts the service for that session
|
|
478
|
+
only. Where no user instance of systemd answers (WSL, a container), the
|
|
479
|
+
answer is `login-item-unavailable` and nothing is left behind.
|
|
480
|
+
- Windows is not offered (`startup-platform-unqualified`), as publication
|
|
481
|
+
itself is refused there.
|
|
482
|
+
|
|
483
|
+
It runs the package installed in the project
|
|
484
|
+
(`<project>/node_modules/@mnstry/atelier/…`, named by that path, so the next
|
|
485
|
+
start runs whatever release the project has installed then), with the Node
|
|
486
|
+
that installed it and the search path you had, in the root folder. It names
|
|
487
|
+
the data folder and the workspace it was installed for, so it finds them at
|
|
488
|
+
login whatever variables your shell set. Run from
|
|
489
|
+
`npx` in a project that has no package installed, it refuses with
|
|
490
|
+
`login-item-needs-installed-package`: install `@mnstry/atelier` in the project
|
|
491
|
+
first. Installing records that you allowed the service to run at login (the
|
|
492
|
+
consent then covers startup): `--consent-actor ID` names who allows it; for a
|
|
493
|
+
person at a terminal, the actor already recorded for this workspace, or else
|
|
494
|
+
the account's name. A program that passes no `--consent-actor` for a
|
|
495
|
+
workspace whose consent covers the service alone is refused
|
|
496
|
+
(`startup-consent-required`). The answer is remembered as the `loginItem`
|
|
497
|
+
decision. `--remove` takes the consent back to the service alone, removes the
|
|
498
|
+
item, and starts the service again for this session only, as a process of its
|
|
499
|
+
own (with the adapter given or remembered; otherwise the next `open` starts
|
|
500
|
+
it). Each workspace has its own login item, port, log and consent, and
|
|
501
|
+
projects may pin different releases; `launchctl list | grep ai.mnstry.atelier`
|
|
502
|
+
lists every one on a Mac.
|
|
503
|
+
|
|
504
|
+
Once a login item is installed, the service is started through it: `service
|
|
505
|
+
start`, `open` and the replacement of an outdated service ask launchd or
|
|
506
|
+
systemd to start it, never start a second one beside it, and accept only the
|
|
507
|
+
service that proves itself with the installed entry. When the unit differs from
|
|
508
|
+
what would be written now (the Node it names was removed, say), the next start
|
|
509
|
+
writes it again and says `login item refreshed`. A refusal of the service at
|
|
510
|
+
login (another service already runs, or the consent does not cover startup)
|
|
511
|
+
ends the process cleanly, so it is not retried every minute, and `status` says
|
|
512
|
+
`the login item did not start the service: <code>` with the next step. A crash
|
|
513
|
+
is restarted after a minute.
|
|
514
|
+
|
|
515
|
+
`uninstall` removes the login item and stops the service. It keeps the vaults,
|
|
516
|
+
the private state, the project file and Obsidian's vault list as they are, and
|
|
517
|
+
prints where each is: every vault under the data root and every folder
|
|
518
|
+
allocated to a view where the workspace decided its vaults live, a view no
|
|
519
|
+
longer declared included. It does not start the service again.
|
|
520
|
+
|
|
521
|
+
After an upgrade of Atelier, a maintenance service started earlier still runs
|
|
522
|
+
the earlier release. One the login item started notices it: after each tick
|
|
523
|
+
it compares the package on disk (read through the path the item names, so a
|
|
524
|
+
re-pointed link or a `file:` install counts) with the release it started
|
|
525
|
+
with, and when they differ it exits after that tick with code 75, and its
|
|
526
|
+
service manager starts the new release within a minute. Otherwise `open` and
|
|
527
|
+
`service start` replace it: when the service of this workspace proves itself
|
|
528
|
+
Atelier's own but runs an earlier release than the installed one (its record
|
|
529
|
+
names the release it runs: the package version and a digest of its modules;
|
|
530
|
+
an earlier version, the same version with other modules, or no release
|
|
531
|
+
named), or refuses a tick that names a view as releases up to 0.2.0-alpha.11
|
|
532
|
+
do, they stop it as `service stop` would and start the installed release under
|
|
533
|
+
the consent already recorded (through the login item when there is one), and
|
|
534
|
+
say `service: restarted (outdated)`. The installed release is read from the
|
|
535
|
+
package of the entry that would be started, so with a login item it is the
|
|
536
|
+
project's own package. A service of a later release is never replaced by an
|
|
537
|
+
earlier one, so two installations used on one workspace (a global and a
|
|
538
|
+
project-local one, say) do not replace each other's service on every open:
|
|
539
|
+
`open` answers `service-unavailable` / `service-other-release`, and `service
|
|
540
|
+
start` answers that it runs, with `release: later`; run `atelier obsidian
|
|
541
|
+
service stop`, then open again, or open with the later release. A service in a
|
|
542
|
+
long tick is not stopped (`open` answers `busy`), and a listener that does not
|
|
543
|
+
prove itself this workspace's service is never touched.
|
|
544
|
+
|
|
545
|
+
The first time Obsidian opens a view's vault it asks "Do you trust the author
|
|
546
|
+
of this vault?", because every vault Atelier publishes carries Atelier's own
|
|
547
|
+
plugin. "Trust author and enable plugins" turns it on: a status bar item then
|
|
548
|
+
says whether the view is current, updating, held for an edit you made, stale,
|
|
549
|
+
or whether the maintenance service does not answer, and "Atelier: show status"
|
|
550
|
+
says why. "Browse vault in Restricted Mode" keeps every community plugin off
|
|
551
|
+
in that vault, and nothing else changes: maintenance, `open` and `status` work
|
|
552
|
+
without the plugin, as they always did. Obsidian keeps the answer per vault in
|
|
553
|
+
its own storage and asks again the next time until the vault is trusted or
|
|
554
|
+
restricted mode is switched on for good in its settings. Turning the plugin
|
|
555
|
+
off in a vault, or uninstalling it there, is respected from then on;
|
|
556
|
+
`atelier obsidian plugin on --scope ID` brings it back. What the plugin does
|
|
557
|
+
and never does is in [obsidian-plugin.md](obsidian-plugin.md).
|
|
311
558
|
|
|
312
559
|
`open` and `status` answer with a freshness state, not a promise. `current`
|
|
313
560
|
means the vault is the present generation, verified by read-back, and the app
|
|
@@ -319,7 +566,9 @@ and the view is not republished over it. The remaining outcomes (`indexing`,
|
|
|
319
566
|
`publisher-conflict`, `app-missing`, `app-version-unsupported`,
|
|
320
567
|
`app-cli-unavailable`, `launch-failed`, `service-unavailable`, `busy`,
|
|
321
568
|
`disabled`) each name what to do next, and exit code 3 says the answer is not
|
|
322
|
-
success.
|
|
569
|
+
success. Both also report Atelier's plugin for each view, under `plugin`:
|
|
570
|
+
present while it holds the vault open in the app, with the app and plugin
|
|
571
|
+
versions, or not present with the reason.
|
|
323
572
|
|
|
324
573
|
Edits made in the vault are preserved before anything is republished. A body
|
|
325
574
|
replacement is held as a pending edit; under manual mode it reaches its source
|
|
@@ -334,42 +583,444 @@ proposals list` and `proposals show OPERATION` read them, and nothing applies
|
|
|
334
583
|
one. A body edit to a note whose source uses CRLF line endings is also a
|
|
335
584
|
proposal, never an apply, because the app normalizes line endings on save.
|
|
336
585
|
|
|
337
|
-
|
|
338
|
-
`~/Library/Application Support/Atelier` on macOS,
|
|
339
|
-
(else `~/.local/share/atelier`) on Linux and
|
|
340
|
-
Windows, under `obsidian/<workspace-id>/`.
|
|
341
|
-
absolute directory. Private state inside an
|
|
342
|
-
Publication is proven on macOS arm64 only and
|
|
343
|
-
[Known limits](#known-limits).
|
|
586
|
+
Atelier's private state lives under the private data root, outside every
|
|
587
|
+
repository: `~/Library/Application Support/Atelier` on macOS,
|
|
588
|
+
`$XDG_DATA_HOME/atelier` (else `~/.local/share/atelier`) on Linux and
|
|
589
|
+
`%LOCALAPPDATA%\Atelier` on Windows, under `obsidian/<workspace-id>/`.
|
|
590
|
+
`--data-root DIR` names another absolute directory. Private state inside an
|
|
591
|
+
enrolled repository is refused. Publication is proven on macOS arm64 only and
|
|
592
|
+
is refused on Windows; see [Known limits](#known-limits).
|
|
593
|
+
|
|
594
|
+
Where the vaults are is decided per workspace. Until a person decides it, a
|
|
595
|
+
view's vault is under the data root too, in `vaults/<view>`, as in every
|
|
596
|
+
earlier release. `atelier obsidian location set DIR` decides a visible folder
|
|
597
|
+
instead (`~/Atelier`, say). Each view that has not been published yet is then
|
|
598
|
+
given its own folder there at its first publication, named
|
|
599
|
+
`<project> (<view>)`: `~/Atelier/harbor-notes (everything)`. That name is also
|
|
600
|
+
the vault's name in Obsidian's vault switcher, so it is readable and unique
|
|
601
|
+
across projects and views. The first name that is free is taken, with a number
|
|
602
|
+
inside the parentheses when needed (`harbor-notes (everything 2)`): free means
|
|
603
|
+
nothing on the disk has it, and no vault Obsidian lists has it in any letter
|
|
604
|
+
case. The folder is created private to this user (mode 0700), and so is `DIR`
|
|
605
|
+
when Atelier creates it; a missing folder on the way to `DIR` is made as any
|
|
606
|
+
other folder is. The allocation is recorded in the workspace's private
|
|
607
|
+
state (`state/allocations/<view>.json`) and is never recomputed: renaming the
|
|
608
|
+
project or deciding another folder later moves no vault, and a vault published
|
|
609
|
+
before under the data root stays there. `location show` says where each
|
|
610
|
+
view's vault is, or will be, or why its record cannot be read.
|
|
611
|
+
|
|
612
|
+
Atelier publishes only into the folder it made. The allocation records the
|
|
613
|
+
folder's real path, device and inode, and the maintenance service checks them
|
|
614
|
+
at every tick, as the publisher does before it writes anything and again
|
|
615
|
+
before each note and before its commit (see Known limits). Another folder
|
|
616
|
+
put where the one made was (moved in, or a link) is not published into
|
|
617
|
+
(`vault-allocation-replaced`), nor is the same folder reached through a link
|
|
618
|
+
put on the way since, into a vault the app lists, say
|
|
619
|
+
(`vault-allocation-moved`). A folder that has gone is made again at the next
|
|
620
|
+
tick, only where its recorded real path leads and only where a location would
|
|
621
|
+
be accepted (not inside a repository, the private state, a vault Atelier
|
|
622
|
+
publishes or one the app lists, and on the data root's volume). A vault
|
|
623
|
+
removed, moved or replaced while it is being published stops that publication
|
|
624
|
+
(`vault-allocation-missing`, `vault-allocation-replaced`, or
|
|
625
|
+
`vault-root-moved` for a vault under the data root). Once the folder is put
|
|
626
|
+
back, or made again, the running service publishes into it again at its next
|
|
627
|
+
tick; no restart is needed. One case waits for the next change at the view's
|
|
628
|
+
sources: a folder made again after a publication that stopped just before its
|
|
629
|
+
commit. That generation is finished by restart recovery, its notes went with
|
|
630
|
+
the folder that went away, and the view reads `vault-note-missing` until then. A
|
|
631
|
+
view that was published and whose vault Atelier cannot find is refused
|
|
632
|
+
(`vault-allocation-lost`) rather than published again into a new, empty vault
|
|
633
|
+
under the data root: its record was lost, or, for a view that never had a
|
|
634
|
+
record (published under the data root), its `vaults/<view>` folder was
|
|
635
|
+
removed. Restore the record from a backup if its vault was allocated
|
|
636
|
+
elsewhere; otherwise make the folder `vaults/<view>` under the data root, and
|
|
637
|
+
the view is published there at the next change at its sources. `status` and
|
|
638
|
+
`open` name that next step for this code, and for `vault-allocation-moved`,
|
|
639
|
+
`vault-allocation-replaced` and `vault-allocation-missing`.
|
|
640
|
+
|
|
641
|
+
`DIR` is refused inside an enrolled repository or the project, inside a vault
|
|
642
|
+
Atelier publishes, inside a folder Obsidian lists as a vault, and on another
|
|
643
|
+
volume than the data root (a note is published by an atomic exchange, which
|
|
644
|
+
cannot cross volumes). A folder a sync client keeps in step (iCloud Drive, a
|
|
645
|
+
cloud storage provider, Dropbox, OneDrive, Google Drive, or a Desktop or
|
|
646
|
+
Documents folder iCloud syncs) is refused unless `--allow-synced-location` is
|
|
647
|
+
given: another machine's Obsidian could hold a vault there unseen. A folder
|
|
648
|
+
macOS protects (Desktop, Documents, Downloads) is accepted with a warning,
|
|
649
|
+
because macOS asks before Obsidian or the maintenance service may read it.
|
|
650
|
+
`~/` is read against the account's home folder, which a shell does not do
|
|
651
|
+
after `--x=`. Each check compares the folder as written and as its real path,
|
|
652
|
+
in any letter case, so a link into a listed or synced vault is refused as
|
|
653
|
+
that vault is. Obsidian's vault list is read through the app when it runs and
|
|
654
|
+
answers, and otherwise from its settings file, never written. When the list
|
|
655
|
+
cannot be read, `location set` says so and accepts the folder, and the
|
|
656
|
+
maintenance service allocates no vault there until it can read the list
|
|
657
|
+
(the view is `stale`, `app-vault-list-unreadable`, and is tried again at
|
|
658
|
+
the next tick).
|
|
659
|
+
|
|
660
|
+
### What `open` does in each state of Obsidian
|
|
661
|
+
|
|
662
|
+
Obsidian opens a vault from a link only when the folder is in its own vault
|
|
663
|
+
list, the `vaults` of `obsidian.json` in its user-data directory. `open` puts
|
|
664
|
+
the view's vault there first, and never asks a person to open a folder by
|
|
665
|
+
hand. It then names the vault by its id (`obsidian://open?vault=<id>`), never
|
|
666
|
+
by path where the id reaches it first: a path is matched against the list by
|
|
667
|
+
string prefix, so a link for a note under `/A/strategy-lab` can open the
|
|
668
|
+
listed vault `/A/strategy`. When another vault's folder is named like the id,
|
|
669
|
+
or the id is unusual, the vault's own path is used, which the app matches
|
|
670
|
+
exactly because the folder is listed.
|
|
671
|
+
|
|
672
|
+
- **Obsidian runs and answers its command line (any vault is open).** `open`
|
|
673
|
+
reads the app's vault list through its command line. A vault the app does
|
|
674
|
+
not list is added and opened in a new window through the app itself (it
|
|
675
|
+
writes its own settings), and read back from its list. `open`
|
|
676
|
+
then waits, bounded, until the app answers for exactly this vault, and asks
|
|
677
|
+
maintenance for the view again: the publication runs through the app, which
|
|
678
|
+
now holds the vault, with every editor check of the publication protocol.
|
|
679
|
+
Obsidian does not have to be quit.
|
|
680
|
+
- **Obsidian is not running.** The view is published on the path with no app,
|
|
681
|
+
as before. `open` then adds the vault to the app's settings file (see
|
|
682
|
+
[Obsidian's vault list](obsidian-contract.md#obsidians-vault-list) for
|
|
683
|
+
exactly when and how that one file is written, marked to reopen) and starts
|
|
684
|
+
Obsidian plainly, with no link: an Obsidian started with a link opens only
|
|
685
|
+
that vault and drops the reopen flag of every other one, so your other
|
|
686
|
+
vaults would not come back the next time you start it. Started plainly, it
|
|
687
|
+
reopens every vault it had open, this one included, and once its command
|
|
688
|
+
line answers (the app itself, not the tool's "unable to find Obsidian")
|
|
689
|
+
`open` hands it the vault's link through that tool, never through the
|
|
690
|
+
operating system. A vault Obsidian already lists but had closed is not
|
|
691
|
+
reopened by a plain start, so if Obsidian refuses that link just after it
|
|
692
|
+
started, `open` hands it the link once more, again through that tool and
|
|
693
|
+
never through the operating system, before it gives up. On Linux a plain start is not
|
|
694
|
+
qualified yet, and Obsidian is started with the link (the other vaults'
|
|
695
|
+
reopen marks are lost there; a known limit).
|
|
696
|
+
In the same write, `open` turns Obsidian's command line on (`cli: true`)
|
|
697
|
+
when it is off: publishing into a vault Obsidian holds needs it until
|
|
698
|
+
Atelier's plugin takes over that part, and it is off in a new installation.
|
|
699
|
+
The answer says what was written and where the backup of the file as it
|
|
700
|
+
was is kept.
|
|
701
|
+
- **Obsidian is installed and never started** (no `obsidian.json` yet). When
|
|
702
|
+
the process table says, positively, that no Obsidian runs, `open` creates
|
|
703
|
+
the file, with this vault flagged open and the command line on, and starts
|
|
704
|
+
Obsidian plainly; Obsidian opens the vault. Nothing else is in the file,
|
|
705
|
+
and the settings folder is created private to you when it does not exist
|
|
706
|
+
yet. The file is created exclusively: if Obsidian writes its own first,
|
|
707
|
+
that one is kept and `open` says so. While an Obsidian may run, nothing is
|
|
708
|
+
created (`app-may-be-running`).
|
|
709
|
+
- **Obsidian runs with no vault open.** Its command line then answers every
|
|
710
|
+
command with "Vault not found.", so nothing can be asked of it, and its
|
|
711
|
+
settings file belongs to the running app, so it is only read. A vault the
|
|
712
|
+
app already lists is opened by path and published through the app as
|
|
713
|
+
above. For a vault it does not list yet, see "Restart, only when you ask"
|
|
714
|
+
below; without that, `open` answers `app-version-unsupported` with reason
|
|
715
|
+
`no-vault-open` and names `--restart-obsidian`.
|
|
716
|
+
- **Obsidian runs with its command line turned off** (the default of a new
|
|
717
|
+
installation). It then answers every command with "Command line interface
|
|
718
|
+
is not enabled", only a link reaches it, and its settings belong to the
|
|
719
|
+
running app, which keeps the switch in memory and would write it back. See
|
|
720
|
+
"Restart, only when you ask" below; without that, `open` adds and launches
|
|
721
|
+
nothing, and answers `app-cli-unavailable` with reason `cli-turned-off`,
|
|
722
|
+
naming `--restart-obsidian` and where to turn the switch on yourself:
|
|
723
|
+
Settings > General > Advanced > Command line interface.
|
|
724
|
+
|
|
725
|
+
**Restart, only when you ask.** In the two states where Obsidian runs but
|
|
726
|
+
`open` cannot reach it (its command line off, or no vault open and the view's
|
|
727
|
+
vault not in its list), `atelier obsidian open --restart-obsidian` lets `open`
|
|
728
|
+
restart Obsidian once:
|
|
729
|
+
|
|
730
|
+
1. Before anything is sent, it checks, reading only, that the write the
|
|
731
|
+
restart is for can succeed: the view's vault folder exists, Obsidian's
|
|
732
|
+
settings file can be read and is yours, is no link and has no second
|
|
733
|
+
name, is not a Flatpak or snap build's, is not too large to take the
|
|
734
|
+
vault, and lists no vault at a folder above the view's. An Obsidian that
|
|
735
|
+
has shown only its starter window has written no settings file yet; then
|
|
736
|
+
the folder it goes in must be yours (or be missing inside a folder of
|
|
737
|
+
yours), and the file is created after the quit, as for an Obsidian that
|
|
738
|
+
never started. Otherwise `open` answers that refusal and leaves Obsidian
|
|
739
|
+
running. Right before the first signal, once the process below is proven,
|
|
740
|
+
it keeps a copy of the settings file beside it
|
|
741
|
+
(`obsidian.json.atelier-backup-<time>`), which this run's write does not
|
|
742
|
+
prune, and the answer names it; a copy that cannot be kept sends nothing.
|
|
743
|
+
2. It sends SIGTERM to Obsidian's main process, and to nothing else. That
|
|
744
|
+
process is found in the process table and must be the only Obsidian main
|
|
745
|
+
process there, one of yours, named by the app bundle's path, with every
|
|
746
|
+
other Obsidian process its child; it is read again just before the signal
|
|
747
|
+
and must be the same process, yours, under the same parent. Anything else
|
|
748
|
+
(two Obsidians, another user's, a helper of another process, a table that
|
|
749
|
+
cannot be read) is answered `app-main-process-unproven`, with the reason in
|
|
750
|
+
`restart.detail`, and nothing is sent.
|
|
751
|
+
3. Obsidian handles that SIGTERM as a quit: it closes every window, keeping
|
|
752
|
+
the vaults it had open flagged to reopen, and its helper processes end. On
|
|
753
|
+
macOS its main process can then stay, with no window. Electron handles
|
|
754
|
+
only the first SIGTERM as a quit: a second one ends the process at once,
|
|
755
|
+
without its quit handlers. `open` sends that second SIGTERM only when the
|
|
756
|
+
same process has shown no window and no helper at every reading for at
|
|
757
|
+
least 5 seconds (a margin, not a proof that it has nothing left to save). There
|
|
758
|
+
is never a third signal, and never a stronger one: an Obsidian that is not
|
|
759
|
+
gone within 30 seconds is answered `launch-failed` with reason
|
|
760
|
+
`app-did-not-quit`, and nothing is written. The answer says how many
|
|
761
|
+
signals were delivered.
|
|
762
|
+
4. It adds the vault to Obsidian's settings and turns the command line on, in
|
|
763
|
+
the one write described above.
|
|
764
|
+
5. It starts Obsidian plainly, and the vaults it had open come back, with this
|
|
765
|
+
one beside them. If the vault could not be added after all, Obsidian is
|
|
766
|
+
still started again, as it was.
|
|
767
|
+
|
|
768
|
+
The answer says that Obsidian was restarted, which process was signalled,
|
|
769
|
+
how, and what was written. The flag is never implied by any other flag or
|
|
770
|
+
answer; every other operation refuses it. The restart is qualified on macOS
|
|
771
|
+
only (on Linux a quit Obsidian is started with a link, which would drop the
|
|
772
|
+
other vaults' reopen flags): elsewhere `open` answers
|
|
773
|
+
`restart-platform-unqualified`.
|
|
774
|
+
|
|
775
|
+
Two limits. `open` asks nothing at a terminal yet: the restart needs the flag
|
|
776
|
+
there too, until the first-run command asks "Obsidian must restart once to add
|
|
777
|
+
this vault … Restart now?" in that state. And if `open` itself is interrupted
|
|
778
|
+
(Ctrl-C, or its process ended) after Obsidian quit and before it was started
|
|
779
|
+
again, Obsidian stays quit: start it yourself, and it reopens its vaults; run
|
|
780
|
+
`open` again to add the view's vault.
|
|
781
|
+
|
|
782
|
+
Only `open` adds a vault to Obsidian: the maintenance service never does, so
|
|
783
|
+
it never opens a window nobody asked for. A declared view that was never
|
|
784
|
+
opened is published while Obsidian is quit, and `open --scope ID` adds it.
|
|
785
|
+
|
|
786
|
+
In no state does `open` add a view's vault inside a folder Obsidian already
|
|
787
|
+
lists as a vault (your home folder, say): that vault would show the view's
|
|
788
|
+
notes too, and a command-line call run in the view's folder would reach it.
|
|
789
|
+
`open` answers `launch-failed` with reason `vault-inside-another-vault`:
|
|
790
|
+
remove that vault from Obsidian's vault list, or keep Atelier's data root
|
|
791
|
+
outside that folder. A view's vault that Obsidian lists already, below such a
|
|
792
|
+
vault, is reached by its id instead (see "Which window answers" in
|
|
793
|
+
[Known limits](#known-limits)).
|
|
344
794
|
|
|
345
|
-
|
|
795
|
+
Obsidian can list one folder more than once, under another letter case or
|
|
796
|
+
through a link, and then open it in one window per entry. Each of those
|
|
797
|
+
windows holds the view's vault, and a publication coordinates with one window
|
|
798
|
+
only, so none is made: the view reports `publisher-conflict` with reason
|
|
799
|
+
`vault-open-in-several-windows`, and `open` answers the same, names the
|
|
800
|
+
entries (`open in Obsidian as: …`; `duplicates` in JSON) and launches nothing.
|
|
801
|
+
Remove the extra entries from Obsidian's vault list and open again. Closing
|
|
802
|
+
the extra windows is not enough: Obsidian keeps the last window it closed
|
|
803
|
+
marked open, so two entries can stay marked open with one window showing, and
|
|
804
|
+
the view stays refused until the list names the folder once.
|
|
805
|
+
While one entry of the folder has a window, `open` reaches only that one and
|
|
806
|
+
never opens another entry of the same folder beside it.
|
|
346
807
|
|
|
347
|
-
|
|
808
|
+
A view's first publication into the folder allocated for it is the one
|
|
809
|
+
exception to the rule below. While no list the app keeps names that folder, a
|
|
810
|
+
folder above it or one inside it, the vault is filled even while Obsidian
|
|
811
|
+
runs, by creating files only. When that run completes, `open` adds the vault
|
|
812
|
+
to Obsidian and opens it after the commit. A run that stops partway commits
|
|
813
|
+
nothing and falls back to the coordinated path. That happens when the list
|
|
814
|
+
names the folder meanwhile, a settings file with other bytes is already
|
|
815
|
+
there, or an interrupted run left a replacement or a removal. `open` may then
|
|
816
|
+
add and open the vault before it is complete, and the app publishes the rest.
|
|
817
|
+
Anything that would replace or remove a file waits for the app. See "First publication into a vault no Obsidian lists" in
|
|
818
|
+
[obsidian-contract.md](obsidian-contract.md). The plugin's entry written this
|
|
819
|
+
way counts as offered until the plugin says hello from the vault.
|
|
820
|
+
|
|
821
|
+
The publisher still writes into a vault only when it can coordinate with every
|
|
348
822
|
Obsidian that may hold it, or when the process table shows, positively, that
|
|
349
823
|
none runs. Otherwise it stops, and the view reports `publisher-conflict` with
|
|
350
824
|
reason `editor-uncoordinated`. That reason has several causes, and the report
|
|
351
825
|
does not say which: Obsidian runs without this vault open, or with it open but
|
|
352
826
|
its command line did not answer; the process table could not be read, or on
|
|
353
827
|
Linux shows an app that runs on a system Electron, which may be Obsidian; the
|
|
354
|
-
app's version was not checked when the publication began
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
version
|
|
828
|
+
app's version was not checked when the publication began; or an app started
|
|
829
|
+
while the view was being published with the app closed. `status` gives
|
|
830
|
+
`atelier obsidian open` as the next step (it adds the vault to Obsidian and
|
|
831
|
+
publishes through it), or quitting Obsidian (on Linux, also any app that runs
|
|
832
|
+
on a system Electron). When `open` itself already did that and the
|
|
833
|
+
publication still stopped, it says to quit Obsidian and open again.
|
|
834
|
+
|
|
835
|
+
The tick `open` asks for prepares and publishes its view once more, whatever
|
|
836
|
+
state the view is in. A view whose last publication did not settle (refused,
|
|
837
|
+
stale or still updating) is also tried again without waiting for a change: as
|
|
838
|
+
soon as the app looks different (it quit or started, or opened or closed a
|
|
839
|
+
vault in its list), and otherwise after a delay that starts at 30 seconds and
|
|
840
|
+
doubles per attempt, up to the full reconciliation every five minutes. What
|
|
841
|
+
the app looks like is read from the process table and the app's vault list
|
|
842
|
+
alone: maintenance runs nothing in Obsidian to find out, and asks it for its
|
|
843
|
+
version only when a view is about to be published, without blocking.
|
|
844
|
+
|
|
845
|
+
While Atelier's plugin holds the view's vault open in the app and the command
|
|
846
|
+
line gives no version (as it answers while a vault is still loading), the
|
|
847
|
+
version the plugin reports stands in (reason `plugin-reported`); a version the
|
|
848
|
+
command line gives always decides, and while the process table shows no app
|
|
849
|
+
running, a plugin's report counts for nothing. `open` then asks the command
|
|
850
|
+
line nothing: a vault the app's settings file lists is opened by path, and one
|
|
851
|
+
it does not show is answered as `app-cli-unavailable` with reason
|
|
852
|
+
`vault-open-cli-silent` (the app has the vault open; make sure its
|
|
853
|
+
command-line interface is turned on). So is a listed vault the command line
|
|
854
|
+
does not answer for once it is opened, while only the plugin reports the
|
|
855
|
+
version: `open` says so at once instead of waiting for the app.
|
|
856
|
+
|
|
857
|
+
## Personal workspaces
|
|
858
|
+
|
|
859
|
+
A personal workspace (see [personal-workspace.md](personal-workspace.md)) is
|
|
860
|
+
projected through one route, `bindPersonalWorkspace({ personalHome,
|
|
861
|
+
generationId })` in `src/projection/obsidian/personal-workspace.mjs`. Both
|
|
862
|
+
arguments are explicit; neither is discovered from the environment or the
|
|
863
|
+
working directory. A loader uses `loadBoundProject` with the same arguments,
|
|
864
|
+
or `loadBoundProjectOffThread`, which composes in a worker thread; the engine
|
|
865
|
+
awaits its loader. No command or service binds one yet: that waits for the selection seam that
|
|
866
|
+
keeps one projection configuration per person.
|
|
867
|
+
|
|
868
|
+
- **One graph.** The binding is attached to the generation's resolved
|
|
869
|
+
`atelier.project.json` under one symbol key. When a project carries it, the
|
|
870
|
+
pipeline's `buildGraph` builds the canonical graph with the caller's file
|
|
871
|
+
cache and composition's own rule that no private note is a link target, then
|
|
872
|
+
applies eligibility as for any project. The engine, view counts, source apply,
|
|
873
|
+
the proposal adapter and the selection operation all build through it, so they
|
|
874
|
+
read one graph. A plain build of the generation's configuration would differ:
|
|
875
|
+
there, a shared note's link can name a private note.
|
|
876
|
+
- **Only a confirmed graph is used.** A graph is returned only under a validity
|
|
877
|
+
key that `composePersonalWorkspace` confirmed. The key names:
|
|
878
|
+
- the authored manifest and overlay, as regular files of at most 1 MiB;
|
|
879
|
+
- every file of the generation, as regular files of at most 8 MiB (the
|
|
880
|
+
personal-workspace module's own limits);
|
|
881
|
+
- the private home's own state, any `.git` above it, and a `.git` in its
|
|
882
|
+
`generations` folder;
|
|
883
|
+
- each enrolled root's link status and its Git configuration (its remote and
|
|
884
|
+
its helpers), through a `gitdir:` file and its common directory where `.git`
|
|
885
|
+
is a file;
|
|
886
|
+
- the user's Git configuration (`~/.gitconfig` and the XDG one), through a
|
|
887
|
+
link, and any ambient Git variable;
|
|
888
|
+
- a digest of the graph's facts: nodes, edges, embeds, assets, resolved links
|
|
889
|
+
and every finding.
|
|
890
|
+
|
|
891
|
+
The inputs are read before the composition runs. A key is confirmed only when
|
|
892
|
+
the composition then accepted the inputs and composed a graph with exactly
|
|
893
|
+
those facts, so every graph used is one the composition built too. A single
|
|
894
|
+
change that lands while it runs is either seen by it or leaves the key behind;
|
|
895
|
+
a change and its exact undo during one composition is caught at the next full
|
|
896
|
+
reconciliation. Binding confirms the first key. An authored or generation
|
|
897
|
+
file the key reads is opened without following a link and without waiting on
|
|
898
|
+
it. A FIFO, a device or a link refuses at once, with the composition's code
|
|
899
|
+
(`generation-corrupt`, `malformed-input`). A Git configuration file is read
|
|
900
|
+
through a link, as Git reads it, but never waited on.
|
|
901
|
+
|
|
902
|
+
When a build finds its key unconfirmed, a caller that builds once composes in
|
|
903
|
+
its own thread. The engine, and the proposal adapter it runs, compose in a
|
|
904
|
+
worker, off the event loop, then build again. The adapter builds only when it
|
|
905
|
+
looks at a newly observed edit, as for any project. On a tick whose graph is
|
|
906
|
+
pending (`personal-validation-pending`), it records nothing for the edits it
|
|
907
|
+
reached and reports `observed.deferred`. It offers those edits, and every
|
|
908
|
+
earlier refusal, again next tick, and leaves a due proposal operation as it
|
|
909
|
+
is, without spending one of its attempts. While shared sources change before
|
|
910
|
+
every tick, every tick is pending: the edit is deferred again, with one full
|
|
911
|
+
build per tick, until a tick with no change. A worker that does not answer
|
|
912
|
+
within two minutes is let go of and refuses `personal-composition-unavailable`,
|
|
913
|
+
so the tick does not wait. A worker blocked in a system call (a FIFO opened for
|
|
914
|
+
reading) cannot be stopped until that call returns. Until then it keeps the
|
|
915
|
+
process from exiting, and each such expiry leaves one thread behind: a service
|
|
916
|
+
stopped in that state needs a kill. A graph that still differs refuses
|
|
917
|
+
`personal-graph-unconfirmed`.
|
|
918
|
+
- **A copy is refused.** The settings member names the bound generation. A copy
|
|
919
|
+
of a bound project that lost the binding (a structured clone, a JSON round
|
|
920
|
+
trip) refuses `personal-binding-lost`, and is never built as an ordinary
|
|
921
|
+
project.
|
|
922
|
+
- **Validity.** Composition decides whether the generation may be used, at bind
|
|
923
|
+
time and at every build. Its refusals keep their codes (`stale-generation`,
|
|
924
|
+
`generation-missing`, `generation-corrupt`, `generation-relocated`,
|
|
925
|
+
`retained-removed-reference`, `not-private-location`, `root-symlinked`,
|
|
926
|
+
`ambient-git-environment`, `future-schema`, `ambiguous-binding` and the rest).
|
|
927
|
+
`bindPersonalWorkspace` throws them as `PersonalWorkspaceRefusal`.
|
|
928
|
+
`loadBoundProject` and every build refuse with the same code as a maintenance
|
|
929
|
+
refusal, so the engine and every command report it typed, and no view stays
|
|
930
|
+
current. Nothing is published, and no vault, manifest, journal or private home
|
|
931
|
+
byte is written. A refusal the projection adds (`personal-view-id-reserved`,
|
|
932
|
+
`personal-views-exceed-settings-limit`) is a maintenance refusal from the
|
|
933
|
+
start.
|
|
934
|
+
- **Staleness is noticed at the next tick.** The engine observes the person's
|
|
935
|
+
`atelier.personal.json` and `atelier.overlay.json` and the bound generation's
|
|
936
|
+
`generation.json` as configuration. A change to any of them prepares every
|
|
937
|
+
view again on the next tick, unasked, and a generation that no longer holds
|
|
938
|
+
is refused there. Every full reconciliation composes a bound workspace again,
|
|
939
|
+
in a worker, whatever else it prepares. A cause the key does not name is
|
|
940
|
+
therefore refused within the reconciliation interval (five minutes by
|
|
941
|
+
default). Those causes are:
|
|
942
|
+
- the system Git configuration, and files a Git configuration includes
|
|
943
|
+
(`include.path`, `config.worktree`);
|
|
944
|
+
- an enrolled repository's work tree or top level changing;
|
|
945
|
+
- a change of the authored inputs and its exact undo during one composition;
|
|
946
|
+
- a shared note replaced by a link;
|
|
947
|
+
- an untracked note becoming ignored.
|
|
948
|
+
|
|
949
|
+
The views are prepared again only when that composition refuses or confirms a
|
|
950
|
+
different key: an unchanged workspace is not rebuilt, republished or locked.
|
|
951
|
+
After a refusal the engine
|
|
952
|
+
loads the project again at the next tick, so a loader that binds the next
|
|
953
|
+
generation is followed. The generation's record and the settings member both
|
|
954
|
+
name the generation, so a rebound generation invalidates every view even when
|
|
955
|
+
its configuration file is byte-identical.
|
|
956
|
+
- **Views.** The overlay's saved views become scopes in memory: each is a
|
|
957
|
+
scoped view of the repositories it names, and `everything` is a full view of
|
|
958
|
+
the composed graph. A saved view named `everything` is refused. More than 255
|
|
959
|
+
saved views, or a view of more than 256 repositories, is refused at bind
|
|
960
|
+
(`personal-views-exceed-settings-limit`), within the Obsidian settings
|
|
961
|
+
contract. The preferred view, when it names a saved one, is the default. No
|
|
962
|
+
generation file is written. `view add` refuses `views-from-personal-overlay`;
|
|
963
|
+
`audience set`, `audience clear` and `location set` refuse
|
|
964
|
+
`personal-binding-decision-unavailable`. Each refuses before anything is
|
|
965
|
+
resolved or written.
|
|
966
|
+
- **Preferences and coverage.** `preferences` are returned read only. A theme
|
|
967
|
+
is reported and never written: `appearance.json` stays the person's.
|
|
968
|
+
`coverage` is passed through untouched. No Obsidian code reads it: it states
|
|
969
|
+
what is not enforced, and is never permission.
|
|
970
|
+
- **Workspace identity.** The bound project's folder is the private home, so
|
|
971
|
+
the workspace pointer is `<personal home>/.atelier-local/obsidian.json`. A
|
|
972
|
+
generation is a closed, verified inventory, and an extra file there would
|
|
973
|
+
invalidate it. This is provisional until the per-person projection
|
|
974
|
+
configuration exists.
|
|
975
|
+
- **Edits.** A vault edit to a private note is never applied. Source apply
|
|
976
|
+
refuses it with `personal-overlay-proposals-only`. The proposal adapter does
|
|
977
|
+
not observe, record or propose it either: it answers
|
|
978
|
+
`personal-overlay-not-proposed`. Nothing is written into a generation, and
|
|
979
|
+
the view stays
|
|
980
|
+
`held-for-your-edit` until the edit is undone. Turning such an edit into a
|
|
981
|
+
change of the person's overlay is not built.
|
|
982
|
+
- **Reserved settings key.** The settings member
|
|
983
|
+
`ext["mnstry.atelier.personal-workspace"]` is reserved: the binding writes it
|
|
984
|
+
in memory. A project configuration that declares it itself is refused at
|
|
985
|
+
every build (`personal-binding-lost`, naming the key).
|
|
986
|
+
|
|
987
|
+
Measured once on 2,156 notes in three repositories, with 50 annotations and five
|
|
988
|
+
saved views (six views in all). The production contributions were loaded, as
|
|
989
|
+
the service loads them, so the proposal adapter was registered. The host's load
|
|
990
|
+
average was near 35, slower than an idle one, so read the times as upper
|
|
991
|
+
bounds. "Main-thread compositions" counts the Git probe a composition makes on
|
|
992
|
+
the event loop's thread.
|
|
993
|
+
|
|
994
|
+
| Step | Wall time | Longest event-loop block | Main-thread compositions |
|
|
995
|
+
| --- | --- | --- | --- |
|
|
996
|
+
| Load, composed in a worker (`loadBoundProjectOffThread`) | 3.8 s | 0.03 s | none |
|
|
997
|
+
| Load in the calling thread (`loadBoundProject`) | 3.5 s | 3.5 s | one |
|
|
998
|
+
| One build without a file cache (a caller that builds once) | 1.4 s | 1.3 s | none |
|
|
999
|
+
| First tick: load, build, and first publication of six vaults | 582 s | 574 s | none |
|
|
1000
|
+
| Tick with every view prepared again | 4.5 s | 4.5 s | none |
|
|
1001
|
+
| Idle tick | 0.25 s | 0.23 s | none |
|
|
1002
|
+
| Tick with a vault edit and a graph change: the adapter defers, the engine confirms in a worker | 12.4 s | 2.8 s | none |
|
|
1003
|
+
| Next tick: the adapter observes that edit (one build) | 2.1 s | 2.0 s | none |
|
|
1004
|
+
| Full-reconciliation tick, the edit still open | 5.0 s | 1.0 s | none |
|
|
1005
|
+
|
|
1006
|
+
**What is met.** No composition runs on the engine's event loop, the proposal
|
|
1007
|
+
adapter's included. The load, a confirmation after a change, and the
|
|
1008
|
+
composition at every full reconciliation run in a worker; the tick does not
|
|
1009
|
+
wait on one that misses its deadline. An unchanged workspace is not prepared
|
|
1010
|
+
again. While an edit stays open and shared sources are quiet, the adapter
|
|
1011
|
+
builds nothing more; under continuous change it builds once per tick until a
|
|
1012
|
+
quiet tick.
|
|
1013
|
+
|
|
1014
|
+
**What remains before a service or `open` binds a personal workspace of this
|
|
1015
|
+
size.** The first publication blocks the event loop far longer than the
|
|
1016
|
+
service's five-second health probe: about ten minutes here. That is the
|
|
1017
|
+
publication path every project takes, not this route: an ordinary project of
|
|
1018
|
+
450 notes, measured the same way, blocked as long as a bound one. Preparing six
|
|
1019
|
+
views again blocked 4.5 s, under the probe. The proposal adapter's build of a
|
|
1020
|
+
newly observed edit, without the engine's file cache, blocked 2.0 s, at a
|
|
1021
|
+
two-second target, as for an ordinary project. A service binding needs the
|
|
1022
|
+
first publication to yield to the event loop (or run off it), or a corpus small
|
|
1023
|
+
enough to stay within the probe.
|
|
373
1024
|
|
|
374
1025
|
## Known limits
|
|
375
1026
|
|
|
@@ -402,8 +1053,10 @@ test reported as a pass.
|
|
|
402
1053
|
built on it does not coordinate with any app it then finds running, and
|
|
403
1054
|
asks it nothing. That publication stops as `publisher-conflict` with reason
|
|
404
1055
|
`editor-uncoordinated`, and the next publication asks again and reads the
|
|
405
|
-
version. A view that stopped is tried again on
|
|
406
|
-
|
|
1056
|
+
version. A view that stopped is tried again on the next tick `open` asks
|
|
1057
|
+
for, as soon as the app looks different, and otherwise after a delay that
|
|
1058
|
+
starts at 30 seconds and doubles, up to the full reconciliation every five
|
|
1059
|
+
minutes. A tick `open` asks for never reuses a remembered app answer.
|
|
407
1060
|
- Install location (macOS): the app is found only at
|
|
408
1061
|
`/Applications/Obsidian.app`, and its command-line tool only inside it. An
|
|
409
1062
|
Obsidian installed elsewhere, or a renamed bundle, is `app-missing`.
|
|
@@ -417,9 +1070,75 @@ test reported as a pass.
|
|
|
417
1070
|
published through the app. `status` (under `service.app`) and `open` say what
|
|
418
1071
|
to do: open any vault in Obsidian, or quit Obsidian. With the app quit,
|
|
419
1072
|
maintenance publishes on its own path again; with a vault open, it reads
|
|
420
|
-
the version again on a later tick.
|
|
421
|
-
|
|
422
|
-
|
|
1073
|
+
the version again on a later tick. While the app runs with no vault open,
|
|
1074
|
+
`open` has it open a vault only when its list already knows that vault,
|
|
1075
|
+
by path; one it does not know cannot be added then (see below). After its
|
|
1076
|
+
own launch `open` waits, bounded, while the app is still opening the vault;
|
|
1077
|
+
an app whose vault window is still loading answers a command with `Error:
|
|
1078
|
+
Command "…" not found`, which is read as not up yet, never as a version.
|
|
1079
|
+
- Vault location: consent to a folder a sync client keeps in step
|
|
1080
|
+
(`--allow-synced-location`) is given when `location set` decides the folder,
|
|
1081
|
+
and is not recorded, so the maintenance service does not check for sync
|
|
1082
|
+
clients again. The decision keeps the folder as it was written, so at a
|
|
1083
|
+
view's first allocation a folder on the way that has since become a link
|
|
1084
|
+
into a synced folder is followed, and its vault is allocated there without
|
|
1085
|
+
being asked; a folder that becomes synced without any link (iCloud's
|
|
1086
|
+
"Desktop & Documents Folders" turned on, say) is not refused either, at the
|
|
1087
|
+
first allocation or when a vault is made again. Every other check runs
|
|
1088
|
+
again at both, and a vault made again, or published into, through a link on
|
|
1089
|
+
the way is refused (`vault-allocation-moved`).
|
|
1090
|
+
- Replacing a vault during a publication: the allocated folder is checked
|
|
1091
|
+
before the vault lock is taken and again once its folder is made, after the
|
|
1092
|
+
app is asked about the vault, before each note and before the generation is
|
|
1093
|
+
committed. A program of the same account that puts a link in its place
|
|
1094
|
+
between one check and what follows it can still have that go through the
|
|
1095
|
+
link: one note's writes (the folders on its way and the note), or the vault
|
|
1096
|
+
lock's folder (made there, or made private if it was there already) and, in
|
|
1097
|
+
a folder that already holds one (another Atelier vault), a lock ticket and
|
|
1098
|
+
its release flag. For a note replaced or removed while the app holds the
|
|
1099
|
+
vault, the app is asked about that note between the check and the write, so
|
|
1100
|
+
that window lasts a round trip to the app. The next check refuses the
|
|
1101
|
+
publication, and it is never reported current.
|
|
1102
|
+
- Vault identity: an allocated folder is known by its real path, device and
|
|
1103
|
+
inode. On Linux a folder made at the same path after the allocated one was
|
|
1104
|
+
removed can be given the same inode number (ext4 reuses a freed one), and is
|
|
1105
|
+
then taken for the one made; macOS (APFS) did not reuse one in 200 tries.
|
|
1106
|
+
Such a folder is published into only at the recorded real path, and the
|
|
1107
|
+
plugin's bearer only when this account owns it.
|
|
1108
|
+
- Obsidian's settings file: `open` adds a view's vault to the app's own list,
|
|
1109
|
+
`obsidian.json` in its user-data directory: `~/Library/Application
|
|
1110
|
+
Support/obsidian` on macOS and `$XDG_CONFIG_HOME/obsidian` (else
|
|
1111
|
+
`~/.config/obsidian`) on Linux. It is written only while the process table
|
|
1112
|
+
shows, positively, that no Obsidian runs, only when Obsidian created it
|
|
1113
|
+
before, and with a backup beside it; see
|
|
1114
|
+
[Obsidian's vault list](obsidian-contract.md#obsidians-vault-list). A
|
|
1115
|
+
Flatpak or snap build keeps its list inside its sandbox and never reads that
|
|
1116
|
+
file. Which build is in use is read from which vault list was written last
|
|
1117
|
+
(every build rewrites its own when a vault window opens or closes), and only
|
|
1118
|
+
when no build wrote one from its installation; for a Flatpak or snap build
|
|
1119
|
+
the file is then neither read nor written: `open` answers
|
|
1120
|
+
`obsidian-sandboxed` and says to start Obsidian with any vault open, then
|
|
1121
|
+
open again, and adds the vault through the app. On Windows no location is
|
|
1122
|
+
known, and `open` adds the vault through the app in the same way.
|
|
1123
|
+
- Recent items: adding a vault through the running app is Obsidian's own
|
|
1124
|
+
"open folder as vault", which also puts the vault's folder in the operating
|
|
1125
|
+
system's recently used documents (Recent Items on macOS).
|
|
1126
|
+
- Which window answers: Obsidian answers a command-line call that names a
|
|
1127
|
+
vault (`vault=<id>` first) in that vault's window; any other call in the
|
|
1128
|
+
window of the first vault in its list whose folder is the tool's working
|
|
1129
|
+
directory or contains it, and otherwise in the vault window that had focus
|
|
1130
|
+
last. A vault that takes a call is opened when it is closed. Calls about a
|
|
1131
|
+
vault therefore name its id; only when that id would name another vault
|
|
1132
|
+
first (one whose folder has the id as its name) do they run inside its
|
|
1133
|
+
folder instead, and not at all when a vault listed before it at a folder
|
|
1134
|
+
above it (your home folder, say) would take them there. The vault root is
|
|
1135
|
+
taken in the spelling the file system stores, so a data root given in
|
|
1136
|
+
another letter case on macOS changes nothing. Publication calls do this
|
|
1137
|
+
only while the app's list shows the view's vault open, and run in a
|
|
1138
|
+
directory that is no vault otherwise. So maintenance never reopens a vault
|
|
1139
|
+
window you closed while Obsidian keeps running, and never reaches another
|
|
1140
|
+
vault: publication then stops as `publisher-conflict` until `atelier
|
|
1141
|
+
obsidian open` opens the vault again or Obsidian quits.
|
|
423
1142
|
- Detecting the app: the process table is read with `ps -A -o comm=`
|
|
424
1143
|
(`pid=,comm=` on Linux), and the app is recognised by the executable a
|
|
425
1144
|
process runs, never by its arguments, so a path argument that contains an
|
|
@@ -469,6 +1188,26 @@ test reported as a pass.
|
|
|
469
1188
|
- An edit the byte lens cannot turn into source bytes (a new or changed link
|
|
470
1189
|
to another note of the vault, an edited front matter) becomes a copy-only
|
|
471
1190
|
proposal. No operation applies one.
|
|
1191
|
+
- Atelier's plugin (phase 1) reports presence and status and decides
|
|
1192
|
+
nothing: publication still coordinates with the app through its
|
|
1193
|
+
command-line tool, which must be enabled, and the plugin only supplies the
|
|
1194
|
+
app version where that tool gives none. A person who turns the plugin off
|
|
1195
|
+
in a vault, or uninstalls it there, is followed: its entry is not added
|
|
1196
|
+
back and a deleted folder is not made again until the person turns it on
|
|
1197
|
+
in Obsidian's settings or runs
|
|
1198
|
+
`atelier obsidian plugin on --scope ID`. Plugin files are never removed from
|
|
1199
|
+
a vault. See [obsidian-plugin.md](obsidian-plugin.md).
|
|
1200
|
+
- Login items: the tests run the launchd and systemd managers' own code
|
|
1201
|
+
against stand-ins that answer as launchctl and systemctl do, and never
|
|
1202
|
+
against a real session. What `launchctl print-disabled` says for an item
|
|
1203
|
+
switched off in System Settings, and the exit statuses read from
|
|
1204
|
+
`launchctl` and `systemctl`, are the documented ones and are not yet
|
|
1205
|
+
confirmed on a host. A unit whose program cannot be loaded at all (the
|
|
1206
|
+
project's package was removed) is restarted by its manager once a minute,
|
|
1207
|
+
and each attempt adds a few lines to `state/service/login-item.log`, which
|
|
1208
|
+
nothing bounds: `service unit --remove` or `uninstall` ends it. An upgrade
|
|
1209
|
+
in the moment between a service's start and the first reading of its release
|
|
1210
|
+
is not noticed until the next change.
|
|
472
1211
|
- Acceptance: a schema-valid receipt closes no gate, the package proof closes
|
|
473
1212
|
no gate, and no adopter acceptance is recorded in this repository.
|
|
474
1213
|
|
|
@@ -482,3 +1221,9 @@ The test suite proves each oracle can fail:
|
|
|
482
1221
|
- `createReceiptValidatorForOracleTests` accepts a rule table with one rule
|
|
483
1222
|
switched off; every negative case that depends on that rule then passes,
|
|
484
1223
|
and even that closes nothing.
|
|
1224
|
+
- `openScopeForOracleTests` with an `OPENING_PRIMITIVES.keptByApp` that
|
|
1225
|
+
never holds: an open with Obsidian running without the vault reports the
|
|
1226
|
+
publisher conflict it could have cleared, and the first-open oracle fails.
|
|
1227
|
+
- `createMaintenanceEngineForOracleTests` with an
|
|
1228
|
+
`ENGINE_PRIMITIVES.isRetryDue` that never holds: a refused view waits for
|
|
1229
|
+
the full reconciliation, and the retry oracle fails.
|