@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,91 @@
|
|
|
1
|
+
// How `open` shows a vault in Obsidian, as steps a launcher carries out. Pure.
|
|
2
|
+
//
|
|
3
|
+
// Two facts of the app (1.13.7, read from its main process and checked on an
|
|
4
|
+
// isolated instance) decide the steps:
|
|
5
|
+
//
|
|
6
|
+
// - An app started with an `obsidian://` URL opens only that URL's vault and
|
|
7
|
+
// deletes the `open` flag of every other vault without a window, so the
|
|
8
|
+
// person's other vaults do not come back the next time Obsidian starts.
|
|
9
|
+
// Started plainly, it reopens every vault its list marks open (the view's
|
|
10
|
+
// vault included, when it was added to the list marked open) and keeps
|
|
11
|
+
// the flags.
|
|
12
|
+
// - `open?path=` picks the listed vault whose folder is the longest string
|
|
13
|
+
// prefix of the path, with no separator check; `open?vault=<id>` names one
|
|
14
|
+
// vault exactly.
|
|
15
|
+
//
|
|
16
|
+
// So a vault is named by its id where that id reaches it first (a vaultRoute
|
|
17
|
+
// of `how: 'id'`), and otherwise by its own path, which the app then matches
|
|
18
|
+
// exactly (a listed folder is the longest prefix of its own path); an app that is not running is
|
|
19
|
+
// started plainly and handed the URL only once it answers: a URL reaching a
|
|
20
|
+
// running app opens a window and changes no flag. On Linux a plain start is not
|
|
21
|
+
// qualified, and the URL starts the app, with the flag loss as a known limit.
|
|
22
|
+
//
|
|
23
|
+
// Steps:
|
|
24
|
+
// { step: 'plain-start' } start the app with no URL
|
|
25
|
+
// { step: 'wait-for-app' } wait, bounded, until the app itself answers its command-line tool
|
|
26
|
+
// { step: 'url', uri } hand the URL to the running app
|
|
27
|
+
// { step: 'url-start', uri } start the app with the URL (Linux only)
|
|
28
|
+
//
|
|
29
|
+
// { ok: true, steps } or { ok: false, reason }.
|
|
30
|
+
|
|
31
|
+
const VAULT_ID = /^[A-Za-z0-9_-]{1,64}$/
|
|
32
|
+
|
|
33
|
+
export function launchPlan({ platform = process.platform, appRunning, vaultId = null, vaultPath = null } = {}) {
|
|
34
|
+
let uri
|
|
35
|
+
if (typeof vaultId === 'string' && VAULT_ID.test(vaultId)) uri = `obsidian://open?vault=${encodeURIComponent(vaultId)}`
|
|
36
|
+
else if (typeof vaultPath === 'string' && vaultPath.startsWith('/') && !vaultPath.includes('\u0000')) uri = `obsidian://open?path=${encodeURIComponent(vaultPath)}`
|
|
37
|
+
else return { ok: false, reason: 'vault-id-unknown' }
|
|
38
|
+
if (platform !== 'darwin' && platform !== 'linux') return { ok: false, reason: 'launcher-platform-unqualified' }
|
|
39
|
+
if (appRunning === true) return { ok: true, steps: [{ step: 'url', uri }] }
|
|
40
|
+
if (platform === 'darwin') return { ok: true, steps: [{ step: 'plain-start' }, { step: 'wait-for-app' }, { step: 'url', uri }] }
|
|
41
|
+
return { ok: true, steps: [{ step: 'url-start', uri }] }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Pure. Whether the command-line tool's reply to a URL says the app took it ("Processed URI …").
|
|
45
|
+
export const urlProcessed = (stdout) => typeof stdout === 'string' && /^processed uri\b/im.test(stdout)
|
|
46
|
+
|
|
47
|
+
// Carries out a launchPlan with injected actions, so the order and the
|
|
48
|
+
// fallbacks are the same for the production launcher and the test harness:
|
|
49
|
+
//
|
|
50
|
+
// start() -> Promise<boolean> start the app with no URL
|
|
51
|
+
// answered() -> Promise<boolean> one poll: the app itself answered (appAnswered); a tool that cannot find the
|
|
52
|
+
// app yet is not an answer
|
|
53
|
+
// handLink(uri) -> Promise<boolean> the app's tool took the URL (urlProcessed)
|
|
54
|
+
// osOpen(uri) -> Promise<boolean> the operating system accepted the URL
|
|
55
|
+
//
|
|
56
|
+
// A URL is never handed to the operating system for an app this launch
|
|
57
|
+
// started: that would start or reach it while it starts, which is what drops
|
|
58
|
+
// the other vaults' reopen flags. A vault added flagged open is opened anyway by
|
|
59
|
+
// a plainly started app, and `open` waits for it; one already listed but closed
|
|
60
|
+
// is handed the link once more instead (opening.mjs). `startedEarlier` says
|
|
61
|
+
// that an earlier launch of the same `open` started the app (a link handed to
|
|
62
|
+
// it once more): the link then goes through the app's tool only, as well.
|
|
63
|
+
export async function runLaunchPlan(plan, { start, answered, handLink, osOpen, sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)), waitMs = 30_000, pollMs = 500, now = () => Date.now(), startedEarlier = false }) {
|
|
64
|
+
if (!plan?.ok) return { launched: false, reason: plan?.reason ?? 'launcher-refused' }
|
|
65
|
+
let started = startedEarlier === true
|
|
66
|
+
let reason = 'url-accepted'
|
|
67
|
+
for (const { step, uri } of plan.steps) {
|
|
68
|
+
if (step === 'plain-start') {
|
|
69
|
+
if (!(await start())) return { launched: false, reason: 'os-open-failed' }
|
|
70
|
+
started = true
|
|
71
|
+
} else if (step === 'wait-for-app') {
|
|
72
|
+
const deadline = now() + waitMs
|
|
73
|
+
let up = false
|
|
74
|
+
while (!up) {
|
|
75
|
+
up = await answered()
|
|
76
|
+
if (up) break
|
|
77
|
+
if (now() >= deadline) return { launched: true, reason: 'app-started-not-answering' }
|
|
78
|
+
await sleep(pollMs)
|
|
79
|
+
}
|
|
80
|
+
} else if (step === 'url') {
|
|
81
|
+
if (await handLink(uri)) continue
|
|
82
|
+
if (started) return { launched: true, reason: 'app-started-link-not-taken' }
|
|
83
|
+
if (!(await osOpen(uri))) return { launched: false, reason: 'os-open-failed' }
|
|
84
|
+
reason = 'os-open-accepted'
|
|
85
|
+
} else if (step === 'url-start') {
|
|
86
|
+
if (!(await osOpen(uri))) return { launched: false, reason: 'os-open-failed' }
|
|
87
|
+
reason = 'os-open-accepted'
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return { launched: true, reason: started && reason === 'url-accepted' ? 'plain-start-then-url' : reason }
|
|
91
|
+
}
|
|
@@ -2,15 +2,17 @@ import childProcess from 'node:child_process'
|
|
|
2
2
|
import { randomBytes as cryptoRandomBytes } from 'node:crypto'
|
|
3
3
|
import fs from 'node:fs'
|
|
4
4
|
import net from 'node:net'
|
|
5
|
+
import path from 'node:path'
|
|
6
|
+
import { compareAppVersions } from './app-capability.mjs'
|
|
5
7
|
import { isoTime } from './documents.mjs'
|
|
6
|
-
import { refuse } from './errors.mjs'
|
|
8
|
+
import { ObsidianMaintenanceRefusal, refuse } from './errors.mjs'
|
|
7
9
|
import { ensureWorkspaceIdentity } from './machine-settings.mjs'
|
|
8
10
|
import { acquirePrivateGenerationLock, createAbandonmentProof, isProcessAlive } from './private-lock.mjs'
|
|
9
11
|
import { processRunsRecordedExecutable } from './process-identity.mjs'
|
|
10
12
|
import { DEFAULT_PROBE_TIMEOUT_MS, LOOPBACK_HOSTS, probeHealth, requestLoopback } from './service-client.mjs'
|
|
11
13
|
import { SERVICE_ENTRY_PATH } from './service-entry-path.mjs'
|
|
12
14
|
import {
|
|
13
|
-
CONSENT_COVERAGES, SERVICE_SETTINGS_SCHEMA, executableIdentity, openServiceLog, publicRecord, readServiceRecord, readServiceSettings, removeServiceRecord,
|
|
15
|
+
CONSENT_COVERAGES, SERVICE_SETTINGS_SCHEMA, executableIdentity, openServiceLog, publicRecord, readLastStartup, readServiceRecord, readServiceSettings, releaseOfEntry, removeServiceRecord,
|
|
14
16
|
serviceNameFor, servicePaths, writeServiceSettings,
|
|
15
17
|
} from './service-record.mjs'
|
|
16
18
|
import { resolveServiceWorkspace } from './service.mjs'
|
|
@@ -103,8 +105,18 @@ function freeLoopbackPort(host) {
|
|
|
103
105
|
})
|
|
104
106
|
}
|
|
105
107
|
|
|
106
|
-
|
|
108
|
+
// The service settings of this workspace with the address and consent given, written when that changes anything: the
|
|
109
|
+
// first start needs a consent naming its actor, and a consent for another actor or coverage replaces the recorded one.
|
|
110
|
+
// Installing and removing a login item raise and lower the coverage through it (login-item.mjs).
|
|
111
|
+
export async function ensureServiceSettings(workspace, { host, port, consent, now }) {
|
|
112
|
+
return resolveSettings(workspace, { host, port, consent, now })
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function resolveSettings({ workspaceRoot, workspaceId }, { host, port, consent: given, now }) {
|
|
107
116
|
const current = readServiceSettings({ workspaceRoot, workspaceId })
|
|
117
|
+
// A consent derived from the account of a person at a terminal (`derived: true`) stands only for a workspace that has
|
|
118
|
+
// none. Read here, under the start lock, so one recorded meanwhile by another run is never replaced or narrowed.
|
|
119
|
+
const consent = given?.derived === true && current !== null ? undefined : given
|
|
108
120
|
if (host !== undefined && !LOOPBACK_HOSTS.includes(host)) refuse('service-address-not-loopback', 'the service host must be the literal 127.0.0.1 or ::1')
|
|
109
121
|
if (port !== undefined && (!Number.isInteger(port) || port < 1024 || port > 65535)) refuse('service-address-not-loopback', 'the service port must be between 1024 and 65535')
|
|
110
122
|
if (consent !== undefined && (typeof consent?.actor !== 'string' || !CONSENT_COVERAGES.includes(consent.coverage ?? 'service'))) refuse('startup-consent-required', 'a consent names its actor and what it covers')
|
|
@@ -119,11 +131,55 @@ async function resolveSettings({ workspaceRoot, workspaceId }, { host, port, con
|
|
|
119
131
|
return changed ? writeServiceSettings({ workspaceRoot, workspaceId, settings: next }) : current
|
|
120
132
|
}
|
|
121
133
|
|
|
134
|
+
// Asks the service manager of the installed login item to start the service, and waits, bounded, for this
|
|
135
|
+
// workspace's service to prove itself (healthy, or busy in its first tick) with a record naming the digest of the
|
|
136
|
+
// entry the item runs. The runtime identifier is the service's own there, so that digest is what makes it the one
|
|
137
|
+
// asked for. A service that refused under the item exited cleanly and recorded why (`last-startup.json`); that code is
|
|
138
|
+
// the answer. { result } or, when the manager did not start it (the item is not loaded: switched off in System
|
|
139
|
+
// Settings, or no user service manager), { fallback: code }.
|
|
140
|
+
async function startThroughLoginItem({ workspace, loginItem, entryPath, deadline, probeTimeoutMs, alive, rules }) {
|
|
141
|
+
const { workspaceRoot, workspaceId } = workspace
|
|
142
|
+
const lastStartup = () => { try { return JSON.stringify(readLastStartup(workspace)) } catch { return null } }
|
|
143
|
+
const before = lastStartup()
|
|
144
|
+
let asked
|
|
145
|
+
try { asked = await loginItem.start() } catch { asked = { ok: false, code: 'login-item-start-failed' } }
|
|
146
|
+
const item = { via: 'login-item', ...(asked?.refreshed === true ? { refreshed: true } : {}) }
|
|
147
|
+
if (asked?.ok !== true) return { fallback: typeof asked?.code === 'string' ? asked.code : 'login-item-start-failed', refreshed: asked?.refreshed === true }
|
|
148
|
+
// A unit written again on the way names the entry of now. One whose entry cannot be read cannot prove anything.
|
|
149
|
+
let expected
|
|
150
|
+
try { expected = executableIdentity(typeof asked.entryPath === 'string' ? asked.entryPath : entryPath).digest } catch { return { result: { state: 'start-failed', started: false, alreadyRunning: false, workspaceId, reason: 'login-item-entry-missing', observed: null, logPath: servicePaths(workspaceRoot).loginItemLog, loginItem: item } } }
|
|
151
|
+
let last = null
|
|
152
|
+
const proves = (status) => status?.record?.executable?.digest === expected
|
|
153
|
+
while (Date.now() < deadline) {
|
|
154
|
+
last = await evaluate(workspace, { probeTimeoutMs, alive, rules }).catch((error) => ({ state: 'refused', reason: error.code ?? 'untyped-error' }))
|
|
155
|
+
if (last.state === 'healthy' && proves(last)) return { result: { ...shown(last), started: true, alreadyRunning: false, loginItem: item } }
|
|
156
|
+
const now = lastStartup()
|
|
157
|
+
if (now !== before && now !== null) {
|
|
158
|
+
const startup = JSON.parse(now)
|
|
159
|
+
if (startup?.outcome === 'refused') return { result: { state: 'start-failed', started: false, alreadyRunning: false, workspaceId, reason: startup.code, observed: last.state ?? null, logPath: servicePaths(workspaceRoot).log, loginItem: item } }
|
|
160
|
+
}
|
|
161
|
+
await sleep(50)
|
|
162
|
+
}
|
|
163
|
+
// As for a child started here: a service that proved itself and went straight into a long first tick runs, and is
|
|
164
|
+
// answered as busy only once the wait for it to be healthy is over.
|
|
165
|
+
if (last?.state === 'busy' && proves(last)) return { result: { ...shown(last), started: true, alreadyRunning: false, busy: true, loginItem: item } }
|
|
166
|
+
return { result: { state: 'start-failed', started: false, alreadyRunning: false, workspaceId, reason: 'health-never-proved-ownership', observed: last?.state ?? null, logPath: servicePaths(workspaceRoot).loginItemLog, loginItem: item } }
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// `loginItem`, for a workspace with an installed login item: { start() }, which asks its service manager to start the
|
|
170
|
+
// service (login-item.mjs). The service is then started through it, never as a child beside it, so two starts never
|
|
171
|
+
// compete; `entryPath` is the entry the item runs. When the manager does not start it, the service is started as a
|
|
172
|
+
// child, and the answer says why (`loginItem: { via: 'child', reason }`).
|
|
173
|
+
//
|
|
174
|
+
// `replaceOutdated`: a proven runtime of this workspace that runs an earlier release than the entry this start would run
|
|
175
|
+
// (runtimeRelease) is stopped as `stopService` stops it and started again in its place, under the consent already
|
|
176
|
+
// recorded (`replaced: 'outdated'`); one of a later release is never replaced (`release: 'later'`). Without it, any
|
|
177
|
+
// proven runtime is answered as already running.
|
|
122
178
|
export async function startService(options = {}, rules = LIFECYCLE_PRIMITIVES) {
|
|
123
179
|
const {
|
|
124
180
|
loadProject, dataRoot, host, port, consent, detached = false, entryPath = SERVICE_ENTRY_PATH, entryArgs = [], intervalMs,
|
|
125
181
|
startTimeoutMs = DEFAULT_START_TIMEOUT_MS, probeTimeoutMs, clock = () => new Date(), env = process.env, platform = process.platform,
|
|
126
|
-
spawn = childProcess.spawn, execPath = process.execPath, alive = isProcessAlive, randomBytes = cryptoRandomBytes,
|
|
182
|
+
spawn = childProcess.spawn, execPath = process.execPath, alive = isProcessAlive, randomBytes = cryptoRandomBytes, loginItem = null, replaceOutdated = false,
|
|
127
183
|
} = options
|
|
128
184
|
const { project, workspace } = context({ loadProject, dataRoot, env, platform, create: true })
|
|
129
185
|
const { workspaceRoot, workspaceId } = workspace
|
|
@@ -144,11 +200,26 @@ export async function startService(options = {}, rules = LIFECYCLE_PRIMITIVES) {
|
|
|
144
200
|
|
|
145
201
|
let child = null
|
|
146
202
|
try {
|
|
147
|
-
|
|
148
|
-
|
|
203
|
+
let before = await evaluate(workspace, { probeTimeoutMs, alive, rules })
|
|
204
|
+
// A runtime of an earlier release, still running after an upgrade, is replaced when asked to; it is stopped through its
|
|
205
|
+
// own listener, as its owner stops it, and nothing else is ever stopped here.
|
|
206
|
+
let replaced = null
|
|
207
|
+
if (rules.isOurs(before)) {
|
|
208
|
+
const standing = replaceOutdated ? runtimeRelease(before, entryPath) : null
|
|
209
|
+
if (standing === 'later') return { ...shown(before), started: false, alreadyRunning: true, release: 'later' }
|
|
210
|
+
if (standing !== 'outdated') return { ...shown(before), started: false, alreadyRunning: true }
|
|
211
|
+
const stopped = await stopService({ loadProject, dataRoot, env, platform, probeTimeoutMs, alive }, rules)
|
|
212
|
+
if (!stopped.stopped) return { ...shown(before), started: false, alreadyRunning: true, release: 'outdated', reason: stopped.reason ?? 'the-runtime-was-not-stopped' }
|
|
213
|
+
replaced = 'outdated'
|
|
214
|
+
before = await evaluate(workspace, { probeTimeoutMs, alive, rules })
|
|
215
|
+
}
|
|
149
216
|
// Running, and in a long tick: nothing is started beside it and nothing replaces it.
|
|
150
217
|
if (before.state === 'busy') return { ...shown(before), started: false, alreadyRunning: true, busy: true }
|
|
151
|
-
|
|
218
|
+
// With a login item, a listener that has not written its record yet may be the service its manager is starting
|
|
219
|
+
// right now (it listens before it records itself): the start below asks the manager, which starts nothing beside
|
|
220
|
+
// a running job, and accepts only a runtime that proves itself. Anything else stays occupied and is never adopted.
|
|
221
|
+
const starting = loginItem !== null && before.state === 'occupied' && before.reason === 'a-listener-without-a-record'
|
|
222
|
+
if (rules.refusesOccupied(before) && !starting) refuse('service-port-occupied', 'something that is not this service answers on the loopback port; it is never taken over', { reason: before.reason, address: before.address })
|
|
152
223
|
// `stale-record` and `pid-not-ours`: nothing listens, so the recorded runtime is not serving. Its PID is never signalled;
|
|
153
224
|
// the new service replaces the record once it listens. Nothing under recovery or staging is touched on the way.
|
|
154
225
|
const settings = await resolveSettings(workspace, { host, port, consent, now: isoTime(clock) })
|
|
@@ -157,13 +228,23 @@ export async function startService(options = {}, rules = LIFECYCLE_PRIMITIVES) {
|
|
|
157
228
|
if (moved.kind !== 'refused') refuse('service-port-occupied', 'something already answers on the selected loopback port; it is never taken over', { address: { host: settings.host, port: settings.port } })
|
|
158
229
|
}
|
|
159
230
|
|
|
231
|
+
// An installed login item starts it. Only when its manager does not is a child started, and the answer says why.
|
|
232
|
+
let fallback = null
|
|
233
|
+
if (loginItem !== null) {
|
|
234
|
+
const managed = await startThroughLoginItem({ workspace, loginItem, entryPath, deadline, probeTimeoutMs, alive, rules })
|
|
235
|
+
if (managed.result) return replaced === null ? managed.result : { ...managed.result, replaced }
|
|
236
|
+
fallback = { via: 'child', reason: managed.fallback, ...(managed.refreshed ? { refreshed: true } : {}) }
|
|
237
|
+
}
|
|
238
|
+
const withFallback = (result) => ({ ...result, ...(fallback === null ? {} : { loginItem: fallback }), ...(replaced === null ? {} : { replaced }) })
|
|
239
|
+
|
|
160
240
|
const runtimeId = `rt-${randomBytes(16).toString('hex')}`
|
|
161
241
|
const executable = executableIdentity(entryPath)
|
|
162
242
|
const log = openServiceLog(workspaceRoot)
|
|
163
243
|
try {
|
|
164
244
|
const args = [executable.path, `--project=${project.configPath}`, ...(dataRoot === undefined ? [] : [`--data-root=${dataRoot}`]), `--runtime-id=${runtimeId}`, ...(intervalMs === undefined ? [] : [`--interval-ms=${intervalMs}`]), ...entryArgs]
|
|
165
|
-
// No shell. Detached only when the service is meant to outlive the command that starts it.
|
|
166
|
-
|
|
245
|
+
// No shell. Detached only when the service is meant to outlive the command that starts it. It runs in the root
|
|
246
|
+
// directory, never in the one the command was started in, which may be a vault or a folder somebody removes.
|
|
247
|
+
child = spawn(execPath, args, { detached, shell: false, windowsHide: true, stdio: ['ignore', log.descriptor, log.descriptor], env, cwd: path.parse(executable.path).root })
|
|
167
248
|
} finally {
|
|
168
249
|
fs.closeSync(log.descriptor)
|
|
169
250
|
}
|
|
@@ -177,19 +258,19 @@ export async function startService(options = {}, rules = LIFECYCLE_PRIMITIVES) {
|
|
|
177
258
|
last = await evaluate(workspace, { probeTimeoutMs, alive, rules }).catch((error) => ({ state: 'refused', reason: error.code ?? 'untyped-error' }))
|
|
178
259
|
if (last.state === 'healthy' && last.record.runtimeId === runtimeId && last.record.pid === child.pid) {
|
|
179
260
|
if (detached) child.unref()
|
|
180
|
-
return { ...shown(last), started: true, alreadyRunning: false, ...(detached ? {} : { child }) }
|
|
261
|
+
return withFallback({ ...shown(last), started: true, alreadyRunning: false, ...(detached ? {} : { child }) })
|
|
181
262
|
}
|
|
182
263
|
await sleep(50)
|
|
183
264
|
}
|
|
184
265
|
// The child created here wrote the record and went straight into a long first tick: it runs, and is not stopped.
|
|
185
266
|
if (exited === null && last?.state === 'busy' && last.record?.runtimeId === runtimeId && last.record?.pid === child.pid) {
|
|
186
267
|
if (detached) child.unref()
|
|
187
|
-
return { ...shown(last), started: true, alreadyRunning: false, busy: true, ...(detached ? {} : { child }) }
|
|
268
|
+
return withFallback({ ...shown(last), started: true, alreadyRunning: false, busy: true, ...(detached ? {} : { child }) })
|
|
188
269
|
}
|
|
189
270
|
// Ownership was never proven: only the child created here is stopped, by its handle.
|
|
190
271
|
if (exited === null) { child.kill(); const until = Date.now() + 5000; while (exited === null && Date.now() < until) await sleep(25) }
|
|
191
272
|
removeServiceRecord({ workspaceRoot, workspaceId, runtimeId, pid: child.pid })
|
|
192
|
-
return { state: 'start-failed', started: false, alreadyRunning: false, workspaceId, reason: exited?.error ?? (exited?.code === null || exited === null ? 'health-never-proved-ownership' : `service-exited-${exited.code}`), observed: last?.state ?? null, logPath: log.file }
|
|
273
|
+
return withFallback({ state: 'start-failed', started: false, alreadyRunning: false, workspaceId, reason: exited?.error ?? (exited?.code === null || exited === null ? 'health-never-proved-ownership' : `service-exited-${exited.code}`), observed: last?.state ?? null, logPath: log.file })
|
|
193
274
|
} finally {
|
|
194
275
|
lock.release()
|
|
195
276
|
}
|
|
@@ -226,26 +307,116 @@ export async function stopService(options = {}, rules = LIFECYCLE_PRIMITIVES) {
|
|
|
226
307
|
|
|
227
308
|
// One authenticated request to the proven runtime, and to nothing else: anything but a healthy status is answered
|
|
228
309
|
// with that status and no request is made.
|
|
229
|
-
async function askProvenRuntime(options, rules, { method, operation, timeoutMs }) {
|
|
310
|
+
async function askProvenRuntime(options, rules, { method, operation, timeoutMs, body = {} }) {
|
|
230
311
|
const { loadProject, dataRoot, probeTimeoutMs, env = process.env, platform = process.platform, alive = isProcessAlive } = options
|
|
231
312
|
const { workspace } = context({ loadProject, dataRoot, env, platform })
|
|
232
313
|
if (!workspace?.workspaceRoot) return { requested: false, state: 'stopped', reason: 'workspace-not-prepared' }
|
|
233
314
|
const status = await evaluate(workspace, { probeTimeoutMs, alive, rules })
|
|
234
315
|
if (status.state !== 'healthy') return { requested: false, state: status.state, reason: status.reason }
|
|
235
316
|
const { record } = status
|
|
236
|
-
const answer = await requestLoopback({ host: record.host, port: record.port, method, path: operation, bearer: record.ext.bearer, payload: method === 'POST' ? { runtimeId: record.runtimeId } : null, timeoutMs })
|
|
237
|
-
return { requested: true, state: 'healthy', answer }
|
|
317
|
+
const answer = await requestLoopback({ host: record.host, port: record.port, method, path: operation, bearer: record.ext.bearer, payload: method === 'POST' ? { runtimeId: record.runtimeId, ...body } : null, timeoutMs })
|
|
318
|
+
return { requested: true, state: 'healthy', answer, runtimeId: record.runtimeId }
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Pure. How the release a runtime recorded at its start (`executable.ext.release`, see releaseIdentity: the package
|
|
322
|
+
// version and a digest of every runtime module) stands to the installed one, `installed` being { entry, release }, the
|
|
323
|
+
// digest of the entry this command would start and the release that entry's package holds now (releaseOfEntry):
|
|
324
|
+
// current the same version, entry module and modules;
|
|
325
|
+
// outdated an earlier version; the same version with another entry module or other modules; or no release named,
|
|
326
|
+
// as releases before the one that began recording it record none;
|
|
327
|
+
// later a later version, or another version that cannot be ordered. The installed release never replaces it, so two
|
|
328
|
+
// installations used on one workspace do not replace each other's runtime.
|
|
329
|
+
// Versions are ordered as semantic versions, a prerelease below its release (0.2.0-alpha.11 < 0.2.0-alpha.12 < 0.2.0).
|
|
330
|
+
export function releaseStanding(executable, installed) {
|
|
331
|
+
const recorded = executable?.ext?.release
|
|
332
|
+
if (recorded === undefined || recorded === null) return 'outdated'
|
|
333
|
+
// The same version string is compared by content, whether or not it can be ordered: a fork's "dev" on both sides
|
|
334
|
+
// is this release when its modules match, and outdated otherwise, never later.
|
|
335
|
+
const order = recorded.version === installed.release.version ? 0 : compareAppVersions(recorded.version, installed.release.version)
|
|
336
|
+
if (order === null || order > 0) return 'later'
|
|
337
|
+
if (order < 0) return 'outdated'
|
|
338
|
+
return executable.digest === installed.entry && recorded.digest === installed.release.digest ? 'current' : 'outdated'
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// How the release the proven runtime runs stands to the installed one (releaseStanding), `entryPath` being the entry
|
|
342
|
+
// this command would start: its digest and the release are both read from that entry, so with a login item the
|
|
343
|
+
// installed release is the project's own package, read through the path the item names, whichever package this command
|
|
344
|
+
// runs from. Null when the runtime is not proven, or the installed side cannot be read.
|
|
345
|
+
export function runtimeRelease(status, entryPath) {
|
|
346
|
+
if (status?.state !== 'healthy' || typeof status.record?.executable?.digest !== 'string' || typeof entryPath !== 'string') return null
|
|
347
|
+
let installed
|
|
348
|
+
try { installed = { entry: executableIdentity(entryPath).digest, release: releaseOfEntry(entryPath) } } catch { return null }
|
|
349
|
+
return releaseStanding(status.record.executable, installed)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Stops the proven runtime of this workspace through its own listener and starts `entryPath` in its place, detached,
|
|
353
|
+
// under the consent already recorded. Only a runtime that proves itself ours is ever stopped (stopService).
|
|
354
|
+
// { ok: true } or { ok: false, state, reason }.
|
|
355
|
+
async function restartProvenRuntime(options, rules) {
|
|
356
|
+
const { consent: _given, ...rest } = options
|
|
357
|
+
const stopped = await stopService(rest, rules)
|
|
358
|
+
if (!stopped.stopped) return { ok: false, state: stopped.state, reason: stopped.reason ?? 'the-runtime-was-not-stopped' }
|
|
359
|
+
let started
|
|
360
|
+
try { started = await startService({ ...rest, detached: true }, rules) } catch (error) {
|
|
361
|
+
if (!(error instanceof ObsidianMaintenanceRefusal)) throw error
|
|
362
|
+
return { ok: false, state: 'stopped', reason: error.code }
|
|
363
|
+
}
|
|
364
|
+
if (started.state === 'healthy') return { ok: true }
|
|
365
|
+
return { ok: false, state: started.state, reason: started.state === 'busy' ? 'restarted-service-in-its-first-tick' : started.reason ?? started.state }
|
|
238
366
|
}
|
|
239
367
|
|
|
240
368
|
// Asks the proven runtime for one tick now and returns what that tick reported. A tick that outlasts the wait is
|
|
241
|
-
// `pending`, not an error.
|
|
369
|
+
// `pending`, not an error. With `scopeId`, that view is prepared and published once more on the tick.
|
|
370
|
+
//
|
|
371
|
+
// `service`, the start options of the entry this command would start ({ entryPath, entryArgs, ... }), lets an
|
|
372
|
+
// outdated runtime be replaced: one that runs an earlier release (runtimeRelease) is restarted before it is asked,
|
|
373
|
+
// and one that refuses a tick naming a view (a runtime of 0.2.0-alpha.11 or earlier, which knows no view in a tick)
|
|
374
|
+
// is restarted and asked again, each time under the consent already recorded (`restarted: 'outdated'`). A listener
|
|
375
|
+
// of now refuses a tick only when it names another runtime: when a concurrent command replaced the runtime between
|
|
376
|
+
// the check and the request, the one that took its place is asked, and nothing is restarted. A runtime of a later
|
|
377
|
+
// release is never replaced by this one, nor asked: `service-other-release`. Without `service`, an outdated runtime
|
|
378
|
+
// is only reported (`service-outdated`). `runtimeId` names the runtime that answered, or the one left running.
|
|
242
379
|
export async function requestServiceTick(options = {}, rules = LIFECYCLE_PRIMITIVES) {
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
380
|
+
const { service = null, scopeId } = options
|
|
381
|
+
const ask = () => askProvenRuntime(options, rules, { method: 'POST', operation: '/tick', timeoutMs: options.tickTimeoutMs ?? 60 * 1000, ...(scopeId === undefined ? {} : { body: { scopeId } }) })
|
|
382
|
+
let restarted = null
|
|
383
|
+
const restart = async () => {
|
|
384
|
+
const renewed = await restartProvenRuntime({ ...options, ...service }, rules)
|
|
385
|
+
if (renewed.ok || renewed.reason === 'restarted-service-in-its-first-tick') restarted = 'outdated'
|
|
386
|
+
return renewed.ok ? null : { requested: false, state: renewed.state, reason: renewed.reason, ...(restarted === null ? {} : { restarted }) }
|
|
387
|
+
}
|
|
388
|
+
const later = (status) => ({ requested: false, state: 'healthy', runtimeId: status.record.runtimeId, reason: 'service-other-release' })
|
|
389
|
+
const replaces = typeof service?.entryPath === 'string'
|
|
390
|
+
if (replaces) {
|
|
391
|
+
const status = await serviceStatus(options, rules)
|
|
392
|
+
const standing = runtimeRelease(status, service.entryPath)
|
|
393
|
+
if (standing === 'later') return later(status)
|
|
394
|
+
if (standing === 'outdated') {
|
|
395
|
+
const failed = await restart()
|
|
396
|
+
if (failed) return failed
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
let asked = await ask()
|
|
400
|
+
const refusesView = () => asked.requested && scopeId !== undefined && asked.answer.kind === 'response' && asked.answer.statusCode === 409
|
|
401
|
+
if (refusesView() && replaces && restarted === null) {
|
|
402
|
+
// The record is read again first: a runtime that took this one's place meanwhile is asked, not replaced.
|
|
403
|
+
const now = await serviceStatus(options, rules)
|
|
404
|
+
if (now.state === 'healthy' && now.record?.runtimeId !== asked.runtimeId) asked = await ask()
|
|
405
|
+
if (refusesView()) {
|
|
406
|
+
if (runtimeRelease(now, service.entryPath) === 'later') return later(now)
|
|
407
|
+
const failed = await restart()
|
|
408
|
+
if (failed) return failed
|
|
409
|
+
asked = await ask()
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
const shown = restarted === null ? {} : { restarted }
|
|
413
|
+
if (!asked.requested) return { ...asked, ...shown }
|
|
414
|
+
const { answer, runtimeId } = asked
|
|
415
|
+
const base = { requested: true, state: 'healthy', runtimeId, ...shown }
|
|
416
|
+
if (refusesView()) return { ...base, pending: false, tick: null, reason: 'service-outdated' }
|
|
417
|
+
if (answer.kind === 'timeout') return { ...base, pending: true, tick: null, reason: 'tick-still-running' }
|
|
418
|
+
if (answer.kind !== 'response' || answer.statusCode !== 200 || answer.body === null) return { ...base, pending: false, tick: null, reason: 'tick-was-not-answered' }
|
|
419
|
+
return { ...base, pending: false, tick: answer.body, reason: 'tick-ran' }
|
|
249
420
|
}
|
|
250
421
|
|
|
251
422
|
// The status document of the proven runtime: loop, last tick, last error code, freshness summary and, where the
|