@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
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { createHmac } from 'node:crypto'
|
|
2
|
+
|
|
3
|
+
// The channel between Atelier's own plugin, inside a vault Atelier manages,
|
|
4
|
+
// and the maintenance service of the workspace that manages that vault.
|
|
5
|
+
//
|
|
6
|
+
// A closed command surface over the service's literal loopback listener:
|
|
7
|
+
//
|
|
8
|
+
// POST /plugin/challenge a fresh nonce and the time it was made, and a hint
|
|
9
|
+
// at which vault's key it means that only the holder
|
|
10
|
+
// of that key can read; the service answers, once
|
|
11
|
+
// and only while it is fresh, with its own nonce and
|
|
12
|
+
// a proof that it holds the key
|
|
13
|
+
// POST /plugin/hello only after the plugin checked that proof: its own
|
|
14
|
+
// proof, the plugin and app versions, an id of this
|
|
15
|
+
// launch of the plugin, and a proof of the vault path
|
|
16
|
+
// the app has open (the path itself is never sent)
|
|
17
|
+
// POST /plugin/lease "this vault is open in an app", renewed every two
|
|
18
|
+
// seconds; it lapses on its own six seconds later
|
|
19
|
+
// POST /plugin/release the vault closed, or the plugin unloaded
|
|
20
|
+
// POST /plugin/status freshness, reason and held edits of this view
|
|
21
|
+
//
|
|
22
|
+
// The key is the vault's bearer, which Atelier writes into the plugin's data
|
|
23
|
+
// file of that vault only and keeps in private state. It never crosses the
|
|
24
|
+
// wire, and neither does anything that names the view or the vault before the
|
|
25
|
+
// listener proved it holds the key: a program squatting the service's port
|
|
26
|
+
// while the service is down learns a nonce and a hint it cannot link to a
|
|
27
|
+
// vault, and cannot answer. Both proofs bind the listener's exact address, so
|
|
28
|
+
// an answer relayed from a service listening elsewhere does not verify.
|
|
29
|
+
//
|
|
30
|
+
// A challenge recorded by such a program and sent to the service later is
|
|
31
|
+
// worth little: the service answers a challenge only within thirty seconds of
|
|
32
|
+
// the time it names, and a nonce only once, and at most four handshakes wait
|
|
33
|
+
// for their hello per view, so one view's challenges never hold up another's.
|
|
34
|
+
//
|
|
35
|
+
// The handshake derives a key for one session. Every later request carries
|
|
36
|
+
// the session, a counter that only goes up, and a MAC over both and the
|
|
37
|
+
// command under that key; every answer carries a MAC over the request's counter
|
|
38
|
+
// and the exact bytes of the answer. A handshake is used once and lapses after
|
|
39
|
+
// five seconds, a session after fifteen minutes. Nothing here takes a path to
|
|
40
|
+
// act on, a command or code, and every command maps to state the service
|
|
41
|
+
// already keeps (see docs/obsidian-plugin.md).
|
|
42
|
+
//
|
|
43
|
+
// The plugin cannot import this module: it runs inside the app, from the
|
|
44
|
+
// vault. It carries the same constants and the same computations, and the test
|
|
45
|
+
// suite holds the two to each other: a plugin that computes any one of them
|
|
46
|
+
// otherwise cannot complete a handshake.
|
|
47
|
+
|
|
48
|
+
export const PLUGIN_ID = 'atelier-projection'
|
|
49
|
+
export const PLUGIN_DIRECTORY = `.obsidian/plugins/${PLUGIN_ID}`
|
|
50
|
+
// Shipped with the package under plugins/obsidian/ and copied into every vault unchanged.
|
|
51
|
+
export const PLUGIN_SOURCE_FILES = Object.freeze(['manifest.json', 'main.js', 'styles.css'])
|
|
52
|
+
// Written per vault: the channel address and that vault's bearer.
|
|
53
|
+
export const PLUGIN_DATA_FILE = 'data.json'
|
|
54
|
+
export const PLUGIN_DATA_PATH = `${PLUGIN_DIRECTORY}/${PLUGIN_DATA_FILE}`
|
|
55
|
+
// The data file holds the vault's key: only the person who runs the vault reads it. The app reads the others.
|
|
56
|
+
export const PLUGIN_DATA_MODE = 0o600
|
|
57
|
+
export const PLUGIN_SOURCE_MODE = 0o644
|
|
58
|
+
|
|
59
|
+
export const PLUGIN_CHANNEL_PROTOCOL = 'atelier-obsidian-plugin-channel/v2'
|
|
60
|
+
export const PLUGIN_DATA_SCHEMA = 'atelier-obsidian-plugin-data/v1'
|
|
61
|
+
export const PLUGIN_STATUS_SCHEMA = 'atelier-obsidian-plugin-status/v1'
|
|
62
|
+
|
|
63
|
+
export const PLUGIN_COMMANDS = Object.freeze(['challenge', 'hello', 'lease', 'release', 'status'])
|
|
64
|
+
export const PLUGIN_ROUTES = Object.freeze(Object.fromEntries(PLUGIN_COMMANDS.map((command) => [command, `/plugin/${command}`])))
|
|
65
|
+
export const PLUGIN_REQUEST_FIELDS = Object.freeze({
|
|
66
|
+
challenge: Object.freeze(['protocol', 'keyHint', 'clientNonce', 'issuedAt']),
|
|
67
|
+
hello: Object.freeze(['handshakeId', 'pluginVersion', 'appVersion', 'instanceId', 'vaultProof', 'clientProof']),
|
|
68
|
+
lease: Object.freeze(['sessionId', 'counter', 'mac']),
|
|
69
|
+
release: Object.freeze(['sessionId', 'counter', 'mac']),
|
|
70
|
+
status: Object.freeze(['sessionId', 'counter', 'mac']),
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
export const PLUGIN_MAX_REQUEST_BYTES = 1024
|
|
74
|
+
export const PLUGIN_RENEW_INTERVAL_MS = 2000
|
|
75
|
+
// Three renewals may be missed before a vault stops counting as open.
|
|
76
|
+
export const PLUGIN_LEASE_TTL_MS = 3 * PLUGIN_RENEW_INTERVAL_MS
|
|
77
|
+
export const PLUGIN_MAX_SESSIONS_PER_SCOPE = 8
|
|
78
|
+
export const PLUGIN_HANDSHAKE_TTL_MS = 5000
|
|
79
|
+
// A challenge is answered only this close to the time it names (both sides read one machine's clock).
|
|
80
|
+
export const PLUGIN_CHALLENGE_WINDOW_MS = 30 * 1000
|
|
81
|
+
export const PLUGIN_MAX_PENDING_HANDSHAKES_PER_SCOPE = 4
|
|
82
|
+
// A session key is short-lived: the plugin shakes hands again after this long.
|
|
83
|
+
export const PLUGIN_MAX_SESSION_AGE_MS = 15 * 60 * 1000
|
|
84
|
+
// The app version the plugin needs, the floor of the publication protocol (app-capability.mjs).
|
|
85
|
+
export const PLUGIN_MINIMUM_APP_VERSION = '1.13.7'
|
|
86
|
+
|
|
87
|
+
export const PLUGIN_BEARER = /^[A-Za-z0-9_-]{43}$/
|
|
88
|
+
export const PLUGIN_NONCE = /^[0-9a-f]{64}$/
|
|
89
|
+
// A key hint, a proof and a MAC are each one HMAC-SHA256, in hex.
|
|
90
|
+
export const PLUGIN_MAC = /^[0-9a-f]{64}$/
|
|
91
|
+
export const PLUGIN_HANDSHAKE_ID = /^ph-[0-9a-f]{32}$/
|
|
92
|
+
export const PLUGIN_SESSION_ID = /^ps-[0-9a-f]{32}$/
|
|
93
|
+
export const PLUGIN_INSTANCE_ID = /^pi-[0-9a-f]{32}$/
|
|
94
|
+
const IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/
|
|
95
|
+
const VERSION_TEXT = /^[0-9A-Za-z.+-]{1,40}$/
|
|
96
|
+
const LOOPBACK_HOSTS = Object.freeze(['127.0.0.1', '::1'])
|
|
97
|
+
|
|
98
|
+
const isPlainObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
99
|
+
|
|
100
|
+
// The route of a request path, or null. Exact paths only: no query, no prefix.
|
|
101
|
+
export function pluginCommandOf(requestPath) {
|
|
102
|
+
return PLUGIN_COMMANDS.find((command) => PLUGIN_ROUTES[command] === requestPath) ?? null
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// { ok: true, body } or { ok: false, code }. The body has exactly the fields
|
|
106
|
+
// of its command, each of its own shape; anything else refuses.
|
|
107
|
+
export function validatePluginRequest(command, body) {
|
|
108
|
+
const fields = PLUGIN_REQUEST_FIELDS[command]
|
|
109
|
+
if (fields === undefined) return { ok: false, code: 'unknown-command' }
|
|
110
|
+
if (!isPlainObject(body)) return { ok: false, code: 'request-malformed' }
|
|
111
|
+
const keys = Object.keys(body)
|
|
112
|
+
if (keys.length !== fields.length || !fields.every((field) => Object.hasOwn(body, field))) return { ok: false, code: 'request-malformed' }
|
|
113
|
+
const shaped = (field, pattern) => typeof body[field] === 'string' && pattern.test(body[field])
|
|
114
|
+
if (command === 'challenge') {
|
|
115
|
+
if (body.protocol !== PLUGIN_CHANNEL_PROTOCOL) return { ok: false, code: 'protocol-unsupported' }
|
|
116
|
+
if (!shaped('keyHint', PLUGIN_MAC) || !shaped('clientNonce', PLUGIN_NONCE) || !Number.isSafeInteger(body.issuedAt) || body.issuedAt < 1) return { ok: false, code: 'request-malformed' }
|
|
117
|
+
} else if (command === 'hello') {
|
|
118
|
+
if (!shaped('handshakeId', PLUGIN_HANDSHAKE_ID) || !shaped('instanceId', PLUGIN_INSTANCE_ID) || !shaped('vaultProof', PLUGIN_MAC) || !shaped('clientProof', PLUGIN_MAC)) return { ok: false, code: 'request-malformed' }
|
|
119
|
+
if (!shaped('pluginVersion', VERSION_TEXT) || !shaped('appVersion', VERSION_TEXT)) return { ok: false, code: 'request-malformed' }
|
|
120
|
+
} else if (!shaped('sessionId', PLUGIN_SESSION_ID) || !shaped('mac', PLUGIN_MAC) || !Number.isSafeInteger(body.counter) || body.counter < 1) {
|
|
121
|
+
return { ok: false, code: 'request-malformed' }
|
|
122
|
+
}
|
|
123
|
+
return { ok: true, body }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// The computations of the handshake and the session, shared with the plugin.
|
|
127
|
+
// Every input but a vault path is one of the shapes above, without a line
|
|
128
|
+
// break, and a vault path is the only input of its computation, so joining
|
|
129
|
+
// them by lines is unambiguous. `key` is the vault's bearer text, or a
|
|
130
|
+
// session key.
|
|
131
|
+
const transcript = (label, fields) => [PLUGIN_CHANNEL_PROTOCOL, label, ...fields.map(String)].join('\n')
|
|
132
|
+
const hmac = (key, label, fields) => createHmac('sha256', key).update(transcript(label, fields), 'utf8').digest()
|
|
133
|
+
const hmacHex = (key, label, fields) => hmac(key, label, fields).toString('hex')
|
|
134
|
+
|
|
135
|
+
// A hint at the vault's key, fresh with every nonce and bound to the time the
|
|
136
|
+
// challenge names: the service finds the key it names by computing it for each
|
|
137
|
+
// key it holds, and a listener that holds none cannot tell two hints of one
|
|
138
|
+
// vault apart, nor move one to another time.
|
|
139
|
+
export const pluginKeyHint = ({ bearer, clientNonce, issuedAt }) => hmacHex(bearer, 'key-hint', [clientNonce, issuedAt])
|
|
140
|
+
// What binds a handshake: the view, the listener's exact address, both nonces and the handshake.
|
|
141
|
+
const handshakeFields = ({ scopeId, authority, clientNonce, serverNonce, handshakeId }) => [scopeId, authority, clientNonce, serverNonce, handshakeId]
|
|
142
|
+
export const pluginServerProof = (input) => hmacHex(input.bearer, 'server-proof', handshakeFields(input))
|
|
143
|
+
export const pluginSessionKey = (input) => hmac(input.bearer, 'session-key', handshakeFields(input))
|
|
144
|
+
// The vault the app has open, proven under the session key rather than named.
|
|
145
|
+
export const pluginVaultProof = ({ sessionKey, vaultPath }) => hmacHex(sessionKey, 'vault', [vaultPath])
|
|
146
|
+
export const pluginClientProof = (input) => hmacHex(input.bearer, 'client-proof', [...handshakeFields(input), input.pluginVersion, input.appVersion, input.instanceId, input.vaultProof])
|
|
147
|
+
export const pluginRequestMac = ({ sessionKey, command, sessionId, counter }) => hmacHex(sessionKey, 'request', [command, sessionId, counter])
|
|
148
|
+
// An answer is the exact text of its JSON document and a MAC over it, the command and the request's counter.
|
|
149
|
+
export const pluginResponseMac = ({ sessionKey, command, sessionId, counter, payload }) => hmacHex(sessionKey, 'response', [command, sessionId, counter, payload])
|
|
150
|
+
|
|
151
|
+
// The plugin's data file of one vault: where the service listens and the
|
|
152
|
+
// bearer of this vault. Canonical bytes, so an unchanged channel republishes
|
|
153
|
+
// nothing.
|
|
154
|
+
export function pluginDataDocument({ host, port, scopeId, bearer }) {
|
|
155
|
+
const document = { schema: PLUGIN_DATA_SCHEMA, channel: { host, port }, scopeId, bearer }
|
|
156
|
+
if (validatePluginData(document) === null) throw new TypeError('the plugin data needs a literal loopback address, a port, a view and a bearer')
|
|
157
|
+
return document
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function pluginDataBytes(input) {
|
|
161
|
+
const { schema, channel, scopeId, bearer } = pluginDataDocument(input)
|
|
162
|
+
return Buffer.from(`${JSON.stringify({ schema, channel: { host: channel.host, port: channel.port }, scopeId, bearer }, null, 2)}\n`, 'utf8')
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// The document when it is exactly a plugin data document, else null.
|
|
166
|
+
export function validatePluginData(document) {
|
|
167
|
+
if (!isPlainObject(document) || Object.keys(document).sort().join(',') !== 'bearer,channel,schema,scopeId') return null
|
|
168
|
+
if (document.schema !== PLUGIN_DATA_SCHEMA || typeof document.scopeId !== 'string' || !IDENTIFIER.test(document.scopeId)) return null
|
|
169
|
+
if (typeof document.bearer !== 'string' || !PLUGIN_BEARER.test(document.bearer)) return null
|
|
170
|
+
const { channel } = document
|
|
171
|
+
if (!isPlainObject(channel) || Object.keys(channel).sort().join(',') !== 'host,port') return null
|
|
172
|
+
if (!LOOPBACK_HOSTS.includes(channel.host) || !Number.isInteger(channel.port) || channel.port < 1024 || channel.port > 65535) return null
|
|
173
|
+
return document
|
|
174
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Atelier's own Obsidian plugin: the channel it speaks and the files that put
|
|
2
|
+
// it into a vault. The plugin source ships under plugins/obsidian/.
|
|
3
|
+
export {
|
|
4
|
+
PLUGIN_BEARER, PLUGIN_CHALLENGE_WINDOW_MS, PLUGIN_CHANNEL_PROTOCOL, PLUGIN_COMMANDS, PLUGIN_DATA_FILE, PLUGIN_DATA_PATH, PLUGIN_DATA_SCHEMA, PLUGIN_DIRECTORY, PLUGIN_HANDSHAKE_ID, PLUGIN_HANDSHAKE_TTL_MS,
|
|
5
|
+
PLUGIN_ID, PLUGIN_INSTANCE_ID, PLUGIN_LEASE_TTL_MS, PLUGIN_MAC, PLUGIN_MAX_PENDING_HANDSHAKES_PER_SCOPE, PLUGIN_MAX_REQUEST_BYTES, PLUGIN_MAX_SESSION_AGE_MS, PLUGIN_MAX_SESSIONS_PER_SCOPE,
|
|
6
|
+
PLUGIN_MINIMUM_APP_VERSION, PLUGIN_NONCE, PLUGIN_RENEW_INTERVAL_MS, PLUGIN_REQUEST_FIELDS, PLUGIN_ROUTES, PLUGIN_SESSION_ID, PLUGIN_SOURCE_FILES,
|
|
7
|
+
PLUGIN_STATUS_SCHEMA, pluginClientProof, pluginCommandOf, pluginDataBytes, pluginDataDocument, pluginKeyHint, pluginRequestMac, pluginResponseMac, pluginServerProof, pluginSessionKey,
|
|
8
|
+
pluginVaultProof, validatePluginData, validatePluginRequest,
|
|
9
|
+
} from './channel.mjs'
|
|
10
|
+
export { PLUGIN_DATA_MODE, PLUGIN_SOURCE_MODE, PLUGIN_SOURCE_ROOT, preparePluginFiles, readPluginSource } from './bundle.mjs'
|
|
@@ -6,7 +6,7 @@ import { AtelierDiagnosticError } from '../../../project/config.mjs'
|
|
|
6
6
|
import { compareText, isoTime } from '../../../runtime/obsidian/documents.mjs'
|
|
7
7
|
import { ObsidianMaintenanceRefusal } from '../../../runtime/obsidian/errors.mjs'
|
|
8
8
|
import { readMachineSettings } from '../../../runtime/obsidian/machine-settings.mjs'
|
|
9
|
-
import {
|
|
9
|
+
import { createProductionSeams, eligibilityFor } from '../../../runtime/obsidian/pipeline.mjs'
|
|
10
10
|
import { acquirePrivateGenerationLock, createAbandonmentProof } from '../../../runtime/obsidian/private-lock.mjs'
|
|
11
11
|
import { OBSIDIAN_EXT_KEY, ObsidianContractRefusal, assertObsidianContract } from '../contracts.mjs'
|
|
12
12
|
import { SOURCE_APPLY_PRIMITIVES } from '../edits/apply.mjs'
|
|
@@ -15,6 +15,7 @@ import { isIdentifier } from '../edits/object-identity.mjs'
|
|
|
15
15
|
import { openObjectStore } from '../edits/object-store.mjs'
|
|
16
16
|
import { decideApply } from '../edits/policy.mjs'
|
|
17
17
|
import { applyEditLens } from '../edits/regions.mjs'
|
|
18
|
+
import { PERSONAL_VALIDATION_PENDING, personalOverlayRepoOf } from '../personal-workspace.mjs'
|
|
18
19
|
import { PublicationRefusal } from '../recovery/store.mjs'
|
|
19
20
|
import {
|
|
20
21
|
PROPOSAL_BACKPRESSURE, PROPOSAL_LEDGER_LIMITS, classifyLedgerRead, classifyStoreRefusal, estimateEventLineBytes, isDue, isExhausted, nextAttemptAt, preflightAppend,
|
|
@@ -168,7 +169,7 @@ export function createProposalAdapterForOracleTests(primitives = PROPOSAL_ADAPTE
|
|
|
168
169
|
// two questions asked of the machine; `proveAbandoned` is the proof a held lock is passed over with.
|
|
169
170
|
return function createProposalAdapter(options = {}) {
|
|
170
171
|
const {
|
|
171
|
-
crash = () => {}, bounds: boundsInput = {}, limits = PROPOSAL_LEDGER_LIMITS, eligibility =
|
|
172
|
+
crash = () => {}, bounds: boundsInput = {}, limits = PROPOSAL_LEDGER_LIMITS, eligibility: fixedEligibility = null,
|
|
172
173
|
openStore = createProposalStore, objectStore = openObjectStore, isGitIgnored = SOURCE_APPLY_PRIMITIVES.isGitIgnored, proveAbandoned = createAbandonmentProof(), queueCrash = () => {},
|
|
173
174
|
} = options
|
|
174
175
|
const bounds = { ...PROPOSAL_BACKPRESSURE, ...boundsInput }
|
|
@@ -184,6 +185,9 @@ export function createProposalAdapterForOracleTests(primitives = PROPOSAL_ADAPTE
|
|
|
184
185
|
let observation = { key: null, run: null }
|
|
185
186
|
// Edits whose operation is known not to be a proposal. A cache: losing it costs one read of an object.
|
|
186
187
|
const notProposals = new Set()
|
|
188
|
+
// Set when an observation found the personal workspace's graph pending: the edits it could not look at are offered
|
|
189
|
+
// again on the next observation, not parked until a full reconciliation.
|
|
190
|
+
let observePendingAgain = false
|
|
187
191
|
|
|
188
192
|
// -- the workspace of one call -------------------------------------------
|
|
189
193
|
|
|
@@ -198,12 +202,31 @@ export function createProposalAdapterForOracleTests(primitives = PROPOSAL_ADAPTE
|
|
|
198
202
|
if (!stores.has(scopeId)) stores.set(scopeId, seams.createRecoveryStore({ workspaceRoot, workspaceId, scopeId, repositoryRoots }))
|
|
199
203
|
return stores.get(scopeId)
|
|
200
204
|
}
|
|
201
|
-
// The canonical graph as it is now and the corpus profile of this machine, built once per call
|
|
205
|
+
// The canonical graph as it is now and the corpus profile of this machine, built once per call with the notes the
|
|
206
|
+
// machine settings let into a view, as the engine builds it (eligibilityFor). Throws typed.
|
|
202
207
|
let corpus = null
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
208
|
+
// A pending answer is kept for the call too, so a call that looks at several edits builds at most once.
|
|
209
|
+
let pendingCorpus = null
|
|
210
|
+
const currentCorpus = () => {
|
|
211
|
+
if (corpus !== null) return corpus
|
|
212
|
+
if (pendingCorpus !== null) throw pendingCorpus
|
|
213
|
+
const machine = readMachineSettings({ workspaceRoot, workspaceId })
|
|
214
|
+
corpus = {
|
|
215
|
+
// The engine hands its deferral over: a personal workspace is then never composed on its event loop here.
|
|
216
|
+
graph: (() => {
|
|
217
|
+
try { return seams.buildGraph({ project, eligibility: fixedEligibility ?? eligibilityFor({ machine, project }), deferPersonalValidation: context.deferPersonalValidation === true }) } catch (error) {
|
|
218
|
+
if (error?.code === PERSONAL_VALIDATION_PENDING) pendingCorpus = error
|
|
219
|
+
throw error
|
|
220
|
+
}
|
|
221
|
+
})(),
|
|
222
|
+
profile: seams.profileFor({ project, workspaceId, audienceAllow: machine?.audienceAllow ?? [] }),
|
|
223
|
+
}
|
|
224
|
+
return corpus
|
|
225
|
+
}
|
|
226
|
+
// Whether the personal workspace's graph is pending on this call. Asked only where a graph would be built anyway.
|
|
227
|
+
const personalPending = () => {
|
|
228
|
+
try { currentCorpus(); return false } catch (error) { if (error?.code === PERSONAL_VALIDATION_PENDING) return true; if (isTyped(error)) return false; throw error }
|
|
229
|
+
}
|
|
207
230
|
// true, false, or null when the canonical graph cannot be read now. The rule is the one source apply asks.
|
|
208
231
|
const visible = options.isVisible ? (identity) => options.isVisible(identity, context) : ({ repoId, nodeId }) => {
|
|
209
232
|
let built
|
|
@@ -223,6 +246,7 @@ export function createProposalAdapterForOracleTests(primitives = PROPOSAL_ADAPTE
|
|
|
223
246
|
return {
|
|
224
247
|
...context, recoveryOf, visible, clock, env: env ?? context.env ?? process.env,
|
|
225
248
|
corpus: currentCorpus,
|
|
249
|
+
personalPending,
|
|
226
250
|
objects: () => (objects ??= objectStore({ stateRoot: workspaceRoot, workspaceId, repositoryRoots, clock })),
|
|
227
251
|
queue,
|
|
228
252
|
managedRoots: () => [workspaceRoot, ...[...stores.values()].map((store) => store.vaultRoot)],
|
|
@@ -304,6 +328,8 @@ export function createProposalAdapterForOracleTests(primitives = PROPOSAL_ADAPTE
|
|
|
304
328
|
if (requireOpenEdit && editState !== 'open') return known ? refused(`edit-${editState}`) : outcome('skipped', null, { code: `edit-${editState}` })
|
|
305
329
|
// The object store no longer says this is a proposed structural edit, so there is nothing to describe.
|
|
306
330
|
if (item.observed === null) return refused('operation-not-proposed')
|
|
331
|
+
// A personal workspace whose graph is pending leaves the operation as it is: no attempt is spent on this tick.
|
|
332
|
+
if (workspace.deferPersonalValidation === true && personalOverlayRepoOf(workspace.project) !== null && workspace.personalPending()) return outcome('deferred', history?.head ?? null, { code: PERSONAL_VALIDATION_PENDING })
|
|
307
333
|
const resolved = resolveProposalRoute({ project: workspace.project, workspaceId: workspace.workspaceId, identity: item, sourcePath: item.sourcePath, managedRoots: workspace.managedRoots(), isVisible: workspace.visible, isGitIgnored, env: env ?? workspace.env ?? process.env })
|
|
308
334
|
if (!resolved.ok && !resolved.transient) return refused(resolved.code)
|
|
309
335
|
// Recorded before anything is asked of the store.
|
|
@@ -432,7 +458,20 @@ export function createProposalAdapterForOracleTests(primitives = PROPOSAL_ADAPTE
|
|
|
432
458
|
async observe(context, { retryRefused = false } = {}) {
|
|
433
459
|
const workspace = open(context)
|
|
434
460
|
const edits = Array.isArray(context.edits) ? context.edits : []
|
|
435
|
-
|
|
461
|
+
// A private note of a personal workspace lives in a generation the personal-workspace module owns: its edit is
|
|
462
|
+
// not observed, recorded or proposed, and stays held in the vault. Answered by name, with nothing written.
|
|
463
|
+
const overlayRepoId = personalOverlayRepoOf(workspace.project)
|
|
464
|
+
const isPrivate = (edit) => overlayRepoId !== null && edit?.identity?.repoId === overlayRepoId
|
|
465
|
+
const privateNotes = edits.filter((edit) => isPrivate(edit) && edit.closedAt === null)
|
|
466
|
+
.map((edit) => ({ editId: edit.editId, repoId: edit.identity.repoId, nodeId: edit.identity.nodeId, status: 'refused', code: 'personal-overlay-not-proposed' }))
|
|
467
|
+
const shared = edits.filter((edit) => !isPrivate(edit))
|
|
468
|
+
// The graph is built only when an edit is looked at, as for any project. When the personal workspace's graph is
|
|
469
|
+
// pending, the edits it reached are not reported or recorded, and are offered again on the next observation.
|
|
470
|
+
const retry = retryRefused || observePendingAgain
|
|
471
|
+
const looked = observation.run(workspace, { edits: shared, retryRefused: retry })
|
|
472
|
+
const pending = looked.filter((item) => item.code === PERSONAL_VALIDATION_PENDING)
|
|
473
|
+
observePendingAgain = pending.length > 0
|
|
474
|
+
return { adapterId: PROPOSAL_ADAPTER_ID, observed: [...privateNotes, ...looked.filter((item) => item.code !== PERSONAL_VALIDATION_PENDING)], ...(pending.length > 0 ? { deferred: PERSONAL_VALIDATION_PENDING } : {}) }
|
|
436
475
|
},
|
|
437
476
|
|
|
438
477
|
// The tick. `context` is { project, workspaceRoot, workspaceId, repositoryRoots, edits }: the pending edit
|
|
@@ -5,7 +5,7 @@ import { compareText, isoTime } from '../../../runtime/obsidian/documents.mjs'
|
|
|
5
5
|
import { readObsidianEnablement } from '../../../runtime/obsidian/enablement.mjs'
|
|
6
6
|
import { ObsidianMaintenanceRefusal } from '../../../runtime/obsidian/errors.mjs'
|
|
7
7
|
import { OPEN_EDIT_STATES, createMaintenanceStateStore } from '../../../runtime/obsidian/state-store.mjs'
|
|
8
|
-
import { OBSIDIAN_EXT_KEY, ObsidianContractRefusal } from '../contracts.mjs'
|
|
8
|
+
import { OBSIDIAN_EXT_KEY, ObsidianContractRefusal, manifestLayoutVersion } from '../contracts.mjs'
|
|
9
9
|
import { SOURCE_APPLY_PRIMITIVES, SourceApplyRefusal, locateSource } from '../edits/apply.mjs'
|
|
10
10
|
import { EditArbitrationRefusal } from '../edits/arbitrate.mjs'
|
|
11
11
|
import { createEditObserverForOracleTests, editIdempotencyKey, observeEdit } from '../edits/observe.mjs'
|
|
@@ -126,22 +126,35 @@ export function createTickObservation(options = {}) {
|
|
|
126
126
|
// The note exactly as it was published, which the lens needs to tell generated bytes from authored ones. The
|
|
127
127
|
// publisher keeps no copy of a note it created, so the note is prepared again from the sources as they are now and
|
|
128
128
|
// used only when it has the digest the manifest recorded; a retained object of that digest serves as well.
|
|
129
|
+
//
|
|
130
|
+
// A source replaced between the look at its path and its open (ELEAFCHANGED) is another program writing it, as it
|
|
131
|
+
// is to the publisher and to source apply: the preparation answers null, and the caller reads the source again and
|
|
132
|
+
// refuses stale-source when it changed. Only a preparation that succeeded is kept for its scope and generation: one
|
|
133
|
+
// failure tells of one moment and is never the answer for the other edits of that generation in the tick.
|
|
129
134
|
function publishedNoteOf(workspace, { scope, manifest, noteEntry }, now) {
|
|
130
135
|
const store = workspace.recoveryOf(scope.scopeId)
|
|
131
136
|
const kept = retained(store, noteEntry.noteDigest)
|
|
132
137
|
if (kept) return kept
|
|
133
138
|
workspace.prepared ??= new Map()
|
|
134
|
-
|
|
135
|
-
|
|
139
|
+
// Prepared in the vault layout of the edit's generation, once per generation.
|
|
140
|
+
const preparedKey = `${scope.scopeId}\u0000${manifest.generationId}`
|
|
141
|
+
if (!workspace.prepared.has(preparedKey)) {
|
|
142
|
+
let files
|
|
136
143
|
try {
|
|
137
144
|
const { graph, profile } = workspace.corpus()
|
|
138
145
|
const snapshot = seams.captureSnapshot({ project: workspace.project, graph, workspaceId: workspace.workspaceId, index: new Map(), configDigest: manifest.ext?.[EXT]?.configDigest ?? `sha256:${'0'.repeat(64)}`, capturedAt: now })
|
|
139
146
|
const persistentPathRegistry = createMaintenanceStateStore({ workspaceRoot: workspace.workspaceRoot, workspaceId: workspace.workspaceId }).readPathRegistry()
|
|
140
|
-
files = seams.prepareView({
|
|
141
|
-
|
|
142
|
-
|
|
147
|
+
files = seams.prepareView({
|
|
148
|
+
snapshot, profile, scope, persistentPathRegistry, priorManifest: manifest, existingSettings: null, clock: workspace.clock,
|
|
149
|
+
vaultRootBytes: Buffer.byteLength(store.vaultRoot, 'utf8'), layout: manifestLayoutVersion(manifest),
|
|
150
|
+
}).files
|
|
151
|
+
} catch (error) {
|
|
152
|
+
if (!isTyped(error) && error?.code !== 'ELEAFCHANGED' && !GONE.has(error?.code)) throw error
|
|
153
|
+
return null
|
|
154
|
+
}
|
|
155
|
+
workspace.prepared.set(preparedKey, files)
|
|
143
156
|
}
|
|
144
|
-
const file = workspace.prepared.get(
|
|
157
|
+
const file = workspace.prepared.get(preparedKey).find((item) => item.path === noteEntry.path && item.digest === noteEntry.noteDigest)
|
|
145
158
|
return file ? file.bytes : null
|
|
146
159
|
}
|
|
147
160
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createRequire } from 'node:module'
|
|
2
|
+
import { PLUGIN_OWNED_PATHS, POLICY_SETTINGS_PATHS } from '../materialize/settings.mjs'
|
|
2
3
|
import { EXCHANGE_CONSTANTS } from './exchange.mjs'
|
|
3
4
|
|
|
4
5
|
// The fixed script that performs one conditional publication. It runs in two
|
|
@@ -26,11 +27,14 @@ const KEYS = {
|
|
|
26
27
|
const isAbsolute = (value) => typeof value === 'string' && value.startsWith('/') && !value.includes('\u0000')
|
|
27
28
|
|
|
28
29
|
// A vault-relative path the publisher may address: visible files only, plus
|
|
29
|
-
// the
|
|
30
|
-
//
|
|
30
|
+
// the settings Atelier owns (the two policy settings files and its own
|
|
31
|
+
// plugin's files). Every other settings path is the person's and cannot be
|
|
32
|
+
// named in a payload at all.
|
|
33
|
+
const ATELIER_OWNED_SETTINGS = new Set([...POLICY_SETTINGS_PATHS, ...PLUGIN_OWNED_PATHS])
|
|
34
|
+
|
|
31
35
|
export function isAddressableVaultPath(value) {
|
|
32
36
|
if (typeof value !== 'string' || value.length === 0 || value.length > 1024 || value.startsWith('/') || value.includes('\\') || value.includes('\u0000')) return false
|
|
33
|
-
if (value
|
|
37
|
+
if (ATELIER_OWNED_SETTINGS.has(value)) return true
|
|
34
38
|
return value.split('/').every((part) => part !== '' && part !== '.' && part !== '..' && !part.startsWith('.'))
|
|
35
39
|
}
|
|
36
40
|
|
|
@@ -43,7 +47,7 @@ export function validatePayload(payload) {
|
|
|
43
47
|
for (const key of Object.keys(payload)) if (!allowed.includes(key)) fail(`unknown key ${key}`)
|
|
44
48
|
for (const key of allowed) if (payload[key] === undefined) fail(`missing key ${key}`)
|
|
45
49
|
if (!isAbsolute(payload.vaultRoot)) fail('vaultRoot must be absolute')
|
|
46
|
-
if (!isAddressableVaultPath(payload.path)) fail('path must be a relative visible path or
|
|
50
|
+
if (!isAddressableVaultPath(payload.path)) fail('path must be a relative visible path or a settings file Atelier owns')
|
|
47
51
|
if (payload.op === 'publish') {
|
|
48
52
|
if (!OPERATION_ID.test(payload.operationId)) fail('operationId required')
|
|
49
53
|
if (!SHA.test(payload.baseSha256)) fail('baseSha256 required')
|
|
@@ -76,7 +80,9 @@ export function criticalSection(P, host) {
|
|
|
76
80
|
const trace = []
|
|
77
81
|
const step = (event, detail) => trace.push({ ms: Number((host.performance.now() - t0).toFixed(3)), event, ...(detail || {}) })
|
|
78
82
|
const crash = (point) => { if (host.crashSeam && host.crashSeam.at === point) host.crashSeam.halt(point) }
|
|
79
|
-
|
|
83
|
+
// As the file system stores the path, except on Windows (see realPathAsStored): an app that holds the vault under
|
|
84
|
+
// another spelling of its folder (a letter case, on a volume that folds it) holds this vault.
|
|
85
|
+
const real = (target) => { try { return host.process.platform !== 'win32' && fs.realpathSync.native ? fs.realpathSync.native(target) : fs.realpathSync(target) } catch (error) { return null } }
|
|
80
86
|
const vaultBasePath = app ? real(app.vault.adapter.getBasePath()) : real(P.vaultRoot)
|
|
81
87
|
const full = nodePath.join(P.vaultRoot, P.path)
|
|
82
88
|
const views = () => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Conditional publication of a prepared view into an editable Obsidian vault.
|
|
2
2
|
export { PROTOCOL_ID, buildEvalCode, createInProcessHost, criticalSection, isAddressableVaultPath, runInProcess, validatePayload } from './bridge-script.mjs'
|
|
3
3
|
export { EXCHANGE_CONSTANTS, ExchangeRefusal, exchangeFiles, probeExchange, resetExchangeProbeCache, resolveExchange } from './exchange.mjs'
|
|
4
|
-
export { TransportTimeout, createDirectAdapter, createEditorAdapter, createInProcessCall, createObsidianCliAdapter, createObsidianCliCall, defaultCliPath, defaultObsidianProcessProbe } from './transport.mjs'
|
|
4
|
+
export { NEUTRAL_DIRECTORY, TransportTimeout, createDirectAdapter, createEditorAdapter, createInProcessCall, createObsidianCliAdapter, createObsidianCliCall, defaultCliPath, defaultObsidianProcessProbe, publicationRoute } from './transport.mjs'
|
|
5
|
+
export { MAX_OBSIDIAN_SETTINGS_BYTES, OBSIDIAN_SETTINGS_FILE, enclosingVaults, findVaultEntry, obsidianSandboxedBuild, obsidianUserDataDir, readObsidianSettings, vaultRoute } from './vault-list.mjs'
|
|
5
6
|
export { publishView } from './publisher.mjs'
|