@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,98 @@
|
|
|
1
|
+
import { projectName } from '../app-nav.js';
|
|
2
|
+
import { settingsView } from '../settings/settings-view.js';
|
|
3
|
+
import { toFixView } from '../to-fix/to-fix-view.js';
|
|
4
|
+
/**
|
|
5
|
+
* What the onboarding shows, decided from the index (`.ai/specs/2026-09-24-onboarding.md`; plan step 2). No HTML:
|
|
6
|
+
* every screen's state is chosen here, and the page only writes it. What is in force is Settings' own reading of the
|
|
7
|
+
* files (`settingsView`), and what is to fix is To fix's (`toFixView`), so the three pages never disagree.
|
|
8
|
+
*/
|
|
9
|
+
/** W18: how many files Done names before "+{n} more on your To fix list". */
|
|
10
|
+
const DONE_FILES = 3;
|
|
11
|
+
/**
|
|
12
|
+
* What Finish compares the choices with, from the settings as the files hold them: read when the page is drawn, and
|
|
13
|
+
* read again by the server at Finish (W15), so a choice made in another tab since is never written over.
|
|
14
|
+
*/
|
|
15
|
+
export function inForceOf(settings) {
|
|
16
|
+
const view = settingsView(settings);
|
|
17
|
+
return {
|
|
18
|
+
watch: settings.hooks?.watch ?? false,
|
|
19
|
+
refuse: settings.hooks?.refuse ?? false,
|
|
20
|
+
stopped: view.stopped.on,
|
|
21
|
+
fine: view.fine.on,
|
|
22
|
+
protected: settings.protected,
|
|
23
|
+
rows: view.rows.map((row) => ({
|
|
24
|
+
key: rowKey(row),
|
|
25
|
+
mode: row.mode,
|
|
26
|
+
watched: row.watched,
|
|
27
|
+
ruled: row.watched && row.patterns.every((pattern) => deniedIn(settings, pattern)),
|
|
28
|
+
switchable: row.switchTo !== undefined,
|
|
29
|
+
patterns: row.patterns,
|
|
30
|
+
})),
|
|
31
|
+
canWrite: view.canWrite,
|
|
32
|
+
canAdd: view.canAdd,
|
|
33
|
+
canTell: view.canTell,
|
|
34
|
+
noticesWritable: view.noticesWritable,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A pattern either settings file denies - Claude Code applies both (R4d) - or one whose rules could not be read, where
|
|
39
|
+
* nothing is claimed and nothing written (K2).
|
|
40
|
+
*/
|
|
41
|
+
export function deniedIn(settings, pattern) {
|
|
42
|
+
return settings.held === undefined || settings.held.local.includes(pattern) || settings.held.shared.includes(pattern);
|
|
43
|
+
}
|
|
44
|
+
/** What the page and the server find a row of Private files by: the group's name, or its first pattern (W12a). */
|
|
45
|
+
export function rowKey(row) {
|
|
46
|
+
return row.name ?? row.patterns[0] ?? '';
|
|
47
|
+
}
|
|
48
|
+
/** `undefined` where there is nothing to set up from: a shared page, or one with no settings behind it (W1). */
|
|
49
|
+
export function onboardingView(index) {
|
|
50
|
+
if (index.shared || index.settings === undefined)
|
|
51
|
+
return undefined;
|
|
52
|
+
const settings = settingsView(index.settings);
|
|
53
|
+
const fix = toFixView(index);
|
|
54
|
+
const files = [...fix.keys, ...fix.look].slice(0, DONE_FILES);
|
|
55
|
+
const generated = index.entries.filter((entry) => entry.report.kind === 'generated');
|
|
56
|
+
return {
|
|
57
|
+
intro: index.onboarding?.intro === true,
|
|
58
|
+
atProject: index.onboarding?.atProject === true,
|
|
59
|
+
project: projectOf(index, fix.total),
|
|
60
|
+
...(index.projects === undefined ? {} : { projects: index.projects }),
|
|
61
|
+
// F56: one answer for who it is all for; where the files hold both, or nothing yet, Just me.
|
|
62
|
+
who: settings.scope === 'shared' ? 'shared' : 'local',
|
|
63
|
+
files: { rows: settings.rows, canAdd: settings.canAdd, canTell: settings.canTell },
|
|
64
|
+
messages: {
|
|
65
|
+
// Row 1 starts on where it can be written: it is what `init` ticks by default (R4a), and this is the setup `init`
|
|
66
|
+
// was. Where it cannot, it shows what the file holds, and nothing moves it.
|
|
67
|
+
alerts: { on: settings.alerts.on || settings.canWrite, writable: settings.canWrite },
|
|
68
|
+
// Rows 2 and 3 start from what is in force, the product's defaults where nothing was chosen (N4).
|
|
69
|
+
stopped: { on: settings.stopped.on, writable: settings.noticesWritable },
|
|
70
|
+
fine: { on: settings.fine.on, writable: settings.noticesWritable },
|
|
71
|
+
},
|
|
72
|
+
inForce: inForceOf(index.settings),
|
|
73
|
+
done: {
|
|
74
|
+
total: fix.total,
|
|
75
|
+
files,
|
|
76
|
+
more: fix.total - files.length,
|
|
77
|
+
state: fix.state,
|
|
78
|
+
conversations: index.entries.length,
|
|
79
|
+
checked: generated.length,
|
|
80
|
+
gaps: index.entries.some((entry) => entry.report.kind === 'failed' || (entry.report.kind === 'generated' && entry.report.incomplete)),
|
|
81
|
+
asked: index.asked,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** V20's starting state: a folder that is no project, one with chats, one inside a project with chats, or neither. */
|
|
86
|
+
function projectOf(index, read) {
|
|
87
|
+
if (index.notAProject !== undefined)
|
|
88
|
+
return { kind: 'none', not: index.notAProject, conversations: index.entries.length };
|
|
89
|
+
const name = projectName(index.project ?? '');
|
|
90
|
+
const place = index.place === undefined ? {} : { place: index.place };
|
|
91
|
+
if (index.entries.length > 0)
|
|
92
|
+
return { kind: 'found', name, ...place, conversations: index.entries.length, entryPoints: index.entryPoints ?? {}, read };
|
|
93
|
+
const above = index.projects?.above;
|
|
94
|
+
const holder = above === undefined ? undefined : index.projects?.rows.find((row) => row.id === above.id && row.exists);
|
|
95
|
+
if (above !== undefined && holder !== undefined)
|
|
96
|
+
return { kind: 'inside', name, ...place, above: holder, within: above.within };
|
|
97
|
+
return { kind: 'empty', name, ...place };
|
|
98
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { escapeHtml as e } from '../../render/html-report-components.js';
|
|
2
|
+
import { inLanguages } from '../../render/report-copy.js';
|
|
3
|
+
import { initial } from '../../render/ui/app-sidebar.js';
|
|
4
|
+
import { pill } from '../../render/ui/button.js';
|
|
5
|
+
import { projectList } from '../../render/ui/project-list.js';
|
|
6
|
+
import { tag } from '../../render/ui/tag.js';
|
|
7
|
+
/** The radio group the step's list chooses in (`.ai/specs/2026-09-27-which-project.md` V11). */
|
|
8
|
+
export const PICK_GROUP = 'ob-project';
|
|
9
|
+
/** The kinds V4 names, in the order the step says them; an unknown kind is counted last and not named. */
|
|
10
|
+
const NAMED = ['editor', 'terminal', 'script'];
|
|
11
|
+
/** A small folder, drawn: the guidelines have no emoji, not even in a button (§9.3). */
|
|
12
|
+
const FOLDER_SVG = '<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round" aria-hidden="true">' +
|
|
13
|
+
'<path d="M3 6.5A1.5 1.5 0 0 1 4.5 5h4.2l2 2.2h8.8A1.5 1.5 0 0 1 21 8.7v9.8a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 18.5z"/></svg>';
|
|
14
|
+
/**
|
|
15
|
+
* The onboarding's first step (`which-project.md` V19-V21), as the maintainer's design *agentwhy - Wybór projektu* draws
|
|
16
|
+
* it: a card for where the run started - the project found, the project a folder lies inside, a folder with no AI chats
|
|
17
|
+
* - with **No, pick another project** beside the way on; the person's projects as a list to pick from; and, while another
|
|
18
|
+
* project's run starts, "Switching to blog…". In the home directory the list is all there is (V7). Choosing this run's
|
|
19
|
+
* own project goes on to *Who* in the page; choosing another shows it in this tab, at its own *Who* (V14-V16). With no
|
|
20
|
+
* script the card and the list are drawn and nothing switches (V13).
|
|
21
|
+
*/
|
|
22
|
+
export function projectStep(view, clock) {
|
|
23
|
+
const project = view.project;
|
|
24
|
+
// Only a run that can show another project offers its list: a choice it could not act on would be a promise.
|
|
25
|
+
const projects = view.projects?.switchable === true ? view.projects : undefined;
|
|
26
|
+
const picking = project.kind === 'none';
|
|
27
|
+
return '<section class="ob-screen ob-step ob-step-project' + (picking ? ' ob-picking' : '') + '" data-ob-screen="project" data-ob-project="' + project.kind + '"' +
|
|
28
|
+
' aria-labelledby="' + (picking ? 'ob-pick-title' : 'ob-project-title') + '">' +
|
|
29
|
+
(project.kind === 'none' ? '' : card(project, projects !== undefined)) +
|
|
30
|
+
pickView(project, projects, clock) +
|
|
31
|
+
(projects === undefined ? '' : switching()) +
|
|
32
|
+
'</section>';
|
|
33
|
+
}
|
|
34
|
+
/** "Step 1 of 3", a heading and its sentence. */
|
|
35
|
+
function top(id, title, text) {
|
|
36
|
+
return '<p class="ob-step-no">' + inLanguages((t) => t('ob.step', { n: 1 })) + '</p>' +
|
|
37
|
+
'<h2 class="ob-h2" id="' + id + '">' + title + '</h2>' +
|
|
38
|
+
'<p class="ob-step-text">' + text + '</p>';
|
|
39
|
+
}
|
|
40
|
+
/** **No, pick another project**: the list, beside the way on - where there is a list to pick from. */
|
|
41
|
+
function pickAnother(listed) {
|
|
42
|
+
return listed
|
|
43
|
+
? pill({ label: FOLDER_SVG + inLanguages((t) => t('ob.project.pick')), tone: 'secondary', size: 'lg', button: true, attributes: ' data-ob-pick' })
|
|
44
|
+
: '';
|
|
45
|
+
}
|
|
46
|
+
/** V20, the first three states: where the run started, what is known of it, and the way on. Hidden once the list is open. */
|
|
47
|
+
function card(project, listed) {
|
|
48
|
+
const name = e(project.name);
|
|
49
|
+
const hint = (key, vars = {}) => '<div class="ob-hint"><span class="ob-hint-mark" aria-hidden="true">✦</span><span>' + inLanguages((t) => t(key, vars)) + '</span></div>';
|
|
50
|
+
const go = (primary) => '<div class="ob-proj-go js-only' + (listed ? '' : ' ob-proj-go-one') + '">' + pickAnother(listed) + primary + '</div>';
|
|
51
|
+
if (project.kind === 'found') {
|
|
52
|
+
const read = project.read;
|
|
53
|
+
return '<div class="ob-proj-view ob-proj-card-view" data-ob-card>' +
|
|
54
|
+
top('ob-project-title', inLanguages((t) => t('ob.project.found.title')), inLanguages((t) => t('ob.project.found.text'))) +
|
|
55
|
+
box('found', project.name, project.place, tag(inLanguages((t) => t('ob.project.found.tag')), 'mint', 'badge'), fact('yes', inLanguages((t) => worked(t, project.conversations, project.entryPoints))) +
|
|
56
|
+
(read === 0 ? '' : fact('look', inLanguages((t) => t('ob.done.found', { n: read }))))) +
|
|
57
|
+
// White, as the maintainer asked on 2026-09-28: the way on here is a choice made, not a setup started.
|
|
58
|
+
go(pill({ label: inLanguages((t) => t('ob.project.use', { name })), tone: 'light', size: 'lg', button: true, attributes: ' data-ob-go="who"' })) +
|
|
59
|
+
// No hint here: "Most people just click Yes" misled people (the maintainer, 2026-09-28).
|
|
60
|
+
'</div>';
|
|
61
|
+
}
|
|
62
|
+
if (project.kind === 'inside') {
|
|
63
|
+
const above = project.above;
|
|
64
|
+
const within = project.within.split(/[\\/]/).join('/');
|
|
65
|
+
const depth = within.split('/').length;
|
|
66
|
+
const here = e(above.name + '/' + within);
|
|
67
|
+
// Where the run cannot show another project, the only way on is the folder it is in.
|
|
68
|
+
const onward = listed
|
|
69
|
+
? pill({
|
|
70
|
+
label: inLanguages((t) => t('ob.project.useIt', { name: e(above.name) })),
|
|
71
|
+
tone: 'light',
|
|
72
|
+
size: 'lg',
|
|
73
|
+
button: true,
|
|
74
|
+
attributes: ' data-ob-switch="' + e(above.id) + '" data-ob-name="' + e(above.name) + '"',
|
|
75
|
+
})
|
|
76
|
+
: pill({ label: inLanguages((t) => t('proj.useAnyway', { name })), tone: 'light', size: 'lg', button: true, attributes: ' data-ob-go="who"' });
|
|
77
|
+
return '<div class="ob-proj-view ob-proj-card-view" data-ob-card>' +
|
|
78
|
+
top('ob-project-title', inLanguages((t) => t('ob.project.inside.title')), inLanguages((t) => t('ob.project.inside.text', { place: e(project.place ?? project.name), up: t('ob.project.up', { n: depth }) }))) +
|
|
79
|
+
box('inside', above.name, above.place, tag(inLanguages((t) => t('ob.project.upTag', { n: depth })), 'grey', 'badge'), fact('yes', inLanguages((t) => t('ob.project.worked', { n: above.conversations }))) +
|
|
80
|
+
fact('yes', inLanguages((t) => t('ob.project.includes', { name: e(within) }))), '<p class="ob-proj-note">' + inLanguages((t) => t('ob.project.whole', { here: '<strong>' + here + '</strong>', name: '<strong>' + e(above.name) + '</strong>' })) + '</p>') +
|
|
81
|
+
go(onward) +
|
|
82
|
+
hint('ob.project.inside.hint', { name: e(within) }) +
|
|
83
|
+
'</div>';
|
|
84
|
+
}
|
|
85
|
+
// V21, VD4: a folder with no AI chats is the person's to choose.
|
|
86
|
+
return '<div class="ob-proj-view ob-proj-card-view" data-ob-card>' +
|
|
87
|
+
top('ob-project-title', inLanguages((t) => t('ob.project.empty.title')), inLanguages((t) => t('ob.project.empty.text'))) +
|
|
88
|
+
box('empty', project.name, project.place, tag(inLanguages((t) => t('ob.project.empty.tag')), 'amber', 'badge'), fact('yes', inLanguages((t) => t('ob.project.isProject'))) + fact('none', inLanguages((t) => t('ob.project.none')))) +
|
|
89
|
+
go(pill({ label: inLanguages((t) => t('ob.project.anyway')), tone: 'light', size: 'lg', button: true, attributes: ' data-ob-go="who"' })) +
|
|
90
|
+
hint('ob.project.empty.hint') +
|
|
91
|
+
'</div>';
|
|
92
|
+
}
|
|
93
|
+
/** The project card: its initial, its name, where it is, a tag, and what is known of it. */
|
|
94
|
+
function box(tone, name, place, label, facts, note = '') {
|
|
95
|
+
return '<div class="ob-proj-card ob-proj-card-' + tone + '">' +
|
|
96
|
+
'<div class="ob-proj-head"><span class="pjl-mark" aria-hidden="true">' + e(initial(name)) + '</span>' +
|
|
97
|
+
'<span class="ob-proj-text"><span class="ob-proj-name">' + e(name) + '</span>' +
|
|
98
|
+
(place === undefined ? '' : '<span class="ob-proj-place">' + e(place) + '</span>') + '</span>' + label + '</div>' +
|
|
99
|
+
'<ul class="ob-proj-facts">' + facts + '</ul>' + note + '</div>';
|
|
100
|
+
}
|
|
101
|
+
/** One thing known of the project: a mint tick for a fact, an amber mark for one to look at, a ring for nothing yet. */
|
|
102
|
+
function fact(kind, words) {
|
|
103
|
+
const mark = kind === 'yes' ? '✓' : kind === 'look' ? '!' : '';
|
|
104
|
+
return '<li><span class="ob-fact ob-fact-' + kind + '" aria-hidden="true">' + mark + '</span><span>' + words + '</span></li>';
|
|
105
|
+
}
|
|
106
|
+
/** "Your AI has worked here: 12 chats", and where they were held (V4): "9 in your code editor, 3 in the terminal". */
|
|
107
|
+
function worked(t, conversations, from) {
|
|
108
|
+
const chats = t('ob.project.worked', { n: conversations });
|
|
109
|
+
const named = NAMED.filter((kind) => (from[kind] ?? 0) > 0).map((kind) => t('ob.project.in.' + kind, { n: from[kind] ?? 0 }));
|
|
110
|
+
if (named.length === 0)
|
|
111
|
+
return chats;
|
|
112
|
+
const unknown = from.unknown ?? 0;
|
|
113
|
+
return chats + '<span class="ob-fact-more"> · ' + named.join(', ') + (unknown > 0 ? ' ' + t('ob.project.in.unknown', { n: unknown }) : '') + '</span>';
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The person's projects to pick from (V20's last two states): this run's own chosen where it is one of them, nothing
|
|
117
|
+
* chosen where it is not, **Choose a folder…** under them where the computer has a folder window. What the folder window
|
|
118
|
+
* came to is said in the box over the list, and a folder inside a project is offered as that project, with the folder
|
|
119
|
+
* itself a button under it - the design's "Your AI chats are in my-app" (V12).
|
|
120
|
+
*/
|
|
121
|
+
function pickView(project, projects, clock) {
|
|
122
|
+
const lead = project.kind === 'none' ? 'ob.project.' + project.not : 'ob.project.text';
|
|
123
|
+
return '<div class="ob-proj-view ob-proj-pick-view" data-ob-pick-view>' +
|
|
124
|
+
top('ob-pick-title', inLanguages((t) => t('ob.project.title')), inLanguages((t) => t(lead))) +
|
|
125
|
+
(projects === undefined
|
|
126
|
+
? '<p class="ob-proj-how">' + inLanguages((t) => t('proj.missing.text')) + ' ' + inLanguages((t) => t('proj.missing.how')) + '</p>'
|
|
127
|
+
: '<div class="ob-notice" data-ob-notice hidden><span class="ob-notice-mark" data-ob-notice-mark aria-hidden="true"></span>' +
|
|
128
|
+
'<span><span class="ob-notice-title" data-ob-notice-title></span><span class="ob-notice-text" data-ob-notice-text></span></span></div>' +
|
|
129
|
+
'<div class="ob-proj-list" data-ob-list>' +
|
|
130
|
+
projectList({ rows: projects.rows, unreadable: projects.unreadable, ...(projects.temporary === undefined ? {} : { temporary: projects.temporary }), now: clock.now, timeZone: clock.timeZone, pick: PICK_GROUP }) +
|
|
131
|
+
'</div>' +
|
|
132
|
+
'<div class="ob-proj-chosen" data-ob-chosen hidden><p class="pjl-label" data-ob-chosen-label></p>' +
|
|
133
|
+
'<div class="pjl pjl-picking"><div class="pjl-chosen-rows" data-ob-chosen-rows></div></div>' +
|
|
134
|
+
'<p class="ob-proj-anyway"><button type="button" class="pill pill-outline pill-md" data-ob-anyway></button>' +
|
|
135
|
+
'<span>' + inLanguages((t) => t('ob.project.nothingYet')) + '</span></p></div>' +
|
|
136
|
+
'<p class="ob-proj-noscript">' + inLanguages((t) => t('proj.noScript')) + '</p>' +
|
|
137
|
+
(projects.choosable
|
|
138
|
+
? '<div class="ob-proj-choose js-only">' + pill({ label: inLanguages((t) => t('proj.choose')), tone: 'outline', size: 'md', button: true, attributes: ' data-ob-choose' }) + '</div>'
|
|
139
|
+
: '<p class="ob-proj-how">' + inLanguages((t) => t('proj.missing.text')) + ' ' + inLanguages((t) => t('proj.missing.how')) + '</p>')) +
|
|
140
|
+
'<p class="ob-proj-which"><span class="ob-proj-i" aria-hidden="true">i</span><span>' + inLanguages((t) => t('proj.which')) + '</span></p>' +
|
|
141
|
+
'<div class="ob-hint"><span class="ob-hint-mark" aria-hidden="true">✦</span><span>' + inLanguages((t) => t('ob.project.hint')) + '</span></div>' +
|
|
142
|
+
'<div class="ob-foot js-only">' +
|
|
143
|
+
pill({ label: inLanguages((t) => t('ob.back')), tone: 'outline', size: 'lg', button: true, attributes: ' data-ob-unpick' }) +
|
|
144
|
+
(projects === undefined ? '' :
|
|
145
|
+
'<span class="ob-foot-end">' +
|
|
146
|
+
// White, as the maintainer asked on 2026-09-29: coral reads as something to fear here, and nothing is started yet.
|
|
147
|
+
pill({ label: inLanguages((t) => t('ob.continue')), tone: 'light', size: 'lg', button: true, attributes: ' data-ob-continue' + (project.kind === 'found' ? '' : ' disabled') }) +
|
|
148
|
+
'</span>') +
|
|
149
|
+
'</div></div>';
|
|
150
|
+
}
|
|
151
|
+
/** V15: the one real wait - another project's run starting - said where the step was. */
|
|
152
|
+
function switching() {
|
|
153
|
+
return '<div class="ob-switching" data-ob-switching role="status" hidden><span class="ob-spinner" aria-hidden="true"></span>' +
|
|
154
|
+
'<p class="ob-switching-title" data-ob-switching-title></p>' +
|
|
155
|
+
'<p class="ob-switching-text">' + inLanguages((t) => t('ob.project.moment')) + '</p></div>';
|
|
156
|
+
}
|
|
157
|
+
/** The step's own look, on the onboarding's frame and the list's kit piece. Colours come from the tokens only. */
|
|
158
|
+
export const PROJECT_STEP_STYLE = String.raw `
|
|
159
|
+
.ob-step-project{max-width:680px}
|
|
160
|
+
.ob-proj-view[hidden],.ob-switching[hidden],.ob-notice[hidden],.ob-proj-chosen[hidden]{display:none!important}
|
|
161
|
+
.js .ob-picking [data-ob-card]{display:none}
|
|
162
|
+
.js .ob-step-project:not(.ob-picking) [data-ob-pick-view]{display:none}
|
|
163
|
+
.js .ob-switching-now>.ob-proj-view{display:none!important}
|
|
164
|
+
.ob-proj-card{padding:18px 20px;border-radius:16px;background:var(--card);border:1.5px solid var(--white-10)}
|
|
165
|
+
.ob-proj-card-found{border-color:var(--mint-50);background:var(--mint-05)}
|
|
166
|
+
.ob-proj-card-empty{border-color:var(--amber-35)}
|
|
167
|
+
.ob-proj-head{display:grid;grid-template-columns:44px minmax(0,1fr) auto;gap:14px;align-items:center}
|
|
168
|
+
.ob-proj-text{min-width:0;display:flex;flex-direction:column;gap:2px}
|
|
169
|
+
.ob-proj-name{font-size:18px;font-weight:650;line-height:1.3;overflow-wrap:anywhere}
|
|
170
|
+
.ob-proj-place{font-family:var(--mono);font-size:12.5px;color:var(--text-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
171
|
+
.ob-proj-facts{list-style:none;margin:14px 0 0;padding:0;display:grid;gap:8px}
|
|
172
|
+
.ob-proj-facts li{display:flex;align-items:flex-start;gap:10px;font-size:14.5px;line-height:1.45;color:var(--text-soft)}
|
|
173
|
+
.ob-fact{flex:none;width:18px;height:18px;margin-top:1px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10.5px;font-weight:700}
|
|
174
|
+
.ob-fact-yes{background:var(--mint-14);color:var(--mint)}
|
|
175
|
+
.ob-fact-look{background:var(--amber-12);color:var(--amber)}
|
|
176
|
+
.ob-fact-none{border:1.5px solid var(--amber);width:16px;height:16px;margin:2px 1px 0}
|
|
177
|
+
.ob-fact-more{color:var(--text-3)}
|
|
178
|
+
.ob-proj-note{margin:14px 0 0;padding:12px 14px;border-radius:10px;background:var(--white-04);border:1px solid var(--white-08);font-size:14px;line-height:1.5;color:var(--text-soft)}
|
|
179
|
+
.ob-proj-note strong{color:var(--text);font-weight:600}
|
|
180
|
+
.ob-proj-go{display:none;margin-top:14px;gap:12px}
|
|
181
|
+
.js .ob-proj-go{display:grid;grid-template-columns:1fr 1fr}
|
|
182
|
+
.js .ob-proj-go-one{grid-template-columns:1fr}
|
|
183
|
+
.ob-proj-go .pill{justify-content:center;gap:9px}
|
|
184
|
+
.ob-proj-pick-view .pjl{margin-top:4px}
|
|
185
|
+
.ob-proj-list.ob-waiting{opacity:.4;pointer-events:none}
|
|
186
|
+
.ob-notice{display:flex;align-items:flex-start;gap:12px;margin:0 0 10px;padding:14px 16px;border-radius:14px;background:var(--card);border:1px solid var(--white-10)}
|
|
187
|
+
.ob-notice-mark{flex:none;width:26px;height:26px;border-radius:50%;background:var(--white-08);color:var(--text);display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:700}
|
|
188
|
+
.ob-notice-warn{background:var(--coral-06);border-color:var(--coral-30)}
|
|
189
|
+
.ob-notice-warn .ob-notice-mark{background:var(--coral);color:var(--on-coral)}
|
|
190
|
+
.ob-notice-title{display:block;font-size:15px;font-weight:600}
|
|
191
|
+
.ob-notice-text{display:block;margin-top:2px;font-size:13.5px;line-height:1.5;color:var(--text-2)}
|
|
192
|
+
.ob-notice-text:empty{display:none}
|
|
193
|
+
.pjl-chosen-rows{display:grid;gap:8px}
|
|
194
|
+
.ob-proj-anyway{display:flex;align-items:center;flex-wrap:wrap;gap:6px 12px;margin:12px 4px 0;font-size:13px;color:var(--text-3)}
|
|
195
|
+
.ob-proj-choose{margin-top:14px}
|
|
196
|
+
.ob-proj-how{margin:12px 4px 0;font-size:13.5px;line-height:1.5;color:var(--text-2)}
|
|
197
|
+
.ob-proj-noscript{margin:12px 4px 0;font-size:13px;color:var(--text-3)}
|
|
198
|
+
.js .ob-proj-noscript{display:none}
|
|
199
|
+
.ob-proj-which{display:flex;align-items:flex-start;gap:10px;margin:18px 4px 0;font-size:13px;line-height:1.5;color:var(--text-3)}
|
|
200
|
+
.ob-proj-i{flex:none;width:16px;height:16px;margin-top:1px;border-radius:50%;border:1px solid var(--white-25);display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700}
|
|
201
|
+
.ob-proj-pick-view .ob-foot .pill[disabled]{opacity:.45;cursor:not-allowed}
|
|
202
|
+
.ob-switching{display:flex;flex-direction:column;align-items:center;text-align:center;padding:16vh 0 8vh}
|
|
203
|
+
.ob-spinner{width:44px;height:44px;border-radius:50%;background:var(--white-06);position:relative;margin-bottom:18px}
|
|
204
|
+
.ob-spinner::after{content:"";position:absolute;inset:12px;border-radius:50%;border:2px solid var(--coral);border-right-color:transparent;animation:obSpin .9s linear infinite}
|
|
205
|
+
@keyframes obSpin{to{transform:rotate(360deg)}}
|
|
206
|
+
.ob-switching-title{margin:0;font-size:30px;font-weight:650;letter-spacing:-.02em}
|
|
207
|
+
.ob-switching-text{margin:8px 0 0;font-size:15px;color:var(--text-2)}
|
|
208
|
+
@media (max-width:640px){.ob-proj-card{padding:16px}.js .ob-proj-go{grid-template-columns:1fr}.ob-proj-go .pill{width:100%}
|
|
209
|
+
.ob-switching-title{font-size:24px}}
|
|
210
|
+
`;
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { escapeHtml as e } from '../../render/html-report-components.js';
|
|
2
|
+
import { inLanguages, labelAttributes } from '../../render/report-copy.js';
|
|
3
|
+
import { pill, textButton, trashButton } from '../../render/ui/button.js';
|
|
4
|
+
import { initial } from '../../render/ui/app-sidebar.js';
|
|
5
|
+
import { MODE_SVG } from '../../render/ui/mode-icon.js';
|
|
6
|
+
import { opener } from '../../render/ui/popup.js';
|
|
7
|
+
import { tag } from '../../render/ui/tag.js';
|
|
8
|
+
import { patternKind, patternShort } from '../settings/files-tab.js';
|
|
9
|
+
import { rowKey } from './onboarding-view.js';
|
|
10
|
+
/**
|
|
11
|
+
* Steps 2-3 (`.ai/specs/2026-09-24-onboarding.md` W10-W12a; step 1 is the project, `project-step.ts`). Each starts from what is in force (W10), and nothing on
|
|
12
|
+
* them writes: the page's script keeps the choices until Finish, and each file says what its choice does (W14). Step 3
|
|
13
|
+
* is not drawn (2026-09-25, the maintainer): its choices stay what is in force. With no script the steps are sections
|
|
14
|
+
* in order, showing what is in force, and their buttons are not drawn (W27).
|
|
15
|
+
*/
|
|
16
|
+
/** The window the kit's add popup is given, on this page (W12). */
|
|
17
|
+
export const ADD_WINDOW = 'ob-add';
|
|
18
|
+
const NEXT = { who: 'files', files: 'finish' };
|
|
19
|
+
// which-project V19: the project step comes before *Who*.
|
|
20
|
+
const BACK = { who: 'project', files: 'who' };
|
|
21
|
+
const SOURCE_TONE = { agentwhy: 'grey', project: 'amber', you: 'mint' };
|
|
22
|
+
/** Steps 2 and 3, for the project the run is in: `name` is its folder's, said above each step's number (V22). */
|
|
23
|
+
export function stepScreens(view, name) {
|
|
24
|
+
return step('who', 2, whoBody(view), name) + step('files', 3, filesBody(view), name);
|
|
25
|
+
}
|
|
26
|
+
function step(name, number, body, project) {
|
|
27
|
+
const last = name === 'files';
|
|
28
|
+
const next = NEXT[name] === 'finish' ? ' data-ob-finish' : ' data-ob-go="' + NEXT[name] + '"';
|
|
29
|
+
const foot = '<div class="ob-foot js-only">' +
|
|
30
|
+
pill({ label: inLanguages((t) => t('ob.back')), tone: 'outline', size: 'lg', button: true, attributes: ' data-ob-go="' + BACK[name] + '"' }) +
|
|
31
|
+
'<span class="ob-foot-end">' + textButton(inLanguages((t) => t('ob.skip')), next, 'ob-skip') +
|
|
32
|
+
// Continue and Finish are white in the whole onboarding (the maintainer, 2026-09-29): coral read as a warning here.
|
|
33
|
+
pill({ label: inLanguages((t) => t(last ? 'ob.finish' : 'ob.continue')), tone: 'light', size: 'lg', button: true, attributes: next }) +
|
|
34
|
+
'</span></div>';
|
|
35
|
+
return '<section class="ob-screen ob-step ob-step-' + name + '" data-ob-screen="' + name + '" aria-labelledby="ob-' + name + '-title">' +
|
|
36
|
+
'<p class="ob-for"><span class="ob-for-mark" aria-hidden="true">' + e(initial(project)) + '</span>' +
|
|
37
|
+
inLanguages((t) => t('ob.for', { name: '<strong>' + e(project) + '</strong>' })) + '</p>' +
|
|
38
|
+
'<p class="ob-step-no">' + inLanguages((t) => t('ob.step', { n: number })) + '</p>' +
|
|
39
|
+
'<h2 class="ob-h2" id="ob-' + name + '-title">' + inLanguages((t) => t('ob.' + name + '.title')) + '</h2>' +
|
|
40
|
+
// W12a: step 3's lead is Settings' own, so Block and Tell me are said one way on both pages.
|
|
41
|
+
'<p class="ob-step-text">' + inLanguages((t) => t(name === 'files' ? 'set.files.lead' : 'ob.' + name + '.text', { name: '<strong>' + e(project) + '</strong>' })) + '</p>' +
|
|
42
|
+
body +
|
|
43
|
+
'<div class="ob-hint"><span class="ob-hint-mark" aria-hidden="true">✦</span><span>' + inLanguages((t) => t('ob.' + name + '.hint')) + '</span></div>' +
|
|
44
|
+
// On the last step Finish stays at the bottom of the window, so it is never scrolled to.
|
|
45
|
+
(last ? '<div class="ob-dock">' + foot + '<p class="ob-say" data-ob-say hidden></p></div>' : foot) +
|
|
46
|
+
'</section>';
|
|
47
|
+
}
|
|
48
|
+
/** W11: two radio cards; the chosen one mint (the maintainer, 2026-09-29: as the project chosen in step 1). */
|
|
49
|
+
function whoBody(view) {
|
|
50
|
+
const card = (value, avatars, recommended) => {
|
|
51
|
+
const on = view.who === value;
|
|
52
|
+
return '<button type="button" class="ob-who-card' + (on ? ' ob-who-on' : '') + '" role="radio" aria-checked="' + String(on) + '" data-ob-who="' + value + '">' +
|
|
53
|
+
'<span class="ob-who-top"><span class="ob-avatars" aria-hidden="true">' + avatars + '</span>' +
|
|
54
|
+
'<span class="ob-radio" aria-hidden="true"><span class="ob-radio-dot"></span></span></span>' +
|
|
55
|
+
'<span class="ob-who-name">' + inLanguages((t) => t('ob.who.' + value)) + '</span>' +
|
|
56
|
+
'<span class="ob-who-sub">' + inLanguages((t) => t('ob.who.' + value + '.sub')) + '</span>' +
|
|
57
|
+
(recommended ? tag(inLanguages((t) => t('ob.recommended')), 'mint', 'badge') : '') + '</button>';
|
|
58
|
+
};
|
|
59
|
+
const you = '<span class="ob-avatar">' + inLanguages((t) => t('ob.who.you')) + '</span>';
|
|
60
|
+
return '<div class="ob-who" role="radiogroup" aria-labelledby="ob-who-title">' +
|
|
61
|
+
card('local', you, true) +
|
|
62
|
+
card('shared', you + '<span class="ob-avatar ob-avatar-coral">A</span><span class="ob-avatar ob-avatar-mint">M</span>', false) +
|
|
63
|
+
'</div>';
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* W12, W12a: Settings' list, drawn as Settings draws it (asked for 2026-09-25) - the mode's mark, a human name with the
|
|
67
|
+
* file as a chip under it, **Block | Tell me** at the mode in force, where the rule came from, and a bin on a name
|
|
68
|
+
* added here - under the same column heads. The switch writes nothing: the page keeps the choice until Finish, which
|
|
69
|
+
* writes it as Settings' own switch does.
|
|
70
|
+
*/
|
|
71
|
+
function filesBody(view) {
|
|
72
|
+
const alertsOff = !view.messages.alerts.on;
|
|
73
|
+
const rows = view.files.rows.map((row) => ruleRow(row, view.files.canTell, view.files.canAdd, alertsOff)).join('');
|
|
74
|
+
const kinds = ['file', 'folder', 'pattern'].map((kind) => '<span data-ob-kind="' + kind + '"' + (kind === 'file' ? '' : ' hidden') + '>' + inLanguages((t) => t('set.rule.own.' + kind)) + '</span>').join('');
|
|
75
|
+
// An added name's tip: what Block stops, said for a file, a folder or a pattern, and Tell me in Settings' words. The
|
|
76
|
+
// name is filled in as text by the script, as the row's own chip is.
|
|
77
|
+
const said = (kind) => '<span data-ob-kind="' + kind + '"' + (kind === 'file' ? '' : ' hidden') + '>' +
|
|
78
|
+
inLanguages((t) => t('ob.change.' + kind, { name: '<code class="ob-code" data-ob-name></code>' })) + '</span>';
|
|
79
|
+
const addedTip = infoTip(said('file') + said('folder') + said('pattern'), inLanguages((t) => t('set.confirm.tell.text', { name: '<code class="ob-code" data-ob-name></code>' })), alertsOff);
|
|
80
|
+
const added = '<template data-ob-added-row><li class="ob-rule ob-rule-is-block ob-rule-new" data-ob-added>' + modeIcon() +
|
|
81
|
+
'<span class="ob-rule-text"><span class="ob-rule-name">' + kinds + addedTip + '</span><span class="chip ob-rule-chip" data-ob-name></span></span>' +
|
|
82
|
+
'<span class="ob-rule-mode">' + modeSwitch('block', view.files.canTell) + '</span>' +
|
|
83
|
+
'<span class="ob-rule-src">' + tag(inLanguages((t) => t('set.src.short.you')), SOURCE_TONE.you) + '</span>' +
|
|
84
|
+
'<span class="ob-rule-act">' + trashButton(labelAttributes((t) => e(t('set.remove'))) + ' data-ob-untick') + '</span>' +
|
|
85
|
+
'</li></template>';
|
|
86
|
+
return '<div class="ob-list">' +
|
|
87
|
+
'<div class="ob-rules-head" aria-hidden="true"><span class="ob-rules-head-file">' + inLanguages((t) => t('set.col.file')) + '</span>' +
|
|
88
|
+
'<span>' + inLanguages((t) => t('set.mode.label')) + '</span><span>' + inLanguages((t) => t('set.col.src')) + '</span>' +
|
|
89
|
+
'<span class="ob-rules-head-act">' + inLanguages((t) => t('set.col.act')) + '</span></div>' +
|
|
90
|
+
'<ul class="ob-rules" data-ob-files>' + rows + '</ul>' + added +
|
|
91
|
+
(view.files.canAdd
|
|
92
|
+
? '<div class="ob-add js-only">' + pill({
|
|
93
|
+
label: '<span class="ob-plus" aria-hidden="true">+</span>' + inLanguages((t) => t('ob.files.add')),
|
|
94
|
+
tone: 'light',
|
|
95
|
+
size: 'lg',
|
|
96
|
+
button: true,
|
|
97
|
+
attributes: opener(ADD_WINDOW),
|
|
98
|
+
}) + '</div>'
|
|
99
|
+
: '') +
|
|
100
|
+
'</div>';
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* One of Settings' rows, as Settings draws it; the switch where Settings offers one, drawn and still where it does not.
|
|
104
|
+
* A group not watched yet is drawn on Block where Finish can write it (KD2): it is what Finish makes it. Where it
|
|
105
|
+
* cannot, it says it is not watched, and has no tip - nothing it could do is chosen here.
|
|
106
|
+
*/
|
|
107
|
+
function ruleRow(row, canTell, canAdd, alertsOff) {
|
|
108
|
+
const pattern = row.patterns[0] ?? '';
|
|
109
|
+
const name = row.name === undefined ? inLanguages((t) => t('set.rule.own.' + patternKind(pattern))) : inLanguages((t) => t('set.rule.' + row.name));
|
|
110
|
+
// KD2: a row not watched starts on Block, which Finish writes where it can add; Tell me puts it on the told list instead.
|
|
111
|
+
const drawn = row.watched || canAdd;
|
|
112
|
+
// W14, as amended: what the row's choice does, beside its name - Block's words or Tell me's, as the switch stands.
|
|
113
|
+
const named = (t) => (row.name === undefined ? '<code class="ob-code">' + e(patternShort(pattern)) + '</code>' : '<strong>' + t('set.rule.' + row.name) + '</strong>');
|
|
114
|
+
const tip = drawn
|
|
115
|
+
? infoTip(inLanguages((t) => t('set.confirm.block.text', { name: named(t) })), inLanguages((t) => t(row.name === undefined ? 'set.confirm.tell.text' : 'set.confirm.tell.secret.text', { name: named(t) })), alertsOff)
|
|
116
|
+
: '';
|
|
117
|
+
const mode = drawn ? modeSwitch(row.mode, canTell && (row.watched ? row.switchTo !== undefined : true)) : tag(inLanguages((t) => t('set.rule.notWatched')), 'grey', 'badge');
|
|
118
|
+
// The key the page and the server find this row by (W12a); the switch writes nothing until Finish.
|
|
119
|
+
return '<li class="ob-rule' + (drawn ? ' ob-rule-is-' + row.mode : ' ob-rule-off') + '" data-ob-row="' + e(rowKey(row)) + '" data-ob-secret="' + String(row.name !== undefined) + '">' +
|
|
120
|
+
(drawn ? modeIcon() : '<span class="ob-icon" aria-hidden="true"></span>') +
|
|
121
|
+
'<span class="ob-rule-text"><span class="ob-rule-name" data-ob-row-name>' + name + tip + '</span>' +
|
|
122
|
+
'<span class="chip ob-rule-chip" title="' + e(pattern) + '">' + e(patternShort(pattern)) + '</span></span>' +
|
|
123
|
+
'<span class="ob-rule-mode">' + mode + '</span>' +
|
|
124
|
+
'<span class="ob-rule-src">' + tag(inLanguages((t) => t('set.src.short.' + row.source)), SOURCE_TONE[row.source]) + '</span>' +
|
|
125
|
+
'<span class="ob-rule-act"><span class="ob-none" aria-hidden="true">—</span></span>' +
|
|
126
|
+
'</li>';
|
|
127
|
+
}
|
|
128
|
+
/** The padlock and the bell, both drawn; the row's mode shows one, so a switch moves it without a script writing markup. */
|
|
129
|
+
function modeIcon() {
|
|
130
|
+
return '<span class="ob-icon" aria-hidden="true"><span class="ob-icon-block">' + MODE_SVG.block + '</span><span class="ob-icon-tell">' + MODE_SVG.tell + '</span></span>';
|
|
131
|
+
}
|
|
132
|
+
/** F57's two-part switch, the mode in force marked; drawn and still where Settings could not switch this row either. */
|
|
133
|
+
function modeSwitch(mode, switchable) {
|
|
134
|
+
const half = (which) => {
|
|
135
|
+
const words = inLanguages((t) => t('set.mode.' + which));
|
|
136
|
+
const on = which === mode;
|
|
137
|
+
return switchable
|
|
138
|
+
? '<button type="button" class="ob-mode-half' + (on ? ' ob-mode-on' : '') + '" aria-pressed="' + String(on) + '" data-ob-mode="' + which + '">' + words + '</button>'
|
|
139
|
+
: '<span class="ob-mode-half' + (on ? ' ob-mode-on' : ' ob-mode-off') + '">' + words + '</span>';
|
|
140
|
+
};
|
|
141
|
+
return '<span class="ob-mode ob-mode-is-' + mode + '" role="group"' + labelAttributes((t) => e(t('set.mode.label'))) + '>' + half('block') + half('tell') + '</span>';
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* W14, as amended 2026-09-25 by the maintainer: no list above Finish. A quiet "i" beside the file's name says what its
|
|
145
|
+
* choice does, on hover or focus: Block's sentence with the guidelines' honesty line (§9.2), or Tell me's, cost
|
|
146
|
+
* included. Both are drawn and the row's mode shows one, so the switch changes it without a script writing markup.
|
|
147
|
+
*/
|
|
148
|
+
function infoTip(block, tell, alertsOff) {
|
|
149
|
+
return '<span class="ob-info" tabindex="0"' + labelAttributes((t) => e(t('ob.files.info'))) + '>' +
|
|
150
|
+
'<span class="ob-info-mark" aria-hidden="true">i</span>' +
|
|
151
|
+
'<span class="ob-tip" role="tooltip">' +
|
|
152
|
+
'<span class="ob-tip-block">' + block + '<span class="ob-tip-quiet">' + inLanguages((t) => t('ob.change.honest')) + '</span></span>' +
|
|
153
|
+
'<span class="ob-tip-tell">' + tell + (alertsOff ? '<span class="ob-tip-quiet">' + inLanguages((t) => t('set.confirm.tell.alertsOff')) + '</span>' : '') + '</span>' +
|
|
154
|
+
'</span></span>';
|
|
155
|
+
}
|
|
156
|
+
/** The steps' own look; the list is Settings' (its columns, marks and switch). Colours come from the tokens only. */
|
|
157
|
+
export const STEPS_STYLE = String.raw `
|
|
158
|
+
.ob-step{max-width:640px;margin:0 auto}
|
|
159
|
+
.ob-step-files{max-width:780px}
|
|
160
|
+
.ob-for{display:flex;align-items:center;gap:8px;margin:0 0 8px;font-size:13.5px;color:var(--text-3);overflow-wrap:anywhere}
|
|
161
|
+
.ob-for strong{color:var(--text);font-weight:600}
|
|
162
|
+
.ob-for-mark{flex:none;width:20px;height:20px;border-radius:6px;background:var(--white-08);border:1px solid var(--white-10);color:var(--text);font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center}
|
|
163
|
+
.ob-step-no{margin:0 0 10px;font-size:14px;font-weight:600;color:var(--coral-text)}
|
|
164
|
+
.ob-h2{margin:0 0 10px;font-size:34px;line-height:1.15;letter-spacing:-.02em;font-weight:650;text-wrap:balance}
|
|
165
|
+
.ob-step-text{margin:0 0 26px;font-size:16.5px;line-height:1.55;color:var(--text-2);text-wrap:pretty}
|
|
166
|
+
.ob-step-text strong{color:var(--text);font-weight:600}
|
|
167
|
+
.ob-who{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px}
|
|
168
|
+
.ob-who-card{display:flex;flex-direction:column;align-items:flex-start;gap:12px;padding:22px;border-radius:16px;background:var(--card);border:1.5px solid var(--white-10);color:inherit;font:inherit;text-align:left;cursor:pointer;transition:border-color .2s,background .2s}
|
|
169
|
+
.ob-who-card:hover{border-color:var(--white-30)}
|
|
170
|
+
.ob-who-on,.ob-who-on:hover{background:var(--mint-05);border-color:var(--mint-50)}
|
|
171
|
+
.ob-who-top{display:flex;justify-content:space-between;align-items:center;width:100%}
|
|
172
|
+
.ob-avatars{display:flex}
|
|
173
|
+
.ob-avatar{width:34px;height:34px;margin-right:-8px;border-radius:50%;background:var(--avatar);border:2px solid var(--card);color:var(--text);font-size:12px;font-weight:700;display:flex;align-items:center;justify-content:center}
|
|
174
|
+
.ob-avatar-coral{background:var(--coral-18);color:var(--coral-text)}
|
|
175
|
+
.ob-avatar-mint{background:var(--mint-16);color:var(--mint)}
|
|
176
|
+
.ob-radio{width:22px;height:22px;border-radius:50%;border:1.5px solid var(--white-30);display:flex;align-items:center;justify-content:center;transition:border-color .2s}
|
|
177
|
+
.ob-radio-dot{width:11px;height:11px;border-radius:50%;transform:scale(0);transition:transform .2s cubic-bezier(.2,.9,.3,1.3),background .2s}
|
|
178
|
+
.ob-who-on .ob-radio{border-color:var(--mint)}.ob-who-on .ob-radio-dot{background:var(--mint);transform:scale(1)}
|
|
179
|
+
.ob-who-name{font-size:18px;font-weight:650}
|
|
180
|
+
.ob-who-sub{font-size:14.5px;line-height:1.5;color:var(--text-2)}
|
|
181
|
+
.ob-list{--ob-cols:36px minmax(0,1fr) auto 104px 40px;border-radius:16px;background:var(--card);border:1px solid var(--white-09)}
|
|
182
|
+
.ob-rules-head{border-radius:16px 16px 0 0;display:grid;grid-template-columns:var(--ob-cols);column-gap:14px;padding:12px 22px;background:var(--panel);font-size:12.5px;font-weight:600;color:var(--text-3)}
|
|
183
|
+
.ob-rules-head-file{grid-column:1 / 3}
|
|
184
|
+
.ob-rules{list-style:none;margin:0;padding:0}
|
|
185
|
+
.ob-rule{display:grid;grid-template-columns:var(--ob-cols);column-gap:14px;align-items:center;padding:14px 22px;border-top:1px solid var(--white-06)}
|
|
186
|
+
.ob-rule-new{animation:obUp .35s cubic-bezier(.2,.8,.2,1) both}
|
|
187
|
+
.ob-rule-gone{animation:obGone .2s ease-in both}
|
|
188
|
+
@keyframes obGone{to{opacity:0;transform:translateX(12px)}}
|
|
189
|
+
.ob-rule-mode,.ob-rule-src,.ob-rule-act{display:flex;align-items:center;min-width:0}
|
|
190
|
+
.ob-icon{flex:none;width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;transition:background .2s,color .2s}
|
|
191
|
+
.ob-icon svg{width:18px;height:18px}
|
|
192
|
+
.ob-icon-block,.ob-icon-tell{display:none}
|
|
193
|
+
.ob-rule-is-block .ob-icon{background:var(--mint-14);color:var(--mint)}.ob-rule-is-block .ob-icon-block{display:flex}
|
|
194
|
+
.ob-rule-is-tell .ob-icon{background:var(--sand-16);color:var(--sand)}.ob-rule-is-tell .ob-icon-tell{display:flex}
|
|
195
|
+
.ob-rule-off .ob-icon{border:1.5px dashed var(--white-25)}
|
|
196
|
+
.ob-rule-text{display:flex;flex-direction:column;align-items:flex-start;gap:5px;min-width:0}
|
|
197
|
+
.ob-rule-name{position:relative;display:block;font-size:16px;font-weight:600;line-height:1.3}
|
|
198
|
+
.ob-info{display:inline-flex;margin-left:7px;vertical-align:-2px;border-radius:50%;outline:none}
|
|
199
|
+
.ob-info-mark{width:16px;height:16px;border-radius:50%;border:1px solid var(--white-25);color:var(--text-3);font-size:10.5px;font-weight:700;display:flex;align-items:center;justify-content:center;cursor:help;transition:color .15s,border-color .15s}
|
|
200
|
+
.ob-info:hover .ob-info-mark,.ob-info:focus-visible .ob-info-mark{color:var(--text);border-color:var(--white-45)}
|
|
201
|
+
.ob-info:focus-visible{box-shadow:0 0 0 2px var(--coral-60)}
|
|
202
|
+
.ob-tip{position:absolute;left:0;bottom:calc(100% + 10px);z-index:6;width:max-content;max-width:min(320px,calc(100vw - 110px));padding:12px 14px;border-radius:12px;background:var(--popup);border:1px solid var(--white-14);box-shadow:0 14px 36px var(--shadow);font-size:13.5px;font-weight:400;line-height:1.5;color:var(--text);white-space:normal;visibility:hidden;opacity:0;transform:translateY(4px);transition:opacity .15s,transform .15s,visibility .15s}
|
|
203
|
+
.ob-info:hover .ob-tip,.ob-info:focus .ob-tip{visibility:visible;opacity:1;transform:none}
|
|
204
|
+
.ob-tip-block,.ob-tip-tell{display:none;flex-direction:column;gap:6px}
|
|
205
|
+
.ob-rule-is-block .ob-tip-block,.ob-rule-is-tell .ob-tip-tell{display:flex}
|
|
206
|
+
.ob-tip-quiet{color:var(--text-2);font-size:12.5px}
|
|
207
|
+
.ob-rule-chip{font-size:12.5px}
|
|
208
|
+
.ob-none{color:var(--text-4)}
|
|
209
|
+
.ob-mode{flex:none;display:inline-flex;padding:3px;border-radius:999px;background:var(--bg);border:1px solid var(--white-08)}
|
|
210
|
+
.ob-mode-half{font:inherit;font-size:13.5px;font-weight:600;color:var(--text-2);background:transparent;border:0;border-radius:999px;padding:6px 13px;white-space:nowrap;transition:background .2s,color .2s}
|
|
211
|
+
button.ob-mode-half{cursor:pointer}button.ob-mode-half:not(.ob-mode-on):hover{color:var(--text);background:var(--white-06)}
|
|
212
|
+
.ob-mode-on{background:var(--white-10);color:var(--text)}
|
|
213
|
+
.ob-mode-is-block .ob-mode-on{background:var(--mint);color:var(--on-mint)}
|
|
214
|
+
.ob-mode-is-tell .ob-mode-on{background:var(--sand);color:var(--on-sand)}
|
|
215
|
+
.ob-mode-off{opacity:.45}
|
|
216
|
+
.ob-add{padding:18px 22px;border-top:1px solid var(--white-06);justify-content:center}
|
|
217
|
+
.js .ob-add{display:flex}
|
|
218
|
+
.ob-add .pill{gap:10px;padding:11px 22px}
|
|
219
|
+
.ob-plus{width:20px;height:20px;border-radius:50%;background:var(--bg);color:var(--text);display:inline-flex;align-items:center;justify-content:center;font-size:15px;line-height:1}
|
|
220
|
+
.ob-code{font-family:var(--mono);font-size:.92em;color:var(--text);background:var(--white-07);border:1px solid var(--white-10);border-radius:6px;padding:1px 7px;overflow-wrap:anywhere}
|
|
221
|
+
.ob-hint{display:flex;align-items:center;gap:12px;margin-top:18px;padding:12px 16px;border-radius:12px;background:var(--coral-05);border:1px solid var(--coral-25);font-size:14px;line-height:1.5;color:var(--text-soft)}
|
|
222
|
+
.ob-hint-mark{flex:none;width:26px;height:26px;border-radius:50%;background:var(--coral-14);color:var(--coral-text);display:flex;align-items:center;justify-content:center;font-size:12px}
|
|
223
|
+
.ob-dock{position:sticky;bottom:0;z-index:2;margin-top:18px;padding:0 0 18px;background:var(--bg);box-shadow:0 -18px 18px -6px var(--bg)}
|
|
224
|
+
.ob-dock .ob-foot{margin-top:14px}
|
|
225
|
+
.ob-foot{margin-top:28px;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}
|
|
226
|
+
.js .ob-foot{display:flex}
|
|
227
|
+
.ob-foot-end{display:flex;align-items:center;gap:14px;margin-left:auto}
|
|
228
|
+
.ob-skip{color:var(--text-3);font-size:15px}
|
|
229
|
+
.ob-skip:hover{color:var(--text)}
|
|
230
|
+
.ob-say{margin:14px 0 0;font-size:14px;line-height:1.5;color:var(--coral-text);text-align:right}
|
|
231
|
+
@media (max-width:640px){
|
|
232
|
+
.ob-h2{font-size:28px}
|
|
233
|
+
.ob-rules-head{display:none}.ob-rule:first-child{border-top:0}
|
|
234
|
+
.ob-rule{grid-template-columns:36px minmax(0,1fr) auto;grid-template-areas:"icon text act" ". mode src";row-gap:12px;column-gap:12px;padding:16px 18px}
|
|
235
|
+
.ob-rule>.ob-icon{grid-area:icon}.ob-rule-text{grid-area:text}.ob-rule-mode{grid-area:mode}.ob-rule-src{grid-area:src;justify-content:flex-end}.ob-rule-act{grid-area:act;justify-content:flex-end}
|
|
236
|
+
.ob-add{padding-left:18px;padding-right:18px}
|
|
237
|
+
.ob-none{display:none}
|
|
238
|
+
}
|
|
239
|
+
`;
|