@mnstry/atelier 0.2.0-alpha.12 → 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 +661 -0
- package/README.md +142 -6
- 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-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/docs/architecture.md +89 -0
- package/docs/assurance-controls.md +2 -2
- 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 +181 -16
- package/docs/obsidian-contract.md +223 -15
- package/docs/obsidian-plugin.md +38 -4
- package/docs/obsidian.md +613 -51
- 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 +49 -0
- 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 +47 -2
- 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/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 +59 -5
- 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 +754 -63
- 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 +30 -0
- package/src/coordination/index.mjs +110 -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/projection/obsidian/edits/apply.mjs +55 -16
- package/src/projection/obsidian/personal-workspace.mjs +436 -0
- package/src/projection/obsidian/proposals/adapter.mjs +47 -8
- package/src/projection/obsidian/proposals/observation.mjs +10 -2
- package/src/projection/obsidian/publication/publisher.mjs +142 -13
- package/src/projection/obsidian/publication/vault-list.mjs +4 -3
- package/src/projection/obsidian/recovery/index.mjs +4 -1
- package/src/projection/obsidian/recovery/store.mjs +160 -7
- package/src/projection/obsidian/selection-ui/contribution.mjs +6 -5
- package/src/readiness/readiness.mjs +10 -3
- package/src/reflection/index.mjs +56 -0
- package/src/runtime/obsidian/app-production-seams.mjs +48 -16
- package/src/runtime/obsidian/app-registration.mjs +175 -28
- package/src/runtime/obsidian/app-restart.mjs +154 -0
- package/src/runtime/obsidian/engine.mjs +163 -20
- package/src/runtime/obsidian/extension-points.mjs +1 -1
- package/src/runtime/obsidian/index.mjs +10 -7
- package/src/runtime/obsidian/launch-plan.mjs +7 -4
- package/src/runtime/obsidian/lifecycle.mjs +92 -12
- package/src/runtime/obsidian/login-item.mjs +332 -0
- package/src/runtime/obsidian/machine-settings.mjs +119 -12
- package/src/runtime/obsidian/opening.mjs +171 -37
- package/src/runtime/obsidian/pipeline.mjs +71 -3
- package/src/runtime/obsidian/plugin-channel.mjs +11 -3
- package/src/runtime/obsidian/plugin-choice.mjs +16 -4
- package/src/runtime/obsidian/plugin-drift.mjs +59 -11
- package/src/runtime/obsidian/plugin-presence.mjs +14 -1
- 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 +99 -16
- 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 +87 -23
- package/src/runtime/obsidian/service.mjs +36 -3
- package/src/runtime/obsidian/startup-adapters.mjs +59 -21
- 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 +169 -2
- package/src/server/server.mjs +28 -2
- 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 +1 -0
- 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,1388 @@
|
|
|
1
|
+
export function renderKnowledgePage() {
|
|
2
|
+
return `<!DOCTYPE html>
|
|
3
|
+
<html lang="en">
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
7
|
+
<title>Knowledge workspace · Atelier</title>
|
|
8
|
+
<style>
|
|
9
|
+
:root {
|
|
10
|
+
color-scheme: light;
|
|
11
|
+
--ink: #202d37;
|
|
12
|
+
--muted: #52616c;
|
|
13
|
+
--line: #cad2d5;
|
|
14
|
+
--paper: #f6f5f0;
|
|
15
|
+
--accent: #215c52;
|
|
16
|
+
--wash: #e8efeb;
|
|
17
|
+
}
|
|
18
|
+
* {
|
|
19
|
+
box-sizing: border-box;
|
|
20
|
+
}
|
|
21
|
+
body {
|
|
22
|
+
margin: 0;
|
|
23
|
+
background: var(--paper);
|
|
24
|
+
color: var(--ink);
|
|
25
|
+
font: 16px/1.55 system-ui, sans-serif;
|
|
26
|
+
}
|
|
27
|
+
header {
|
|
28
|
+
padding: 24px 4vw;
|
|
29
|
+
border-bottom: 1px solid var(--line);
|
|
30
|
+
display: flex;
|
|
31
|
+
gap: 20px;
|
|
32
|
+
align-items: center;
|
|
33
|
+
justify-content: space-between;
|
|
34
|
+
}
|
|
35
|
+
.eyebrow {
|
|
36
|
+
text-transform: uppercase;
|
|
37
|
+
font-size: 0.75rem;
|
|
38
|
+
letter-spacing: 0.13em;
|
|
39
|
+
font-weight: 750;
|
|
40
|
+
color: var(--muted);
|
|
41
|
+
}
|
|
42
|
+
h1 {
|
|
43
|
+
font-size: 1.5rem;
|
|
44
|
+
margin: 4px 0;
|
|
45
|
+
}
|
|
46
|
+
h2 {
|
|
47
|
+
font-size: 1.7rem;
|
|
48
|
+
line-height: 1.2;
|
|
49
|
+
margin: 0 0 16px;
|
|
50
|
+
}
|
|
51
|
+
h3 {
|
|
52
|
+
font-size: 1.1rem;
|
|
53
|
+
margin: 0 0 10px;
|
|
54
|
+
}
|
|
55
|
+
p {
|
|
56
|
+
margin: 8px 0 16px;
|
|
57
|
+
}
|
|
58
|
+
.muted,
|
|
59
|
+
small {
|
|
60
|
+
color: var(--muted);
|
|
61
|
+
}
|
|
62
|
+
small {
|
|
63
|
+
font-size: 0.85rem;
|
|
64
|
+
}
|
|
65
|
+
.shell {
|
|
66
|
+
max-width: 1500px;
|
|
67
|
+
margin: auto;
|
|
68
|
+
padding: 28px 4vw;
|
|
69
|
+
}
|
|
70
|
+
.steps {
|
|
71
|
+
display: flex;
|
|
72
|
+
gap: 8px;
|
|
73
|
+
flex-wrap: wrap;
|
|
74
|
+
margin-bottom: 24px;
|
|
75
|
+
}
|
|
76
|
+
.steps button {
|
|
77
|
+
flex: 1;
|
|
78
|
+
min-width: 112px;
|
|
79
|
+
text-align: left;
|
|
80
|
+
background: transparent;
|
|
81
|
+
}
|
|
82
|
+
.steps button[aria-pressed='true'] {
|
|
83
|
+
background: var(--ink);
|
|
84
|
+
color: white;
|
|
85
|
+
border-color: var(--ink);
|
|
86
|
+
}
|
|
87
|
+
.steps span {
|
|
88
|
+
display: block;
|
|
89
|
+
font-size: 0.75rem;
|
|
90
|
+
opacity: 0.8;
|
|
91
|
+
}
|
|
92
|
+
.layout {
|
|
93
|
+
display: grid;
|
|
94
|
+
grid-template-columns: minmax(0, 1fr) minmax(300px, 390px);
|
|
95
|
+
gap: 32px;
|
|
96
|
+
align-items: start;
|
|
97
|
+
}
|
|
98
|
+
.card {
|
|
99
|
+
padding: 22px;
|
|
100
|
+
background: white;
|
|
101
|
+
border: 1px solid var(--line);
|
|
102
|
+
border-radius: 10px;
|
|
103
|
+
margin-bottom: 16px;
|
|
104
|
+
overflow-wrap: anywhere;
|
|
105
|
+
}
|
|
106
|
+
.grid {
|
|
107
|
+
display: grid;
|
|
108
|
+
grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
|
|
109
|
+
gap: 14px;
|
|
110
|
+
}
|
|
111
|
+
.grid .card {
|
|
112
|
+
margin: 0;
|
|
113
|
+
}
|
|
114
|
+
.callout {
|
|
115
|
+
border-left: 4px solid var(--accent);
|
|
116
|
+
background: var(--wash);
|
|
117
|
+
}
|
|
118
|
+
.tag {
|
|
119
|
+
display: inline-block;
|
|
120
|
+
padding: 3px 8px;
|
|
121
|
+
border-radius: 4px;
|
|
122
|
+
background: var(--wash);
|
|
123
|
+
font-size: 0.8rem;
|
|
124
|
+
color: var(--accent);
|
|
125
|
+
}
|
|
126
|
+
button,
|
|
127
|
+
input,
|
|
128
|
+
select,
|
|
129
|
+
textarea {
|
|
130
|
+
font: inherit;
|
|
131
|
+
color: inherit;
|
|
132
|
+
min-height: 44px;
|
|
133
|
+
max-width: 100%;
|
|
134
|
+
border: 1px solid #819298;
|
|
135
|
+
border-radius: 5px;
|
|
136
|
+
padding: 9px 12px;
|
|
137
|
+
background: white;
|
|
138
|
+
}
|
|
139
|
+
button {
|
|
140
|
+
cursor: pointer;
|
|
141
|
+
font-weight: 650;
|
|
142
|
+
}
|
|
143
|
+
button.primary {
|
|
144
|
+
background: var(--accent);
|
|
145
|
+
color: white;
|
|
146
|
+
border-color: var(--accent);
|
|
147
|
+
}
|
|
148
|
+
button:disabled {
|
|
149
|
+
opacity: 0.55;
|
|
150
|
+
cursor: not-allowed;
|
|
151
|
+
}
|
|
152
|
+
button:hover:not(:disabled) {
|
|
153
|
+
filter: brightness(0.94);
|
|
154
|
+
}
|
|
155
|
+
button:focus-visible,
|
|
156
|
+
input:focus-visible,
|
|
157
|
+
select:focus-visible,
|
|
158
|
+
textarea:focus-visible,
|
|
159
|
+
summary:focus-visible,
|
|
160
|
+
a:focus-visible {
|
|
161
|
+
outline: 3px solid #477dbe;
|
|
162
|
+
outline-offset: 3px;
|
|
163
|
+
}
|
|
164
|
+
label {
|
|
165
|
+
display: block;
|
|
166
|
+
font-size: 0.9rem;
|
|
167
|
+
font-weight: 650;
|
|
168
|
+
margin: 16px 0 6px;
|
|
169
|
+
}
|
|
170
|
+
input,
|
|
171
|
+
select,
|
|
172
|
+
textarea {
|
|
173
|
+
width: 100%;
|
|
174
|
+
}
|
|
175
|
+
textarea {
|
|
176
|
+
min-height: 155px;
|
|
177
|
+
resize: vertical;
|
|
178
|
+
font-weight: 400;
|
|
179
|
+
}
|
|
180
|
+
fieldset {
|
|
181
|
+
border: 0;
|
|
182
|
+
margin: 0;
|
|
183
|
+
padding: 0;
|
|
184
|
+
min-width: 0;
|
|
185
|
+
}
|
|
186
|
+
fieldset:disabled {
|
|
187
|
+
opacity: 0.75;
|
|
188
|
+
}
|
|
189
|
+
.actions {
|
|
190
|
+
display: flex;
|
|
191
|
+
gap: 8px;
|
|
192
|
+
flex-wrap: wrap;
|
|
193
|
+
margin: 14px 0;
|
|
194
|
+
}
|
|
195
|
+
.notice {
|
|
196
|
+
padding: 12px 16px;
|
|
197
|
+
background: var(--wash);
|
|
198
|
+
border-radius: 6px;
|
|
199
|
+
overflow-wrap: anywhere;
|
|
200
|
+
}
|
|
201
|
+
.error {
|
|
202
|
+
background: #ffeadb;
|
|
203
|
+
color: #6f3114;
|
|
204
|
+
}
|
|
205
|
+
#status {
|
|
206
|
+
margin: 0 0 20px;
|
|
207
|
+
}
|
|
208
|
+
#status:empty {
|
|
209
|
+
display: none;
|
|
210
|
+
}
|
|
211
|
+
#session-status {
|
|
212
|
+
margin: 8px 0;
|
|
213
|
+
}
|
|
214
|
+
pre {
|
|
215
|
+
white-space: pre-wrap;
|
|
216
|
+
overflow-wrap: anywhere;
|
|
217
|
+
font: 0.85rem/1.6 ui-monospace, monospace;
|
|
218
|
+
background: #f1f3f3;
|
|
219
|
+
padding: 14px;
|
|
220
|
+
border-radius: 5px;
|
|
221
|
+
}
|
|
222
|
+
details {
|
|
223
|
+
margin: 10px 0;
|
|
224
|
+
}
|
|
225
|
+
summary {
|
|
226
|
+
cursor: pointer;
|
|
227
|
+
min-height: 44px;
|
|
228
|
+
padding: 10px 0;
|
|
229
|
+
font-weight: 650;
|
|
230
|
+
}
|
|
231
|
+
.scroll {
|
|
232
|
+
overflow: auto;
|
|
233
|
+
}
|
|
234
|
+
table {
|
|
235
|
+
border-collapse: collapse;
|
|
236
|
+
width: 100%;
|
|
237
|
+
font-size: 0.9rem;
|
|
238
|
+
}
|
|
239
|
+
th,
|
|
240
|
+
td {
|
|
241
|
+
padding: 12px 10px;
|
|
242
|
+
border-bottom: 1px solid var(--line);
|
|
243
|
+
text-align: left;
|
|
244
|
+
vertical-align: top;
|
|
245
|
+
}
|
|
246
|
+
ul {
|
|
247
|
+
padding-left: 24px;
|
|
248
|
+
}
|
|
249
|
+
.session-list button {
|
|
250
|
+
width: 100%;
|
|
251
|
+
text-align: left;
|
|
252
|
+
margin-top: 8px;
|
|
253
|
+
}
|
|
254
|
+
.session-list small {
|
|
255
|
+
display: block;
|
|
256
|
+
font-weight: 400;
|
|
257
|
+
}
|
|
258
|
+
.skip {
|
|
259
|
+
position: absolute;
|
|
260
|
+
left: 16px;
|
|
261
|
+
top: -100px;
|
|
262
|
+
background: white;
|
|
263
|
+
padding: 12px;
|
|
264
|
+
z-index: 3;
|
|
265
|
+
}
|
|
266
|
+
.skip:focus {
|
|
267
|
+
top: 12px;
|
|
268
|
+
}
|
|
269
|
+
.split {
|
|
270
|
+
display: flex;
|
|
271
|
+
justify-content: space-between;
|
|
272
|
+
gap: 14px;
|
|
273
|
+
align-items: center;
|
|
274
|
+
}
|
|
275
|
+
.saved {
|
|
276
|
+
border-left: 3px solid var(--accent);
|
|
277
|
+
padding-left: 14px;
|
|
278
|
+
}
|
|
279
|
+
.scope {
|
|
280
|
+
font-size: 0.85rem;
|
|
281
|
+
color: var(--muted);
|
|
282
|
+
margin-top: 20px;
|
|
283
|
+
}
|
|
284
|
+
[hidden] {
|
|
285
|
+
display: none !important;
|
|
286
|
+
}
|
|
287
|
+
@media (max-width: 900px) {
|
|
288
|
+
.layout {
|
|
289
|
+
grid-template-columns: 1fr;
|
|
290
|
+
}
|
|
291
|
+
.shell {
|
|
292
|
+
padding: 20px;
|
|
293
|
+
}
|
|
294
|
+
.steps button {
|
|
295
|
+
min-width: 100px;
|
|
296
|
+
}
|
|
297
|
+
header {
|
|
298
|
+
padding: 20px;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
302
|
+
button {
|
|
303
|
+
transition: background 0.12s;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
@media print {
|
|
307
|
+
button,
|
|
308
|
+
.steps,
|
|
309
|
+
#start-form,
|
|
310
|
+
#editor {
|
|
311
|
+
display: none;
|
|
312
|
+
}
|
|
313
|
+
.layout {
|
|
314
|
+
display: block;
|
|
315
|
+
}
|
|
316
|
+
.card {
|
|
317
|
+
break-inside: avoid;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
</style>
|
|
321
|
+
</head>
|
|
322
|
+
<body>
|
|
323
|
+
<a class="skip" href="#workspace">Skip to workspace</a>
|
|
324
|
+
<header>
|
|
325
|
+
<div>
|
|
326
|
+
<div class="eyebrow">Atelier / knowledge practice</div>
|
|
327
|
+
<h1>Knowledge workspace</h1>
|
|
328
|
+
</div>
|
|
329
|
+
<button id="refresh">Refresh evidence</button>
|
|
330
|
+
</header>
|
|
331
|
+
<main class="shell" id="workspace">
|
|
332
|
+
<p class="notice" id="status" role="status" aria-live="polite">
|
|
333
|
+
Loading the current plan and graph…
|
|
334
|
+
</p>
|
|
335
|
+
<nav class="steps" aria-label="Knowledge workflow" id="steps"></nav>
|
|
336
|
+
<div class="layout">
|
|
337
|
+
<section aria-label="Current workspace">
|
|
338
|
+
<div class="card callout" id="purpose"></div>
|
|
339
|
+
<div class="card">
|
|
340
|
+
<label for="question">Work on a question</label
|
|
341
|
+
><select id="question"></select>
|
|
342
|
+
<p class="muted" id="work"></p>
|
|
343
|
+
</div>
|
|
344
|
+
<div id="dashboard"></div>
|
|
345
|
+
</section>
|
|
346
|
+
<aside aria-label="Coauthoring">
|
|
347
|
+
<div class="card">
|
|
348
|
+
<div class="eyebrow">
|
|
349
|
+
Human planning → assisted drafting → review
|
|
350
|
+
</div>
|
|
351
|
+
<h2 style="margin-top: 12px">Coauthor the next step</h2>
|
|
352
|
+
<p class="muted">
|
|
353
|
+
One useful question at a time. Saved wording stays in private
|
|
354
|
+
local history.
|
|
355
|
+
</p>
|
|
356
|
+
<form id="start-form">
|
|
357
|
+
<label for="author">Your name or role</label
|
|
358
|
+
><input
|
|
359
|
+
id="author"
|
|
360
|
+
maxlength="160"
|
|
361
|
+
required
|
|
362
|
+
autocomplete="name"
|
|
363
|
+
/><label for="flow">Guided flow</label
|
|
364
|
+
><select id="flow"></select
|
|
365
|
+
><button class="primary" style="margin-top: 16px" id="start">
|
|
366
|
+
Start a session
|
|
367
|
+
</button>
|
|
368
|
+
</form>
|
|
369
|
+
<p
|
|
370
|
+
id="session-status"
|
|
371
|
+
class="notice"
|
|
372
|
+
role="status"
|
|
373
|
+
aria-live="polite"
|
|
374
|
+
>
|
|
375
|
+
Start here, or resume a session below.
|
|
376
|
+
</p>
|
|
377
|
+
<div id="pending-controls" class="notice" hidden>
|
|
378
|
+
<p>
|
|
379
|
+
The request is unconfirmed. Editing is paused so retry sends the
|
|
380
|
+
exact same wording. Reload and export remain available.
|
|
381
|
+
</p>
|
|
382
|
+
<div class="actions">
|
|
383
|
+
<button id="retry-request">Retry exact request</button>
|
|
384
|
+
<button id="end-retry">End retry and inspect history</button>
|
|
385
|
+
<button id="export-request">Export pending request</button>
|
|
386
|
+
</div>
|
|
387
|
+
</div>
|
|
388
|
+
<div id="session" hidden>
|
|
389
|
+
<p id="session-meta" class="muted"></p>
|
|
390
|
+
<p id="source-state" class="notice"></p>
|
|
391
|
+
<div id="recorded-wording"></div>
|
|
392
|
+
<fieldset id="editor">
|
|
393
|
+
<label for="answer" id="prompt"></label>
|
|
394
|
+
<p id="hint" class="muted"></p>
|
|
395
|
+
<textarea
|
|
396
|
+
id="answer"
|
|
397
|
+
maxlength="24000"
|
|
398
|
+
aria-describedby="hint"
|
|
399
|
+
></textarea>
|
|
400
|
+
<p id="confirmation" hidden>
|
|
401
|
+
Compare this proposed revision with your original answer.
|
|
402
|
+
Confirm it before saving.
|
|
403
|
+
</p>
|
|
404
|
+
<div class="actions" id="controls"></div>
|
|
405
|
+
</fieldset>
|
|
406
|
+
<div class="actions">
|
|
407
|
+
<button id="reload-session">Reload session</button
|
|
408
|
+
><button id="discard" hidden>Discard unsaved text</button
|
|
409
|
+
><button id="snapshot">Export draft snapshot</button>
|
|
410
|
+
</div>
|
|
411
|
+
<p class="muted">
|
|
412
|
+
Unsaved text remains in this tab. Export a snapshot before
|
|
413
|
+
closing it. Reloading a session preserves your unsaved text.
|
|
414
|
+
</p>
|
|
415
|
+
<div id="bound-context"></div>
|
|
416
|
+
<div id="history"></div>
|
|
417
|
+
</div>
|
|
418
|
+
<p class="scope">
|
|
419
|
+
A saved draft is ready for owner review. It does not edit the
|
|
420
|
+
plan, accept evidence, or authorize an action. Names are locally
|
|
421
|
+
asserted.
|
|
422
|
+
</p>
|
|
423
|
+
</div>
|
|
424
|
+
<div class="card session-list">
|
|
425
|
+
<h3>Continue earlier work</h3>
|
|
426
|
+
<form id="open-session-form">
|
|
427
|
+
<label for="session-id">Open an exact session ID</label>
|
|
428
|
+
<input
|
|
429
|
+
id="session-id"
|
|
430
|
+
required
|
|
431
|
+
placeholder="kg-…"
|
|
432
|
+
autocomplete="off"
|
|
433
|
+
/>
|
|
434
|
+
<button id="open-session">Open session</button>
|
|
435
|
+
</form>
|
|
436
|
+
<div id="sessions"></div>
|
|
437
|
+
</div>
|
|
438
|
+
</aside>
|
|
439
|
+
</div>
|
|
440
|
+
</main>
|
|
441
|
+
<script type="module">
|
|
442
|
+
const el = (id) => document.getElementById(id)
|
|
443
|
+
let dashboard = null,
|
|
444
|
+
stage = 'onboard',
|
|
445
|
+
active = null,
|
|
446
|
+
busy = false,
|
|
447
|
+
pending = null,
|
|
448
|
+
endedRequests = [],
|
|
449
|
+
dirty = false,
|
|
450
|
+
contextRequest = 0,
|
|
451
|
+
editGeneration = 0,
|
|
452
|
+
composing = false
|
|
453
|
+
const note = (id, text, error = false) => {
|
|
454
|
+
el(id).textContent = text
|
|
455
|
+
el(id).classList.toggle('error', error)
|
|
456
|
+
}
|
|
457
|
+
function node(tag, text, parent, cls) {
|
|
458
|
+
const item = document.createElement(tag)
|
|
459
|
+
if (text !== undefined) item.textContent = text
|
|
460
|
+
if (cls) item.className = cls
|
|
461
|
+
parent?.append(item)
|
|
462
|
+
return item
|
|
463
|
+
}
|
|
464
|
+
function card(parent, title) {
|
|
465
|
+
const box = node('article', undefined, parent, 'card')
|
|
466
|
+
node('h3', title, box)
|
|
467
|
+
return box
|
|
468
|
+
}
|
|
469
|
+
async function request(route, body) {
|
|
470
|
+
if (!/^[-a-z]+$/.test(route.split('?')[0]))
|
|
471
|
+
throw new Error('Invalid local route')
|
|
472
|
+
const options =
|
|
473
|
+
body === undefined
|
|
474
|
+
? {}
|
|
475
|
+
: {
|
|
476
|
+
method: 'POST',
|
|
477
|
+
headers: { 'Content-Type': 'application/json' },
|
|
478
|
+
body: JSON.stringify(body),
|
|
479
|
+
}
|
|
480
|
+
if (body !== undefined && route !== 'session') {
|
|
481
|
+
const grant = await request('session', {})
|
|
482
|
+
options.headers['X-Atelier-Nonce'] = grant.mutationNonce
|
|
483
|
+
}
|
|
484
|
+
const response = await fetch('/api/knowledge/' + route, options)
|
|
485
|
+
const value = await response.json()
|
|
486
|
+
if (!response.ok || !value.ok)
|
|
487
|
+
throw new Error(value.error || 'Request failed')
|
|
488
|
+
return value
|
|
489
|
+
}
|
|
490
|
+
const selected = () =>
|
|
491
|
+
dashboard?.questions.find((q) => q.id === el('question').value)
|
|
492
|
+
const details = (parent, title, value) => {
|
|
493
|
+
const d = node('details', undefined, parent)
|
|
494
|
+
node('summary', title, d)
|
|
495
|
+
node(
|
|
496
|
+
'pre',
|
|
497
|
+
typeof value === 'string' ? value : JSON.stringify(value, null, 2),
|
|
498
|
+
d
|
|
499
|
+
)
|
|
500
|
+
return d
|
|
501
|
+
}
|
|
502
|
+
function choose(next) {
|
|
503
|
+
stage = next
|
|
504
|
+
for (const b of el('steps').children)
|
|
505
|
+
b.setAttribute('aria-pressed', String(b.dataset.stage === stage))
|
|
506
|
+
el('flow').value = stage
|
|
507
|
+
render()
|
|
508
|
+
}
|
|
509
|
+
async function refresh() {
|
|
510
|
+
try {
|
|
511
|
+
const data = (await request('dashboard')).dashboard
|
|
512
|
+
const old = el('question').value
|
|
513
|
+
dashboard = data
|
|
514
|
+
el('purpose').replaceChildren()
|
|
515
|
+
node(
|
|
516
|
+
'div',
|
|
517
|
+
'THE WORK THIS GRAPH SHOULD IMPROVE',
|
|
518
|
+
el('purpose'),
|
|
519
|
+
'eyebrow'
|
|
520
|
+
)
|
|
521
|
+
node('h2', data.purpose, el('purpose'))
|
|
522
|
+
node('p', data.next.reason, el('purpose'))
|
|
523
|
+
node('small', data.assurance, el('purpose'))
|
|
524
|
+
el('question').replaceChildren()
|
|
525
|
+
for (const q of data.questions) {
|
|
526
|
+
const o = node('option', q.question, el('question'))
|
|
527
|
+
o.value = q.id
|
|
528
|
+
}
|
|
529
|
+
if (data.questions.some((q) => q.id === old))
|
|
530
|
+
el('question').value = old
|
|
531
|
+
const firstLoad = !el('steps').children.length
|
|
532
|
+
if (firstLoad)
|
|
533
|
+
for (const [i, f] of data.flows.entries()) {
|
|
534
|
+
const b = node('button', undefined, el('steps'))
|
|
535
|
+
b.type = 'button'
|
|
536
|
+
b.dataset.stage = f.id
|
|
537
|
+
node('span', '0' + (i + 1), b)
|
|
538
|
+
node('strong', f.title, b)
|
|
539
|
+
b.onclick = () => choose(f.id)
|
|
540
|
+
const o = node('option', f.title, el('flow'))
|
|
541
|
+
o.value = f.id
|
|
542
|
+
}
|
|
543
|
+
if (firstLoad && !active && data.workshop?.available) stage = 'workshop'
|
|
544
|
+
choose(stage)
|
|
545
|
+
note(
|
|
546
|
+
'status',
|
|
547
|
+
'Current plan and graph loaded. Coverage checks do not establish acceptance.'
|
|
548
|
+
)
|
|
549
|
+
await sessions()
|
|
550
|
+
} catch (error) {
|
|
551
|
+
note(
|
|
552
|
+
'status',
|
|
553
|
+
'Workspace unavailable: ' +
|
|
554
|
+
error.message +
|
|
555
|
+
'. Check the plan and restart with atelier dev --knowledge if needed. Earlier session history remains available.',
|
|
556
|
+
true
|
|
557
|
+
)
|
|
558
|
+
await sessions().catch(() => {})
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
function render() {
|
|
562
|
+
if (!dashboard) return
|
|
563
|
+
contextRequest++
|
|
564
|
+
const out = el('dashboard')
|
|
565
|
+
out.replaceChildren()
|
|
566
|
+
const flow = dashboard.flows.find((f) => f.id === stage)
|
|
567
|
+
node('h2', flow.title, out)
|
|
568
|
+
node('p', flow.description, out, 'muted')
|
|
569
|
+
el('work').textContent = selected()?.work || ''
|
|
570
|
+
if (stage === 'workshop') {
|
|
571
|
+
const box = card(out, 'One missing supporting relationship')
|
|
572
|
+
node('p', 'Read both invented sources. Keep your words, interpretation, response and revision separate.', box)
|
|
573
|
+
node('p', 'A draft or copy-only handoff does not apply a source change or approve readiness.', box, 'notice')
|
|
574
|
+
details(box, 'Current finding and exact source evidence', dashboard.workshop.context)
|
|
575
|
+
}
|
|
576
|
+
if (stage === 'onboard') {
|
|
577
|
+
const box = card(out, 'People and purpose')
|
|
578
|
+
node('p', 'Steward: ' + dashboard.steward, box)
|
|
579
|
+
node('p', 'Reviewer: ' + dashboard.reviewer, box)
|
|
580
|
+
node(
|
|
581
|
+
'p',
|
|
582
|
+
'These roles and policies are declarations to review with the people involved.',
|
|
583
|
+
box,
|
|
584
|
+
'muted'
|
|
585
|
+
)
|
|
586
|
+
const grid = node('div', undefined, out, 'grid')
|
|
587
|
+
for (const [key, value] of Object.entries(dashboard.governance)) {
|
|
588
|
+
const c = card(grid, key[0].toUpperCase() + key.slice(1))
|
|
589
|
+
node('p', value, c)
|
|
590
|
+
}
|
|
591
|
+
const c = card(out, 'Start small')
|
|
592
|
+
node(
|
|
593
|
+
'p',
|
|
594
|
+
'Choose one permitted source, one consequential question, and one reviewer. Replace the starter plan with your own definitions and test an end-to-end answer before expanding.',
|
|
595
|
+
c
|
|
596
|
+
)
|
|
597
|
+
node(
|
|
598
|
+
'p',
|
|
599
|
+
'Context budget: ' +
|
|
600
|
+
dashboard.budget.maxContextBytes.toLocaleString() +
|
|
601
|
+
' bytes across at most ' +
|
|
602
|
+
dashboard.budget.maxDocuments +
|
|
603
|
+
' complete documents.',
|
|
604
|
+
c
|
|
605
|
+
)
|
|
606
|
+
}
|
|
607
|
+
if (stage === 'model') {
|
|
608
|
+
const grid = node('div', undefined, out, 'grid')
|
|
609
|
+
for (const c of dashboard.concepts) {
|
|
610
|
+
const box = card(grid, c.id)
|
|
611
|
+
node('p', c.definition, box)
|
|
612
|
+
node('div', 'Identity rule', box, 'eyebrow')
|
|
613
|
+
node('p', c.identityRule, box)
|
|
614
|
+
node(
|
|
615
|
+
'small',
|
|
616
|
+
(c.coverage?.eligibleRecords ?? 0) +
|
|
617
|
+
' eligible / ' + (c.coverage?.records ?? 0) +
|
|
618
|
+
' total records · questions: ' +
|
|
619
|
+
(c.coverage?.questions.join(', ') || 'none'),
|
|
620
|
+
box
|
|
621
|
+
)
|
|
622
|
+
}
|
|
623
|
+
const c = card(out, 'Relationships with a reason')
|
|
624
|
+
for (const r of dashboard.relations) {
|
|
625
|
+
node('h3', r.from + ' → ' + r.to, c)
|
|
626
|
+
node('span', r.predicate, c, 'tag')
|
|
627
|
+
node('p', r.meaning, c)
|
|
628
|
+
node(
|
|
629
|
+
'small',
|
|
630
|
+
(r.coverage?.eligibleMatchingEdges ?? 0) + ' eligible / ' +
|
|
631
|
+
(r.coverage?.matchingEdges ?? 0) + ' total declared matching edges',
|
|
632
|
+
c
|
|
633
|
+
)
|
|
634
|
+
}
|
|
635
|
+
node(
|
|
636
|
+
'p',
|
|
637
|
+
'Coverage describes recorded structure. Review identity, direction, and meaning against the source.',
|
|
638
|
+
c,
|
|
639
|
+
'muted'
|
|
640
|
+
)
|
|
641
|
+
}
|
|
642
|
+
if (stage === 'deepen') {
|
|
643
|
+
const c = card(out, 'Evidence and modeling gaps')
|
|
644
|
+
const issues = [
|
|
645
|
+
...dashboard.inspection.errors,
|
|
646
|
+
...dashboard.inspection.warnings,
|
|
647
|
+
]
|
|
648
|
+
if (!issues.length)
|
|
649
|
+
node(
|
|
650
|
+
'p',
|
|
651
|
+
'No graph structure warnings. Review the retrieval checks below, then check meaning, contradictions, and an unseen question.',
|
|
652
|
+
c
|
|
653
|
+
)
|
|
654
|
+
else {
|
|
655
|
+
const list = node('ul', undefined, c)
|
|
656
|
+
for (const issue of issues) node('li', issue, list)
|
|
657
|
+
}
|
|
658
|
+
for (const q of dashboard.evaluation?.cases || []) {
|
|
659
|
+
const g = q.runs.graph
|
|
660
|
+
if (!g.expectedEvidencePresent || g.stale.length) {
|
|
661
|
+
const b = card(out, q.question)
|
|
662
|
+
node(
|
|
663
|
+
'p',
|
|
664
|
+
g.status === 'abstain-unverified'
|
|
665
|
+
? 'Abstention unverified: matching evidence omitted'
|
|
666
|
+
: q.expect === 'abstain'
|
|
667
|
+
? 'Abstention needs review: matching evidence retrieved'
|
|
668
|
+
: 'Evidence needs attention',
|
|
669
|
+
b,
|
|
670
|
+
'notice'
|
|
671
|
+
)
|
|
672
|
+
node(
|
|
673
|
+
'p',
|
|
674
|
+
'Candidates: ' + g.candidates + '. Selected: ' + g.sourceIds.length +
|
|
675
|
+
'. Omitted: ' + g.omitted + '. Omission details not listed: ' +
|
|
676
|
+
g.omissionsUnlisted + '.',
|
|
677
|
+
b
|
|
678
|
+
)
|
|
679
|
+
if (q.expect === 'abstain') {
|
|
680
|
+
if (g.sourceIds.length) node('p', 'Selected evidence: ' + g.sourceIds.join(', '), b)
|
|
681
|
+
} else {
|
|
682
|
+
node(
|
|
683
|
+
'p',
|
|
684
|
+
'Missing evidence: ' +
|
|
685
|
+
(g.missing.join(', ') || 'none') +
|
|
686
|
+
'. Changed pins: ' +
|
|
687
|
+
(g.stale.join(', ') || 'none') +
|
|
688
|
+
'. Missing relationships: ' +
|
|
689
|
+
(g.missingRelations.join(', ') || 'none') +
|
|
690
|
+
'.',
|
|
691
|
+
b
|
|
692
|
+
)
|
|
693
|
+
}
|
|
694
|
+
if (g.omitted) {
|
|
695
|
+
const list = node('ul', undefined, b)
|
|
696
|
+
for (const omission of g.omissions) node('li', omission.id + ': ' + omission.reason, list)
|
|
697
|
+
node('p', 'Inspect omitted sources and their limits before relying on the result.', b)
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
node(
|
|
702
|
+
'p',
|
|
703
|
+
'Keep unmodeled observations and disagreement visible. A forecast, a proposal, and an observed outcome have different meanings.',
|
|
704
|
+
c
|
|
705
|
+
)
|
|
706
|
+
}
|
|
707
|
+
if (stage === 'apply') {
|
|
708
|
+
const c = card(out, selected()?.question || 'Choose a question')
|
|
709
|
+
node(
|
|
710
|
+
'p',
|
|
711
|
+
'Inspect complete sources before drafting an answer. The context builder selects evidence and makes no model call.',
|
|
712
|
+
c
|
|
713
|
+
)
|
|
714
|
+
const actions = node('div', undefined, c, 'actions')
|
|
715
|
+
for (const mode of ['graph', 'lexical']) {
|
|
716
|
+
const b = node(
|
|
717
|
+
'button',
|
|
718
|
+
mode === 'graph'
|
|
719
|
+
? 'Inspect graph context'
|
|
720
|
+
: 'Inspect direct-search baseline',
|
|
721
|
+
actions
|
|
722
|
+
)
|
|
723
|
+
b.onclick = () => loadContext(mode)
|
|
724
|
+
}
|
|
725
|
+
node('div', undefined, out).id = 'evidence'
|
|
726
|
+
}
|
|
727
|
+
if (stage === 'learn') {
|
|
728
|
+
const c = card(out, 'Is the graph helping?')
|
|
729
|
+
node(
|
|
730
|
+
'p',
|
|
731
|
+
'The same questions and byte budget are checked with direct metadata search and one hop of declared relationships. These are author-specified retrieval checks.',
|
|
732
|
+
c
|
|
733
|
+
)
|
|
734
|
+
if (dashboard.evaluation) {
|
|
735
|
+
const wrap = node('div', undefined, c, 'scroll'),
|
|
736
|
+
table = node('table', undefined, wrap)
|
|
737
|
+
const tr = node('tr', undefined, node('thead', undefined, table))
|
|
738
|
+
for (const h of ['Question', 'Direct search', 'Graph context'])
|
|
739
|
+
node('th', h, tr)
|
|
740
|
+
const body = node('tbody', undefined, table)
|
|
741
|
+
for (const q of dashboard.evaluation.cases) {
|
|
742
|
+
const row = node('tr', undefined, body)
|
|
743
|
+
node('th', q.question, row)
|
|
744
|
+
for (const mode of ['lexical', 'graph']) {
|
|
745
|
+
const run = q.runs[mode]
|
|
746
|
+
node(
|
|
747
|
+
'td',
|
|
748
|
+
(run.expectedEvidencePresent && !run.stale.length
|
|
749
|
+
? q.expect === 'abstain'
|
|
750
|
+
? 'No evidence retrieved; abstention expected'
|
|
751
|
+
: 'Expected evidence retained'
|
|
752
|
+
: run.status === 'abstain-unverified'
|
|
753
|
+
? 'Abstention unverified: matching evidence omitted'
|
|
754
|
+
: 'Needs attention') +
|
|
755
|
+
' · ' +
|
|
756
|
+
run.payloadBytes.toLocaleString() +
|
|
757
|
+
' bytes',
|
|
758
|
+
row
|
|
759
|
+
)
|
|
760
|
+
if (run.omitted) details(row.lastElementChild, 'Omitted evidence', {
|
|
761
|
+
candidates: run.candidates,
|
|
762
|
+
omitted: run.omitted,
|
|
763
|
+
unreadable: run.unreadable,
|
|
764
|
+
omissions: run.omissions,
|
|
765
|
+
omissionsUnlisted: run.omissionsUnlisted,
|
|
766
|
+
})
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
node(
|
|
771
|
+
'p',
|
|
772
|
+
'Actual tokens, cost, answer correctness, time saved, and user acceptance: not measured by this dashboard.',
|
|
773
|
+
c,
|
|
774
|
+
'notice'
|
|
775
|
+
)
|
|
776
|
+
node(
|
|
777
|
+
'p',
|
|
778
|
+
'Use the Learn flow to retain observed outcomes and measurement notes. Compare unseen questions, including cases where the right answer is “not enough evidence.”',
|
|
779
|
+
c
|
|
780
|
+
)
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
async function loadContext(mode) {
|
|
784
|
+
const generation = ++contextRequest
|
|
785
|
+
const q = selected()
|
|
786
|
+
try {
|
|
787
|
+
const result = await request(
|
|
788
|
+
'context?' + new URLSearchParams({ id: q.id, mode })
|
|
789
|
+
)
|
|
790
|
+
if (generation !== contextRequest || stage !== 'apply') return
|
|
791
|
+
const out = el('evidence')
|
|
792
|
+
out.replaceChildren()
|
|
793
|
+
const context = result.context
|
|
794
|
+
const c = card(
|
|
795
|
+
out,
|
|
796
|
+
context.sources.length
|
|
797
|
+
? 'Evidence selected'
|
|
798
|
+
: 'More evidence needed'
|
|
799
|
+
)
|
|
800
|
+
node(
|
|
801
|
+
'p',
|
|
802
|
+
context.budget.payloadBytes.toLocaleString() +
|
|
803
|
+
' bytes · approximately ' +
|
|
804
|
+
context.budget.estimatedTokens.toLocaleString() +
|
|
805
|
+
' tokens · 0 provider calls',
|
|
806
|
+
c
|
|
807
|
+
)
|
|
808
|
+
node(
|
|
809
|
+
'small',
|
|
810
|
+
'Token estimate uses bytes / 4. Actual token usage is unknown. ' +
|
|
811
|
+
context.coverage.omitted +
|
|
812
|
+
' sources omitted; ' +
|
|
813
|
+
context.coverage.unreadable +
|
|
814
|
+
' unreadable.',
|
|
815
|
+
c
|
|
816
|
+
)
|
|
817
|
+
node('p', context.use, c)
|
|
818
|
+
if (context.coverage.omitted) {
|
|
819
|
+
const list = node('ul', undefined, c)
|
|
820
|
+
for (const omission of context.omissions)
|
|
821
|
+
node('li', omission.id + ': ' + omission.reason, list)
|
|
822
|
+
if (context.coverage.omissionsUnlisted)
|
|
823
|
+
node('p', context.coverage.omissionsUnlisted + ' further omission details exceed the packet allowance. Narrow the source scope or increase the budget, then inspect again.', c, 'notice')
|
|
824
|
+
}
|
|
825
|
+
for (const source of context.sources) {
|
|
826
|
+
const b = card(out, source.id)
|
|
827
|
+
node(
|
|
828
|
+
'p',
|
|
829
|
+
source.repo +
|
|
830
|
+
'/' +
|
|
831
|
+
source.path +
|
|
832
|
+
' · lines ' +
|
|
833
|
+
source.lines.start +
|
|
834
|
+
'–' +
|
|
835
|
+
source.lines.end,
|
|
836
|
+
b,
|
|
837
|
+
'muted'
|
|
838
|
+
)
|
|
839
|
+
details(b, 'Read complete source', source.text)
|
|
840
|
+
details(b, 'Source identity', source.sha256)
|
|
841
|
+
}
|
|
842
|
+
details(out, 'Declared relationships', context.relations)
|
|
843
|
+
details(out, 'Context for your agent', context)
|
|
844
|
+
} catch (error) {
|
|
845
|
+
if (generation === contextRequest)
|
|
846
|
+
note('status', 'Context unavailable: ' + error.message, true)
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
async function sessions() {
|
|
850
|
+
try {
|
|
851
|
+
const report = await request('sessions')
|
|
852
|
+
const list = report.sessions
|
|
853
|
+
el('sessions').replaceChildren()
|
|
854
|
+
if (report.truncated)
|
|
855
|
+
node(
|
|
856
|
+
'p',
|
|
857
|
+
'Showing the newest ' +
|
|
858
|
+
report.limit +
|
|
859
|
+
' of ' +
|
|
860
|
+
report.total +
|
|
861
|
+
' local session files. Open any older session by its exact ID.',
|
|
862
|
+
el('sessions'),
|
|
863
|
+
'muted'
|
|
864
|
+
)
|
|
865
|
+
if (!list.length)
|
|
866
|
+
node('p', 'No sessions yet.', el('sessions'), 'muted')
|
|
867
|
+
for (const s of list) {
|
|
868
|
+
if (!s.available) {
|
|
869
|
+
const box = node('div', undefined, el('sessions'), 'saved')
|
|
870
|
+
node('p', s.id, box)
|
|
871
|
+
node('p', s.reason, box)
|
|
872
|
+
if (s.recoverable) {
|
|
873
|
+
const resume = node('button', 'Resume incomplete start', box)
|
|
874
|
+
resume.onclick = () => send('recover', { sessionId: s.id })
|
|
875
|
+
}
|
|
876
|
+
continue
|
|
877
|
+
}
|
|
878
|
+
const b = node('button', s.title + ' · ' + s.phase, el('sessions'))
|
|
879
|
+
node(
|
|
880
|
+
'small',
|
|
881
|
+
s.question +
|
|
882
|
+
' · ' +
|
|
883
|
+
s.saved +
|
|
884
|
+
'/' +
|
|
885
|
+
s.fields +
|
|
886
|
+
' saved' +
|
|
887
|
+
(s.current
|
|
888
|
+
? ''
|
|
889
|
+
: s.currency === 'unavailable'
|
|
890
|
+
? ' · source check unavailable'
|
|
891
|
+
: ' · earlier source revision'),
|
|
892
|
+
b
|
|
893
|
+
)
|
|
894
|
+
node('small', s.id + (s.createdAt ? ' · ' + s.createdAt : ''), b)
|
|
895
|
+
b.disabled = dirty || busy || Boolean(pending)
|
|
896
|
+
b.onclick = () => readSession(s.id)
|
|
897
|
+
}
|
|
898
|
+
setBusy(busy)
|
|
899
|
+
} catch (error) {
|
|
900
|
+
el('sessions').textContent = 'History unavailable: ' + error.message
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
function setBusy(value) {
|
|
904
|
+
busy = value
|
|
905
|
+
el('discard').hidden = !dirty
|
|
906
|
+
el('discard').disabled = value || Boolean(pending) || composing
|
|
907
|
+
el('start').disabled = value || dirty || Boolean(pending) || composing
|
|
908
|
+
el('open-session').disabled = value || dirty || Boolean(pending)
|
|
909
|
+
el('reload-session').disabled = value || composing
|
|
910
|
+
// The native field owns text, IME and undo while a request is pending.
|
|
911
|
+
el('editor').disabled = !active
|
|
912
|
+
if (value || pending || composing) el('answer').readOnly = false
|
|
913
|
+
for (const b of el('controls').querySelectorAll('button'))
|
|
914
|
+
b.disabled = value || Boolean(pending) || composing || !active?.current
|
|
915
|
+
el('pending-controls').hidden = !pending
|
|
916
|
+
el('retry-request').disabled = value
|
|
917
|
+
el('end-retry').disabled = value
|
|
918
|
+
el('export-request').disabled = value
|
|
919
|
+
for (const b of el('sessions').querySelectorAll('button'))
|
|
920
|
+
b.disabled = value || dirty || Boolean(pending)
|
|
921
|
+
}
|
|
922
|
+
function participantText(value, field) {
|
|
923
|
+
if (active?.record.context?.participantResponseProfile === 'four-choice-separate-review-r1'
|
|
924
|
+
&& field === 'interpretation') {
|
|
925
|
+
try { return JSON.parse(value).text } catch { return value }
|
|
926
|
+
}
|
|
927
|
+
return value
|
|
928
|
+
}
|
|
929
|
+
function showWorkshopReview() {
|
|
930
|
+
if (!active?.current || busy || pending || dirty || composing) return
|
|
931
|
+
const parentId = active.record.id
|
|
932
|
+
const preview = node('div', undefined, el('controls'), 'saved')
|
|
933
|
+
node('h3', 'Review declaration', preview)
|
|
934
|
+
node('p', 'Current declaration: []', preview)
|
|
935
|
+
node('p', 'Selected draft: ["devday:workshop"]', preview)
|
|
936
|
+
node('p', 'This preview has no saved or source effect. Select the draft to record and save it separately.', preview)
|
|
937
|
+
const select = node('button', 'Select this draft', preview)
|
|
938
|
+
select.type = 'button'
|
|
939
|
+
select.onclick = () => {
|
|
940
|
+
if (active.record.id !== parentId || busy || pending || dirty || composing) return
|
|
941
|
+
send('workshop-review', { requestId: crypto.randomUUID(), sessionId: parentId })
|
|
942
|
+
}
|
|
943
|
+
const back = node('button', 'Return', preview)
|
|
944
|
+
back.type = 'button'
|
|
945
|
+
back.onclick = () => preview.remove()
|
|
946
|
+
}
|
|
947
|
+
function renderSession({ preserve = false } = {}) {
|
|
948
|
+
if (!active) return
|
|
949
|
+
el('session').hidden = false
|
|
950
|
+
const { record, state, current } = active
|
|
951
|
+
el('session-meta').textContent =
|
|
952
|
+
record.title +
|
|
953
|
+
' · ' +
|
|
954
|
+
record.question.question +
|
|
955
|
+
' · ' +
|
|
956
|
+
record.author +
|
|
957
|
+
' (locally asserted) · ' +
|
|
958
|
+
state.saved.length +
|
|
959
|
+
'/' +
|
|
960
|
+
state.fields.length +
|
|
961
|
+
' saved'
|
|
962
|
+
note(
|
|
963
|
+
'source-state',
|
|
964
|
+
current
|
|
965
|
+
? 'Bound sources still match this session.'
|
|
966
|
+
: active.currency === 'unavailable'
|
|
967
|
+
? 'Bound sources could not be checked. History is retained; repair the workspace before continuing.'
|
|
968
|
+
: 'Earlier source revision. History is retained; refresh evidence and start a new session to continue.',
|
|
969
|
+
!current
|
|
970
|
+
)
|
|
971
|
+
const prompt = record.prompts[state.index]
|
|
972
|
+
el('start-form').hidden = false
|
|
973
|
+
el('prompt').textContent = prompt?.[1] || 'All draft fields saved'
|
|
974
|
+
el('hint').textContent =
|
|
975
|
+
prompt?.[2] ||
|
|
976
|
+
'Review the retained wording and export it for the source owner.'
|
|
977
|
+
if (!preserve && !dirty) el('answer').value = participantText(state.proposal?.text || '', state.fields[state.index]?.id)
|
|
978
|
+
|| (record.flow === 'workshop-review' && state.phase === 'input' ? '["devday:workshop"]' : '')
|
|
979
|
+
const recorded = el('recorded-wording')
|
|
980
|
+
recorded.replaceChildren()
|
|
981
|
+
const field = state.fields[state.index]?.id
|
|
982
|
+
const answers = state.answers.filter((a) => a.fieldId === field)
|
|
983
|
+
if (
|
|
984
|
+
dirty &&
|
|
985
|
+
state.proposal &&
|
|
986
|
+
el('answer').value !== participantText(state.proposal.text, field)
|
|
987
|
+
) {
|
|
988
|
+
node(
|
|
989
|
+
'p',
|
|
990
|
+
'Recorded wording differs from your tab text. Compare it before recording another answer.',
|
|
991
|
+
recorded,
|
|
992
|
+
'notice'
|
|
993
|
+
)
|
|
994
|
+
node('h3', 'Current recorded wording', recorded)
|
|
995
|
+
node('p', participantText(state.proposal.text, field), recorded, 'saved')
|
|
996
|
+
node(
|
|
997
|
+
'small',
|
|
998
|
+
'Session revision ' +
|
|
999
|
+
state.revision +
|
|
1000
|
+
'. Recording a new answer keeps both versions in history and makes your wording the current proposal.',
|
|
1001
|
+
recorded
|
|
1002
|
+
)
|
|
1003
|
+
}
|
|
1004
|
+
if (answers.length) {
|
|
1005
|
+
const history = details(
|
|
1006
|
+
recorded,
|
|
1007
|
+
'Retained answers for this step',
|
|
1008
|
+
answers.map((a) => ({
|
|
1009
|
+
text: participantText(a.text, field),
|
|
1010
|
+
eventId: a.eventId,
|
|
1011
|
+
revision:
|
|
1012
|
+
(state.events.find((e) => e.id === a.eventId)?.event
|
|
1013
|
+
.expectedRevision ?? -1) + 1,
|
|
1014
|
+
}))
|
|
1015
|
+
)
|
|
1016
|
+
history.open = Boolean(
|
|
1017
|
+
dirty &&
|
|
1018
|
+
state.proposal &&
|
|
1019
|
+
el('answer').value !== participantText(state.proposal.text, field)
|
|
1020
|
+
)
|
|
1021
|
+
}
|
|
1022
|
+
el('answer').hidden = !prompt && !dirty
|
|
1023
|
+
el('answer').readOnly =
|
|
1024
|
+
!['input', 'draft'].includes(state.phase) && !dirty && !composing && !pending && !busy
|
|
1025
|
+
el('confirmation').hidden = state.phase !== 'confirmation'
|
|
1026
|
+
el('controls').replaceChildren()
|
|
1027
|
+
const action = (title, type) => {
|
|
1028
|
+
const b = node(
|
|
1029
|
+
'button',
|
|
1030
|
+
title,
|
|
1031
|
+
el('controls'),
|
|
1032
|
+
['save', 'answer'].includes(type) ? 'primary' : undefined
|
|
1033
|
+
)
|
|
1034
|
+
b.type = 'button'
|
|
1035
|
+
b.onclick = () => intent(type)
|
|
1036
|
+
}
|
|
1037
|
+
if (['input', 'draft'].includes(state.phase)) {
|
|
1038
|
+
const participant = record.context?.participantResponseProfile === 'four-choice-separate-review-r1'
|
|
1039
|
+
if (participant && field === 'choice') {
|
|
1040
|
+
for (const [value, label] of [['note', 'Note'], ['perspective-only', 'Perspective'], ['disagreement', 'Disagreement'], ['pause', 'Pause']]) {
|
|
1041
|
+
const choice = node('button', label, el('controls'))
|
|
1042
|
+
choice.type = 'button'
|
|
1043
|
+
choice.onclick = () => {
|
|
1044
|
+
if (busy || pending || composing) return
|
|
1045
|
+
el('answer').value = value
|
|
1046
|
+
editGeneration++
|
|
1047
|
+
dirty = true
|
|
1048
|
+
intent('answer')
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
} else action(record.flow === 'workshop-review' ? 'Record selected draft'
|
|
1052
|
+
: participant && field === 'interpretation' ? 'Record optional interpretation' : 'Record my answer', 'answer')
|
|
1053
|
+
if (state.phase === 'draft' && (!participant || field === 'interpretation')) action('Propose revised wording', 'propose')
|
|
1054
|
+
if (state.phase === 'draft') action('Save private draft', 'save')
|
|
1055
|
+
}
|
|
1056
|
+
if (state.phase === 'confirmation') {
|
|
1057
|
+
details(el('controls'), 'Proposed wording', participantText(state.proposal.text, field))
|
|
1058
|
+
details(
|
|
1059
|
+
el('controls'),
|
|
1060
|
+
'Original wording',
|
|
1061
|
+
participantText(state.answers.find(
|
|
1062
|
+
(a) => a.eventId === state.proposal.originalEventId
|
|
1063
|
+
)?.text || '', field)
|
|
1064
|
+
)
|
|
1065
|
+
action('Confirm revised wording', 'confirm')
|
|
1066
|
+
action('Keep original wording', 'reject')
|
|
1067
|
+
}
|
|
1068
|
+
if (state.phase === 'saved') action('Continue', 'advance')
|
|
1069
|
+
if (state.phase === 'complete' && record.flow === 'workshop'
|
|
1070
|
+
&& record.context?.participantResponseProfile === 'four-choice-separate-review-r1'
|
|
1071
|
+
&& active.owningReadbacks?.verified === true) {
|
|
1072
|
+
const review = node('button', 'Review', el('controls'))
|
|
1073
|
+
review.type = 'button'
|
|
1074
|
+
review.onclick = showWorkshopReview
|
|
1075
|
+
}
|
|
1076
|
+
if (state.phase === 'complete' && (record.flow === 'workshop-review'
|
|
1077
|
+
|| record.flow === 'workshop' && state.saved.find(s => s.fieldId === 'choice')?.text === 'revision')) {
|
|
1078
|
+
const b = node('button', 'Prepare source-owner handoff', el('controls'))
|
|
1079
|
+
b.onclick = async () => {
|
|
1080
|
+
if (busy || pending || dirty || composing) return
|
|
1081
|
+
setBusy(true)
|
|
1082
|
+
try {
|
|
1083
|
+
const value = await request('workshop-handoff', { sessionId: record.id })
|
|
1084
|
+
details(el('bound-context'), 'Copy-only source-owner handoff', value.handoff)
|
|
1085
|
+
note('session-status', 'Handoff prepared from durable readback. Source-owner editing and reassessment remain required.')
|
|
1086
|
+
} catch (error) { note('session-status', error.message, true) }
|
|
1087
|
+
finally { setBusy(false) }
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
if (state.phase === 'paused') action('Resume', 'resume')
|
|
1091
|
+
else if (
|
|
1092
|
+
['input', 'draft', 'confirmation', 'saved', 'recovery'].includes(
|
|
1093
|
+
state.phase
|
|
1094
|
+
)
|
|
1095
|
+
)
|
|
1096
|
+
action('Pause', 'pause')
|
|
1097
|
+
if (state.phase === 'recovery' && state.pending.retries < 1)
|
|
1098
|
+
action('Retry private save', 'retry')
|
|
1099
|
+
if (state.phase === 'saving')
|
|
1100
|
+
action('Reconcile pending save', 'recover')
|
|
1101
|
+
if (state.phase === 'recovery' && state.pending.retries >= 1)
|
|
1102
|
+
node(
|
|
1103
|
+
'p',
|
|
1104
|
+
'Retry exhausted. Preserve history for operator reconciliation.',
|
|
1105
|
+
el('controls')
|
|
1106
|
+
)
|
|
1107
|
+
el('bound-context').replaceChildren()
|
|
1108
|
+
details(
|
|
1109
|
+
el('bound-context'),
|
|
1110
|
+
'Evidence captured for this session',
|
|
1111
|
+
record.context || 'No context available at session start.'
|
|
1112
|
+
)
|
|
1113
|
+
if (active.owningReadbacks) details(el('bound-context'), 'Descriptor, event history and immutable saved values', active.owningReadbacks)
|
|
1114
|
+
if (record.context?.participantResponseProfile === 'four-choice-separate-review-r1' && record.flow === 'workshop')
|
|
1115
|
+
details(el('bound-context'), 'Original contribution and choice IDs', {
|
|
1116
|
+
contributionId: state.answers.filter(a => a.fieldId === 'original-words').at(-1)?.eventId || null,
|
|
1117
|
+
choiceId: state.answers.filter(a => a.fieldId === 'choice').at(-1)?.eventId || null,
|
|
1118
|
+
choiceStatus: state.saved.some(s => s.fieldId === 'choice') && active.owningReadbacks?.verified ? 'confirmed'
|
|
1119
|
+
: state.answers.some(a => a.fieldId === 'choice') ? 'unconfirmed' : 'not-recorded'
|
|
1120
|
+
})
|
|
1121
|
+
el('history').replaceChildren()
|
|
1122
|
+
for (const saved of state.saved) {
|
|
1123
|
+
const box = node('div', undefined, el('history'), 'saved')
|
|
1124
|
+
node(
|
|
1125
|
+
'h3',
|
|
1126
|
+
record.prompts.find((p) => p[0] === saved.fieldId)?.[1] ||
|
|
1127
|
+
saved.fieldId,
|
|
1128
|
+
box
|
|
1129
|
+
)
|
|
1130
|
+
node('p', participantText(saved.text, saved.fieldId), box)
|
|
1131
|
+
details(box, 'Durable draft receipt', saved.receipt)
|
|
1132
|
+
}
|
|
1133
|
+
setBusy(busy)
|
|
1134
|
+
}
|
|
1135
|
+
async function readSession(id) {
|
|
1136
|
+
try {
|
|
1137
|
+
active = await request('read?' + new URLSearchParams({ id }))
|
|
1138
|
+
renderSession({ preserve: dirty })
|
|
1139
|
+
note(
|
|
1140
|
+
'session-status',
|
|
1141
|
+
'Session loaded. ' +
|
|
1142
|
+
(dirty
|
|
1143
|
+
? 'Your unsaved text is still in the editor.'
|
|
1144
|
+
: 'Saved drafts and retained intents were read from local history.')
|
|
1145
|
+
)
|
|
1146
|
+
await sessions()
|
|
1147
|
+
return true
|
|
1148
|
+
} catch (error) {
|
|
1149
|
+
note('session-status', 'Session unavailable: ' + error.message, true)
|
|
1150
|
+
return false
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
async function send(route, input, generation = editGeneration) {
|
|
1154
|
+
pending = { route, input, generation }
|
|
1155
|
+
setBusy(true)
|
|
1156
|
+
try {
|
|
1157
|
+
active = await request(route, input)
|
|
1158
|
+
pending = null
|
|
1159
|
+
if (generation === editGeneration && !composing) dirty = false
|
|
1160
|
+
renderSession({ preserve: dirty || composing })
|
|
1161
|
+
note(
|
|
1162
|
+
'session-status',
|
|
1163
|
+
active.current
|
|
1164
|
+
? operationMessage(route, input, active.state)
|
|
1165
|
+
: 'Sources changed during the operation. Retained history is available; start a newly bound session.'
|
|
1166
|
+
)
|
|
1167
|
+
await sessions()
|
|
1168
|
+
} catch (error) {
|
|
1169
|
+
note(
|
|
1170
|
+
'session-status',
|
|
1171
|
+
'Not confirmed saved: ' +
|
|
1172
|
+
error.message +
|
|
1173
|
+
'. Your wording remains here. If the service is unavailable, restore atelier dev --knowledge and retry. For a revision, source, or event refusal, end retry and inspect history before another intent.',
|
|
1174
|
+
true
|
|
1175
|
+
)
|
|
1176
|
+
} finally {
|
|
1177
|
+
setBusy(false)
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
function operationMessage(route, input, state) {
|
|
1181
|
+
const step = ' Current step: ' + state.phase + '.'
|
|
1182
|
+
if (['saving', 'recovery'].includes(state.phase))
|
|
1183
|
+
return (
|
|
1184
|
+
'Save not confirmed. Preserve your wording and inspect the recovery controls.' +
|
|
1185
|
+
step
|
|
1186
|
+
)
|
|
1187
|
+
if (route === 'start' || route === 'workshop-review')
|
|
1188
|
+
return 'Session started. Its retained state was read back.' + step
|
|
1189
|
+
const type = input.event?.type
|
|
1190
|
+
if (type === 'answer')
|
|
1191
|
+
return (
|
|
1192
|
+
'Answer retained in session history; this request did not save a draft.' +
|
|
1193
|
+
step
|
|
1194
|
+
)
|
|
1195
|
+
if (
|
|
1196
|
+
type === 'save' &&
|
|
1197
|
+
state.saved.some((s) => s.receipt.requestId === input.event.id)
|
|
1198
|
+
)
|
|
1199
|
+
return 'Saved draft receipt read back.' + step
|
|
1200
|
+
if (
|
|
1201
|
+
(type === 'retry' || route === 'recover') &&
|
|
1202
|
+
state.phase === 'saved'
|
|
1203
|
+
)
|
|
1204
|
+
return 'Saved draft receipt read back.' + step
|
|
1205
|
+
if (type === 'reject' || type === 'confirm')
|
|
1206
|
+
return (
|
|
1207
|
+
'Wording choice recorded; save the private draft when ready.' + step
|
|
1208
|
+
)
|
|
1209
|
+
return 'Session state read back.' + step
|
|
1210
|
+
}
|
|
1211
|
+
async function intent(type) {
|
|
1212
|
+
if (pending)
|
|
1213
|
+
return note(
|
|
1214
|
+
'session-status',
|
|
1215
|
+
'Resolve the pending request with Retry or End retry before recording another intent.',
|
|
1216
|
+
true
|
|
1217
|
+
)
|
|
1218
|
+
if (!active || busy || composing) return
|
|
1219
|
+
if (dirty && !['answer', 'propose'].includes(type))
|
|
1220
|
+
return note(
|
|
1221
|
+
'session-status',
|
|
1222
|
+
'Record or export your changed answer before moving on.',
|
|
1223
|
+
true
|
|
1224
|
+
)
|
|
1225
|
+
if (type === 'recover')
|
|
1226
|
+
return send('recover', { sessionId: active.record.id })
|
|
1227
|
+
const event = {
|
|
1228
|
+
id: crypto.randomUUID(),
|
|
1229
|
+
type,
|
|
1230
|
+
expectedRevision: active.state.revision,
|
|
1231
|
+
}
|
|
1232
|
+
if (['answer', 'propose'].includes(type)) {
|
|
1233
|
+
event.text = el('answer').value
|
|
1234
|
+
if (active.record.context?.participantResponseProfile === 'four-choice-separate-review-r1'
|
|
1235
|
+
&& active.state.fields[active.state.index]?.id === 'interpretation') event.text = JSON.stringify({ text: event.text })
|
|
1236
|
+
if (!event.text.trim())
|
|
1237
|
+
return note('session-status', 'Write an answer first.', true)
|
|
1238
|
+
}
|
|
1239
|
+
await send('event', { sessionId: active.record.id, event })
|
|
1240
|
+
}
|
|
1241
|
+
el('start-form').onsubmit = (event) => {
|
|
1242
|
+
event.preventDefault()
|
|
1243
|
+
if (pending)
|
|
1244
|
+
return note(
|
|
1245
|
+
'session-status',
|
|
1246
|
+
'Resolve the pending request before starting another session.',
|
|
1247
|
+
true
|
|
1248
|
+
)
|
|
1249
|
+
if (!dashboard || busy || dirty || composing) return
|
|
1250
|
+
send('start', {
|
|
1251
|
+
requestId: crypto.randomUUID(),
|
|
1252
|
+
flow: el('flow').value,
|
|
1253
|
+
questionId: selected().id,
|
|
1254
|
+
snapshot: dashboard.snapshot,
|
|
1255
|
+
author: el('author').value,
|
|
1256
|
+
})
|
|
1257
|
+
}
|
|
1258
|
+
el('discard').onclick = () => {
|
|
1259
|
+
dirty = false
|
|
1260
|
+
renderSession()
|
|
1261
|
+
note(
|
|
1262
|
+
'session-status',
|
|
1263
|
+
'Unsaved tab text discarded. Retained session history is unchanged.'
|
|
1264
|
+
)
|
|
1265
|
+
}
|
|
1266
|
+
el('answer').oninput = () => {
|
|
1267
|
+
editGeneration++
|
|
1268
|
+
dirty = true
|
|
1269
|
+
setBusy(busy)
|
|
1270
|
+
note(
|
|
1271
|
+
'session-status',
|
|
1272
|
+
'Unsaved wording in this tab. Record it to retain the answer in session history.'
|
|
1273
|
+
)
|
|
1274
|
+
}
|
|
1275
|
+
el('answer').oncompositionstart = () => {
|
|
1276
|
+
composing = true
|
|
1277
|
+
dirty = true
|
|
1278
|
+
editGeneration++
|
|
1279
|
+
setBusy(busy)
|
|
1280
|
+
}
|
|
1281
|
+
el('answer').oncompositionend = () => {
|
|
1282
|
+
composing = false
|
|
1283
|
+
dirty = true
|
|
1284
|
+
editGeneration++
|
|
1285
|
+
renderSession({ preserve: true })
|
|
1286
|
+
}
|
|
1287
|
+
el('question').onchange = render
|
|
1288
|
+
el('refresh').onclick = refresh
|
|
1289
|
+
el('reload-session').onclick = () =>
|
|
1290
|
+
active && readSession(active.record.id)
|
|
1291
|
+
el('retry-request').onclick = async () => {
|
|
1292
|
+
if (!pending || busy || composing) return
|
|
1293
|
+
const original = pending
|
|
1294
|
+
setBusy(true)
|
|
1295
|
+
try {
|
|
1296
|
+
const sessionId = ['start', 'workshop-review'].includes(original.route)
|
|
1297
|
+
? 'kg-' + original.input.requestId.toLowerCase() : original.input.sessionId
|
|
1298
|
+
const lookup = await request('lookup', { sessionId, eventId: original.input.event?.id || null })
|
|
1299
|
+
if (lookup.outcome === 'unknown') {
|
|
1300
|
+
note('session-status', 'Original outcome unknown. Keep this request and inspect retained history; no retry was sent.', true)
|
|
1301
|
+
} else if (lookup.outcome === 'observed') {
|
|
1302
|
+
// Compare the actual retained event before clearing original custody.
|
|
1303
|
+
const retained = lookup.session.state.events.find(e => e.id === original.input.event?.id)
|
|
1304
|
+
if (original.route === 'event' && (!retained || Object.keys(retained.event).length !== Object.keys(original.input.event).length || Object.keys(original.input.event).some(k => retained.event[k] !== original.input.event[k])))
|
|
1305
|
+
throw new Error('original ID has different retained intent')
|
|
1306
|
+
if (original.route === 'start' && (['flow', 'snapshot'].some(k => lookup.session.record[k] !== original.input[k]) || lookup.session.record.author !== original.input.author.trim()))
|
|
1307
|
+
throw new Error('original start ID has different retained intent')
|
|
1308
|
+
if (original.route === 'workshop-review' && (lookup.session.record.flow !== 'workshop-review'
|
|
1309
|
+
|| lookup.session.record.context.participant?.sessionId !== original.input.sessionId))
|
|
1310
|
+
throw new Error('original Review ID has different retained participant')
|
|
1311
|
+
active = lookup.session
|
|
1312
|
+
pending = null
|
|
1313
|
+
if (original.generation === editGeneration && !composing) dirty = false
|
|
1314
|
+
renderSession({ preserve: dirty || composing })
|
|
1315
|
+
note('session-status', 'Original request found in durable history; no repeated effect was sent.')
|
|
1316
|
+
} else if (lookup.outcome === 'not-found') {
|
|
1317
|
+
await send(original.route, original.input, original.generation)
|
|
1318
|
+
} else throw new Error('original outcome not established')
|
|
1319
|
+
} catch (error) { note('session-status', 'Original lookup failed: ' + error.message, true) }
|
|
1320
|
+
finally { setBusy(false) }
|
|
1321
|
+
}
|
|
1322
|
+
el('end-retry').onclick = async () => {
|
|
1323
|
+
if (!pending || busy) return
|
|
1324
|
+
const ended = pending
|
|
1325
|
+
endedRequests.push(ended)
|
|
1326
|
+
pending = null
|
|
1327
|
+
setBusy(false)
|
|
1328
|
+
if (active) {
|
|
1329
|
+
if (!(await readSession(active.record.id))) return
|
|
1330
|
+
} else await sessions()
|
|
1331
|
+
note(
|
|
1332
|
+
'session-status',
|
|
1333
|
+
'Retry ended; no server history was deleted or cancelled. Inspect the session before another intent. Your text and the ended request remain in this tab and its exported snapshot. Session: ' +
|
|
1334
|
+
(ended.input.sessionId || 'kg-' + ended.input.requestId)
|
|
1335
|
+
)
|
|
1336
|
+
}
|
|
1337
|
+
el('open-session-form').onsubmit = (event) => {
|
|
1338
|
+
event.preventDefault()
|
|
1339
|
+
if (busy || dirty || pending)
|
|
1340
|
+
return note(
|
|
1341
|
+
'session-status',
|
|
1342
|
+
'Resolve your current wording and pending request before opening another session.',
|
|
1343
|
+
true
|
|
1344
|
+
)
|
|
1345
|
+
readSession(el('session-id').value.trim())
|
|
1346
|
+
}
|
|
1347
|
+
function exportSnapshot() {
|
|
1348
|
+
if (!active && !pending && !endedRequests.length) return
|
|
1349
|
+
const value = {
|
|
1350
|
+
status: 'private-draft-for-owner-review',
|
|
1351
|
+
sourceEditsApplied: false,
|
|
1352
|
+
session: active,
|
|
1353
|
+
unsavedText: dirty ? el('answer').value : null,
|
|
1354
|
+
pendingRequest: pending,
|
|
1355
|
+
endedRequests,
|
|
1356
|
+
}
|
|
1357
|
+
const url = URL.createObjectURL(
|
|
1358
|
+
new Blob([JSON.stringify(value, null, 2)], {
|
|
1359
|
+
type: 'application/json',
|
|
1360
|
+
})
|
|
1361
|
+
)
|
|
1362
|
+
const a = document.createElement('a')
|
|
1363
|
+
a.href = url
|
|
1364
|
+
a.download =
|
|
1365
|
+
'knowledge-draft-' +
|
|
1366
|
+
(active?.record.id || pending?.input.requestId || 'request') +
|
|
1367
|
+
'.json'
|
|
1368
|
+
a.click()
|
|
1369
|
+
setTimeout(() => URL.revokeObjectURL(url), 1000)
|
|
1370
|
+
note(
|
|
1371
|
+
'session-status',
|
|
1372
|
+
'Private draft snapshot exported. Review its audience before sharing.'
|
|
1373
|
+
)
|
|
1374
|
+
}
|
|
1375
|
+
el('snapshot').onclick = exportSnapshot
|
|
1376
|
+
el('export-request').onclick = exportSnapshot
|
|
1377
|
+
window.addEventListener('beforeunload', (event) => {
|
|
1378
|
+
if (dirty || pending) {
|
|
1379
|
+
event.preventDefault()
|
|
1380
|
+
event.returnValue = ''
|
|
1381
|
+
}
|
|
1382
|
+
})
|
|
1383
|
+
refresh()
|
|
1384
|
+
</script>
|
|
1385
|
+
</body>
|
|
1386
|
+
</html>
|
|
1387
|
+
`
|
|
1388
|
+
}
|