@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,444 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Atelier's own plugin. Atelier ships it into every vault it manages, under
|
|
4
|
+
// .obsidian/plugins/atelier-projection/, beside a data file that names the
|
|
5
|
+
// maintenance service of the workspace and this vault's key (its bearer). The
|
|
6
|
+
// person never installs it; Obsidian asks once per vault whether to trust the
|
|
7
|
+
// vault's plugins, and until then (or in restricted mode, or on an app older
|
|
8
|
+
// than 1.13.7) everything works without it.
|
|
9
|
+
//
|
|
10
|
+
// Phase 1: presence and status, read-only. While the vault is open the plugin
|
|
11
|
+
// tells the service so (a lease renewed every two seconds, released when the
|
|
12
|
+
// plugin unloads), reports the app version it runs in, and shows the view's
|
|
13
|
+
// freshness in the status bar and in "Atelier: show status".
|
|
14
|
+
//
|
|
15
|
+
// The key never leaves this machine's files. The plugin first asks whatever
|
|
16
|
+
// listens at the service's address to prove that it holds the key, and sends
|
|
17
|
+
// nothing that names this vault until it did; then it proves the same, and
|
|
18
|
+
// every later request and answer is sealed with a key for that session only.
|
|
19
|
+
//
|
|
20
|
+
// What it never does: write a file (a note, a setting, its own data file),
|
|
21
|
+
// run code it is sent, or reach anything but that one service, on a literal
|
|
22
|
+
// loopback address, with no name to resolve.
|
|
23
|
+
|
|
24
|
+
const obsidian = require('obsidian')
|
|
25
|
+
|
|
26
|
+
// Held equal to src/projection/obsidian/plugin-bridge/channel.mjs by the test suite.
|
|
27
|
+
const CHANNEL = Object.freeze({
|
|
28
|
+
pluginId: 'atelier-projection',
|
|
29
|
+
protocol: 'atelier-obsidian-plugin-channel/v2',
|
|
30
|
+
dataSchema: 'atelier-obsidian-plugin-data/v1',
|
|
31
|
+
statusSchema: 'atelier-obsidian-plugin-status/v1',
|
|
32
|
+
routes: Object.freeze({ challenge: '/plugin/challenge', hello: '/plugin/hello', lease: '/plugin/lease', release: '/plugin/release', status: '/plugin/status' }),
|
|
33
|
+
renewEveryMs: 2000,
|
|
34
|
+
requestTimeoutMs: 1500,
|
|
35
|
+
maxResponseBytes: 64 * 1024,
|
|
36
|
+
minimumAppVersion: '1.13.7',
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const BEARER = /^[A-Za-z0-9_-]{43}$/
|
|
40
|
+
const IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/
|
|
41
|
+
const NONCE = /^[0-9a-f]{64}$/
|
|
42
|
+
const MAC = /^[0-9a-f]{64}$/
|
|
43
|
+
const HANDSHAKE_ID = /^ph-[0-9a-f]{32}$/
|
|
44
|
+
const SESSION_ID = /^ps-[0-9a-f]{32}$/
|
|
45
|
+
const VERSION = /^v?(\d{1,9})\.(\d{1,9})\.(\d{1,9})(?:-([0-9A-Za-z.]+))?/
|
|
46
|
+
|
|
47
|
+
// -1, 0 or 1; null when either side is not a version. A prerelease ranks below its release.
|
|
48
|
+
function compareVersions(left, right) {
|
|
49
|
+
const [a, b] = [VERSION.exec(String(left || '')), VERSION.exec(String(right || ''))]
|
|
50
|
+
if (!a || !b) return null
|
|
51
|
+
for (let index = 1; index <= 3; index += 1) if (Number(a[index]) !== Number(b[index])) return Number(a[index]) < Number(b[index]) ? -1 : 1
|
|
52
|
+
if (Boolean(a[4]) === Boolean(b[4])) return a[4] === b[4] || !a[4] ? 0 : a[4] < b[4] ? -1 : 1
|
|
53
|
+
return a[4] ? -1 : 1
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function meetsFloor(version) {
|
|
57
|
+
const order = compareVersions(version, CHANNEL.minimumAppVersion)
|
|
58
|
+
return order !== null && order >= 0
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const isPlainObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
62
|
+
|
|
63
|
+
// The handshake and session computations of plugin-bridge/channel.mjs; the
|
|
64
|
+
// test suite holds the two to each other. Every input but the vault path is a
|
|
65
|
+
// shape without a line break, and the vault path is the only input of its
|
|
66
|
+
// computation, so joining them by lines is unambiguous.
|
|
67
|
+
function transcript(label, fields) {
|
|
68
|
+
return [CHANNEL.protocol, label].concat(fields.map(String)).join('\n')
|
|
69
|
+
}
|
|
70
|
+
function hmac(crypto, key, label, fields) {
|
|
71
|
+
return crypto.createHmac('sha256', key).update(transcript(label, fields), 'utf8').digest()
|
|
72
|
+
}
|
|
73
|
+
function hmacHex(crypto, key, label, fields) {
|
|
74
|
+
return hmac(crypto, key, label, fields).toString('hex')
|
|
75
|
+
}
|
|
76
|
+
// Two MACs in hex, compared in time that does not depend on where they differ.
|
|
77
|
+
function sameMac(presented, expected) {
|
|
78
|
+
if (typeof presented !== 'string' || !MAC.test(presented) || presented.length !== expected.length) return false
|
|
79
|
+
let difference = 0
|
|
80
|
+
for (let index = 0; index < expected.length; index += 1) difference |= presented.charCodeAt(index) ^ expected.charCodeAt(index)
|
|
81
|
+
return difference === 0
|
|
82
|
+
}
|
|
83
|
+
// The exact address the service is reached at, as both proofs bind it.
|
|
84
|
+
const authorityOf = (channel) => (channel.host === '::1' ? `[::1]:${channel.port}` : `127.0.0.1:${channel.port}`)
|
|
85
|
+
|
|
86
|
+
// The channel this vault's data file names, or null when it names none that can be used.
|
|
87
|
+
function channelOf(data) {
|
|
88
|
+
if (!isPlainObject(data) || data.schema !== CHANNEL.dataSchema || !isPlainObject(data.channel)) return null
|
|
89
|
+
const { host, port } = data.channel
|
|
90
|
+
if (host !== '127.0.0.1' && host !== '::1') return null
|
|
91
|
+
if (!Number.isInteger(port) || port < 1024 || port > 65535) return null
|
|
92
|
+
if (typeof data.scopeId !== 'string' || !IDENTIFIER.test(data.scopeId) || typeof data.bearer !== 'string' || !BEARER.test(data.bearer)) return null
|
|
93
|
+
return Object.freeze({ host, port, scopeId: data.scopeId, bearer: data.bearer })
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// What the status bar says. `held` carries the number of held edits.
|
|
97
|
+
const LABELS = Object.freeze({
|
|
98
|
+
connecting: 'Atelier: connecting',
|
|
99
|
+
current: 'Atelier: current',
|
|
100
|
+
updating: 'Atelier: updating',
|
|
101
|
+
stale: 'Atelier: stale',
|
|
102
|
+
unreachable: 'Atelier: service unreachable',
|
|
103
|
+
'not-set-up': 'Atelier: not set up',
|
|
104
|
+
unsupported: 'Atelier: needs a newer Obsidian',
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
function labelOf(view) {
|
|
108
|
+
return view.state === 'held' ? `Atelier: held (${view.held})` : LABELS[view.state]
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const plural = (count, one, many) => (count === 1 ? one : many)
|
|
112
|
+
|
|
113
|
+
// The two ways a round can fail to reach the view. Between them the status bar moves only once two rounds agree.
|
|
114
|
+
const ROUND_FAILURES = new Set(['not-set-up', 'unreachable'])
|
|
115
|
+
|
|
116
|
+
// Notices on a transition into a state that needs a person, and back out of one.
|
|
117
|
+
const ATTENTION = Object.freeze({
|
|
118
|
+
held: (view) => `Atelier kept ${plural(view.held, 'an edit', `${view.held} edits`)} you made. This view is not updated over ${plural(view.held, 'it', 'them')} until ${plural(view.held, 'it is', 'they are')} applied or withdrawn.`,
|
|
119
|
+
stale: () => 'Atelier: this view is not current. "Atelier: show status" says why.',
|
|
120
|
+
unreachable: () => 'Atelier: the maintenance service does not answer. The vault stays as it is.',
|
|
121
|
+
unsupported: () => `Atelier's plugin needs Obsidian ${CHANNEL.minimumAppVersion} or later. The vault keeps working without it.`,
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
// The view as the service reports it. Anything but current, updating or held is stale.
|
|
125
|
+
function viewOfStatus(body) {
|
|
126
|
+
const view = isPlainObject(body) && body.schema === CHANNEL.statusSchema && isPlainObject(body.view) ? body.view : null
|
|
127
|
+
const common = { reason: view && typeof view.reason === 'string' ? view.reason : 'no-freshness-recorded', report: isPlainObject(body) ? body : null }
|
|
128
|
+
if (view === null) return { state: 'stale', ...common }
|
|
129
|
+
if (view.state === 'current') return { state: 'current', ...common }
|
|
130
|
+
if (view.state === 'updating') return { state: 'updating', ...common }
|
|
131
|
+
if (view.state === 'held-for-your-edit') return { state: 'held', held: Number.isInteger(view.heldNoteCount) ? view.heldNoteCount : 0, ...common }
|
|
132
|
+
return { state: 'stale', ...common }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const readable = (code) => (typeof code === 'string' && code !== '' ? code.replace(/[-_]+/g, ' ') : 'none')
|
|
136
|
+
const byteLength = (text) => new TextEncoder().encode(text).length
|
|
137
|
+
|
|
138
|
+
// One request to the service. Resolves, never rejects:
|
|
139
|
+
// { kind: 'response', statusCode, body } body is a JSON object or null
|
|
140
|
+
// { kind: 'unreachable', code } nothing usable came back
|
|
141
|
+
function post(http, channel, route, body) {
|
|
142
|
+
return new Promise((resolve) => {
|
|
143
|
+
let settled = false
|
|
144
|
+
const settle = (value) => { if (!settled) { settled = true; resolve(value) } }
|
|
145
|
+
const text = JSON.stringify(body)
|
|
146
|
+
const authority = authorityOf(channel)
|
|
147
|
+
let request
|
|
148
|
+
try {
|
|
149
|
+
// A literal loopback address, whatever the data file said: nothing is resolved by name.
|
|
150
|
+
request = http.request({ host: channel.host === '::1' ? '::1' : '127.0.0.1', family: channel.host === '::1' ? 6 : 4, port: channel.port, method: 'POST', path: route, agent: false, timeout: CHANNEL.requestTimeoutMs,
|
|
151
|
+
headers: { Host: authority, 'Content-Type': 'application/json', 'Content-Length': byteLength(text), Connection: 'close' } }, (response) => {
|
|
152
|
+
let size = 0
|
|
153
|
+
let received = ''
|
|
154
|
+
response.setEncoding('utf8')
|
|
155
|
+
response.on('data', (chunk) => {
|
|
156
|
+
size += chunk.length
|
|
157
|
+
if (size > CHANNEL.maxResponseBytes) { settle({ kind: 'unreachable', code: 'answer-too-large' }); request.destroy() } else received += chunk
|
|
158
|
+
})
|
|
159
|
+
response.on('end', () => {
|
|
160
|
+
let parsed = null
|
|
161
|
+
try { parsed = JSON.parse(received) } catch { parsed = null }
|
|
162
|
+
settle({ kind: 'response', statusCode: response.statusCode, body: isPlainObject(parsed) ? parsed : null })
|
|
163
|
+
})
|
|
164
|
+
response.on('error', () => settle({ kind: 'unreachable', code: 'answer-failed' }))
|
|
165
|
+
})
|
|
166
|
+
} catch {
|
|
167
|
+
settle({ kind: 'unreachable', code: 'request-failed' })
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
request.on('timeout', () => { settle({ kind: 'unreachable', code: 'timeout' }); request.destroy() })
|
|
171
|
+
request.on('error', (error) => settle({ kind: 'unreachable', code: error && error.code === 'ECONNREFUSED' ? 'refused' : 'request-failed' }))
|
|
172
|
+
request.end(text)
|
|
173
|
+
})
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
class AtelierStatusModal extends obsidian.Modal {
|
|
177
|
+
constructor(app, rows) {
|
|
178
|
+
super(app)
|
|
179
|
+
this.rows = rows
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
onOpen() {
|
|
183
|
+
this.setTitle('Atelier status')
|
|
184
|
+
const list = this.contentEl.createEl('dl', { cls: 'atelier-projection-status' })
|
|
185
|
+
for (const [label, value] of this.rows) {
|
|
186
|
+
list.createEl('dt', { text: label })
|
|
187
|
+
list.createEl('dd', { text: value })
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
onClose() {
|
|
192
|
+
this.contentEl.empty()
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
class AtelierProjectionPlugin extends obsidian.Plugin {
|
|
197
|
+
async onload() {
|
|
198
|
+
this.channel = null
|
|
199
|
+
this.session = null
|
|
200
|
+
this.cycling = null
|
|
201
|
+
this.unloaded = false
|
|
202
|
+
this.view = { state: 'connecting', reason: 'not-yet-asked', report: null }
|
|
203
|
+
this.shownState = null
|
|
204
|
+
// A round's failure that differs from the failure shown, not yet seen twice in a row.
|
|
205
|
+
this.pendingFailure = null
|
|
206
|
+
this.appVersion = typeof obsidian.apiVersion === 'string' ? obsidian.apiVersion : null
|
|
207
|
+
this.statusBarEl = this.addStatusBarItem()
|
|
208
|
+
this.statusBarEl.addClass('atelier-projection-status-bar')
|
|
209
|
+
this.registerDomEvent(this.statusBarEl, 'click', () => this.showStatus())
|
|
210
|
+
this.addCommand({ id: 'show-status', name: 'Show status', callback: () => this.showStatus() })
|
|
211
|
+
this.setView(this.view)
|
|
212
|
+
|
|
213
|
+
if (!meetsFloor(this.appVersion)) {
|
|
214
|
+
// Older than the floor, or a version that cannot be read: visible, and the channel stays closed.
|
|
215
|
+
this.setView({ state: 'unsupported', reason: 'app-below-minimum-version', report: null })
|
|
216
|
+
return
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
this.http = require('http')
|
|
220
|
+
this.fs = require('fs')
|
|
221
|
+
this.crypto = require('crypto')
|
|
222
|
+
} catch {
|
|
223
|
+
this.http = null
|
|
224
|
+
}
|
|
225
|
+
if (!this.http || typeof this.http.request !== 'function' || !this.fs || typeof this.fs.realpathSync !== 'function' || !this.crypto || typeof this.crypto.createHmac !== 'function' || typeof this.crypto.randomBytes !== 'function') {
|
|
226
|
+
this.setView({ state: 'not-set-up', reason: 'node-modules-unavailable', report: null })
|
|
227
|
+
return
|
|
228
|
+
}
|
|
229
|
+
// This launch of the plugin: the service tells two apps holding the same vault apart by it.
|
|
230
|
+
this.instanceId = `pi-${this.crypto.randomBytes(16).toString('hex')}`
|
|
231
|
+
await this.readChannel()
|
|
232
|
+
this.registerInterval(globalThis.setInterval(() => { void this.cycle() }, CHANNEL.renewEveryMs))
|
|
233
|
+
// Not awaited: the app finishes loading while the first round trip is under way.
|
|
234
|
+
void this.cycle()
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
onunload() {
|
|
238
|
+
// The lease lapses by itself; releasing it says at once that the vault closed. A round still under way stops at its
|
|
239
|
+
// next step, and a session it opens after this is released at once.
|
|
240
|
+
this.unloaded = true
|
|
241
|
+
const session = this.session
|
|
242
|
+
this.session = null
|
|
243
|
+
if (this.channel && session) void this.release(this.channel, session)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Obsidian calls this when data.json changed on disk: Atelier republished the channel.
|
|
247
|
+
async onExternalSettingsChange() {
|
|
248
|
+
await this.readChannel()
|
|
249
|
+
// A round under way still speaks for the old channel; the next one uses the new.
|
|
250
|
+
if (this.cycling) await this.cycling
|
|
251
|
+
await this.cycle()
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async readChannel() {
|
|
255
|
+
let data = null
|
|
256
|
+
try { data = await this.loadData() } catch { data = null }
|
|
257
|
+
const next = channelOf(data)
|
|
258
|
+
const same = next && this.channel && next.host === this.channel.host && next.port === this.channel.port && next.scopeId === this.channel.scopeId && next.bearer === this.channel.bearer
|
|
259
|
+
if (!same) this.session = null
|
|
260
|
+
this.channel = next
|
|
261
|
+
if (next === null) this.setView({ state: 'not-set-up', reason: data === null ? 'no-channel-data' : 'channel-data-unusable', report: null })
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// One round: shake hands (once per session), renew the lease, read the status.
|
|
265
|
+
cycle() {
|
|
266
|
+
if (this.cycling) return this.cycling
|
|
267
|
+
this.cycling = this.runCycle().finally(() => { this.cycling = null })
|
|
268
|
+
return this.cycling
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Whether a round that started for `channel` may still act.
|
|
272
|
+
current(channel) {
|
|
273
|
+
return !this.unloaded && channel === this.channel
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
async runCycle() {
|
|
277
|
+
const channel = this.channel
|
|
278
|
+
if (channel === null || this.unloaded) return
|
|
279
|
+
if (this.session === null) {
|
|
280
|
+
if (!(await this.handshake(channel))) return
|
|
281
|
+
} else {
|
|
282
|
+
const lease = await this.request(channel, 'lease')
|
|
283
|
+
if (!this.current(channel)) return
|
|
284
|
+
if (lease.kind !== 'sealed') {
|
|
285
|
+
// Whatever answered did not seal its answer with the session's key: the session ends here, and the next request
|
|
286
|
+
// starts a handshake, which only the service can answer. An unproven listener gets no second request of it.
|
|
287
|
+
this.session = null
|
|
288
|
+
if (!(lease.kind === 'refused' && (lease.error === 'session-unknown' || lease.statusCode === 401))) {
|
|
289
|
+
this.showRound(this.unreachable(lease))
|
|
290
|
+
return
|
|
291
|
+
}
|
|
292
|
+
// The service started again since, the vault's key changed, or the session is not accepted: shake hands at once.
|
|
293
|
+
if (!(await this.handshake(channel))) return
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
const status = await this.request(channel, 'status')
|
|
297
|
+
if (!this.current(channel)) return
|
|
298
|
+
if (status.kind !== 'sealed') this.session = null
|
|
299
|
+
this.showRound(status.kind === 'sealed' ? viewOfStatus(status.document) : this.unreachable(status))
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// The handshake. Nothing that names this vault is sent before the listener proved it holds the vault's key.
|
|
303
|
+
async handshake(channel) {
|
|
304
|
+
let vaultPath = null
|
|
305
|
+
// As the file system stores the path, as the service proves it: the app may have the vault in another letter case.
|
|
306
|
+
// On Windows Node's own resolution, as the service's (the native one also expands short names).
|
|
307
|
+
const native = globalThis.process?.platform !== 'win32' && typeof this.fs.realpathSync.native === 'function'
|
|
308
|
+
try { vaultPath = native ? this.fs.realpathSync.native(this.app.vault.adapter.getBasePath()) : this.fs.realpathSync(this.app.vault.adapter.getBasePath()) } catch { vaultPath = null }
|
|
309
|
+
if (typeof vaultPath !== 'string') {
|
|
310
|
+
this.showRound({ state: 'not-set-up', reason: 'vault-path-unknown', report: null })
|
|
311
|
+
return false
|
|
312
|
+
}
|
|
313
|
+
const crypto = this.crypto
|
|
314
|
+
const clientNonce = crypto.randomBytes(32).toString('hex')
|
|
315
|
+
const issuedAt = Date.now()
|
|
316
|
+
const challenge = await post(this.http, channel, CHANNEL.routes.challenge, { protocol: CHANNEL.protocol, keyHint: hmacHex(crypto, channel.bearer, 'key-hint', [clientNonce, issuedAt]), clientNonce, issuedAt })
|
|
317
|
+
if (!this.current(channel)) return false
|
|
318
|
+
const offer = challenge.kind === 'response' && challenge.statusCode === 200 ? challenge.body : null
|
|
319
|
+
if (offer === null) {
|
|
320
|
+
// A 401 is a key the service does not know, unless the service says the challenge itself came too late or was
|
|
321
|
+
// answered already: the key is not in question then, and the next round's fresh challenge tries again.
|
|
322
|
+
const refusal = challenge.kind === 'response' && challenge.body ? challenge.body.error : null
|
|
323
|
+
const keyUnknown = challenge.kind === 'response' && challenge.statusCode === 401 && refusal !== 'challenge-stale' && refusal !== 'challenge-replayed'
|
|
324
|
+
this.showRound(keyUnknown ? { state: 'not-set-up', reason: 'key-not-known-to-the-service', report: null } : this.unreachable(challenge))
|
|
325
|
+
return false
|
|
326
|
+
}
|
|
327
|
+
const bound = [channel.scopeId, authorityOf(channel), clientNonce, offer.serverNonce, offer.handshakeId]
|
|
328
|
+
if (offer.protocol !== CHANNEL.protocol || typeof offer.handshakeId !== 'string' || !HANDSHAKE_ID.test(offer.handshakeId) || typeof offer.serverNonce !== 'string' || !NONCE.test(offer.serverNonce)
|
|
329
|
+
|| !sameMac(offer.serverProof, hmacHex(crypto, channel.bearer, 'server-proof', bound))) {
|
|
330
|
+
// Whatever answers there does not hold this vault's key: it is told nothing more.
|
|
331
|
+
this.showRound({ state: 'unreachable', reason: 'listener-not-proven', report: null })
|
|
332
|
+
return false
|
|
333
|
+
}
|
|
334
|
+
const key = hmac(crypto, channel.bearer, 'session-key', bound)
|
|
335
|
+
const vaultProof = hmacHex(crypto, key, 'vault', [vaultPath])
|
|
336
|
+
const pluginVersion = String(this.manifest.version)
|
|
337
|
+
const clientProof = hmacHex(crypto, channel.bearer, 'client-proof', bound.concat([pluginVersion, this.appVersion, this.instanceId, vaultProof]))
|
|
338
|
+
const answer = await post(this.http, channel, CHANNEL.routes.hello, { handshakeId: offer.handshakeId, pluginVersion, appVersion: this.appVersion, instanceId: this.instanceId, vaultProof, clientProof })
|
|
339
|
+
const sealed = this.opened(answer, 'hello', { key, id: null }, 0)
|
|
340
|
+
if (sealed.kind === 'sealed') {
|
|
341
|
+
const session = { id: sealed.sessionId, key, counter: 0 }
|
|
342
|
+
if (!this.current(channel)) {
|
|
343
|
+
// Unloaded, or a new channel, while the hello was under way: the session it opened is let go at once.
|
|
344
|
+
void this.release(channel, session)
|
|
345
|
+
return false
|
|
346
|
+
}
|
|
347
|
+
this.session = session
|
|
348
|
+
return true
|
|
349
|
+
}
|
|
350
|
+
if (!this.current(channel)) return false
|
|
351
|
+
// A copy of a vault carries its data file, but the service maintains the original only.
|
|
352
|
+
if (sealed.kind === 'refused' && sealed.statusCode === 409 && sealed.error === 'wrong-vault') this.showRound({ state: 'not-set-up', reason: 'not-the-vault-atelier-maintains', report: null })
|
|
353
|
+
else this.showRound(this.unreachable(sealed))
|
|
354
|
+
return false
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// One command of the session: a counter that only goes up, and a MAC over it under the session's key.
|
|
358
|
+
request(channel, command) {
|
|
359
|
+
const session = this.session
|
|
360
|
+
session.counter += 1
|
|
361
|
+
const counter = session.counter
|
|
362
|
+
return post(this.http, channel, CHANNEL.routes[command], { sessionId: session.id, counter, mac: hmacHex(this.crypto, session.key, 'request', [command, session.id, counter]) })
|
|
363
|
+
.then((answer) => this.opened(answer, command, session, counter))
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
release(channel, session) {
|
|
367
|
+
session.counter += 1
|
|
368
|
+
return post(this.http, channel, CHANNEL.routes.release, { sessionId: session.id, counter: session.counter, mac: hmacHex(this.crypto, session.key, 'request', ['release', session.id, session.counter]) })
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// An answer counts only when it is sealed with the session's key over this very request:
|
|
372
|
+
// { kind: 'sealed', document, sessionId } the service's own answer
|
|
373
|
+
// { kind: 'refused', statusCode, error } an error; nobody vouches for it, so it only ever makes the plugin ask again
|
|
374
|
+
// { kind: 'unreachable', code } nothing usable came back
|
|
375
|
+
opened(answer, command, session, counter) {
|
|
376
|
+
if (answer.kind !== 'response') return answer
|
|
377
|
+
const body = answer.body
|
|
378
|
+
if (answer.statusCode !== 200) return { kind: 'refused', statusCode: answer.statusCode, error: body && typeof body.error === 'string' ? body.error : null }
|
|
379
|
+
let document = null
|
|
380
|
+
try { document = body && typeof body.payload === 'string' ? JSON.parse(body.payload) : null } catch { document = null }
|
|
381
|
+
// A hello's answer names the session it opened; the MAC over it is what vouches for that name.
|
|
382
|
+
const sessionId = command === 'hello' ? (isPlainObject(document) && typeof document.sessionId === 'string' && SESSION_ID.test(document.sessionId) ? document.sessionId : null) : session.id
|
|
383
|
+
if (!isPlainObject(document) || sessionId === null || !sameMac(body.mac, hmacHex(this.crypto, session.key, 'response', [command, sessionId, counter, body.payload]))) return { kind: 'unreachable', code: 'answer-not-authenticated' }
|
|
384
|
+
return { kind: 'sealed', document, sessionId }
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
unreachable(answer) {
|
|
388
|
+
const reason = answer.kind === 'unreachable' ? answer.code : typeof answer.error === 'string' ? answer.error : answer.body && typeof answer.body.error === 'string' ? answer.body.error : `answered-${answer.statusCode}`
|
|
389
|
+
return { state: 'unreachable', reason, report: null }
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// What a round found. A failure other than the one shown ('not set up' where 'service unreachable' is shown, or the other
|
|
393
|
+
// way round) is shown only when the next round finds it too, so answers that alternate between them do not make the
|
|
394
|
+
// status bar flip. Anything else is shown at once.
|
|
395
|
+
showRound(view) {
|
|
396
|
+
if (ROUND_FAILURES.has(view.state) && ROUND_FAILURES.has(this.shownState) && view.state !== this.shownState && this.pendingFailure !== view.state) {
|
|
397
|
+
this.pendingFailure = view.state
|
|
398
|
+
return
|
|
399
|
+
}
|
|
400
|
+
this.setView(view)
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
setView(view) {
|
|
404
|
+
// Nothing is shown once the plugin unloaded.
|
|
405
|
+
if (this.unloaded) return
|
|
406
|
+
this.pendingFailure = null
|
|
407
|
+
const previous = this.shownState
|
|
408
|
+
this.view = view
|
|
409
|
+
this.statusBarEl.setText(labelOf(view))
|
|
410
|
+
this.statusBarEl.setAttr('aria-label', `${labelOf(view)} (${readable(view.reason)})`)
|
|
411
|
+
this.shownState = view.state
|
|
412
|
+
if (previous === view.state || previous === null) return
|
|
413
|
+
if (Object.prototype.hasOwnProperty.call(ATTENTION, view.state)) new obsidian.Notice(ATTENTION[view.state](view))
|
|
414
|
+
else if (view.state === 'current' && Object.prototype.hasOwnProperty.call(ATTENTION, previous)) new obsidian.Notice('Atelier: this view is current again.')
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
statusRows() {
|
|
418
|
+
const report = this.view.report || {}
|
|
419
|
+
const view = isPlainObject(report.view) ? report.view : {}
|
|
420
|
+
const count = (value) => (Number.isInteger(value) ? String(value) : 'unknown')
|
|
421
|
+
const channel = this.channel
|
|
422
|
+
return [
|
|
423
|
+
['View', channel ? channel.scopeId : 'not set up'],
|
|
424
|
+
['State', labelOf(this.view).replace(/^Atelier: /, '')],
|
|
425
|
+
['Reason', readable(this.view.reason)],
|
|
426
|
+
['Generation', typeof view.generationId === 'string' ? view.generationId : 'none yet'],
|
|
427
|
+
['Prepared generation', typeof view.preparedGenerationId === 'string' ? view.preparedGenerationId : 'none yet'],
|
|
428
|
+
['Checked at', typeof view.checkedAt === 'string' ? view.checkedAt : 'not yet'],
|
|
429
|
+
['Held edits', count(view.heldNoteCount)],
|
|
430
|
+
['Retained edits', count(view.retainedEdits)],
|
|
431
|
+
['Pending edits', count(isPlainObject(report.pendingEdits) ? report.pendingEdits.open : null)],
|
|
432
|
+
['Service', channel ? `${channel.host === '::1' ? '[::1]' : '127.0.0.1'}:${channel.port}, ${isPlainObject(report.service) && typeof report.service.status === 'string' ? report.service.status : 'no answer'}` : 'not set up'],
|
|
433
|
+
['Plugin', String(this.manifest.version)],
|
|
434
|
+
['Obsidian', this.appVersion || 'unknown'],
|
|
435
|
+
]
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
showStatus() {
|
|
439
|
+
new AtelierStatusModal(this.app, this.statusRows()).open()
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
AtelierProjectionPlugin.channel = CHANNEL
|
|
444
|
+
module.exports = AtelierProjectionPlugin
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "atelier-projection",
|
|
3
|
+
"name": "Atelier",
|
|
4
|
+
"version": "1.1.1",
|
|
5
|
+
"minAppVersion": "1.13.7",
|
|
6
|
+
"description": "Shows whether this Atelier view is current and tells Atelier's maintenance service that the vault is open. Shipped by Atelier into the vaults it manages.",
|
|
7
|
+
"author": "MNSTRY",
|
|
8
|
+
"isDesktopOnly": true
|
|
9
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/* Atelier's plugin: the status bar item and the status modal. */
|
|
2
|
+
|
|
3
|
+
.atelier-projection-status-bar {
|
|
4
|
+
cursor: pointer;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.atelier-projection-status {
|
|
8
|
+
display: grid;
|
|
9
|
+
grid-template-columns: max-content 1fr;
|
|
10
|
+
gap: var(--size-4-1) var(--size-4-4);
|
|
11
|
+
margin: 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.atelier-projection-status dt {
|
|
15
|
+
color: var(--text-muted);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.atelier-projection-status dd {
|
|
19
|
+
margin: 0;
|
|
20
|
+
font-variant-numeric: tabular-nums;
|
|
21
|
+
overflow-wrap: anywhere;
|
|
22
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atelier-build-harness
|
|
3
|
+
description: Turn an accepted objective into a bounded, evidence-backed deliverable with candidate custody, dependencies, verification gates, recovery and delivery acceptance. Use for implementation and cross-repository delivery coordination.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build Harness
|
|
7
|
+
|
|
8
|
+
People establish the objective and acceptance criteria; agents implement admitted
|
|
9
|
+
work; owners review consequential decisions and actual delivery. Coordinate with
|
|
10
|
+
the user's existing coding, testing, review and CI tools. Fabric may consume the
|
|
11
|
+
coordination proposal; creating that proposal does not enroll or wake an owner.
|
|
12
|
+
|
|
13
|
+
## Bound the work
|
|
14
|
+
|
|
15
|
+
Establish purpose, owner, scope, acceptance criteria, required gates, admitted
|
|
16
|
+
effects, attempt budget and stopping rule. A dependency names the exact producer
|
|
17
|
+
artifact and the receiving need. Shared initiative membership creates no dependency
|
|
18
|
+
or authority. Keep independent work moving while a concrete prerequisite is absent.
|
|
19
|
+
|
|
20
|
+
Use `atelier harness build` and `@mnstry/atelier/build`, with the shared
|
|
21
|
+
`@mnstry/atelier/harnesses` records. `atelier build` retains its older projection
|
|
22
|
+
meaning. The reference example has simulated reviews and CI: never reuse its
|
|
23
|
+
approval reports as real evidence. If tooling is missing, prepare a plan and report
|
|
24
|
+
the gap without fabricating execution.
|
|
25
|
+
|
|
26
|
+
## Implement and verify
|
|
27
|
+
|
|
28
|
+
Reserve an isolated writer lane or follow the repository's existing custody
|
|
29
|
+
mechanism. Preserve local edits and do not claim another task's ownership.
|
|
30
|
+
Implement against the admitted inputs. Use existing tools to run appropriate
|
|
31
|
+
tests and actual review/CI workflows only within the task's authority.
|
|
32
|
+
|
|
33
|
+
The read-only Git adapter binds clean committed source and selected artifact bytes.
|
|
34
|
+
A writer declaration remains caller-reported. Record the exact commit, tree,
|
|
35
|
+
artifact digest, skill binding and evidence; a changed candidate needs new proof.
|
|
36
|
+
|
|
37
|
+
Persist an attempt intent before invoking an external executor. These records do
|
|
38
|
+
not invoke tools. On uncertain dispatch, preserve its identity and reconcile the
|
|
39
|
+
existing attempt before retrying. A completed transport or command does not satisfy
|
|
40
|
+
a review or CI gate. Keep unavailable, failed and passed evidence distinct.
|
|
41
|
+
|
|
42
|
+
## Integrate and return learning
|
|
43
|
+
|
|
44
|
+
Evaluate the current candidate, every required gate and current dependency
|
|
45
|
+
snapshots. Report missing evidence and candidate changes without treating stale
|
|
46
|
+
receipts as current. Review, CI, integration, delivery and recipient acceptance
|
|
47
|
+
remain distinct. Record only the actual owner's decision and observed delivery.
|
|
48
|
+
The harness reports consistency; repository and host controls enforce authority.
|
|
49
|
+
|
|
50
|
+
Prepare a coordination proposal for the existing owner/coordinator. Do not create
|
|
51
|
+
tasks, send messages, publish or deploy from a manifest alone. Emit an accepted
|
|
52
|
+
artifact handoff to Knowledge Harness, preserving assumptions, limitations and
|
|
53
|
+
the evidence behind the result. Research quality or business usefulness cannot
|
|
54
|
+
be inferred from a successful build.
|
|
55
|
+
|
|
56
|
+
When an upstream source changes, refresh dependency snapshots and prepare the
|
|
57
|
+
affected decisions for reconsideration. Route observed skill, tool, host, context
|
|
58
|
+
or provider problems through version-bound Steward feedback. Preserve unknown
|
|
59
|
+
causes and adopter consent; do not automatically rewrite or upgrade skills.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atelier-coordination
|
|
3
|
+
description: Coordinate bounded outcomes across repositories using exact producer and receiver references, independent gates, directive dispositions and retained recovery history.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Portable Coordination
|
|
7
|
+
|
|
8
|
+
Name the outcome, integration owner, scope, exact candidate or artifact, receiving
|
|
9
|
+
need, next action and forecast. Discover the existing native source of each fact.
|
|
10
|
+
Reuse Build, Harness and repository coordination records rather than starting a
|
|
11
|
+
parallel approval system. Local operation does not require a Fabric service.
|
|
12
|
+
|
|
13
|
+
Use the installed Coordination contracts for bounded outcome, dependency,
|
|
14
|
+
directive, disposition and recovery observations. Preserve source references,
|
|
15
|
+
observation time and expiry. Missing, stale, changed or future-dated observations
|
|
16
|
+
cannot become fresh merely because a dashboard can render them. Detect dependency
|
|
17
|
+
cycles and keep receiving acceptance separate from producer source completion.
|
|
18
|
+
|
|
19
|
+
Bind each gate to its candidate. Tests, independent review, CI, merge, deployment,
|
|
20
|
+
activation and recipient acceptance retain separate evidence and authority.
|
|
21
|
+
A reported waiver is not a passed test. A receipt reference is not authenticated
|
|
22
|
+
verification. Use native verification where acceptance depends on that receipt.
|
|
23
|
+
|
|
24
|
+
Directives preserve target, scope, expiry, supersession and proposed/sent/read/
|
|
25
|
+
applied/verified distinctions. Do not infer a later stage from an earlier report.
|
|
26
|
+
A directive or skill grants no messaging, execution or repository adoption power.
|
|
27
|
+
Act only within existing user authority and the destination's actual contracts.
|
|
28
|
+
|
|
29
|
+
For interruption or retirement, preserve exact prior state, recovery evidence and
|
|
30
|
+
successor identity. Do not wake another owner, overwrite dirty work or delete
|
|
31
|
+
uncertain journals to make a view appear settled. Report the smallest concrete
|
|
32
|
+
receiving dependency and keep unrelated admitted work moving.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atelier-discovery-harness
|
|
3
|
+
description: Frame uncertain questions, compare explanations, plan evidence collection and prepare accountable decisions through the Atelier inquiry ledger.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Discovery Harness
|
|
7
|
+
|
|
8
|
+
Start with the person's purpose and the repository's actual rules, tools and
|
|
9
|
+
source boundaries. Resolve the installed Atelier version and use `atelier
|
|
10
|
+
inquiry help` when available. This source capability uses `@mnstry/atelier/inquiry`
|
|
11
|
+
and `contracts/atelier-inquiry.v1.schema.json`; older packages may lack them.
|
|
12
|
+
|
|
13
|
+
Record a bounded campaign, competing explanations and a hypothesis with a
|
|
14
|
+
context, scope and prospective test plan. Exploratory work can remain qualitative.
|
|
15
|
+
Use conceptual lenses where useful: definitions, mechanisms, systems and causal
|
|
16
|
+
structure, alternatives, counterfactuals, context variation and consequences.
|
|
17
|
+
For each lens say what it can reveal and what evidence would challenge it.
|
|
18
|
+
|
|
19
|
+
Prepare a request with independent purposes for each inquiry, source standards,
|
|
20
|
+
budget and admitted effects. Emit a standalone handoff for the user's chosen
|
|
21
|
+
research workflow. A provider-specific skill can fulfill this contract; do not
|
|
22
|
+
replace an existing skill merely because its name differs. Package installation
|
|
23
|
+
and effect declarations grant no execution permission.
|
|
24
|
+
|
|
25
|
+
On return, inspect complete captures, exact quotes, verification states, evidence
|
|
26
|
+
families, contradictions and new questions. Use current immutable references.
|
|
27
|
+
Record delayed answers against their original request; revise the hypothesis
|
|
28
|
+
explicitly if the question changes. Unsupported conclusions remain gaps.
|
|
29
|
+
|
|
30
|
+
Prefer qualitative assessment when no defensible numerical model exists.
|
|
31
|
+
For elicited odds, identify the source of the prior and every likelihood ratio,
|
|
32
|
+
state conditional-independence assumptions and show sensitivity. For a rate
|
|
33
|
+
model, define the population and binary trial before supplying counts. Interview
|
|
34
|
+
enthusiasm is not automatically a trial or a likelihood ratio. Disclose evidence
|
|
35
|
+
already used in the prior. Repeated reports from one family do not create new
|
|
36
|
+
independent observations. Broad graph links never justify confidence arithmetic.
|
|
37
|
+
|
|
38
|
+
Use `inquiry append` with the current history digest. The ledger checks references
|
|
39
|
+
and arithmetic; verification and reviewer identities are caller reports. Record
|
|
40
|
+
only actual owner dispositions within existing authority. Use `inquiry graph`
|
|
41
|
+
to prepare a source diff and relation proposals, then follow the receiving
|
|
42
|
+
repository's review and graph workflow. Keep raw captures outside accepted
|
|
43
|
+
knowledge. A source withdrawal requires reconsidering affected decisions.
|
|
44
|
+
|
|
45
|
+
Send only permitted, version-bound feedback to Skill Steward. A failure can come
|
|
46
|
+
from a method, tool, source, context or provider. Feedback proposes evaluation;
|
|
47
|
+
it never edits the skill or adopts an upgrade. Retain prior heuristic scores as
|
|
48
|
+
`legacy-assessment` records, without turning them into probabilities.
|
|
@@ -44,6 +44,35 @@ Verify the resolved identity and inventory before running its commands. Inspect
|
|
|
44
44
|
migration/compatibility effects before rewriting the old Atelier lock. Retain the
|
|
45
45
|
old lock and all lineage. Keep installation changes distinct from generated files.
|
|
46
46
|
|
|
47
|
+
When the package manager identified above is npm, check advisory-pinned
|
|
48
|
+
dependencies in the staged candidate: the selected package's exact-version
|
|
49
|
+
`overrides` entries and any package the owner names. Record an override that is
|
|
50
|
+
not an exact version as unchecked. A dependency publisher's root-project
|
|
51
|
+
`overrides` are not inherited by its consumers. `npm ls <package> --all` lists
|
|
52
|
+
every installed copy and reports copies outside a declared range; a valid range
|
|
53
|
+
need not equal the resolved version literally. Each copy must be at its pin or
|
|
54
|
+
an owner-approved version; more than one copy can be valid in a consumer's
|
|
55
|
+
tree. `npm ls` alone does not compare with the lock. Using the lock of the
|
|
56
|
+
candidate's npm root project, compare `npm ls --all --json` with
|
|
57
|
+
`npm ls --all --json --package-lock-only` by dependency path and version, and
|
|
58
|
+
refuse a tree that reports `problems`. Classify each difference on evidence.
|
|
59
|
+
Two different versions at one dependency path are a stale installation. A lock
|
|
60
|
+
entry with no installed version is not installed: call it a package for another
|
|
61
|
+
platform only when its entry in the lock file lists an `os`, `cpu` or `libc`
|
|
62
|
+
that excludes this host as npm is configured. Otherwise record it as missing,
|
|
63
|
+
with the cause when known, and as stale unless the owner confirms the omission.
|
|
64
|
+
Do not report that the tree agrees with the lock while any difference is
|
|
65
|
+
unexplained. Changing a pin or an override in the owner's project is an
|
|
66
|
+
installation effect that needs the owner's consent; adoption requires the
|
|
67
|
+
completed change and its readback. This skill does not prove an offline
|
|
68
|
+
reinstall. When the owner or the repository's procedure requires offline
|
|
69
|
+
installs, follow that procedure and record its result separately. The lock
|
|
70
|
+
comparison was observed once on one development tree whose only differences
|
|
71
|
+
were packages for other platforms, on macOS with npm 10. Other platforms, npm
|
|
72
|
+
versions, real workspaces and missing packages are unqualified. Record the Node
|
|
73
|
+
and npm versions, registry and platform in private evidence, and whether each
|
|
74
|
+
observation used a real registry or a fixture.
|
|
75
|
+
|
|
47
76
|
Check exact-plan eligibility: Linux/macOS, one managed repository at `.`, config
|
|
48
77
|
and workspace at its root, linked candidate worktree, clean state and supported
|
|
49
78
|
Git settings. Packs, overlays and other unsupported participants require the
|