@agentwhy/cli 0.0.0-dev
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/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +181 -0
- package/THIRD_PARTY_NOTICES.md +31 -0
- package/dist/adapter/claude-code/contract/assumptions.js +208 -0
- package/dist/adapter/claude-code/contract/denials.js +15 -0
- package/dist/adapter/claude-code/contract/entry-points.js +15 -0
- package/dist/adapter/claude-code/contract/fields.js +73 -0
- package/dist/adapter/claude-code/contract/hooks.js +96 -0
- package/dist/adapter/claude-code/contract/identifiers.js +15 -0
- package/dist/adapter/claude-code/contract/layout.js +29 -0
- package/dist/adapter/claude-code/contract/line-types.js +26 -0
- package/dist/adapter/claude-code/contract/projects.js +23 -0
- package/dist/adapter/claude-code/contract/recognition.js +14 -0
- package/dist/adapter/claude-code/contract/session-title.js +20 -0
- package/dist/adapter/claude-code/contract/settings.js +27 -0
- package/dist/adapter/claude-code/contract/task-notifications.js +33 -0
- package/dist/adapter/claude-code/contract/tools.js +37 -0
- package/dist/adapter/claude-code/contract/version.js +51 -0
- package/dist/adapter/claude-code/discovery/claude-code-project-catalogue.js +129 -0
- package/dist/adapter/claude-code/discovery/claude-code-recognition.js +46 -0
- package/dist/adapter/claude-code/discovery/claude-code-session-catalogue.js +100 -0
- package/dist/adapter/claude-code/discovery/claude-code-session-discovery.js +61 -0
- package/dist/adapter/claude-code/discovery/claude-code-session-titles.js +28 -0
- package/dist/adapter/claude-code/discovery/discovered-session.js +1 -0
- package/dist/adapter/claude-code/discovery/session-entries.js +41 -0
- package/dist/adapter/claude-code/discovery/transcript-tail.js +81 -0
- package/dist/adapter/claude-code/events/claude-code-session-source.js +197 -0
- package/dist/adapter/claude-code/events/delegation-index.js +15 -0
- package/dist/adapter/claude-code/events/transcript-scan.js +179 -0
- package/dist/adapter/claude-code/hooks/hook-output.js +42 -0
- package/dist/adapter/claude-code/hooks/pre-tool-use-input.js +23 -0
- package/dist/adapter/claude-code/hooks/stop-input.js +25 -0
- package/dist/adapter/claude-code/hooks/subagent-stop-input.js +26 -0
- package/dist/adapter/claude-code/policy/deny-rules.js +46 -0
- package/dist/adapter/claude-code/probe/claude-code-probe.js +86 -0
- package/dist/adapter/claude-code/probe/collectors/agent-tool-input-key-collector.js +24 -0
- package/dist/adapter/claude-code/probe/collectors/denial-kind-collector.js +20 -0
- package/dist/adapter/claude-code/probe/collectors/denied-call-collector.js +11 -0
- package/dist/adapter/claude-code/probe/collectors/identifier-collector.js +19 -0
- package/dist/adapter/claude-code/probe/collectors/line-collector.js +1 -0
- package/dist/adapter/claude-code/probe/collectors/line-type-collector.js +29 -0
- package/dist/adapter/claude-code/probe/collectors/sidechain-collector.js +20 -0
- package/dist/adapter/claude-code/probe/collectors/task-notification-collector.js +51 -0
- package/dist/adapter/claude-code/probe/collectors/tool-result-reference-collector.js +31 -0
- package/dist/adapter/claude-code/probe/collectors/tool-use-collector.js +24 -0
- package/dist/adapter/claude-code/probe/collectors/tool-version-collector.js +14 -0
- package/dist/adapter/claude-code/probe/collectors/top-level-key-collector.js +14 -0
- package/dist/adapter/claude-code/probe/collectors/unknown-line-type-key-collector.js +24 -0
- package/dist/adapter/claude-code/probe/collectors/working-directory-collector.js +28 -0
- package/dist/adapter/claude-code/probe/doctor-report.js +1 -0
- package/dist/adapter/claude-code/probe/meta-tally.js +42 -0
- package/dist/adapter/claude-code/probe/session-probe.js +1 -0
- package/dist/adapter/claude-code/probe/session-tally.js +41 -0
- package/dist/adapter/claude-code/probe/transcript-line.js +30 -0
- package/dist/adapter/claude-code/probe/transcript-tally.js +74 -0
- package/dist/adapter/claude-code/settings/deny-entries.js +65 -0
- package/dist/adapter/claude-code/settings/hook-entries.js +303 -0
- package/dist/adapter/codex/contract/actions.js +69 -0
- package/dist/adapter/codex/contract/assumptions.js +55 -0
- package/dist/adapter/codex/contract/capabilities.js +24 -0
- package/dist/adapter/codex/contract/delegations.js +30 -0
- package/dist/adapter/codex/contract/deliveries.js +25 -0
- package/dist/adapter/codex/contract/envelope.js +33 -0
- package/dist/adapter/codex/contract/hook-refusals.js +14 -0
- package/dist/adapter/codex/contract/hooks.js +46 -0
- package/dist/adapter/codex/contract/messages.js +47 -0
- package/dist/adapter/codex/contract/permissions.js +27 -0
- package/dist/adapter/codex/contract/reviews.js +13 -0
- package/dist/adapter/codex/contract/session.js +31 -0
- package/dist/adapter/codex/contract/turns.js +23 -0
- package/dist/adapter/codex/contract/version.js +15 -0
- package/dist/adapter/codex/discovery/codex-conversations.js +44 -0
- package/dist/adapter/codex/discovery/codex-project-catalogue.js +49 -0
- package/dist/adapter/codex/discovery/codex-recognition.js +20 -0
- package/dist/adapter/codex/discovery/codex-session-catalogue.js +28 -0
- package/dist/adapter/codex/discovery/codex-session-discovery.js +115 -0
- package/dist/adapter/codex/discovery/codex-session-index.js +21 -0
- package/dist/adapter/codex/discovery/codex-session-titles.js +135 -0
- package/dist/adapter/codex/discovery/session-header.js +86 -0
- package/dist/adapter/codex/discovery/session-owners.js +11 -0
- package/dist/adapter/codex/discovery/session-roots.js +49 -0
- package/dist/adapter/codex/events/action-items.js +138 -0
- package/dist/adapter/codex/events/capability-records.js +26 -0
- package/dist/adapter/codex/events/codex-session-source.js +121 -0
- package/dist/adapter/codex/events/hook-refusals.js +27 -0
- package/dist/adapter/codex/events/rollout-scan.js +614 -0
- package/dist/adapter/codex/events/turn-permissions.js +60 -0
- package/dist/adapter/codex/hooks/pre-tool-use-input.js +24 -0
- package/dist/adapter/codex/hooks/stop-refusals.js +57 -0
- package/dist/adapter/codex/probe/codex-doctor-report.js +1 -0
- package/dist/adapter/codex/probe/codex-probe.js +268 -0
- package/dist/adapter/codex/settings/codex-hooks.js +83 -0
- package/dist/cli/cli-command.js +1 -0
- package/dist/cli/command-router.js +42 -0
- package/dist/cli/commands/check-cli-command.js +128 -0
- package/dist/cli/commands/codex-stop-cli-command.js +27 -0
- package/dist/cli/commands/doctor-arguments.js +32 -0
- package/dist/cli/commands/doctor-cli-command.js +31 -0
- package/dist/cli/commands/doctor-usage.js +14 -0
- package/dist/cli/commands/init-cli-command.js +123 -0
- package/dist/cli/commands/menu-cli-command.js +58 -0
- package/dist/cli/commands/notify-cli-command.js +158 -0
- package/dist/cli/commands/refuse-cli-command.js +79 -0
- package/dist/cli/commands/report-arguments.js +62 -0
- package/dist/cli/commands/report-cli-command.js +36 -0
- package/dist/cli/commands/report-usage.js +41 -0
- package/dist/cli/commands/sessions-cli-command.js +184 -0
- package/dist/cli/commands/start-cli-command.js +83 -0
- package/dist/cli/commands/watch-cli-command.js +142 -0
- package/dist/cli/exit-codes.js +13 -0
- package/dist/cli/project-switches.js +46 -0
- package/dist/cli.js +80 -0
- package/dist/composition-root.js +411 -0
- package/dist/core/access/command-line.js +454 -0
- package/dist/core/access/listing.js +58 -0
- package/dist/core/access/path-shape.js +59 -0
- package/dist/core/access/path-tokens.js +37 -0
- package/dist/core/access/protected-access.js +310 -0
- package/dist/core/access/protected-values.js +102 -0
- package/dist/core/access/recorded-effect.js +67 -0
- package/dist/core/access/returns.js +173 -0
- package/dist/core/access/search-output.js +34 -0
- package/dist/core/access/search-reach.js +268 -0
- package/dist/core/access/uses.js +143 -0
- package/dist/core/access/words-before.js +52 -0
- package/dist/core/agent.js +1 -0
- package/dist/core/capability.js +11 -0
- package/dist/core/combined-project-catalogue.js +36 -0
- package/dist/core/combined-session-catalogue.js +25 -0
- package/dist/core/completeness.js +10 -0
- package/dist/core/context.js +1 -0
- package/dist/core/correlation/correlate.js +329 -0
- package/dist/core/delegation.js +1 -0
- package/dist/core/detector/prompt-signals.js +78 -0
- package/dist/core/entry-point.js +1 -0
- package/dist/core/event.js +1 -0
- package/dist/core/evidence.js +9 -0
- package/dist/core/late-message.js +32 -0
- package/dist/core/message.js +1 -0
- package/dist/core/nearest-project.js +28 -0
- package/dist/core/policy/default-policy.js +32 -0
- package/dist/core/policy/glob.js +56 -0
- package/dist/core/policy/parse-policy.js +70 -0
- package/dist/core/policy/policy.js +20 -0
- package/dist/core/policy/resolve-policy.js +16 -0
- package/dist/core/project-catalogue.js +1 -0
- package/dist/core/project-root.js +133 -0
- package/dist/core/provider-titles.js +10 -0
- package/dist/core/redaction/entropy.js +46 -0
- package/dist/core/redaction/redacted.js +4 -0
- package/dist/core/redaction/redactor.js +339 -0
- package/dist/core/redaction/secret-patterns.js +22 -0
- package/dist/core/redaction/value-shapes.js +81 -0
- package/dist/core/redaction/value-trace.js +110 -0
- package/dist/core/review.js +1 -0
- package/dist/core/session-catalogue.js +19 -0
- package/dist/core/session-filter.js +42 -0
- package/dist/core/session-format.js +27 -0
- package/dist/core/session-model.js +1 -0
- package/dist/core/session-reader.js +22 -0
- package/dist/core/session-records.js +1 -0
- package/dist/core/session-source.js +1 -0
- package/dist/core/session-titles.js +21 -0
- package/dist/core/turn.js +1 -0
- package/dist/doctor/codex-doctor.js +14 -0
- package/dist/doctor/doctor-use-case.js +1 -0
- package/dist/doctor/format-selecting-doctor.js +28 -0
- package/dist/doctor/render/attention/attention-rule.js +1 -0
- package/dist/doctor/render/attention/doctor-attention-rules.js +28 -0
- package/dist/doctor/render/attention/rules/damaged-meta-files-rule.js +8 -0
- package/dist/doctor/render/attention/rules/damaged-transcripts-rule.js +9 -0
- package/dist/doctor/render/attention/rules/incomplete-subagent-pairs-rule.js +6 -0
- package/dist/doctor/render/attention/rules/missing-main-transcript-rule.js +5 -0
- package/dist/doctor/render/attention/rules/missing-spilled-results-rule.js +6 -0
- package/dist/doctor/render/attention/rules/multiple-working-directories-rule.js +15 -0
- package/dist/doctor/render/attention/rules/unknown-denial-kinds-rule.js +5 -0
- package/dist/doctor/render/attention/rules/unknown-line-types-rule.js +6 -0
- package/dist/doctor/render/attention/rules/unrecognised-entries-rule.js +6 -0
- package/dist/doctor/render/attention/rules/unusable-directories-rule.js +12 -0
- package/dist/doctor/render/attention/transcript-scopes.js +6 -0
- package/dist/doctor/render/codex-text-doctor-renderer.js +97 -0
- package/dist/doctor/render/doctor-renderers.js +1 -0
- package/dist/doctor/render/json-doctor-renderer.js +7 -0
- package/dist/doctor/render/output-format.js +1 -0
- package/dist/doctor/render/text-doctor-renderer.js +124 -0
- package/dist/doctor/session-doctor.js +16 -0
- package/dist/infrastructure/clack-asker.js +24 -0
- package/dist/infrastructure/clack-chooser.js +40 -0
- package/dist/infrastructure/clack-multi-chooser.js +31 -0
- package/dist/infrastructure/file-alert-store.js +120 -0
- package/dist/infrastructure/file-checked-store.js +55 -0
- package/dist/infrastructure/file-mark-store.js +67 -0
- package/dist/infrastructure/file-onboarding-store.js +93 -0
- package/dist/infrastructure/folder-window.js +26 -0
- package/dist/infrastructure/node-agentwhy-invocation.js +99 -0
- package/dist/infrastructure/node-browser.js +40 -0
- package/dist/infrastructure/node-file-system.js +111 -0
- package/dist/infrastructure/node-local-server.js +115 -0
- package/dist/infrastructure/node-text-input.js +26 -0
- package/dist/infrastructure/os-notifier.js +21 -0
- package/dist/infrastructure/osascript-folder-chooser.js +53 -0
- package/dist/infrastructure/powershell-folder-chooser.js +78 -0
- package/dist/infrastructure/real-directory.js +18 -0
- package/dist/infrastructure/stream-printer.js +11 -0
- package/dist/infrastructure/terminal-banner.js +19 -0
- package/dist/ports/agentwhy-invocation.js +1 -0
- package/dist/ports/alert-store.js +1 -0
- package/dist/ports/asker.js +1 -0
- package/dist/ports/browser.js +1 -0
- package/dist/ports/checked-store.js +1 -0
- package/dist/ports/chooser.js +1 -0
- package/dist/ports/directory-reader.js +1 -0
- package/dist/ports/file-access-error.js +11 -0
- package/dist/ports/file-reader.js +1 -0
- package/dist/ports/file-tail-reader.js +1 -0
- package/dist/ports/file-writer.js +1 -0
- package/dist/ports/folder-chooser.js +1 -0
- package/dist/ports/local-server.js +1 -0
- package/dist/ports/mark-store.js +10 -0
- package/dist/ports/multi-chooser.js +1 -0
- package/dist/ports/notifier.js +1 -0
- package/dist/ports/onboarding-store.js +1 -0
- package/dist/ports/printer.js +1 -0
- package/dist/ports/text-input.js +1 -0
- package/dist/refuse/command-reach.js +135 -0
- package/dist/refuse/command-refusal.js +88 -0
- package/dist/refuse/render/codex-stop-words.js +21 -0
- package/dist/refuse/render/refusal-words.js +34 -0
- package/dist/report/build-report.js +1037 -0
- package/dist/report/check/actions-digest.js +73 -0
- package/dist/report/check/check-lines.js +83 -0
- package/dist/report/check/mark-request.js +90 -0
- package/dist/report/check/marks.js +84 -0
- package/dist/report/check/render/text-digest-renderer.js +332 -0
- package/dist/report/check/session-actions.js +90 -0
- package/dist/report/check/session-check.js +91 -0
- package/dist/report/choose-policy.js +61 -0
- package/dist/report/flow-reads.js +18 -0
- package/dist/report/private-files/tell-lists.js +84 -0
- package/dist/report/project-rules.js +33 -0
- package/dist/report/render/home-relative.js +18 -0
- package/dist/report/render/html-head.js +26 -0
- package/dist/report/render/html-report-components.js +48 -0
- package/dist/report/render/html-report-styles.js +500 -0
- package/dist/report/render/html-sidebar.js +42 -0
- package/dist/report/render/path-tail.js +14 -0
- package/dist/report/render/report-copy.js +1177 -0
- package/dist/report/render/report-page/advanced-view.js +167 -0
- package/dist/report/render/report-page/file-story.js +114 -0
- package/dist/report/render/report-page/files-view.js +381 -0
- package/dist/report/render/report-page/files.js +77 -0
- package/dist/report/render/report-page/fix-wizard-script.js +269 -0
- package/dist/report/render/report-page/fix-wizard.js +310 -0
- package/dist/report/render/report-page/helpers-view.js +383 -0
- package/dist/report/render/report-page/helpers.js +51 -0
- package/dist/report/render/report-page/item-names.js +63 -0
- package/dist/report/render/report-page/protect-patterns.js +13 -0
- package/dist/report/render/report-page/providers.js +208 -0
- package/dist/report/render/report-page/record-view.js +367 -0
- package/dist/report/render/report-page/report-page-renderer.js +129 -0
- package/dist/report/render/report-page/report-views.js +31 -0
- package/dist/report/render/report-page/story-window.js +356 -0
- package/dist/report/render/report-page/times.js +25 -0
- package/dist/report/render/report-page/to-do-view.js +299 -0
- package/dist/report/render/report-page/to-do.js +152 -0
- package/dist/report/render/report-page.js +1 -0
- package/dist/report/render/session-view.js +250 -0
- package/dist/report/render/text-report-renderer.js +981 -0
- package/dist/report/render/ui/add-file-popup.js +122 -0
- package/dist/report/render/ui/app-sidebar.js +78 -0
- package/dist/report/render/ui/ask-panel.js +80 -0
- package/dist/report/render/ui/avatar.js +19 -0
- package/dist/report/render/ui/backdrop.js +29 -0
- package/dist/report/render/ui/brand-mark.js +4 -0
- package/dist/report/render/ui/button.js +67 -0
- package/dist/report/render/ui/callout.js +20 -0
- package/dist/report/render/ui/chat-example.js +17 -0
- package/dist/report/render/ui/checklist.js +50 -0
- package/dist/report/render/ui/confirm-dialog.js +34 -0
- package/dist/report/render/ui/data-table.js +49 -0
- package/dist/report/render/ui/drawer.js +25 -0
- package/dist/report/render/ui/file-chip.js +37 -0
- package/dist/report/render/ui/fold-line.js +22 -0
- package/dist/report/render/ui/guide-card.js +25 -0
- package/dist/report/render/ui/hero.js +37 -0
- package/dist/report/render/ui/labelled-select.js +10 -0
- package/dist/report/render/ui/live-script.js +222 -0
- package/dist/report/render/ui/local-date.js +58 -0
- package/dist/report/render/ui/mode-icon.js +6 -0
- package/dist/report/render/ui/page-shell.js +101 -0
- package/dist/report/render/ui/pill-tabs.js +47 -0
- package/dist/report/render/ui/popup.js +77 -0
- package/dist/report/render/ui/progress.js +35 -0
- package/dist/report/render/ui/project-list.js +284 -0
- package/dist/report/render/ui/scope-choice.js +19 -0
- package/dist/report/render/ui/stats.js +21 -0
- package/dist/report/render/ui/status-icon.js +30 -0
- package/dist/report/render/ui/status-look.js +21 -0
- package/dist/report/render/ui/switch.js +11 -0
- package/dist/report/render/ui/tag.js +19 -0
- package/dist/report/render/ui/task-list.js +56 -0
- package/dist/report/render/ui/tokens.js +46 -0
- package/dist/report/render/ui/update-notice.js +146 -0
- package/dist/report/render/ui/words/app-words.js +163 -0
- package/dist/report/render/ui/words/conversations-words.js +457 -0
- package/dist/report/render/ui/words/month-words.js +59 -0
- package/dist/report/render/ui/words/onboarding-words.js +446 -0
- package/dist/report/render/ui/words/projects-words.js +217 -0
- package/dist/report/render/ui/words/report-words.js +2099 -0
- package/dist/report/render/ui/words/settings-words.js +611 -0
- package/dist/report/render/ui/words/to-fix-words.js +287 -0
- package/dist/report/report-model.js +2 -0
- package/dist/report/report-use-case.js +1 -0
- package/dist/report/rule-names.js +20 -0
- package/dist/report/session-report.js +163 -0
- package/dist/report/start/app-nav.js +37 -0
- package/dist/report/start/conversations/calendar-view.js +104 -0
- package/dist/report/start/conversations/conversation-columns.js +187 -0
- package/dist/report/start/conversations/conversations-renderer.js +54 -0
- package/dist/report/start/conversations/empty-week.js +120 -0
- package/dist/report/start/conversations/files-window.js +166 -0
- package/dist/report/start/conversations/period-section.js +280 -0
- package/dist/report/start/conversations/periods-script.js +440 -0
- package/dist/report/start/conversations/periods.js +110 -0
- package/dist/report/start/conversations/week-view.js +30 -0
- package/dist/report/start/conversations/weeks.js +17 -0
- package/dist/report/start/month/month-renderer.js +50 -0
- package/dist/report/start/month/month-view.js +135 -0
- package/dist/report/start/month/months.js +17 -0
- package/dist/report/start/onboarding/done.js +171 -0
- package/dist/report/start/onboarding/finish-onboarding.js +93 -0
- package/dist/report/start/onboarding/intro.js +100 -0
- package/dist/report/start/onboarding/onboarding-changes.js +40 -0
- package/dist/report/start/onboarding/onboarding-renderer.js +195 -0
- package/dist/report/start/onboarding/onboarding-script.js +400 -0
- package/dist/report/start/onboarding/onboarding-view.js +98 -0
- package/dist/report/start/onboarding/project-step.js +210 -0
- package/dist/report/start/onboarding/steps.js +239 -0
- package/dist/report/start/onboarding/welcome.js +66 -0
- package/dist/report/start/page-notice.js +10 -0
- package/dist/report/start/projects/index-projects.js +43 -0
- package/dist/report/start/projects/moved-page.js +82 -0
- package/dist/report/start/projects/project-switch.js +138 -0
- package/dist/report/start/projects/projects-window.js +67 -0
- package/dist/report/start/projects/temporary-space.js +18 -0
- package/dist/report/start/render/air-datepicker-vendor.js +27 -0
- package/dist/report/start/render/session-status.js +41 -0
- package/dist/report/start/render/start-words.js +84 -0
- package/dist/report/start/repository.js +28 -0
- package/dist/report/start/serve/index-handler.js +372 -0
- package/dist/report/start/serve/onboarding-request.js +50 -0
- package/dist/report/start/serve/settings-request.js +1 -0
- package/dist/report/start/serve/settings-setup.js +193 -0
- package/dist/report/start/session-index.js +1 -0
- package/dist/report/start/session-start.js +974 -0
- package/dist/report/start/settings/alerts-tab.js +104 -0
- package/dist/report/start/settings/files-tab.js +169 -0
- package/dist/report/start/settings/general-tab.js +71 -0
- package/dist/report/start/settings/settings-renderer.js +254 -0
- package/dist/report/start/settings/settings-script.js +161 -0
- package/dist/report/start/settings/settings-view.js +240 -0
- package/dist/report/start/settings/settings-windows.js +334 -0
- package/dist/report/start/settings-files.js +43 -0
- package/dist/report/start/to-fix/done-list.js +45 -0
- package/dist/report/start/to-fix/file-window.js +110 -0
- package/dist/report/start/to-fix/to-fix-list.js +70 -0
- package/dist/report/start/to-fix/to-fix-renderer.js +237 -0
- package/dist/report/start/to-fix/to-fix-script.js +94 -0
- package/dist/report/start/to-fix/to-fix-view.js +124 -0
- package/dist/report/watch/agent-alert.js +72 -0
- package/dist/report/watch/notice-choices.js +35 -0
- package/dist/report/watch/notice-settings.js +65 -0
- package/dist/report/watch/preferences.js +100 -0
- package/dist/report/watch/render/instruction-words.js +54 -0
- package/dist/report/watch/render/notice-words.js +182 -0
- package/dist/report/watch/subagent-watch.js +345 -0
- package/dist/report/watch/watch-notice.js +1 -0
- package/dist/setup/behind.js +18 -0
- package/dist/setup/codex-mirror.js +171 -0
- package/dist/setup/not-a-project.js +19 -0
- package/dist/setup/project-setup.js +644 -0
- package/dist/setup/protected-patterns.js +30 -0
- package/dist/shared/colour.js +23 -0
- package/dist/shared/compare.js +4 -0
- package/dist/shared/content-version.js +13 -0
- package/dist/shared/counter.js +11 -0
- package/dist/shared/file-stamp.js +4 -0
- package/dist/shared/json.js +13 -0
- package/dist/shared/label.js +13 -0
- package/dist/shared/package-name.js +6 -0
- package/dist/shared/plain-invocation.js +44 -0
- package/dist/shared/plain-version.js +21 -0
- package/dist/shared/printable.js +25 -0
- package/dist/shared/renderer.js +1 -0
- package/dist/shared/sentence.js +20 -0
- package/dist/shared/terminal-logo.js +41 -0
- package/dist/shared/text-table.js +15 -0
- package/dist/shared/wrap.js +29 -0
- package/package.json +70 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { escapeHtml as e } from '../../render/html-report-components.js';
|
|
2
|
+
import { INDEX_CONTENT_SECURITY_POLICY_META } from '../../render/html-head.js';
|
|
3
|
+
import { DEFAULT_LANG, inLanguages, LANG_NAMES, LANGS, labelAttributes, TABLES, translator } from '../../render/report-copy.js';
|
|
4
|
+
import { addFilePopup, ADD_FILE_POPUP_SCRIPT, ADD_FILE_POPUP_STYLE } from '../../render/ui/add-file-popup.js';
|
|
5
|
+
import { BRAND_MARK } from '../../render/ui/brand-mark.js';
|
|
6
|
+
import { BUTTON_STYLE, pill } from '../../render/ui/button.js';
|
|
7
|
+
import { FILE_CHIP_STYLE } from '../../render/ui/file-chip.js';
|
|
8
|
+
import { pageShell } from '../../render/ui/page-shell.js';
|
|
9
|
+
import { POPUP_SCRIPT, POPUP_STYLE } from '../../render/ui/popup.js';
|
|
10
|
+
import { PROJECT_LIST_SCRIPT, PROJECT_LIST_STYLE } from '../../render/ui/project-list.js';
|
|
11
|
+
import { SWITCH_STYLE } from '../../render/ui/switch.js';
|
|
12
|
+
import { TAG_STYLE } from '../../render/ui/tag.js';
|
|
13
|
+
import { doneScreen, DONE_STYLE } from './done.js';
|
|
14
|
+
import { introScreen, INTRO_STYLE } from './intro.js';
|
|
15
|
+
import { ONBOARDING_SCRIPT } from './onboarding-script.js';
|
|
16
|
+
import { onboardingView } from './onboarding-view.js';
|
|
17
|
+
import { projectStep, PROJECT_STEP_STYLE } from './project-step.js';
|
|
18
|
+
import { ADD_WINDOW, stepScreens, STEPS_STYLE } from './steps.js';
|
|
19
|
+
import { welcomeScreen, WELCOME_STYLE } from './welcome.js';
|
|
20
|
+
/**
|
|
21
|
+
* The onboarding, written as `onboarding.html` beside the index (`.ai/specs/2026-09-24-onboarding.md`; plan step 5):
|
|
22
|
+
* the intro, the welcome, three steps - the project first (`which-project.md` V19) - and Done, on the kit, with no
|
|
23
|
+
* sidebar (W2). In the home directory it is the project step alone: nothing there is set up (V7). Every screen is in the page and the
|
|
24
|
+
* script shows one at a time; with no script the welcome and the steps are sections in order, with the way to Settings
|
|
25
|
+
* under them (W27). The page is written only where a run serves it (W1), so it can always post its one request.
|
|
26
|
+
*/
|
|
27
|
+
export class OnboardingRenderer {
|
|
28
|
+
#links;
|
|
29
|
+
constructor(links) {
|
|
30
|
+
this.#links = links;
|
|
31
|
+
}
|
|
32
|
+
render(index) {
|
|
33
|
+
const view = onboardingView(index);
|
|
34
|
+
return pageShell({
|
|
35
|
+
title: 'ob.title',
|
|
36
|
+
policy: INDEX_CONTENT_SECURITY_POLICY_META,
|
|
37
|
+
styles: [BUTTON_STYLE, TAG_STYLE, SWITCH_STYLE, FILE_CHIP_STYLE, POPUP_STYLE, ADD_FILE_POPUP_STYLE, PROJECT_LIST_STYLE,
|
|
38
|
+
MOTION_STYLE, FRAME_STYLE, INTRO_STYLE, WELCOME_STYLE, STEPS_STYLE, PROJECT_STEP_STYLE, DONE_STYLE],
|
|
39
|
+
scripts: [POPUP_SCRIPT, ADD_FILE_POPUP_SCRIPT, PROJECT_LIST_SCRIPT, ONBOARDING_SCRIPT],
|
|
40
|
+
main: view === undefined ? '' : this.#page(view, index),
|
|
41
|
+
// live-pages: the onboarding is answered once; an update would take away the answers not yet sent.
|
|
42
|
+
live: false,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
#page(view, index) {
|
|
46
|
+
const anyConversation = index.entries.length > 0;
|
|
47
|
+
// which-project V7: in the home directory there is no project to set up - only the step that picks one.
|
|
48
|
+
const project = view.project.kind === 'none' ? undefined : view.project.name;
|
|
49
|
+
const state = {
|
|
50
|
+
intro: view.intro,
|
|
51
|
+
atProject: view.atProject,
|
|
52
|
+
// V23: Done's line begins with the project's name.
|
|
53
|
+
...(project === undefined ? {} : { name: project }),
|
|
54
|
+
who: view.who,
|
|
55
|
+
// Step 3 is not drawn (2026-09-25): its choices are what it would have started from (W10).
|
|
56
|
+
alerts: view.messages.alerts,
|
|
57
|
+
inForce: view.inForce,
|
|
58
|
+
rows: view.files.rows.length,
|
|
59
|
+
};
|
|
60
|
+
return '<div class="ob" data-ob data-ob-at="welcome" data-ob-state="' + e(JSON.stringify(state)) + '" data-ob-words="' + e(JSON.stringify(scriptWords())) + '">' +
|
|
61
|
+
header() +
|
|
62
|
+
'<div class="ob-body">' + introScreen() + welcomeScreen() +
|
|
63
|
+
projectStep(view, { now: index.now, timeZone: index.timeZone ?? 'UTC' }) +
|
|
64
|
+
(project === undefined ? '' : stepScreens(view, project) + doneScreen(view.done, this.#links)) +
|
|
65
|
+
noScript(this.#links, anyConversation, project !== undefined) + '</div>' +
|
|
66
|
+
(view.files.canAdd && project !== undefined ? addFilePopup(ADD_WINDOW) : '') +
|
|
67
|
+
'</div>';
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** W2: the logo; the stepper on steps 1-3; "Runs on your computer", or **Skip intro** on the intro; the language. */
|
|
71
|
+
function header() {
|
|
72
|
+
const steps = ['project', 'who', 'files'].map((name, at) => '<li class="ob-stepper-step" data-ob-step><span class="ob-stepper-num" aria-hidden="true"><span class="ob-stepper-n">' + (at + 1) +
|
|
73
|
+
'</span><span class="ob-stepper-done">✓</span></span>' + inLanguages((t) => t('ob.stepper.' + name)) + '</li>').join('');
|
|
74
|
+
return '<header class="ob-head">' +
|
|
75
|
+
'<span class="ob-brand">' + BRAND_MARK + '<span class="ob-word">agent<span class="ob-why">why</span></span></span>' +
|
|
76
|
+
'<ol class="ob-stepper js-only" data-ob-stepper' + labelAttributes((t) => e(t('ob.stepper'))) + '>' + steps + '</ol>' +
|
|
77
|
+
'<span class="ob-head-end">' +
|
|
78
|
+
pill({ label: inLanguages((t) => t('ob.skipIntro')), tone: 'outline', size: 'sm', button: true, attributes: ' data-ob-skip-intro' }) +
|
|
79
|
+
'<span class="ob-local"><span class="ob-local-dot" aria-hidden="true"></span>' + inLanguages((t) => t('ob.local')) + '</span>' +
|
|
80
|
+
'<select class="ob-lang js-only" id="lang"' + labelAttributes((t) => t('app.lang')) + '>' +
|
|
81
|
+
LANGS.map((lang) => '<option value="' + lang + '"' + (lang === DEFAULT_LANG ? ' selected' : '') + '>' + LANG_NAMES[lang] + '</option>').join('') +
|
|
82
|
+
'</select></span></header>';
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* W27: without a script nothing here can be written, so the page says where the same choices are made - where there is a
|
|
86
|
+
* project to make them for. In the home directory the project step already leads to its chats (which-project V7).
|
|
87
|
+
*/
|
|
88
|
+
function noScript(links, anyConversation, aProject) {
|
|
89
|
+
if (!aProject)
|
|
90
|
+
return '';
|
|
91
|
+
return '<div class="ob-nojs"><p>' + inLanguages((t) => t('ob.nojs')) + '</p><p class="ob-nojs-links">' +
|
|
92
|
+
pill({ label: inLanguages((t) => t('ob.nojs.settings')), tone: 'primary', size: 'lg', href: links.settings }) +
|
|
93
|
+
(anyConversation ? pill({ label: inLanguages((t) => t('ob.nojs.conversations')), tone: 'outline', size: 'lg', href: links.conversations }) : '') +
|
|
94
|
+
'</p></div>';
|
|
95
|
+
}
|
|
96
|
+
/** What the script says, in every language: it cannot hold three languages in one text node. */
|
|
97
|
+
function scriptWords() {
|
|
98
|
+
return Object.fromEntries(LANGS.map((lang) => {
|
|
99
|
+
const t = translator(lang);
|
|
100
|
+
return [lang, {
|
|
101
|
+
saving: t('set.saving'),
|
|
102
|
+
refused: t('set.refused'),
|
|
103
|
+
unreachable: t('set.unreachable'),
|
|
104
|
+
local: t('ob.summary.local'),
|
|
105
|
+
shared: t('ob.summary.shared'),
|
|
106
|
+
// Every plural form the language has, with its {n} left for the script, which counts the rows itself.
|
|
107
|
+
...Object.fromEntries(['one', 'few', 'many', 'other'].flatMap((form) => {
|
|
108
|
+
const text = TABLES[lang]['ob.summary.kinds.' + form];
|
|
109
|
+
return text === undefined ? [] : [['kinds.' + form, text]];
|
|
110
|
+
})),
|
|
111
|
+
messages: t('ob.summary.messages'),
|
|
112
|
+
// which-project V12, V15: what the project step says of a folder chosen, and of a switch.
|
|
113
|
+
switching: t('proj.switching', { name: '{name}' }),
|
|
114
|
+
refusedTitle: t('ob.project.refused.title'),
|
|
115
|
+
refusedHome: t('ob.project.refused.home'),
|
|
116
|
+
refusedRoot: t('ob.project.refused.root'),
|
|
117
|
+
chatsIn: t('ob.project.chatsIn', { name: '{name}' }),
|
|
118
|
+
chatsInside: t('ob.project.chatsInside', { name: '{name}' }),
|
|
119
|
+
picked: t('ob.project.picked', { place: '{place}' }),
|
|
120
|
+
weUse: t('ob.project.weUse'),
|
|
121
|
+
inThere: t('ob.project.inThere'),
|
|
122
|
+
useAnyway: t('proj.useAnyway', { name: '{name}' }),
|
|
123
|
+
failedTitle: t('ob.project.failed.title'),
|
|
124
|
+
failed: t('proj.switchFailed', { reason: '{reason}' }),
|
|
125
|
+
chooseHere: t('proj.chooseHere'),
|
|
126
|
+
}];
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
/** Every moment the onboarding draws (W4, W7, W17), and the move from one screen to the next, named once; none plays where motion is unwelcome (W29). */
|
|
130
|
+
const MOTION_STYLE = String.raw `
|
|
131
|
+
@keyframes obIn{from{opacity:0;transform:translateY(16px) scale(.96)}to{opacity:1;transform:none}}
|
|
132
|
+
@keyframes obOut{to{opacity:0;transform:scale(.9);filter:blur(6px)}}
|
|
133
|
+
@keyframes obUp{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
|
|
134
|
+
@keyframes obType{from{width:0}to{width:100%}}
|
|
135
|
+
@keyframes obTwinkle{0%,100%{opacity:.25}50%{opacity:.9}}
|
|
136
|
+
@keyframes obBeam{0%{left:-10%;opacity:1}100%{left:110%;opacity:1}}
|
|
137
|
+
@keyframes obLit{to{border-color:var(--coral-60);background:var(--coral-18);box-shadow:0 0 22px var(--coral-45)}}
|
|
138
|
+
@keyframes obPing{0%{transform:scale(.6);opacity:.9}100%{transform:scale(2.2);opacity:0}}
|
|
139
|
+
@keyframes obConverge{0%{transform:translate(var(--x),var(--y)) scale(1);opacity:0}20%{opacity:1}100%{transform:translate(0,0) scale(.3);opacity:0}}
|
|
140
|
+
@keyframes obDraw{from{stroke-dashoffset:120}to{stroke-dashoffset:0}}
|
|
141
|
+
@keyframes obFlash{0%{opacity:0;transform:scale(.6)}30%{opacity:.9}100%{opacity:0;transform:scale(2.4)}}
|
|
142
|
+
@keyframes obBloom{0%{transform:scale(.2);opacity:0}40%{opacity:1}100%{transform:scale(1);opacity:.7}}
|
|
143
|
+
@keyframes obGlow{0%,100%{opacity:.55;transform:scale(1)}50%{opacity:.9;transform:scale(1.08)}}
|
|
144
|
+
@keyframes obFloat{0%,100%{transform:translateY(0)}50%{transform:translateY(-6px)}}
|
|
145
|
+
@keyframes obPop{0%{transform:scale(.4);opacity:0}60%{transform:scale(1.08);opacity:1}100%{transform:scale(1)}}
|
|
146
|
+
@keyframes obConfetti{0%{transform:translate(0,0) rotate(0);opacity:1}100%{transform:translate(calc(var(--dx) * var(--spread,1)),calc(var(--dy) * var(--spread,1))) rotate(var(--r));opacity:0}}
|
|
147
|
+
@keyframes obRipple{0%{transform:scale(.55);opacity:.7}100%{transform:scale(1.9);opacity:0}}
|
|
148
|
+
@keyframes obStepIn{from{opacity:0;transform:translateX(var(--ob-from,32px))}to{opacity:1;transform:none}}
|
|
149
|
+
@keyframes obStepOut{to{opacity:0;transform:translateX(var(--ob-to,-32px))}}
|
|
150
|
+
@keyframes obRise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
|
|
151
|
+
.ob-enter{animation:obStepIn .42s cubic-bezier(.2,.8,.2,1) both}
|
|
152
|
+
.ob-enter.ob-step>*{animation:obRise .45s cubic-bezier(.2,.8,.2,1) both}
|
|
153
|
+
.ob-enter.ob-step>:nth-child(2){animation-delay:.04s}.ob-enter.ob-step>:nth-child(3){animation-delay:.08s}
|
|
154
|
+
.ob-enter.ob-step>:nth-child(4){animation-delay:.12s}.ob-enter.ob-step>:nth-child(n+5){animation-delay:.16s}
|
|
155
|
+
.ob-leave{animation:obStepOut .18s ease-in both;pointer-events:none}
|
|
156
|
+
.ob-back{--ob-from:-32px;--ob-to:32px}
|
|
157
|
+
@media (prefers-reduced-motion:reduce){
|
|
158
|
+
.ob *,.ob *::before,.ob *::after{animation:none!important;transition:none!important}
|
|
159
|
+
.ob-knot path{stroke-dashoffset:0}.ob-pt,.ob-flash,.ob-conf,.ob-ripple,.ob-beam,.ob-ping{display:none}
|
|
160
|
+
}
|
|
161
|
+
`;
|
|
162
|
+
/** The frame: the header, one screen at a time, and what a page with no script shows. Colours from the tokens only. */
|
|
163
|
+
const FRAME_STYLE = String.raw `
|
|
164
|
+
.ob{min-height:calc(100vh - 136px);display:flex;flex-direction:column}
|
|
165
|
+
.ob-head{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:28px}
|
|
166
|
+
.ob-brand{display:flex;align-items:center;gap:9px;color:var(--coral);font-size:20px;font-weight:650}
|
|
167
|
+
.ob-brand .brand-mark{width:26px;height:26px;flex:none}
|
|
168
|
+
.ob-word{color:var(--text)}.ob-why{color:var(--coral)}
|
|
169
|
+
.ob-stepper{list-style:none;margin:0;padding:0;align-items:center;gap:8px;visibility:hidden}
|
|
170
|
+
.js .ob-stepper{display:flex}
|
|
171
|
+
.ob[data-ob-at="project"] .ob-stepper,.ob[data-ob-at="who"] .ob-stepper,.ob[data-ob-at="files"] .ob-stepper{visibility:visible}
|
|
172
|
+
.ob-stepper-step{display:flex;align-items:center;gap:8px;font-size:13.5px;font-weight:600;color:var(--text-3);padding:6px 12px;border-radius:999px;transition:color .3s,background .3s}
|
|
173
|
+
.ob-stepper-num{width:20px;height:20px;border-radius:50%;background:var(--white-08);color:var(--text-2);font-size:11px;display:flex;align-items:center;justify-content:center;transition:color .3s,background .3s}
|
|
174
|
+
.ob-stepper-done{display:none}
|
|
175
|
+
.ob-stepper-now{color:var(--text);background:var(--white-07)}.ob-stepper-now .ob-stepper-num{background:var(--coral);color:var(--on-coral)}
|
|
176
|
+
.ob-stepper-past{color:var(--mint)}.ob-stepper-past .ob-stepper-num{background:var(--mint);color:var(--on-mint)}
|
|
177
|
+
.ob-stepper-past .ob-stepper-n{display:none}.ob-stepper-past .ob-stepper-done{display:inline}
|
|
178
|
+
.ob-head-end{display:flex;align-items:center;gap:14px}
|
|
179
|
+
.ob-head-end [data-ob-skip-intro]{display:none}
|
|
180
|
+
.ob[data-ob-at="intro"] [data-ob-skip-intro]{display:inline-flex}
|
|
181
|
+
.ob[data-ob-at="intro"] .ob-local{display:none}
|
|
182
|
+
.ob-local{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--text-3)}
|
|
183
|
+
.ob-local-dot{width:7px;height:7px;border-radius:50%;background:var(--mint)}
|
|
184
|
+
.ob-lang{background:var(--card);color:var(--text-2);border:1px solid var(--white-10);border-radius:8px;padding:5px 8px;font:inherit;font-size:13px}
|
|
185
|
+
.ob-body{flex:1;display:flex;flex-direction:column;justify-content:center;gap:56px}
|
|
186
|
+
.ob-screen{width:100%}
|
|
187
|
+
.js .ob-body{gap:0}
|
|
188
|
+
.ob-screen[hidden]{display:none!important}
|
|
189
|
+
.ob-screen h1[tabindex="-1"]:focus,.ob-screen h2[tabindex="-1"]:focus{outline:none}
|
|
190
|
+
.ob-nojs{max-width:640px;margin:0 auto;padding:22px;border-radius:16px;background:var(--card);border:1px solid var(--white-09);font-size:15px;line-height:1.55;color:var(--text-soft)}
|
|
191
|
+
.ob-nojs p{margin:0}
|
|
192
|
+
.ob-nojs-links{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px!important}
|
|
193
|
+
.js .ob-nojs{display:none}
|
|
194
|
+
@media (max-width:640px){.ob-stepper-step{font-size:0;gap:0;padding:4px}.ob-stepper-num{font-size:11px}.ob-local{display:none}.ob-head{margin-bottom:20px}}
|
|
195
|
+
`;
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
import { INTRO_MS } from './intro.js';
|
|
2
|
+
import { PICK_GROUP } from './project-step.js';
|
|
3
|
+
/**
|
|
4
|
+
* The address of step *Who* (`.ai/specs/2026-09-27-which-project.md` V16): `onboarding.html#who` opens there, past the
|
|
5
|
+
* intro, the welcome and the project step - where a page that chose this project in another's onboarding lands.
|
|
6
|
+
*/
|
|
7
|
+
export const WHO_STEP = 'who';
|
|
8
|
+
/**
|
|
9
|
+
* What only the onboarding does (`.ai/specs/2026-09-24-onboarding.md`). The kit opens and closes the add popup, and the
|
|
10
|
+
* switch's script shows another project (`which-project.md` V14); this moves between the screens, opens the project
|
|
11
|
+
* step's list, keeps the two other steps' choices - nothing is written before Finish (W10) - posts them (W15),
|
|
12
|
+
* and draws Done from the server's answer
|
|
13
|
+
* (W17-W20, W26). It plays the intro, and moves from one screen to the next, only where motion is welcome (W6, W24, W29).
|
|
14
|
+
*
|
|
15
|
+
* A picked file gives its name and nothing else: the kit's add popup reads a picked file's name and hands this page the
|
|
16
|
+
* pattern (F36). Nothing here reads a file.
|
|
17
|
+
*/
|
|
18
|
+
export const ONBOARDING_SCRIPT = String.raw `
|
|
19
|
+
(() => {
|
|
20
|
+
const root = document.querySelector('[data-ob]');
|
|
21
|
+
if (!root) return;
|
|
22
|
+
const state = JSON.parse(root.dataset.obState || '{}');
|
|
23
|
+
const words = JSON.parse(root.dataset.obWords || '{}');
|
|
24
|
+
const lang = () => document.documentElement.dataset.lang || 'en';
|
|
25
|
+
const word = (key, which) => ((words[which || lang()] || words.en || {})[key]) || (words.en || {})[key] || '';
|
|
26
|
+
const plural = (which, n) => n === 1 ? 'one' : which !== 'pl' ? 'other' : (n % 10 >= 2 && n % 10 <= 4 && !(n % 100 >= 12 && n % 100 <= 14)) ? 'few' : 'many';
|
|
27
|
+
const counted = (key, n, which) => (word(key + '.' + plural(which, n), which) || word(key + '.other', which)).replace('{n}', String(n));
|
|
28
|
+
const served = location.protocol === 'http:' || location.protocol === 'https:';
|
|
29
|
+
const still = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
30
|
+
const screens = [...root.querySelectorAll('[data-ob-screen]')];
|
|
31
|
+
const STEPS = ['project', 'who', 'files'];
|
|
32
|
+
// The order the screens come in, so a move back slides the other way.
|
|
33
|
+
const ORDER = ['intro', 'welcome', ...STEPS, 'done'];
|
|
34
|
+
const LEAVE_MS = 180;
|
|
35
|
+
const ENTER_MS = 700;
|
|
36
|
+
let timer;
|
|
37
|
+
let moving;
|
|
38
|
+
|
|
39
|
+
const show = (name, back) => {
|
|
40
|
+
clearTimeout(timer);
|
|
41
|
+
screens.forEach((screen) => {
|
|
42
|
+
screen.hidden = screen.dataset.obScreen !== name;
|
|
43
|
+
screen.classList.remove('ob-enter', 'ob-leave', 'ob-back');
|
|
44
|
+
});
|
|
45
|
+
root.dataset.obAt = name;
|
|
46
|
+
const at = STEPS.indexOf(name);
|
|
47
|
+
root.querySelectorAll('[data-ob-stepper] [data-ob-step]').forEach((pill, index) => {
|
|
48
|
+
pill.classList.toggle('ob-stepper-now', index === at);
|
|
49
|
+
pill.classList.toggle('ob-stepper-past', at >= 0 && index < at);
|
|
50
|
+
if (index === at) pill.setAttribute('aria-current', 'step'); else pill.removeAttribute('aria-current');
|
|
51
|
+
});
|
|
52
|
+
window.scrollTo(0, 0);
|
|
53
|
+
const screen = screens.find((each) => each.dataset.obScreen === name);
|
|
54
|
+
if (screen && back !== undefined && !still) {
|
|
55
|
+
screen.classList.add('ob-enter');
|
|
56
|
+
screen.classList.toggle('ob-back', back);
|
|
57
|
+
timer = setTimeout(() => screen.classList.remove('ob-enter', 'ob-back'), ENTER_MS);
|
|
58
|
+
}
|
|
59
|
+
// The project step holds a heading for each of its views; the one shown is the one read.
|
|
60
|
+
const heading = screen && [...screen.querySelectorAll('h1, h2')].find((one) => one.offsetParent !== null);
|
|
61
|
+
if (heading && name !== 'intro') { heading.tabIndex = -1; heading.focus({ preventScroll: true }); }
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// A click from one screen to the next: the one shown slides out, the next slides in from the side it lies on.
|
|
65
|
+
const go = (name) => {
|
|
66
|
+
const from = screens.find((screen) => !screen.hidden);
|
|
67
|
+
const back = ORDER.indexOf(name) < ORDER.indexOf(root.dataset.obAt);
|
|
68
|
+
clearTimeout(moving);
|
|
69
|
+
if (still || !from || root.dataset.obAt === 'intro') { show(name, back); return; }
|
|
70
|
+
from.classList.remove('ob-enter');
|
|
71
|
+
from.classList.add('ob-leave');
|
|
72
|
+
from.classList.toggle('ob-back', back);
|
|
73
|
+
moving = setTimeout(() => show(name, back), LEAVE_MS);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// which-project V16: a page that chose this project in another's onboarding lands here at Who, the project chosen.
|
|
77
|
+
const addressed = location.hash === '#${WHO_STEP}' && screens.some((screen) => screen.dataset.obScreen === '${WHO_STEP}');
|
|
78
|
+
// W6, W24, W29: the intro once per person, never where motion is unwelcome; then the welcome - or, in the home
|
|
79
|
+
// directory for someone who has been through it before, the project step (V7).
|
|
80
|
+
if (addressed) {
|
|
81
|
+
show('${WHO_STEP}');
|
|
82
|
+
} else if (state.atProject) {
|
|
83
|
+
show('project');
|
|
84
|
+
} else if (state.intro && !still) {
|
|
85
|
+
show('intro');
|
|
86
|
+
timer = setTimeout(() => show('welcome'), ${INTRO_MS});
|
|
87
|
+
} else {
|
|
88
|
+
show('welcome');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
// which-project V20, V12, V14-V16: the project step - its card, the list it opens, what the folder window came to, and a
|
|
93
|
+
// switch. Choosing this run's own project goes on to Who in the page; any other is shown in this tab, at its own Who.
|
|
94
|
+
const projectStep = root.querySelector('[data-ob-screen="project"]');
|
|
95
|
+
if (projectStep) {
|
|
96
|
+
const list = projectStep.querySelector('[data-ob-list]');
|
|
97
|
+
const chosenBox = projectStep.querySelector('[data-ob-chosen]');
|
|
98
|
+
const notice = projectStep.querySelector('[data-ob-notice]');
|
|
99
|
+
const onward = projectStep.querySelector('[data-ob-continue]');
|
|
100
|
+
const chooser = projectStep.querySelector('[data-ob-choose]');
|
|
101
|
+
const switching = projectStep.querySelector('[data-ob-switching]');
|
|
102
|
+
const radios = () => [...projectStep.querySelectorAll('input[name="${PICK_GROUP}"]')];
|
|
103
|
+
const picked = () => radios().find((radio) => radio.checked && !radio.closest('[hidden]'));
|
|
104
|
+
const own = () => radios().find((radio) => radio.hasAttribute('data-pick-here') && !radio.closest('[data-ob-chosen]'));
|
|
105
|
+
const drawOnward = () => { if (onward) onward.disabled = !picked(); };
|
|
106
|
+
const say = (tone, title, text) => {
|
|
107
|
+
if (!notice) return;
|
|
108
|
+
notice.classList.toggle('ob-notice-warn', tone === 'warn');
|
|
109
|
+
notice.querySelector('[data-ob-notice-mark]').textContent = tone === 'warn' ? '!' : '→';
|
|
110
|
+
notice.querySelector('[data-ob-notice-title]').textContent = title;
|
|
111
|
+
notice.querySelector('[data-ob-notice-text]').textContent = text || '';
|
|
112
|
+
notice.hidden = false;
|
|
113
|
+
};
|
|
114
|
+
const unsay = () => { if (notice) notice.hidden = true; };
|
|
115
|
+
// The list as it was drawn, what the folder window came to set aside.
|
|
116
|
+
const toList = () => {
|
|
117
|
+
unsay();
|
|
118
|
+
if (chosenBox) { chosenBox.hidden = true; chosenBox.querySelector('[data-ob-chosen-rows]').textContent = ''; }
|
|
119
|
+
if (list) list.hidden = false;
|
|
120
|
+
const mine = own();
|
|
121
|
+
if (mine && !picked()) mine.checked = true;
|
|
122
|
+
drawOnward();
|
|
123
|
+
};
|
|
124
|
+
const ask = (route, body) => fetch(route, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) })
|
|
125
|
+
.then((response) => response.json().then((answer) => ({ ok: response.ok && answer.ok === true, answer })))
|
|
126
|
+
.catch(() => ({ ok: false, answer: {}, unreachable: true }));
|
|
127
|
+
const failed = (answer) => say('warn', word('failedTitle'), answer.unreachable ? word('unreachable') : word('failed').replace('{reason}', (answer.answer && answer.answer.message) || ''));
|
|
128
|
+
// V15: "Switching to blog…" where the step was, until the run that shows it answers with its address.
|
|
129
|
+
const showSwitching = (name) => {
|
|
130
|
+
projectStep.classList.add('ob-switching-now');
|
|
131
|
+
if (!switching) return;
|
|
132
|
+
switching.querySelector('[data-ob-switching-title]').textContent = word('switching').replace('{name}', name);
|
|
133
|
+
switching.hidden = false;
|
|
134
|
+
};
|
|
135
|
+
const switchTo = (id, name) => {
|
|
136
|
+
if (!served) { projectStep.classList.add('ob-picking'); say('warn', word('failedTitle'), word('unreachable')); return; }
|
|
137
|
+
showSwitching(name);
|
|
138
|
+
ask('api/switch-project', { id, from: 'step' }).then((answer) => {
|
|
139
|
+
if (answer.ok && typeof answer.answer.url === 'string') { location.assign(answer.answer.url); return; }
|
|
140
|
+
projectStep.classList.remove('ob-switching-now');
|
|
141
|
+
if (switching) switching.hidden = true;
|
|
142
|
+
projectStep.classList.add('ob-picking');
|
|
143
|
+
failed(answer);
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
// A chosen folder's project, as its row in the list draws it - or by its name and place, where the list does not hold it.
|
|
147
|
+
const rowFor = (project) => {
|
|
148
|
+
const listed = radios().find((one) => one.value === project.id && !one.closest('[data-ob-chosen]'));
|
|
149
|
+
if (listed) {
|
|
150
|
+
const row = listed.closest('.pjl-pick').cloneNode(true);
|
|
151
|
+
row.classList.add('pjl-pick-here');
|
|
152
|
+
return row;
|
|
153
|
+
}
|
|
154
|
+
const row = document.createElement('label');
|
|
155
|
+
row.className = 'pjl-pick pjl-pick-here';
|
|
156
|
+
const input = document.createElement('input');
|
|
157
|
+
input.type = 'radio';
|
|
158
|
+
input.className = 'pjl-radio-input';
|
|
159
|
+
input.name = '${PICK_GROUP}';
|
|
160
|
+
input.value = project.id;
|
|
161
|
+
input.setAttribute('data-pick-name', project.name);
|
|
162
|
+
if (project.here) input.setAttribute('data-pick-here', '');
|
|
163
|
+
const mark = document.createElement('span');
|
|
164
|
+
mark.className = 'pjl-radio';
|
|
165
|
+
const dot = document.createElement('span');
|
|
166
|
+
dot.className = 'pjl-radio-dot';
|
|
167
|
+
mark.append(dot);
|
|
168
|
+
const text = document.createElement('span');
|
|
169
|
+
text.className = 'pjl-project';
|
|
170
|
+
const name = document.createElement('span');
|
|
171
|
+
name.className = 'pjl-name';
|
|
172
|
+
name.textContent = project.name;
|
|
173
|
+
const place = document.createElement('span');
|
|
174
|
+
place.className = 'pjl-detail';
|
|
175
|
+
place.textContent = project.place || '';
|
|
176
|
+
text.append(name, place);
|
|
177
|
+
row.append(input, mark, text);
|
|
178
|
+
return row;
|
|
179
|
+
};
|
|
180
|
+
// V12: the computer's folder window, and what it came to, said over the list.
|
|
181
|
+
const chooseFolder = () => {
|
|
182
|
+
if (!served) { say('warn', word('failedTitle'), word('unreachable')); return; }
|
|
183
|
+
toList();
|
|
184
|
+
// The maintainer, 2026-09-28: a loader on the button, not a sentence, while the folder window opens and is open.
|
|
185
|
+
const busy = (on) => {
|
|
186
|
+
if (list) list.classList.toggle('ob-waiting', on);
|
|
187
|
+
if (!chooser) return;
|
|
188
|
+
chooser.classList.toggle('pill-busy', on);
|
|
189
|
+
if (on) chooser.setAttribute('aria-busy', 'true'); else chooser.removeAttribute('aria-busy');
|
|
190
|
+
};
|
|
191
|
+
busy(true);
|
|
192
|
+
if (onward) onward.disabled = true;
|
|
193
|
+
ask('api/choose-folder', { lang: lang(), from: 'step' }).then((answer) => {
|
|
194
|
+
busy(false);
|
|
195
|
+
if (!answer.ok) { failed(answer); drawOnward(); return; }
|
|
196
|
+
const said = answer.answer;
|
|
197
|
+
if (said.kind === 'switched' && typeof said.url === 'string') { showSwitching(said.name || ''); location.assign(said.url); return; }
|
|
198
|
+
if (said.kind === 'refused') say('warn', word('refusedTitle'), word(said.not === 'home' ? 'refusedHome' : 'refusedRoot'));
|
|
199
|
+
else if (said.kind === 'here') { const mine = own(); if (mine) { mine.checked = true; unsay(); } else say('arrow', word('chooseHere'), ''); }
|
|
200
|
+
else if (said.kind === 'near' && chosenBox && (said.projects || []).length > 0) {
|
|
201
|
+
const projects = said.projects;
|
|
202
|
+
say('arrow', (said.above ? word('chatsIn') : word('chatsInside')).replace('{name}', said.above ? projects[0].name : said.chosen.name),
|
|
203
|
+
word('picked').replace('{place}', said.chosen.place || said.chosen.name));
|
|
204
|
+
chosenBox.querySelector('[data-ob-chosen-label]').textContent = word(said.above ? 'weUse' : 'inThere');
|
|
205
|
+
const rows = chosenBox.querySelector('[data-ob-chosen-rows]');
|
|
206
|
+
rows.textContent = '';
|
|
207
|
+
projects.forEach((project, at) => {
|
|
208
|
+
const row = rowFor(project);
|
|
209
|
+
row.querySelector('input').checked = at === 0;
|
|
210
|
+
rows.append(row);
|
|
211
|
+
});
|
|
212
|
+
const anyway = chosenBox.querySelector('[data-ob-anyway]');
|
|
213
|
+
anyway.textContent = word('useAnyway').replace('{name}', said.chosen.name);
|
|
214
|
+
anyway.setAttribute('data-ob-switch', said.chosen.id);
|
|
215
|
+
anyway.setAttribute('data-ob-name', said.chosen.name);
|
|
216
|
+
if (list) list.hidden = true;
|
|
217
|
+
chosenBox.hidden = false;
|
|
218
|
+
} else unsay();
|
|
219
|
+
drawOnward();
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
projectStep.addEventListener('change', drawOnward);
|
|
223
|
+
projectStep.addEventListener('click', (event) => {
|
|
224
|
+
if (event.target.closest('[data-ob-pick]')) {
|
|
225
|
+
projectStep.classList.add('ob-picking');
|
|
226
|
+
toList();
|
|
227
|
+
const first = picked() || radios()[0];
|
|
228
|
+
if (first) first.focus({ preventScroll: true });
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (event.target.closest('[data-ob-unpick]')) {
|
|
232
|
+
if (chosenBox && !chosenBox.hidden) { toList(); return; }
|
|
233
|
+
unsay();
|
|
234
|
+
if (projectStep.querySelector('[data-ob-card]')) projectStep.classList.remove('ob-picking'); else go('welcome');
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const other = event.target.closest('[data-ob-switch]');
|
|
238
|
+
if (other) { switchTo(other.getAttribute('data-ob-switch'), other.getAttribute('data-ob-name') || ''); return; }
|
|
239
|
+
if (event.target.closest('[data-ob-continue]')) {
|
|
240
|
+
const chosen = picked();
|
|
241
|
+
if (!chosen) return;
|
|
242
|
+
if (chosen.hasAttribute('data-pick-here')) go('who'); else switchTo(chosen.value, chosen.getAttribute('data-pick-name') || '');
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if (event.target.closest('[data-ob-choose]')) chooseFolder();
|
|
246
|
+
});
|
|
247
|
+
drawOnward();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// The steps' answers, from what is in force (W10), kept here until Finish. Step 3 is not drawn (2026-09-25): alerts
|
|
251
|
+
// start on where they can be written, as it started them, and the two other moments stay as they are.
|
|
252
|
+
const choices = { scope: state.who, watch: state.alerts.on, modes: {}, stopped: state.inForce.stopped, fine: state.inForce.fine };
|
|
253
|
+
// W12a: the names added here, each with its own Block or Tell me.
|
|
254
|
+
const added = [];
|
|
255
|
+
const payload = () => ({
|
|
256
|
+
scope: choices.scope,
|
|
257
|
+
watch: choices.watch,
|
|
258
|
+
protect: added.filter((item) => item.mode === 'block').map((item) => item.pattern),
|
|
259
|
+
tell: added.filter((item) => item.mode === 'tell').map((item) => item.pattern),
|
|
260
|
+
modes: choices.modes,
|
|
261
|
+
stopped: choices.stopped,
|
|
262
|
+
fine: choices.fine,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// Step 1 (W11): the chosen card.
|
|
266
|
+
const whoCards = [...root.querySelectorAll('[data-ob-who]')];
|
|
267
|
+
const drawWho = () => whoCards.forEach((card) => {
|
|
268
|
+
const on = card.dataset.obWho === choices.scope;
|
|
269
|
+
card.classList.toggle('ob-who-on', on);
|
|
270
|
+
card.setAttribute('aria-checked', String(on));
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Step 2 (W12a): a row's switch and mark, drawn at the mode chosen.
|
|
274
|
+
const drawMode = (holder, mode) => {
|
|
275
|
+
const box = holder.querySelector('.ob-mode');
|
|
276
|
+
if (!box) return;
|
|
277
|
+
holder.classList.toggle('ob-rule-is-block', mode === 'block');
|
|
278
|
+
holder.classList.toggle('ob-rule-is-tell', mode === 'tell');
|
|
279
|
+
box.classList.toggle('ob-mode-is-block', mode === 'block');
|
|
280
|
+
box.classList.toggle('ob-mode-is-tell', mode === 'tell');
|
|
281
|
+
box.querySelectorAll('[data-ob-mode]').forEach((half) => {
|
|
282
|
+
const on = half.dataset.obMode === mode;
|
|
283
|
+
half.classList.toggle('ob-mode-on', on);
|
|
284
|
+
half.setAttribute('aria-pressed', String(on));
|
|
285
|
+
});
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// Step 2 (W12, W12a): a name the kit's popup hands over becomes a row, on Block, and can be taken off again.
|
|
289
|
+
const list = root.querySelector('[data-ob-files]');
|
|
290
|
+
const template = root.querySelector('[data-ob-added-row]');
|
|
291
|
+
const picker = document.getElementById('ob-add');
|
|
292
|
+
const shown = (item) => item.kind === 'folder' ? item.name + '/' : item.name;
|
|
293
|
+
if (picker) picker.addEventListener('add-file', (event) => {
|
|
294
|
+
const { name, kind, pattern } = event.detail;
|
|
295
|
+
if (picker.open) picker.close();
|
|
296
|
+
if (added.some((each) => each.pattern === pattern) || (state.inForce.protected || []).includes(pattern) || !list || !template) return;
|
|
297
|
+
const item = { name, kind, pattern, mode: 'block' };
|
|
298
|
+
added.push(item);
|
|
299
|
+
const row = template.content.firstElementChild.cloneNode(true);
|
|
300
|
+
row.querySelectorAll('[data-ob-name]').forEach((slot) => { slot.textContent = shown(item); slot.title = pattern; });
|
|
301
|
+
row.querySelectorAll('[data-ob-kind]').forEach((slot) => { slot.hidden = slot.dataset.obKind !== kind; });
|
|
302
|
+
row.querySelector('[data-ob-untick]').addEventListener('click', () => {
|
|
303
|
+
added.splice(added.indexOf(item), 1);
|
|
304
|
+
if (still) { row.remove(); return; }
|
|
305
|
+
row.classList.add('ob-rule-gone');
|
|
306
|
+
setTimeout(() => row.remove(), 200);
|
|
307
|
+
});
|
|
308
|
+
row.querySelectorAll('[data-ob-mode]').forEach((half) => half.addEventListener('click', () => {
|
|
309
|
+
item.mode = half.dataset.obMode;
|
|
310
|
+
drawMode(row, item.mode);
|
|
311
|
+
}));
|
|
312
|
+
list.append(row);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
const say = (where, text) => {
|
|
316
|
+
const line = where && where.querySelector('[data-ob-say]');
|
|
317
|
+
if (!line) return;
|
|
318
|
+
line.textContent = text;
|
|
319
|
+
line.hidden = text === '';
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const filesStep = root.querySelector('[data-ob-screen="files"]');
|
|
323
|
+
|
|
324
|
+
// W15: one request. A refusal is said where the person is; anything else is Done, which names what failed (W20).
|
|
325
|
+
const send = (where, button) => {
|
|
326
|
+
if (!served) { say(where, word('unreachable')); return; }
|
|
327
|
+
if (button) { button.disabled = true; button.setAttribute('aria-busy', 'true'); }
|
|
328
|
+
say(where, word('saving'));
|
|
329
|
+
fetch('api/onboarding', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload()) })
|
|
330
|
+
.then((response) => response.json().then((answer) => ({ ok: response.ok && answer.ok === true, answer })))
|
|
331
|
+
.catch(() => ({ ok: false, answer: { message: word('unreachable') } }))
|
|
332
|
+
.then(({ ok, answer }) => {
|
|
333
|
+
if (button) { button.disabled = false; button.removeAttribute('aria-busy'); }
|
|
334
|
+
if (!ok) { say(where, word('refused') + ' ' + (answer.message || '')); return; }
|
|
335
|
+
done(answer);
|
|
336
|
+
});
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
// W17-W20, W26: Done, from the answer. Alerts count as on only where the hook runs now.
|
|
340
|
+
const done = (answer) => {
|
|
341
|
+
const results = answer.results || [];
|
|
342
|
+
const failed = results.filter((result) => !result.written);
|
|
343
|
+
const hook = results.find((result) => result.change === 'watch');
|
|
344
|
+
const on = choices.watch && (hook ? hook.written : state.inForce.watch !== false);
|
|
345
|
+
root.querySelectorAll('[data-ob-if]').forEach((part) => { part.hidden = part.dataset.obIf !== (on ? 'on' : 'off'); });
|
|
346
|
+
const failures = root.querySelector('[data-ob-failed]');
|
|
347
|
+
failed.forEach((result) => {
|
|
348
|
+
// A name added on Tell me and a row switched are one line: the Block and Tell me choices.
|
|
349
|
+
const line = failures.querySelector('[data-ob-fail="' + (result.change === 'tell' ? 'mode' : result.change) + '"]');
|
|
350
|
+
if (!line) return;
|
|
351
|
+
line.querySelectorAll('[data-ob-fail-said]').forEach((slot) => { slot.textContent = result.message || ''; });
|
|
352
|
+
line.hidden = false;
|
|
353
|
+
});
|
|
354
|
+
failures.hidden = failed.length === 0;
|
|
355
|
+
const tick = root.querySelector('[data-ob-summary-tick]');
|
|
356
|
+
if (tick) tick.hidden = failed.length > 0;
|
|
357
|
+
const kinds = (state.rows || 0) + added.length;
|
|
358
|
+
const messages = choices.watch ? 1 + (choices.stopped ? 1 : 0) + (choices.fine ? 1 : 0) : 0;
|
|
359
|
+
root.querySelectorAll('[data-ob-summary]').forEach((slot) => {
|
|
360
|
+
const which = (slot.closest('[lang]') || {}).lang || 'en';
|
|
361
|
+
slot.textContent = word(choices.scope === 'shared' ? 'shared' : 'local', which) + ' · ' + counted('kinds', kinds, which) + ' · ' +
|
|
362
|
+
word('messages', which).replace('{n}', String(messages));
|
|
363
|
+
// which-project V23: the line begins with the project it was for.
|
|
364
|
+
if (state.name) {
|
|
365
|
+
const name = document.createElement('strong');
|
|
366
|
+
name.textContent = state.name;
|
|
367
|
+
slot.prepend(name, ' · ');
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
// W20a: the line for Codex that Finish's answer names, where it names one.
|
|
371
|
+
root.querySelectorAll('[data-ob-codex]').forEach((part) => { part.hidden = part.dataset.obCodex !== answer.codex; });
|
|
372
|
+
const unrecorded = root.querySelector('[data-ob-unrecorded]');
|
|
373
|
+
if (unrecorded) unrecorded.hidden = answer.recorded !== false;
|
|
374
|
+
const backdrop = document.querySelector('.bd');
|
|
375
|
+
if (backdrop) backdrop.classList.add('bd-mint');
|
|
376
|
+
go('done');
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
root.addEventListener('click', (event) => {
|
|
380
|
+
if (event.target.closest('[data-ob-skip-intro]')) { show('welcome'); return; }
|
|
381
|
+
const to = event.target.closest('[data-ob-go]');
|
|
382
|
+
if (to) { go(to.dataset.obGo); return; }
|
|
383
|
+
const finish = event.target.closest('[data-ob-finish]');
|
|
384
|
+
if (finish) { send(filesStep, finish); return; }
|
|
385
|
+
|
|
386
|
+
const who = event.target.closest('[data-ob-who]');
|
|
387
|
+
if (who) { choices.scope = who.dataset.obWho; drawWho(); return; }
|
|
388
|
+
|
|
389
|
+
// W12a: a row's Block or Tell me; the choice is kept only where it differs from what is in force.
|
|
390
|
+
const half = event.target.closest('[data-ob-row] [data-ob-mode]');
|
|
391
|
+
if (half) {
|
|
392
|
+
const row = half.closest('[data-ob-row]');
|
|
393
|
+
const key = row.dataset.obRow;
|
|
394
|
+
const was = (state.inForce.rows.find((each) => each.key === key) || {}).mode;
|
|
395
|
+
if (half.dataset.obMode === was) delete choices.modes[key]; else choices.modes[key] = half.dataset.obMode;
|
|
396
|
+
drawMode(row, half.dataset.obMode);
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
})();
|
|
400
|
+
`;
|