@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,104 @@
|
|
|
1
|
+
import { escapeHtml as e } from '../../render/html-report-components.js';
|
|
2
|
+
import { inLanguages, labelAttributes } from '../../render/report-copy.js';
|
|
3
|
+
import { textButton } from '../../render/ui/button.js';
|
|
4
|
+
import { chatExample } from '../../render/ui/chat-example.js';
|
|
5
|
+
import { opener } from '../../render/ui/popup.js';
|
|
6
|
+
import { toggleSwitch } from '../../render/ui/switch.js';
|
|
7
|
+
import { tag } from '../../render/ui/tag.js';
|
|
8
|
+
import { hookWindowId } from './settings-windows.js';
|
|
9
|
+
/**
|
|
10
|
+
* Alerts (`for-people-who-build-with-ai.md` F29-F31): the incident first, in a card of its own with a bell, and the two
|
|
11
|
+
* optional moments hanging from it on a line, because they need it. Row 1, the default, is the `watch` hook, so its
|
|
12
|
+
* switch opens the confirmation (F40); rows 2 and 3 are optional notice choices for this project, written at once
|
|
13
|
+
* (R26a), and say nothing while row 1 is off, because without the hook nothing is said at all. Their switch then does
|
|
14
|
+
* not move, but it still answers a click - a greyed switch that does nothing reads as broken - with a bubble that says
|
|
15
|
+
* row 1 comes first and turns it on.
|
|
16
|
+
*/
|
|
17
|
+
export function alertsTab(view) {
|
|
18
|
+
const turnOn = view.canWrite ? opener(hookWindowId('watch', true)) : undefined;
|
|
19
|
+
const onOff = (on) => ({ key: on ? 'set.state.on' : 'set.state.off', on });
|
|
20
|
+
// Rows 2 and 3 work only through row 1: where its state is unknown, a line saying theirs would claim more than is known.
|
|
21
|
+
const optional = (on, locked) => (view.known ? onOff(!locked && on) : undefined);
|
|
22
|
+
return '<div class="set-head"><h2 class="set-h2">' + inLanguages((t) => t('set.alerts.title')) + '</h2>' +
|
|
23
|
+
'<p class="set-lead">' + inLanguages((t) => t('set.alerts.lead')) + '</p></div>' +
|
|
24
|
+
'<div class="set-msgs">' +
|
|
25
|
+
row({
|
|
26
|
+
tone: 'coral',
|
|
27
|
+
key: 'read',
|
|
28
|
+
main: true,
|
|
29
|
+
state: !view.known ? { key: 'set.state.unknown', on: false }
|
|
30
|
+
: view.alerts.on ? { key: view.alerts.who === 'shared' ? 'set.state.shared' : 'set.state.local', on: true } : onOff(false),
|
|
31
|
+
control: !view.known ? '' : toggleSwitch({
|
|
32
|
+
on: view.alerts.on,
|
|
33
|
+
disabled: !view.canWrite,
|
|
34
|
+
attributes: labelAttributes((t) => t('set.card.read.name')) + opener(hookWindowId('watch', !view.alerts.on)),
|
|
35
|
+
}),
|
|
36
|
+
}) +
|
|
37
|
+
'<div class="set-opt"><p class="set-opt-label">' + inLanguages((t) => t('set.alerts.optional')) + '</p>' +
|
|
38
|
+
row({
|
|
39
|
+
tone: 'mint',
|
|
40
|
+
key: 'stopped',
|
|
41
|
+
locked: view.stopped.locked,
|
|
42
|
+
state: optional(view.stopped.on, view.stopped.locked),
|
|
43
|
+
control: view.stopped.locked ? lockedSwitch('stopped', turnOn) : toggleSwitch({
|
|
44
|
+
on: view.stopped.on,
|
|
45
|
+
disabled: !view.noticesWritable,
|
|
46
|
+
attributes: labelAttributes((t) => t('set.card.stopped.name')) +
|
|
47
|
+
' data-set-notice="' + e(JSON.stringify({ on: view.stopped.on ? 'value' : 'refused' })) + '"',
|
|
48
|
+
}),
|
|
49
|
+
}) +
|
|
50
|
+
row({
|
|
51
|
+
tone: 'grey',
|
|
52
|
+
key: 'fine',
|
|
53
|
+
locked: view.fine.locked,
|
|
54
|
+
state: optional(view.fine.on, view.fine.locked),
|
|
55
|
+
control: view.fine.locked ? lockedSwitch('fine', turnOn) : toggleSwitch({
|
|
56
|
+
on: view.fine.on,
|
|
57
|
+
disabled: !view.noticesWritable,
|
|
58
|
+
attributes: labelAttributes((t) => t('set.card.fine.name')) +
|
|
59
|
+
' data-set-notice="' + e(JSON.stringify({ clean: view.fine.on ? 'off' : 'once' })) + '"',
|
|
60
|
+
}),
|
|
61
|
+
}) +
|
|
62
|
+
'</div></div>' +
|
|
63
|
+
(view.noticesWritable || !view.alerts.on ? '' : '<p class="set-quiet">' + inLanguages((t) => t('set.notices.unusable')) + '</p>');
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The switch of a row that needs row 1: off, marked `aria-disabled` rather than `disabled` so a click still reaches the
|
|
67
|
+
* page's script, which shows the bubble beside it. The bubble says why, and turns row 1 on where this page can write.
|
|
68
|
+
*/
|
|
69
|
+
function lockedSwitch(key, turnOn) {
|
|
70
|
+
const tip = 'set-need-' + key;
|
|
71
|
+
return '<div class="set-sw">' +
|
|
72
|
+
toggleSwitch({
|
|
73
|
+
on: false,
|
|
74
|
+
attributes: labelAttributes((t) => t('set.card.' + key + '.name')) + ' aria-disabled="true" aria-describedby="' + tip + '" data-set-needs-first',
|
|
75
|
+
}) +
|
|
76
|
+
'<div class="set-tip" id="' + tip + '" role="status" data-set-tip hidden>' +
|
|
77
|
+
'<span class="set-tip-text">' + inLanguages((t) => t('set.need')) + '</span>' +
|
|
78
|
+
(turnOn === undefined ? '' : textButton(inLanguages((t) => t('set.need.go')), turnOn, 'set-tip-go')) +
|
|
79
|
+
'</div></div>';
|
|
80
|
+
}
|
|
81
|
+
function stateLine(state) {
|
|
82
|
+
return '<div class="set-state' + (state.on ? ' set-state-on' : '') + '"><span class="set-dot" aria-hidden="true"></span>' +
|
|
83
|
+
inLanguages((t) => t(state.key)) + '</div>';
|
|
84
|
+
}
|
|
85
|
+
/** Drawn, not loaded (§7.5 constraint 1): the bell beside the alert that matters. */
|
|
86
|
+
const BELL = '<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
|
|
87
|
+
'<path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>';
|
|
88
|
+
function row(spec) {
|
|
89
|
+
const word = (part) => inLanguages((t) => t('set.card.' + spec.key + '.' + part));
|
|
90
|
+
const main = spec.main === true;
|
|
91
|
+
return '<article class="set-msg' + (main ? ' set-msg-main' : ' set-msg-opt') + (spec.state?.on === true ? ' set-msg-on' : '') +
|
|
92
|
+
(spec.locked === true ? ' set-msg-locked' : '') + '"' + (main ? ' data-set-first' : '') + '>' +
|
|
93
|
+
(main ? '<span class="set-msg-icon">' + BELL + '</span>' : '') +
|
|
94
|
+
'<div class="set-card-body">' +
|
|
95
|
+
'<div class="set-card-name"><h3 class="set-msg-name">' + word('name') + '</h3>' +
|
|
96
|
+
(main
|
|
97
|
+
? tag(inLanguages((t) => t('set.card.read.badge')), 'mint', 'badge')
|
|
98
|
+
: tag(inLanguages((t) => t('set.card.optional')), 'grey', 'badge')) + '</div>' +
|
|
99
|
+
'<p class="set-msg-why">' + word('when') + '</p>' +
|
|
100
|
+
chatExample({ tone: spec.tone, ai: inLanguages((t) => t('set.chat.ai')), answer: word('answer') }) +
|
|
101
|
+
(spec.state === undefined ? '' : stateLine(spec.state)) +
|
|
102
|
+
'<p class="set-say" data-set-say hidden></p>' +
|
|
103
|
+
'</div>' + spec.control + '</article>';
|
|
104
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { escapeHtml as e } from '../../render/html-report-components.js';
|
|
2
|
+
import { inLanguages, labelAttributes } from '../../render/report-copy.js';
|
|
3
|
+
import { pill, trashButton } from '../../render/ui/button.js';
|
|
4
|
+
import { callout } from '../../render/ui/callout.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 { ADD_WINDOW, CODEX_WINDOW, FINISH_WINDOW, modeWindowId, removeWindowId, rowWatchWindowId, untellWindowId, WATCH_WINDOW } from './settings-windows.js';
|
|
9
|
+
const SOURCE_TONE = { agentwhy: 'grey', project: 'amber', you: 'mint' };
|
|
10
|
+
/** A padlock left open: a row that says Block and is not blocked whole (`block-means-blocked` K7). Settings' alone. */
|
|
11
|
+
const OPEN_LOCK_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
|
|
12
|
+
'<rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V7.5a4 4 0 0 1 7.75-1.4"/></svg>';
|
|
13
|
+
/**
|
|
14
|
+
* Private files (F33-F38): what the hooks read, in words, with where each rule came from; the project's rules they do
|
|
15
|
+
* not read yet, above the list (F34); adding a file under it (F35); and, on each row and above the list, where a file
|
|
16
|
+
* that says Block is not blocked whole (`block-means-blocked` K7, K8): the rules stop Claude Code's file tools, and only
|
|
17
|
+
* `refuse` stops `cat .env` or a `grep -r` that prints it. Block is both, and a row with half of it says which is missing.
|
|
18
|
+
*/
|
|
19
|
+
export function filesTab(view, allowed) {
|
|
20
|
+
// K10: blocked is what is blocked whole; the rest are counted by the line above the list.
|
|
21
|
+
const blocked = view.rows.filter((row) => row.watched && row.mode === 'block' && row.kept === undefined).length;
|
|
22
|
+
const told = view.rows.filter((row) => row.watched && row.mode === 'tell').length;
|
|
23
|
+
return unreadCard(view) + finishCard(view) + codexCard(view) +
|
|
24
|
+
'<div class="set-head"><h2 class="set-h2">' + inLanguages((t) => t('set.files.title')) + '</h2>' +
|
|
25
|
+
'<p class="set-lead">' + inLanguages((t) => t('set.files.lead')) + '</p></div>' +
|
|
26
|
+
// What each half of the switch means, said once in a bubble of its own pointing at the list rather than on every row.
|
|
27
|
+
'<p class="set-legend">' + legend('block') + legend('tell') + '</p>' +
|
|
28
|
+
'<section class="set-list">' +
|
|
29
|
+
// One grid for the heads and every row (asked for 2026-09-24): the switch, the source and the action each keep a column
|
|
30
|
+
// of their own, so they line up whatever a row holds, and a row with no action keeps its empty cell.
|
|
31
|
+
'<div class="set-rules-head" aria-hidden="true"><span class="set-rules-head-file">' + inLanguages((t) => t('set.col.file')) + '</span>' +
|
|
32
|
+
'<span>' + inLanguages((t) => t('set.mode.label')) + '</span><span>' + inLanguages((t) => t('set.col.src')) + '</span>' +
|
|
33
|
+
'<span class="set-rules-head-act">' + inLanguages((t) => t('set.col.act')) + '</span></div>' +
|
|
34
|
+
'<ul class="set-rules">' + view.rows.map((row, at) => ruleRow(row, at, view)).join('') + '</ul>' +
|
|
35
|
+
(view.canAdd
|
|
36
|
+
? '<div class="set-list-add">' + pill({
|
|
37
|
+
label: '<span class="set-plus" aria-hidden="true">+</span>' + inLanguages((t) => t('set.add')),
|
|
38
|
+
tone: 'light',
|
|
39
|
+
size: 'lg',
|
|
40
|
+
href: '#' + ADD_WINDOW,
|
|
41
|
+
attributes: opener(ADD_WINDOW),
|
|
42
|
+
}) + '</div>'
|
|
43
|
+
: '') +
|
|
44
|
+
'<p class="set-list-foot"><span class="set-count set-count-block">' + inLanguages((t) => t('set.count.block', { n: blocked })) + '</span>' +
|
|
45
|
+
'<span class="set-count set-count-tell">' + inLanguages((t) => t('set.count.tell', { n: told })) + '</span>' +
|
|
46
|
+
(allowed === 0 ? '' : '<span class="set-list-exc">' + inLanguages((t) => t('set.exceptions', { n: allowed })) + '</span>') + '</p>' +
|
|
47
|
+
'</section>';
|
|
48
|
+
}
|
|
49
|
+
function legend(mode) {
|
|
50
|
+
return '<span class="set-legend-item"><span class="set-icon set-icon-sm set-icon-' + mode + '">' + MODE_SVG[mode] + '</span>' +
|
|
51
|
+
'<span><strong>' + inLanguages((t) => t('set.mode.' + mode)) + '</strong> — ' + inLanguages((t) => t('set.legend.' + mode)) + '</span></span>';
|
|
52
|
+
}
|
|
53
|
+
/** F34 - or, where the hooks read a file without some of the built-in patterns, the same card for those. */
|
|
54
|
+
function unreadCard(view) {
|
|
55
|
+
const missing = view.rows.some((row) => !row.watched);
|
|
56
|
+
if (view.unread.length === 0 && !missing)
|
|
57
|
+
return '';
|
|
58
|
+
const n = view.unread.length;
|
|
59
|
+
const action = view.canWrite
|
|
60
|
+
? pill({ label: inLanguages((t) => t('set.watch', { n: view.toWatch })), tone: 'primary', size: 'task', href: '#' + WATCH_WINDOW, attributes: opener(WATCH_WINDOW) })
|
|
61
|
+
: undefined;
|
|
62
|
+
return callout({
|
|
63
|
+
tone: 'coral',
|
|
64
|
+
body: inLanguages((t) => (n > 0 ? t('set.unread', { n }) : t('set.unwatched'))),
|
|
65
|
+
...(action === undefined ? {} : { action }),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* One row. A built-in group the hooks do not read yet (F34a) offers **Start watching** - on its button or anywhere on
|
|
70
|
+
* the row - which opens the confirmation for that group, the way "Watch them too" confirms them all.
|
|
71
|
+
*/
|
|
72
|
+
function ruleRow(row, at, view) {
|
|
73
|
+
const canWrite = view.canWrite;
|
|
74
|
+
const watchable = !row.watched && canWrite && row.name !== undefined;
|
|
75
|
+
const pattern = row.patterns[0] ?? '';
|
|
76
|
+
// A human name first, then the file as a chip under it (guidelines §1.2). The chip is the pattern shortened to what a
|
|
77
|
+
// person would recognise; the pattern itself is its tooltip.
|
|
78
|
+
const label = row.name === undefined ? inLanguages((t) => t('set.rule.own.' + patternKind(pattern))) : inLanguages((t) => t('set.rule.' + row.name));
|
|
79
|
+
const mode = row.watched ? modeSwitch(row, at)
|
|
80
|
+
: watchable
|
|
81
|
+
? pill({
|
|
82
|
+
label: inLanguages((t) => t('set.rule.watch')),
|
|
83
|
+
tone: 'primary',
|
|
84
|
+
size: 'sm',
|
|
85
|
+
href: '#' + rowWatchWindowId(at),
|
|
86
|
+
attributes: opener(rowWatchWindowId(at)),
|
|
87
|
+
})
|
|
88
|
+
: tag(inLanguages((t) => t('set.rule.notWatched')), 'coral', 'badge');
|
|
89
|
+
// The kit's bin, as the onboarding draws it on a name added there; a link to the confirmation, so it works without a script.
|
|
90
|
+
const remove = (id) => trashButton(labelAttributes((t) => e(t('set.remove'))) + opener(id), '#' + id);
|
|
91
|
+
const action = row.remove !== undefined && canWrite ? remove(removeWindowId(at))
|
|
92
|
+
: row.untell !== undefined ? remove(untellWindowId(at))
|
|
93
|
+
: '<span class="set-none" aria-hidden="true">—</span>';
|
|
94
|
+
const icon = !row.watched ? '' : row.kept !== undefined ? OPEN_LOCK_SVG : MODE_SVG[row.mode];
|
|
95
|
+
const iconClass = !row.watched ? '' : ' set-icon-' + (row.kept !== undefined ? 'gap' : row.mode);
|
|
96
|
+
return '<li class="set-rule' + (row.watched ? '' : ' set-rule-off') + (watchable ? ' set-rule-watchable' : '') + '"' + (watchable ? ' data-set-row' : '') + '>' +
|
|
97
|
+
'<span class="set-icon' + iconClass + '" aria-hidden="true">' + icon + '</span>' +
|
|
98
|
+
'<span class="set-rule-text"><span class="set-rule-name">' + label + '</span>' +
|
|
99
|
+
'<span class="chip set-rule-chip" title="' + e(pattern) + '">' + e(patternShort(pattern)) + '</span>' +
|
|
100
|
+
(row.kept === undefined ? '' : '<span class="set-rule-gap">' + inLanguages((t) => t('set.rule.gap.' + row.kept)) + '</span>') + '</span>' +
|
|
101
|
+
'<span class="set-rule-mode">' + mode + '</span>' +
|
|
102
|
+
'<span class="set-rule-src">' + tag(inLanguages((t) => t('set.src.short.' + row.source)), SOURCE_TONE[row.source]) + '</span>' +
|
|
103
|
+
'<span class="set-rule-act">' + action + '</span>' +
|
|
104
|
+
'</li>';
|
|
105
|
+
}
|
|
106
|
+
/** Whether a pattern names every file of a name, everything in a folder of a name, or whatever matches it. */
|
|
107
|
+
export function patternKind(pattern) {
|
|
108
|
+
if (/^\*\*\/[^*?/]+\/\*\*$/.test(pattern))
|
|
109
|
+
return 'folder';
|
|
110
|
+
return /^(?:\*\*\/|\.\/)?[^*?/]+$/.test(pattern) ? 'file' : 'pattern';
|
|
111
|
+
}
|
|
112
|
+
/** A pattern as a person reads it: `**\/secrets/**` is `secrets/`, `**\/.npmrc` is `.npmrc`; anything else as written. */
|
|
113
|
+
export function patternShort(pattern) {
|
|
114
|
+
const folder = /^\*\*\/(.+)\/\*\*$/.exec(pattern)?.[1];
|
|
115
|
+
if (folder !== undefined)
|
|
116
|
+
return folder + '/';
|
|
117
|
+
return /^(?:\*\*\/|\.\/)(.+)$/.exec(pattern)?.[1] ?? pattern;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* F57: Block | Tell me, the mode in force marked. The other half opens that row's confirmation, where the page can make
|
|
121
|
+
* the change; where it cannot - a rule written by hand, a list that could not be read - it is drawn, and does nothing.
|
|
122
|
+
*/
|
|
123
|
+
function modeSwitch(row, at) {
|
|
124
|
+
const half = (mode) => {
|
|
125
|
+
const words = inLanguages((t) => t('set.mode.' + mode));
|
|
126
|
+
if (row.mode === mode)
|
|
127
|
+
return '<span class="set-mode-half set-mode-on" aria-current="true">' + words + '</span>';
|
|
128
|
+
if (row.switchTo === undefined)
|
|
129
|
+
return '<span class="set-mode-half set-mode-off">' + words + '</span>';
|
|
130
|
+
return '<a class="set-mode-half" href="#' + modeWindowId(at) + '"' + opener(modeWindowId(at)) + '>' + words + '</a>';
|
|
131
|
+
};
|
|
132
|
+
return '<span class="set-mode set-mode-is-' + row.mode + '" role="group"' + labelAttributes((t) => t('set.mode.label')) + '>' + half('block') + half('tell') + '</span>';
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* K8: one coral line above the list, where a row that says Block is not blocked whole, with the one button that closes
|
|
136
|
+
* every gap at once - offered where the page can write, and where one write can close it (`unfinished`). Where `refuse`
|
|
137
|
+
* runs and reads other rules, `init` points it again only when it writes a rule (R4d): the line and the rows say so,
|
|
138
|
+
* and the developer details say which file each hook reads.
|
|
139
|
+
*/
|
|
140
|
+
function finishCard(view) {
|
|
141
|
+
const n = view.unfinished.rows;
|
|
142
|
+
if (!view.known || n === 0)
|
|
143
|
+
return '';
|
|
144
|
+
const fixable = view.canWrite && (view.unfinished.patterns.length > 0 || view.unfinished.refuse);
|
|
145
|
+
return callout({
|
|
146
|
+
tone: 'coral',
|
|
147
|
+
body: inLanguages((t) => t('set.finish.gap', { n })),
|
|
148
|
+
...(fixable ? { action: pill({ label: inLanguages((t) => t('set.finish.go')), tone: 'primary', size: 'task', href: '#' + FINISH_WINDOW, attributes: opener(FINISH_WINDOW) }) } : {}),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* `codex-blocks-too` CK8: in a project that uses Codex, whether the files blocked here are kept from Codex too. Where
|
|
153
|
+
* agentwhy's hook is written, a grey line says it holds once approved in Codex, which nothing here can see (CKB9). Where
|
|
154
|
+
* it is not and Claude Code's block runs, a coral line with the one write that adds it; where Claude Code's does not
|
|
155
|
+
* run either, Finish blocking above writes both, and this says nothing.
|
|
156
|
+
*/
|
|
157
|
+
function codexCard(view) {
|
|
158
|
+
if (!view.known || view.codex === undefined)
|
|
159
|
+
return '';
|
|
160
|
+
if (view.codex === 'on')
|
|
161
|
+
return callout({ tone: 'grey', body: inLanguages((t) => t('set.codex.on')) });
|
|
162
|
+
if (!view.stop.on)
|
|
163
|
+
return '';
|
|
164
|
+
return callout({
|
|
165
|
+
tone: 'coral',
|
|
166
|
+
body: inLanguages((t) => t('set.codex.off')),
|
|
167
|
+
...(view.canWrite ? { action: pill({ label: inLanguages((t) => t('set.codex.go')), tone: 'primary', size: 'task', href: '#' + CODEX_WINDOW, attributes: opener(CODEX_WINDOW) }) } : {}),
|
|
168
|
+
});
|
|
169
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { inLanguages } from '../../render/report-copy.js';
|
|
2
|
+
import { avatar } from '../../render/ui/avatar.js';
|
|
3
|
+
import { BRAND_MARK } from '../../render/ui/brand-mark.js';
|
|
4
|
+
import { pill, TRASH_SVG } from '../../render/ui/button.js';
|
|
5
|
+
import { callout } from '../../render/ui/callout.js';
|
|
6
|
+
import { opener } from '../../render/ui/popup.js';
|
|
7
|
+
import { tag } from '../../render/ui/tag.js';
|
|
8
|
+
import { scopeWindowId, UNINSTALL_WINDOW } from './settings-windows.js';
|
|
9
|
+
/**
|
|
10
|
+
* General (`for-people-who-build-with-ai.md` F56, asked for 2026-09-24; redrawn 2026-09-25): who what agentwhy saved in
|
|
11
|
+
* the project is for, asked once here rather than in every window that writes. Two cards, each with a ring, the one in
|
|
12
|
+
* force filled and tagged; the other card is itself the way to it, through a confirmation that moves everything
|
|
13
|
+
* agentwhy wrote (F40). Where the project holds some of each, the page says so first, and either card makes it one.
|
|
14
|
+
* Under them, which AI agentwhy sees (`which-project.md` V5), and **Uninstall** (F59), where there is anything of
|
|
15
|
+
* agentwhy's to take out.
|
|
16
|
+
*/
|
|
17
|
+
export function generalTab(view, welcome) {
|
|
18
|
+
const cards = ['local', 'shared'].map((file) => scopeCard(view, file)).join('');
|
|
19
|
+
return '<section class="set-box set-who"><div class="set-head"><h2 class="set-h2">' + inLanguages((t) => t('set.general.title')) + '</h2>' +
|
|
20
|
+
'<p class="set-lead">' + inLanguages((t) => t('set.general.lead')) + '</p></div>' +
|
|
21
|
+
(view.scope === 'mixed' ? callout({ tone: 'coral', body: inLanguages((t) => t('set.general.mixed')) }) : '') +
|
|
22
|
+
'<div class="set-scopes">' + cards + '</div>' +
|
|
23
|
+
(view.known && view.scope === undefined ? '<p class="set-quiet set-general-note">' + inLanguages((t) => t('set.general.none')) + '</p>' : '') +
|
|
24
|
+
'<p class="set-quiet set-general-note"><span class="set-info" aria-hidden="true">i</span><span>' + inLanguages((t) => t('set.general.note')) + '</span></p>' +
|
|
25
|
+
// which-project V5: which AI agentwhy sees, in the words the project step and the list of projects say it.
|
|
26
|
+
'<p class="set-quiet set-general-note"><span class="set-info" aria-hidden="true">i</span><span>' + inLanguages((t) => t('proj.which')) + '</span></p>' +
|
|
27
|
+
'</section>' +
|
|
28
|
+
setupCard(welcome) +
|
|
29
|
+
uninstallCard(view);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* W25a: the onboarding again, where this run serves it - drawn as Uninstall is (a mark, one sentence, the button), and
|
|
33
|
+
* above it: going through the setup again comes before taking it all out. Nothing is written until its Finish (W10).
|
|
34
|
+
*/
|
|
35
|
+
function setupCard(welcome) {
|
|
36
|
+
if (welcome === undefined)
|
|
37
|
+
return '';
|
|
38
|
+
return '<section class="set-box set-again"><span class="set-again-icon" aria-hidden="true">' + BRAND_MARK + '</span>' +
|
|
39
|
+
'<div class="set-card-body"><h2 class="set-h3">' + inLanguages((t) => t('ob.again.title')) + '</h2>' +
|
|
40
|
+
'<p class="set-uninstall-text">' + inLanguages((t) => t('ob.again.text')) + '</p></div>' +
|
|
41
|
+
pill({ label: inLanguages((t) => t('ob.again.go')), tone: 'outline', size: 'lg', href: welcome }) +
|
|
42
|
+
'</section>';
|
|
43
|
+
}
|
|
44
|
+
function scopeCard(view, file) {
|
|
45
|
+
// Nothing saved yet is "just me" in force: it is where the next thing turned on goes.
|
|
46
|
+
const current = view.known && (view.scope === file || (view.scope === undefined && file === 'local'));
|
|
47
|
+
const move = view.moves[file];
|
|
48
|
+
const canSwitch = view.canWrite && !current && (move.patterns.length > 0 || move.hooks.length > 0);
|
|
49
|
+
const body = '<span class="set-scope-top">' + who(file) + '<span class="set-scope-ring" aria-hidden="true"></span></span>' +
|
|
50
|
+
'<span class="set-card-name"><span class="set-scope-name">' + inLanguages((t) => t('set.general.' + file)) + '</span>' +
|
|
51
|
+
(current ? tag(inLanguages((t) => t('set.general.current')), 'mint', 'badge') : '') + '</span>' +
|
|
52
|
+
'<span class="set-scope-sub">' + inLanguages((t) => t('set.general.' + file + '.sub')) + '</span>';
|
|
53
|
+
if (canSwitch)
|
|
54
|
+
return '<a class="set-scope" href="#' + scopeWindowId(file) + '"' + opener(scopeWindowId(file)) + '>' + body + '</a>';
|
|
55
|
+
return '<div class="set-scope' + (current ? ' set-scope-on' : '') + '"' + (current ? ' aria-current="true"' : '') + '>' + body + '</div>';
|
|
56
|
+
}
|
|
57
|
+
/** Who a card is for, drawn: you alone, or you and two others - initials of nobody, only a picture of "everyone". */
|
|
58
|
+
function who(file) {
|
|
59
|
+
const you = '<span class="av av-grey av-40" aria-hidden="true">' + inLanguages((t) => t('set.general.you')) + '</span>';
|
|
60
|
+
return '<span class="set-scope-who">' + you + (file === 'shared' ? avatar('A', 'coral', 40) + avatar('M', 'mint', 40) : '') + '</span>';
|
|
61
|
+
}
|
|
62
|
+
/** F59: what agentwhy put into the project, taken out behind one coral confirmation. Nothing to take out, no card. */
|
|
63
|
+
function uninstallCard(view) {
|
|
64
|
+
if (!view.canWrite || Object.keys(view.uninstall).length === 0)
|
|
65
|
+
return '';
|
|
66
|
+
return '<section class="set-box set-uninstall"><span class="set-uninstall-icon" aria-hidden="true">' + TRASH_SVG + '</span>' +
|
|
67
|
+
'<div class="set-card-body"><h2 class="set-h3">' + inLanguages((t) => t('set.uninstall.title')) + '</h2>' +
|
|
68
|
+
'<p class="set-uninstall-text">' + inLanguages((t) => t('set.uninstall.text')) + '</p></div>' +
|
|
69
|
+
pill({ label: inLanguages((t) => t('set.uninstall.go')), tone: 'outline-coral', size: 'lg', href: '#' + UNINSTALL_WINDOW, attributes: opener(UNINSTALL_WINDOW) }) +
|
|
70
|
+
'</section>';
|
|
71
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
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 { inLanguages, LANGS, translator } from '../../render/report-copy.js';
|
|
4
|
+
import { ADD_FILE_POPUP_SCRIPT, ADD_FILE_POPUP_STYLE } from '../../render/ui/add-file-popup.js';
|
|
5
|
+
import { appSidebar, APP_SIDEBAR_STYLE } from '../../render/ui/app-sidebar.js';
|
|
6
|
+
import { AVATAR_STYLE } from '../../render/ui/avatar.js';
|
|
7
|
+
import { askCard, writtenAnswer, ASK_PANEL_SCRIPT, ASK_PANEL_STYLE } from '../../render/ui/ask-panel.js';
|
|
8
|
+
import { BUTTON_STYLE } from '../../render/ui/button.js';
|
|
9
|
+
import { CALLOUT_STYLE } from '../../render/ui/callout.js';
|
|
10
|
+
import { CHAT_EXAMPLE_STYLE } from '../../render/ui/chat-example.js';
|
|
11
|
+
import { CONFIRM_DIALOG_STYLE } from '../../render/ui/confirm-dialog.js';
|
|
12
|
+
import { FILE_CHIP_STYLE } from '../../render/ui/file-chip.js';
|
|
13
|
+
import { hero, HERO_STYLE } from '../../render/ui/hero.js';
|
|
14
|
+
import { pageShell } from '../../render/ui/page-shell.js';
|
|
15
|
+
import { pillTabs, PILL_TABS_SCRIPT, PILL_TABS_STYLE } from '../../render/ui/pill-tabs.js';
|
|
16
|
+
import { POPUP_SCRIPT, POPUP_STYLE } from '../../render/ui/popup.js';
|
|
17
|
+
import { SCOPE_CHOICE_STYLE } from '../../render/ui/scope-choice.js';
|
|
18
|
+
import { SWITCH_STYLE } from '../../render/ui/switch.js';
|
|
19
|
+
import { TAG_STYLE } from '../../render/ui/tag.js';
|
|
20
|
+
import { appNav, sidebarProject } from '../app-nav.js';
|
|
21
|
+
import { projectsWindows } from '../projects/projects-window.js';
|
|
22
|
+
import { alertsTab } from './alerts-tab.js';
|
|
23
|
+
import { filesTab } from './files-tab.js';
|
|
24
|
+
import { generalTab } from './general-tab.js';
|
|
25
|
+
import { SETTINGS_SCRIPT } from './settings-script.js';
|
|
26
|
+
import { settingsView } from './settings-view.js';
|
|
27
|
+
import { settingsWindows } from './settings-windows.js';
|
|
28
|
+
import { pageNotice } from '../page-notice.js';
|
|
29
|
+
/**
|
|
30
|
+
* Settings, written as `settings.html` beside the index (`for-people-who-build-with-ai.md` §3 C; design file *agentwhy
|
|
31
|
+
* Settings*; `.ai/plans/2026-09-23-settings-redesign.md`): three tabs a person who builds with AI can read - Private
|
|
32
|
+
* files, Alerts, General (F56, which replaced Stop the AI on 2026-09-24) - and, folded, everything a developer needs. Every state is read from the files (F28, R60); every write goes through a confirmation
|
|
33
|
+
* and the server (F40), and the page is read again once it lands.
|
|
34
|
+
*/
|
|
35
|
+
export class SettingsRenderer {
|
|
36
|
+
#links;
|
|
37
|
+
constructor(links) {
|
|
38
|
+
this.#links = links;
|
|
39
|
+
}
|
|
40
|
+
render(index) {
|
|
41
|
+
// A shared page names no machine and offers no choices (R48): it says so, and shows none of this machine's state.
|
|
42
|
+
const settings = index.shared ? undefined : index.settings;
|
|
43
|
+
const view = settings === undefined ? undefined : settingsView(settings);
|
|
44
|
+
// A dot says on or off; where the hooks could not be read there is no dot, rather than a grey one saying "off".
|
|
45
|
+
const dot = (on) => (view?.known !== true ? undefined : on ? 'mint' : 'grey');
|
|
46
|
+
const tabs = view === undefined ? '' : pillTabs([
|
|
47
|
+
{ label: inLanguages((t) => t('set.tab.files')), dot: 'mint', panel: filesTab(view, settings?.allowed.length ?? 0) + ask('files') },
|
|
48
|
+
{ label: inLanguages((t) => t('set.tab.alerts')), ...withDot(dot(view.alerts.on)), panel: alertsTab(view) + ask('alerts') },
|
|
49
|
+
// F56: who all of it is for, asked once. Its dot says whether that is one answer; a split project is grey here
|
|
50
|
+
// and says what to do in the tab itself.
|
|
51
|
+
{ label: inLanguages((t) => t('set.tab.general')), ...withDot(dot(view.scope !== 'mixed')), panel: generalTab(view, index.onboarding === undefined ? undefined : this.#links.onboarding) + ask('general') },
|
|
52
|
+
], 'state');
|
|
53
|
+
return pageShell({
|
|
54
|
+
// which-project V2, V11: the person's projects, opened from the sidebar's card.
|
|
55
|
+
windows: projectsWindows(index),
|
|
56
|
+
title: 'set.title',
|
|
57
|
+
// nothing-updates-by-itself U4: the update notice, where the project's hooks run an older release.
|
|
58
|
+
...pageNotice(index),
|
|
59
|
+
policy: INDEX_CONTENT_SECURITY_POLICY_META,
|
|
60
|
+
// Wider than the 780px Settings began at (2026-09-24): the list's rows carry a switch, a source and an action in
|
|
61
|
+
// columns of their own, and at 780px the name had to squeeze them out of line.
|
|
62
|
+
width: 'list',
|
|
63
|
+
styles: [APP_SIDEBAR_STYLE, HERO_STYLE, BUTTON_STYLE, PILL_TABS_STYLE, SWITCH_STYLE, CHAT_EXAMPLE_STYLE, TAG_STYLE, CALLOUT_STYLE,
|
|
64
|
+
FILE_CHIP_STYLE, POPUP_STYLE, CONFIRM_DIALOG_STYLE, ADD_FILE_POPUP_STYLE, SCOPE_CHOICE_STYLE, AVATAR_STYLE, ASK_PANEL_STYLE, SETTINGS_STYLE],
|
|
65
|
+
scripts: [PILL_TABS_SCRIPT, POPUP_SCRIPT, ADD_FILE_POPUP_SCRIPT, ASK_PANEL_SCRIPT, SETTINGS_SCRIPT],
|
|
66
|
+
sidebar: appSidebar({
|
|
67
|
+
...sidebarProject(index),
|
|
68
|
+
home: this.#links.conversations,
|
|
69
|
+
items: appNav(index, 'settings', this.#links),
|
|
70
|
+
}),
|
|
71
|
+
main: '<div class="set" data-settings data-set-words="' + e(JSON.stringify(scriptWords())) + '">' +
|
|
72
|
+
hero({
|
|
73
|
+
eyebrow: inLanguages((t) => t('set.eyebrow')),
|
|
74
|
+
fact: inLanguages((t) => t('set.hero')),
|
|
75
|
+
action: '',
|
|
76
|
+
lead: inLanguages((t) => t('set.lead')),
|
|
77
|
+
}) +
|
|
78
|
+
(index.shared ? '<p class="set-quiet set-cannot">' + inLanguages((t) => t('set.shared')) + '</p>' : '') +
|
|
79
|
+
(view === undefined || view.canWrite ? '' : '<p class="set-quiet set-cannot">' + inLanguages((t) => t('set.cannot')) + '</p>') +
|
|
80
|
+
tabs +
|
|
81
|
+
(view === undefined ? '' : developer(view)) +
|
|
82
|
+
(view === undefined ? '' : settingsWindows(view)) +
|
|
83
|
+
'</div>',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function withDot(dot) {
|
|
88
|
+
return dot === undefined ? {} : { dot };
|
|
89
|
+
}
|
|
90
|
+
/** "Not sure what to pick? Ask me." under each tab: three ready-made questions and their written answers (F43). */
|
|
91
|
+
function ask(tab) {
|
|
92
|
+
const questions = [1, 2, 3].map((n) => ({
|
|
93
|
+
question: inLanguages((t) => t('set.ask.' + tab + '.' + n)),
|
|
94
|
+
answer: inLanguages((t) => writtenAnswer(t('set.ask.' + tab + '.' + n + '.a'))),
|
|
95
|
+
}));
|
|
96
|
+
return askCard(inLanguages((t) => t('set.ask.title')), questions, 'set-ask-' + tab);
|
|
97
|
+
}
|
|
98
|
+
/** F41: folded, in the tool's own words; every value is text from a file, escaped. */
|
|
99
|
+
function developer(view) {
|
|
100
|
+
return '<details class="set-dev"><summary class="set-dev-toggle">' + inLanguages((t) => t('set.dev')) + '</summary>' +
|
|
101
|
+
'<dl class="set-dev-rows">' + view.developer.map((row) => '<div class="set-dev-row"><dt>' + inLanguages((t) => t(row.key)) + '</dt><dd>' +
|
|
102
|
+
(typeof row.value === 'string' ? e(row.value) : inLanguages((t) => t(row.value.word))) + '</dd></div>').join('') +
|
|
103
|
+
'</dl></details>';
|
|
104
|
+
}
|
|
105
|
+
/** What the script says, in every language: it cannot hold three languages in one text node. */
|
|
106
|
+
function scriptWords() {
|
|
107
|
+
return Object.fromEntries(LANGS.map((lang) => {
|
|
108
|
+
const t = translator(lang);
|
|
109
|
+
return [lang, { saving: t('set.saving'), refused: t('set.refused'), asFile: t('set.asFile'), unreachable: t('set.unreachable') }];
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
/** What only this page lays out. Colours come from the tokens (plan rule 1). */
|
|
113
|
+
const SETTINGS_STYLE = String.raw `
|
|
114
|
+
.set .hero{margin-bottom:28px}
|
|
115
|
+
.set-cannot{margin:-8px 0 22px}
|
|
116
|
+
.set-quiet{font-size:14px;line-height:1.5;color:var(--text-3)}
|
|
117
|
+
.set-soft{color:var(--text-2)}
|
|
118
|
+
.set-head{margin-bottom:16px}
|
|
119
|
+
.co+.set-head{margin-top:30px}
|
|
120
|
+
.set-h2{margin:0;font-size:19px;font-weight:650;line-height:1.3}
|
|
121
|
+
.set-h3{margin:0;font-size:17px;font-weight:650}
|
|
122
|
+
.set-lead{margin:6px 0 0;font-size:15px;line-height:1.5;color:var(--text-2)}
|
|
123
|
+
.set-msg{position:relative;display:flex;align-items:flex-start;gap:20px;padding:26px 28px;border-radius:18px;background:var(--card);border:1px solid var(--white-09);transition:background .3s,border-color .3s}
|
|
124
|
+
.set-msg-main{border-color:var(--coral-35)}
|
|
125
|
+
.set-msg-opt.set-msg-on{border-color:var(--mint-20)}
|
|
126
|
+
.set-msg-icon{flex:none;width:40px;height:40px;border-radius:50%;background:var(--coral-14);color:var(--coral-text);display:flex;align-items:center;justify-content:center}
|
|
127
|
+
.set-msg .sw{margin-top:2px}
|
|
128
|
+
.set-opt{position:relative;margin-left:48px;padding-left:28px}
|
|
129
|
+
.set-opt-label{position:relative;margin:0;padding:22px 0 14px;font-size:14.5px;font-weight:600;color:var(--text-2)}
|
|
130
|
+
.set-opt-label:before,.set-msg-opt:not(:last-child):after{content:"";position:absolute;left:-28px;top:0;bottom:0;border-left:1.5px solid var(--coral-30)}
|
|
131
|
+
.set-msg-opt:not(:last-child):after{left:-29px;top:37px;bottom:-15px}
|
|
132
|
+
.set-msg-opt:before{content:"";position:absolute;left:-29px;top:-1px;width:28px;height:38px;border-left:1.5px solid var(--coral-30);border-bottom:1.5px solid var(--coral-30);border-bottom-left-radius:14px}
|
|
133
|
+
.set-msg-opt+.set-msg-opt{margin-top:14px}
|
|
134
|
+
.set-msg-locked{cursor:not-allowed}
|
|
135
|
+
.set-msg-locked .set-card-body{opacity:.35;filter:grayscale(1)}
|
|
136
|
+
.set-msg-point{background:var(--coral-06)}
|
|
137
|
+
.set-sw{position:relative;flex:none;display:flex}
|
|
138
|
+
.set-sw .sw[aria-disabled="true"]{opacity:.35;cursor:not-allowed}
|
|
139
|
+
.set-tip{cursor:default}
|
|
140
|
+
.set-tip{position:absolute;right:-10px;bottom:calc(100% + 14px);z-index:5;width:290px;padding:14px 16px;border-radius:14px;background:var(--popup);border:1px solid var(--white-14);box-shadow:0 18px 44px var(--shadow);display:flex;flex-direction:column;align-items:flex-start;gap:10px}
|
|
141
|
+
.set-tip[hidden]{display:none}
|
|
142
|
+
.set-tip:after{content:"";position:absolute;right:30px;bottom:-7px;width:12px;height:12px;background:var(--popup);border-right:1px solid var(--white-14);border-bottom:1px solid var(--white-14);transform:rotate(45deg)}
|
|
143
|
+
.set-tip-text{font-size:14px;line-height:1.5;color:var(--text)}
|
|
144
|
+
.set-tip-go{padding:0;font-weight:600}
|
|
145
|
+
.set-msg-name{margin:0;font-size:17.5px;font-weight:650}
|
|
146
|
+
.set-msg-why{margin:8px 0 0;font-size:15px;line-height:1.55;color:var(--text-2)}
|
|
147
|
+
.set-msg .set-state{margin-top:16px;font-size:14px}
|
|
148
|
+
.set-msg .ce{gap:12px;margin-top:16px}
|
|
149
|
+
.set-msg .ce-who{width:30px;height:30px;margin-top:4px;font-size:11px}
|
|
150
|
+
.set-msg .ce-say{font-size:15px;line-height:1.5;padding:12px 16px;border-radius:4px 14px 14px 14px}
|
|
151
|
+
.set-card-on{border-color:var(--mint-30)}
|
|
152
|
+
.set-card-body{flex:1;min-width:0}
|
|
153
|
+
.set-card-name{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
|
|
154
|
+
.set-state{display:flex;align-items:center;gap:8px;margin-top:12px;font-size:13.5px;font-weight:600;color:var(--text-3)}
|
|
155
|
+
.set-state-lg{font-size:14px}
|
|
156
|
+
.set-state-on{color:var(--mint)}
|
|
157
|
+
.set-dot{width:7px;height:7px;border-radius:50%;background:currentColor}
|
|
158
|
+
.set-say{margin:10px 0 0;font-size:13.5px;line-height:1.5;color:var(--coral-text)}
|
|
159
|
+
.set-say[hidden]{display:none}
|
|
160
|
+
.set-say code{display:block;margin-top:6px;font-family:var(--mono);font-size:12.5px;color:var(--text);background:var(--panel);border:1px solid var(--white-08);border-radius:8px;padding:8px 10px;word-break:break-all;user-select:all}
|
|
161
|
+
.set-say-busy{color:var(--text-3)}
|
|
162
|
+
.set-list{border-radius:16px;background:var(--card);border:1px solid var(--white-09);overflow:hidden}
|
|
163
|
+
.set-legend{position:relative;display:flex;flex-wrap:wrap;gap:10px 28px;margin:0 0 18px;padding:14px 20px;border-radius:14px;background:var(--panel);border:1px solid var(--white-09);font-size:14.5px;color:var(--text-2)}
|
|
164
|
+
.set-legend:after{content:"";position:absolute;left:34px;bottom:-7px;width:12px;height:12px;background:var(--panel);border-right:1px solid var(--white-09);border-bottom:1px solid var(--white-09);transform:rotate(45deg)}
|
|
165
|
+
.set-legend-item{display:inline-flex;align-items:center;gap:10px}
|
|
166
|
+
.set-legend strong{color:var(--text);font-weight:600}
|
|
167
|
+
.set-rules{list-style:none;margin:0;padding:0}
|
|
168
|
+
.set-list{--set-cols:40px minmax(0,1fr) 172px 118px 56px}
|
|
169
|
+
.set-rules-head{display:grid;grid-template-columns:var(--set-cols);column-gap:16px;padding:12px 28px;background:var(--panel);font-size:12.5px;font-weight:600;color:var(--text-3)}
|
|
170
|
+
.set-rules-head-file{grid-column:1 / 3}
|
|
171
|
+
.set-rule{display:grid;grid-template-columns:var(--set-cols);column-gap:16px;align-items:center;padding:16px 28px;border-top:1px solid var(--white-06)}
|
|
172
|
+
.set-rule-mode,.set-rule-src,.set-rule-act{display:flex;align-items:center;min-width:0}
|
|
173
|
+
.set-icon{flex:none;width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center}
|
|
174
|
+
.set-icon svg{width:18px;height:18px}
|
|
175
|
+
.set-icon-sm{width:28px;height:28px}.set-icon-sm svg{width:14px;height:14px}
|
|
176
|
+
.set-icon-block{background:var(--mint-14);color:var(--mint)}
|
|
177
|
+
.set-icon-tell{background:var(--sand-16);color:var(--sand)}
|
|
178
|
+
.set-icon-gap{background:var(--coral-14);color:var(--coral-text);box-shadow:inset 0 0 0 1.5px var(--coral)}
|
|
179
|
+
.set-rule-off .set-icon{border:1.5px dashed var(--white-25)}
|
|
180
|
+
.set-rule-watchable{cursor:pointer;transition:background .15s}.set-rule-watchable:hover{background:var(--white-02)}
|
|
181
|
+
.set-rule-watchable:hover .set-icon{border-color:var(--coral)}
|
|
182
|
+
.set-rule-text{display:flex;flex-direction:column;align-items:flex-start;gap:5px;min-width:0}
|
|
183
|
+
.set-rule-name{display:block;font-size:16px;font-weight:600;line-height:1.3}
|
|
184
|
+
.set-rule-chip{font-size:12.5px}
|
|
185
|
+
.set-rule-gap{font-size:13px;line-height:1.4;color:var(--coral-text)}
|
|
186
|
+
.set-honest{display:block;margin-top:10px}
|
|
187
|
+
.set-none{color:var(--text-4)}
|
|
188
|
+
.set-list-add{padding:20px 28px;border-top:1px solid var(--white-06);display:flex;justify-content:center}
|
|
189
|
+
.set-list-add .pill{gap:10px;padding:11px 22px}
|
|
190
|
+
.set-plus{width:20px;height:20px;border-radius:50%;background:var(--bg);color:var(--text);display:flex;align-items:center;justify-content:center;font-size:15px;line-height:1}
|
|
191
|
+
.set-list-foot{display:flex;flex-wrap:wrap;gap:6px 22px;margin:0;padding:14px 28px;border-top:1px solid var(--white-06);font-size:14px;color:var(--text-2)}
|
|
192
|
+
.set-count-n{font-weight:650}
|
|
193
|
+
.set-count-block .set-count-n{color:var(--mint)}.set-count-tell .set-count-n{color:var(--sand)}
|
|
194
|
+
.set-list-exc{margin-left:auto;color:var(--text-3)}
|
|
195
|
+
.set-stop{border-radius:16px;background:var(--card);border:1px solid var(--white-09);overflow:hidden}
|
|
196
|
+
.set-stop-main{display:flex;align-items:flex-start;gap:18px;padding:24px}
|
|
197
|
+
.set-stop-note{margin:0 24px 24px}
|
|
198
|
+
.set-code{font-family:var(--mono);font-size:.92em;color:var(--text)}
|
|
199
|
+
.set-pattern:empty{display:none}
|
|
200
|
+
.set-mode{flex:none;display:inline-flex;padding:3px;border-radius:999px;background:var(--bg);border:1px solid var(--white-08)}
|
|
201
|
+
.set-mode-half{padding:6px 13px;border-radius:999px;font-size:13.5px;font-weight:600;color:var(--text-2);white-space:nowrap}
|
|
202
|
+
a.set-mode-half:hover{color:var(--text);background:var(--white-06)}
|
|
203
|
+
.set-mode-on{background:var(--white-10);color:var(--text)}
|
|
204
|
+
.set-mode-is-block .set-mode-on{background:var(--mint);color:var(--on-mint)}
|
|
205
|
+
.set-mode-is-tell .set-mode-on{background:var(--sand);color:var(--on-sand)}
|
|
206
|
+
.set-mode-off{opacity:.45}
|
|
207
|
+
.set-general-note{display:flex;align-items:center;gap:10px;margin:18px 0 0}
|
|
208
|
+
.set-box{border-radius:20px;background:var(--card);border:1px solid var(--white-09);padding:28px}
|
|
209
|
+
.set-box+.set-box{margin-top:16px}
|
|
210
|
+
.set-who .set-head{margin-bottom:22px}
|
|
211
|
+
.set-scopes{display:grid;grid-template-columns:1fr 1fr;gap:14px}
|
|
212
|
+
.set-scope{display:flex;flex-direction:column;padding:24px;border-radius:18px;background:var(--panel);border:1.5px solid var(--white-09);color:var(--text);transition:border-color .15s,background .15s}
|
|
213
|
+
a.set-scope:hover{color:var(--text);border-color:var(--white-25);background:var(--white-02)}
|
|
214
|
+
.set-scope-on{background:var(--mint-06);border-color:var(--mint-50)}
|
|
215
|
+
.set-scope-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:18px}
|
|
216
|
+
.set-scope-who{display:flex}
|
|
217
|
+
.set-scope-who .av{border:2px solid var(--card)}
|
|
218
|
+
.set-scope-who .av+.av{margin-left:-9px}
|
|
219
|
+
.set-scope-ring{flex:none;width:24px;height:24px;border-radius:50%;border:1.5px solid var(--white-30);display:flex;align-items:center;justify-content:center}
|
|
220
|
+
.set-scope-ring:after{content:"";width:12px;height:12px;border-radius:50%}
|
|
221
|
+
.set-scope-on .set-scope-ring{border:2px solid var(--mint)}.set-scope-on .set-scope-ring:after{background:var(--mint)}
|
|
222
|
+
a.set-scope:hover .set-scope-ring{border-color:var(--mint)}
|
|
223
|
+
.set-scope-name{font-size:18px;font-weight:650}
|
|
224
|
+
.set-scope-sub{display:block;margin-top:12px;font-size:14.5px;line-height:1.55;color:var(--text-2)}
|
|
225
|
+
.set-info{flex:none;width:20px;height:20px;border-radius:50%;background:var(--white-06);color:var(--text-2);font-size:12px;font-weight:700;display:flex;align-items:center;justify-content:center}
|
|
226
|
+
.set-uninstall{display:flex;align-items:center;gap:20px;padding:24px 28px}
|
|
227
|
+
.set-uninstall-icon{flex:none;width:46px;height:46px;border-radius:50%;background:var(--coral-12);color:var(--coral-text);display:flex;align-items:center;justify-content:center}
|
|
228
|
+
.set-uninstall-text{margin:4px 0 0;font-size:14.5px;line-height:1.55;color:var(--text-2)}
|
|
229
|
+
.set-dev{margin-top:4px}
|
|
230
|
+
.set-again{display:flex;align-items:center;gap:20px;padding:24px 28px}
|
|
231
|
+
.set-again-icon{flex:none;width:46px;height:46px;border-radius:50%;background:var(--white-06);color:var(--coral);display:flex;align-items:center;justify-content:center}
|
|
232
|
+
.set-again-icon .brand-mark{width:24px;height:24px}
|
|
233
|
+
.set-dev-toggle{display:inline-block;cursor:pointer;list-style:none;color:var(--text-2);font-size:14px;font-weight:600;padding:4px 0}
|
|
234
|
+
.set-dev-toggle::-webkit-details-marker{display:none}
|
|
235
|
+
.set-dev-toggle:after{content:" ▾"}.set-dev[open] .set-dev-toggle:after{content:" ▴"}
|
|
236
|
+
.set-dev-toggle:hover{color:var(--text)}
|
|
237
|
+
.set-dev-rows{margin:10px 0 0;border-radius:12px;background:var(--panel);border:1px solid var(--white-08);padding:6px 18px}
|
|
238
|
+
.set-dev-row{display:grid;grid-template-columns:190px minmax(0,1fr);gap:16px;padding:10px 0;border-bottom:1px solid var(--white-05);font-size:13.5px}
|
|
239
|
+
.set-dev-row:last-child{border-bottom:0}
|
|
240
|
+
.set-dev-row dt{color:var(--text-3)}
|
|
241
|
+
.set-dev-row dd{margin:0;font-family:var(--mono);color:var(--text-soft);word-break:break-all}
|
|
242
|
+
@media (max-width:640px){
|
|
243
|
+
.set-msg{padding:22px 18px;gap:14px}.set-msg-main{flex-wrap:wrap}.set-msg-main .set-card-body{order:3;flex-basis:100%}.set-msg-main .sw{margin-left:auto}
|
|
244
|
+
.set-opt{margin-left:20px;padding-left:18px}.set-opt-label:before,.set-msg-opt:not(:last-child):after{left:-18px}.set-msg-opt:not(:last-child):after{left:-19px}.set-msg-opt:before{left:-19px;width:18px;border-bottom-left-radius:10px}.set-legend{padding:12px 16px}
|
|
245
|
+
.set-rules-head{display:none}.set-rule:first-child{border-top:0}
|
|
246
|
+
.set-rule{grid-template-columns:40px minmax(0,1fr) auto;grid-template-areas:"icon text act" ". mode src";row-gap:12px;column-gap:12px;padding:16px 18px}
|
|
247
|
+
.set-rule>.set-icon{grid-area:icon}.set-rule-text{grid-area:text}.set-rule-mode{grid-area:mode}.set-rule-src{grid-area:src;justify-content:flex-end}.set-rule-act{grid-area:act;justify-content:flex-end}
|
|
248
|
+
.set-list-add,.set-list-foot{padding-left:18px;padding-right:18px}
|
|
249
|
+
.set-none{display:none}
|
|
250
|
+
.set-dev-row{grid-template-columns:1fr;gap:4px}
|
|
251
|
+
.set-box{padding:22px 18px}.set-scopes{grid-template-columns:1fr}.set-scope{padding:20px}
|
|
252
|
+
.set-uninstall,.set-again{flex-wrap:wrap;gap:14px 16px}.set-uninstall .set-card-body,.set-again .set-card-body{flex-basis:calc(100% - 62px)}
|
|
253
|
+
}
|
|
254
|
+
`;
|