@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,381 @@
|
|
|
1
|
+
import { escapeHtml as e } from '../html-report-components.js';
|
|
2
|
+
import { inLanguages, labelAttributes, LANGS, translator } from '../report-copy.js';
|
|
3
|
+
import { closeButton, pill, textButton } from '../ui/button.js';
|
|
4
|
+
import { dataTable } from '../ui/data-table.js';
|
|
5
|
+
import { guideCard } from '../ui/guide-card.js';
|
|
6
|
+
import { hero } from '../ui/hero.js';
|
|
7
|
+
import { labelledSelect } from '../ui/labelled-select.js';
|
|
8
|
+
import { CLOSES, opener, popup, popupFoot } from '../ui/popup.js';
|
|
9
|
+
import { glyphIcon, statusIcon } from '../ui/status-icon.js';
|
|
10
|
+
import { MODE_SVG } from '../ui/mode-icon.js';
|
|
11
|
+
import { LOOKS } from '../ui/status-look.js';
|
|
12
|
+
import { tag } from '../ui/tag.js';
|
|
13
|
+
import { holdsKeys } from '../../check/session-actions.js';
|
|
14
|
+
import { fileStory } from './file-story.js';
|
|
15
|
+
import { onlyNamed } from './files.js';
|
|
16
|
+
import { storyPopup } from './story-window.js';
|
|
17
|
+
import { titleOf } from './item-names.js';
|
|
18
|
+
import { fixId, storyId } from './to-do-view.js';
|
|
19
|
+
/**
|
|
20
|
+
* "Files" (the report page spec P31-P37; design file *agentwhy App*): everything the AI reached, what it did to each,
|
|
21
|
+
* whether a rule of the project protects it, and what to do - filtered by a script, all on the page without one.
|
|
22
|
+
* `protectKeys` names the files **Protect it** is offered for - private, not protected yet, and inside the project - and
|
|
23
|
+
* the everyday ones inside it, offered **Make it private**.
|
|
24
|
+
*/
|
|
25
|
+
export function filesView(rows, items, protectKeys, names) {
|
|
26
|
+
const entries = rows.map((row, key) => ({ row, key }));
|
|
27
|
+
const opened = entries.filter(({ row }) => !onlyNamed(row));
|
|
28
|
+
// One list, in the order a person deals with it (the maintainer, 2026-09-24): what the AI read, in coral; then the
|
|
29
|
+
// private files it only saw the name of, in blue; then everything else. A name only seen is still never counted as
|
|
30
|
+
// a file opened - it may not be in the project at all (P32, P49) - but it is not hidden under a fold either.
|
|
31
|
+
const listed = [...entries].sort((a, b) => tierOf(a.row) - tierOf(b.row));
|
|
32
|
+
if (opened.length === 0) {
|
|
33
|
+
return '<div class="fl"><div class="rp-alone">' + guideCard({ tone: 'mint', title: inLanguages((t) => t('fl.noneListed')), body: inLanguages((t) => t('fl.commands')) }) +
|
|
34
|
+
'</div>' + (listed.length === 0 ? '' : table(listed, items, protectKeys, false, names)) + '</div>';
|
|
35
|
+
}
|
|
36
|
+
const privates = opened.filter(({ row }) => row.private).length;
|
|
37
|
+
const action = privates === 0 ? inLanguages((t) => t('fl.noneRead'))
|
|
38
|
+
: privates === opened.length ? inLanguages((t) => t('fl.all', { n: opened.length }))
|
|
39
|
+
: inLanguages((t) => t('fl.some', { n: privates }));
|
|
40
|
+
const lead = privates === 0 ? 'fl.leadNone' : privates === opened.length ? 'fl.leadAll' : 'fl.lead';
|
|
41
|
+
return '<div class="fl' + (privates === 0 ? ' fl-clean' : '') + '">' +
|
|
42
|
+
hero({ eyebrow: inLanguages((t) => t('fl.eyebrow')), fact: inLanguages((t) => t('fl.fact', { n: opened.length })), action, lead: inLanguages((t) => t(lead)) }) +
|
|
43
|
+
filters(listed.map(({ row }) => row)) + table(listed, items, protectKeys, true, names) +
|
|
44
|
+
'<p class="fl-note">' + inLanguages((t) => t('fl.shown', { shown: '<span data-files-shown>' + listed.length + '</span>', n: listed.length })) + ' ' +
|
|
45
|
+
inLanguages((t) => t('fl.commands')) + '</p></div>';
|
|
46
|
+
}
|
|
47
|
+
/** The table's three parts, in the order a person deals with them: read (coral), only its name seen (blue), the rest. */
|
|
48
|
+
const TIERS = [{ key: 'fl.tier.read', tone: 'coral' }, { key: 'fl.tier.name', tone: 'blue' }, { key: 'fl.tier.rest', tone: 'grey' }];
|
|
49
|
+
function tierOf(row) {
|
|
50
|
+
return row.private && (row.access === 'read' || row.access === 'changed') ? 0 : onlyNamed(row) ? 1 : 2;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The window of every row not on the to-do list, written beside the page's other windows, outside the views. A private
|
|
54
|
+
* file opens the same "What happened" window a file on the list does - its story, the diagram and the record (the
|
|
55
|
+
* maintainer, 2026-09-25) - with what was done said first and what to do under it, and no Fix it. An everyday file, of
|
|
56
|
+
* which the model holds no steps, and a private one the flows name nowhere keep the simple window (P37).
|
|
57
|
+
*/
|
|
58
|
+
export function fileWindows(rows, protectKeys, report, clock, names) {
|
|
59
|
+
return rows.map((row, key) => {
|
|
60
|
+
if (row.item !== undefined)
|
|
61
|
+
return '';
|
|
62
|
+
const story = row.private ? fileStory(report, row.path) : undefined;
|
|
63
|
+
return story === undefined || story.entries.length === 0 ? fileWindow(row, key, protectKeys, names) : rowStoryWindow(row, key, story, report, protectKeys, clock, names);
|
|
64
|
+
}).join('');
|
|
65
|
+
}
|
|
66
|
+
/** A private file with nothing to fix, in the story window: its row's words for what happened and what to do. */
|
|
67
|
+
function rowStoryWindow(row, key, story, report, protectKeys, clock, names) {
|
|
68
|
+
const label = (k) => inLanguages((t) => t(k));
|
|
69
|
+
const read = report.privateFiles.find((file) => file.path === row.path);
|
|
70
|
+
const pattern = report.findings.find((finding) => finding.path === row.path)?.pattern;
|
|
71
|
+
const reach = LOOKS[LOOK[row.access === 'changed' ? 'read' : row.access]];
|
|
72
|
+
const exposed = row.access === 'read' || row.access === 'changed';
|
|
73
|
+
const protectKey = protectKeys.get(row.path);
|
|
74
|
+
return storyPopup(story, {
|
|
75
|
+
path: row.path,
|
|
76
|
+
keys: read !== undefined && holdsKeys(read),
|
|
77
|
+
title: label(row.kind),
|
|
78
|
+
...(pattern === undefined ? {} : { pattern }),
|
|
79
|
+
exposed,
|
|
80
|
+
summary: label('fl.w.did.' + row.access),
|
|
81
|
+
...(exposed ? {} : { look: { glyph: reach.glyph, tone: reach.tone } }),
|
|
82
|
+
}, 'file-' + key, report.scope.sessionId, clock, { context: label(nextOf(row)), names }, protectKey === undefined ? '' : '<span data-protect-open="' + protectKey + '">' +
|
|
83
|
+
pill({ label: label(protectLabel(row)), tone: 'light', size: 'md', href: '#protect-' + protectKey, attributes: opener('protect-' + protectKey) }) + '</span>');
|
|
84
|
+
}
|
|
85
|
+
/** What to do about a file with nothing on the to-do list: the last answer of its window. */
|
|
86
|
+
function nextOf(row) {
|
|
87
|
+
return !row.private ? 'fl.w.next.none' : row.protection === 'yes' ? 'fl.w.next.safe' : row.protection === 'told' ? 'fl.w.next.told' : 'fl.w.next.maybe';
|
|
88
|
+
}
|
|
89
|
+
/** The look of a private file in its row, said of that one file (P35). */
|
|
90
|
+
const LOOK = { read: 'read', name: 'name', unknown: 'unchecked', stopped: 'stopped' };
|
|
91
|
+
/**
|
|
92
|
+
* The glyph beside "Protected?": mint where a rule protects it, coral where a private file has none, grey otherwise. A
|
|
93
|
+
* file kept from the AI and one the person chose to track carry Settings' padlock and eye (`mode-icon.ts`), so the
|
|
94
|
+
* mode reads the same on both pages; Track is in its own sand, as Settings draws it - nothing is wrong with it.
|
|
95
|
+
*/
|
|
96
|
+
const PROTECTED = {
|
|
97
|
+
yes: [MODE_SVG.block, 'mint'], no: ['!', 'coral'], unknown: ['?', 'grey'], na: ['○', 'grey'], told: [MODE_SVG.tell, 'sand'],
|
|
98
|
+
};
|
|
99
|
+
/** What the filter "What the AI did" knows a row as; an outcome not recorded and a change are neither of its three. */
|
|
100
|
+
function didOf(row) {
|
|
101
|
+
return row.access === 'read' || row.access === 'name' || row.access === 'stopped' ? row.access : 'other';
|
|
102
|
+
}
|
|
103
|
+
/** P34: the search, the three groups with their counts, and the two questions - a script's, so only with one. */
|
|
104
|
+
function filters(rows) {
|
|
105
|
+
const count = (test) => rows.filter(test).length;
|
|
106
|
+
const groups = [['all', rows.length], ['fix', count((row) => row.group === 'fix')], ['fixed', count((row) => row.group === 'fixed')]]
|
|
107
|
+
.map(([group, n]) => '<button type="button" class="fl-pill' + (group === 'all' ? ' fl-on' : '') + '" data-files-group="' + group + '" data-live-keep aria-pressed="' + String(group === 'all') + '">' +
|
|
108
|
+
inLanguages((t) => t('fl.group.' + group)) + '<span class="fl-count" data-files-count="' + group + '">' + n + '</span></button>').join('');
|
|
109
|
+
const did = (t) => labelledSelect(e(t('fl.did.q')), [
|
|
110
|
+
{ value: 'any', label: e(t('fl.did.any')) },
|
|
111
|
+
...['read', 'name', 'stopped'].map((value) => ({ value, label: e(t('fl.did.' + value)) + ' (' + count((row) => row.access === value) + ')' })),
|
|
112
|
+
], ' data-files-did data-live-keep');
|
|
113
|
+
const prot = (t) => labelledSelect(e(t('fl.prot.q')), [
|
|
114
|
+
{ value: 'any', label: e(t('fl.prot.any')) },
|
|
115
|
+
...['no', 'yes', 'told', 'na'].map((value) => ({ value, label: e(t('fl.prot.' + value)) + ' (' + count((row) => row.protection === value) + ')' })),
|
|
116
|
+
], ' data-files-prot data-live-keep');
|
|
117
|
+
return '<div class="fl-filters js-only"><div class="fl-row">' +
|
|
118
|
+
'<input class="fl-search" type="search" data-files-search data-live-keep placeholder="' + e(translator('en')('fl.search')) + '"' +
|
|
119
|
+
LANGS.map((lang) => ' data-placeholder-' + lang + '="' + e(translator(lang)('fl.search')) + '"').join('') + labelAttributes((t) => e(t('fl.search'))) + '>' +
|
|
120
|
+
'<div class="fl-pills">' + groups + '</div></div>' +
|
|
121
|
+
'<div class="fl-row">' + inLanguages(did) + inLanguages(prot) + textButton(inLanguages((t) => t('fl.clear')), ' data-files-clear hidden', 'fl-clear') + '</div></div>';
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* P35: `File · AI · Private file · When your AI reaches it · Action` (the mode its own column since 2026-09-25; X28 names
|
|
125
|
+
* the AI it holds for since 2026-09-29), a row opening its story window or its simple one (P37).
|
|
126
|
+
*/
|
|
127
|
+
function table(entries, items, protectKeys, filtered, names) {
|
|
128
|
+
const label = (key) => inLanguages((t) => t(key));
|
|
129
|
+
return dataTable({
|
|
130
|
+
head: [label('fl.col.file'), label('fl.col.ai'), label('fl.col.prot'), label('fl.col.mode'), label('fl.col.action')],
|
|
131
|
+
// The file is what a row is about, so its column takes the room: the others hold one tag or one answer each.
|
|
132
|
+
columns: 'minmax(240px,2fr) 120px 140px minmax(250px,1.2fr) 110px',
|
|
133
|
+
minWidth: 980,
|
|
134
|
+
empty: label('fl.noMatch'),
|
|
135
|
+
// Only the table of opened files is the one the filters work on; the names under it are a list, not a filter's rows.
|
|
136
|
+
...(filtered ? { attributes: ' data-files-table' } : {}),
|
|
137
|
+
rows: entries.flatMap(({ row, key }, at) => {
|
|
138
|
+
const tier = tierOf(row);
|
|
139
|
+
// A heading over each part, where the table has more than one: its first row is where the part begins.
|
|
140
|
+
const parts = new Set(entries.map((entry) => tierOf(entry.row))).size;
|
|
141
|
+
const heading = parts > 1 && (at === 0 || tierOf(entries[at - 1].row) !== tier)
|
|
142
|
+
? [{
|
|
143
|
+
group: label(TIERS[tier].key), tone: TIERS[tier].tone, count: entries.filter((entry) => tierOf(entry.row) === tier).length,
|
|
144
|
+
attributes: ' data-files-tier="' + tier + '"',
|
|
145
|
+
}]
|
|
146
|
+
: [];
|
|
147
|
+
const item = row.item === undefined ? undefined : items[row.item];
|
|
148
|
+
const target = row.item === undefined ? 'file-' + key : storyId(row.item);
|
|
149
|
+
const kind = item === undefined ? label(row.kind) : inLanguages((t, lang) => titleOf(item, t, lang));
|
|
150
|
+
return [...heading, {
|
|
151
|
+
cells: [
|
|
152
|
+
'<span class="fl-kind">' + kind + '</span><span class="fl-chip" title="' + e(row.path) + '">' + e(names(row.path)) + '</span>',
|
|
153
|
+
row.private ? statusIcon(LOOK[row.access === 'changed' ? 'read' : row.access], label('fl.acc.' + row.access)) : '<span class="fl-plain">' + label('fl.acc.' + row.access) + '</span>',
|
|
154
|
+
privateCell(row, protectKeys.get(row.path)),
|
|
155
|
+
modeCell(row, protectKeys.get(row.path)),
|
|
156
|
+
actionCell(row),
|
|
157
|
+
],
|
|
158
|
+
href: '#' + target,
|
|
159
|
+
linkAttributes: opener(target),
|
|
160
|
+
label: e(row.path),
|
|
161
|
+
// The status bar: protected now, read before, and not fixed - the one row whose rule came too late (guidelines §4).
|
|
162
|
+
bar: row.private && row.protection === 'yes' && row.access === 'read' && row.group === 'fix',
|
|
163
|
+
attributes: ' data-live-key="' + e(row.path) + '" data-file-key="' + key + '" data-tier="' + tier + '" data-group="' + row.group + '" data-did="' + didOf(row) + '" data-prot="' + row.protection + '"' +
|
|
164
|
+
' data-search="' + e(row.path.toLowerCase()) + '"' + (row.item === undefined ? '' : ' data-file-item="' + row.item + '"'),
|
|
165
|
+
}];
|
|
166
|
+
}),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* The Private file column: whether the file is private, and nothing else - what stops the AI, and the buttons that
|
|
171
|
+
* change it, are the next column's. Its colour is the row's story, coral where nothing keeps a private file from the AI,
|
|
172
|
+
* mint where the person's settings hold it - blocked, or Track, which they chose (the maintainer, 2026-09-25) - and grey
|
|
173
|
+
* where that cannot be told.
|
|
174
|
+
*/
|
|
175
|
+
function privateCell(row, key) {
|
|
176
|
+
const label = (id) => inLanguages((t) => t(id));
|
|
177
|
+
const tone = !row.private ? 'grey' : row.protection === 'no' ? 'coral' : row.protection === 'yes' || row.protection === 'told' ? 'mint' : 'grey';
|
|
178
|
+
const now = tag(label(row.private ? 'fl.tag.private' : 'fl.tag.na'), tone);
|
|
179
|
+
if (key === undefined)
|
|
180
|
+
return now;
|
|
181
|
+
return '<span data-protect-open="' + key + '">' + now + '</span>' +
|
|
182
|
+
'<span data-protected="' + key + '" hidden>' + tag(label('fl.tag.private'), 'mint') + '</span>';
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* The mode column (the maintainer, 2026-09-25: a mode inside the private tag went unseen): what happens when the AI
|
|
186
|
+
* reaches the file, in Settings' words and glyphs (`mode-icon.ts`) - **Blocked** with its padlock, **Track** with its
|
|
187
|
+
* eye, and coral **Not blocked** with **Protect it** beside it where nothing keeps a private file from the AI. An
|
|
188
|
+
* everyday file needs nothing, and offers **Make it private** where it can be, the same rule Settings writes when a file
|
|
189
|
+
* is added there. A file protected from this page becomes Blocked here, and Private in the column before.
|
|
190
|
+
*/
|
|
191
|
+
function modeCell(row, key) {
|
|
192
|
+
const label = (id) => inLanguages((t) => t(id));
|
|
193
|
+
const blocked = glyphIcon(MODE_SVG.block, 'mint', label('fl.mode.yes'));
|
|
194
|
+
const made = key === undefined ? '' : '<span data-protected="' + key + '" hidden>' + blocked + '</span>';
|
|
195
|
+
if (row.protection === 'yes')
|
|
196
|
+
return blocked;
|
|
197
|
+
// F57: the person chose this. Nothing is wrong with it, so it is in Track's sand, and nothing offers to protect it.
|
|
198
|
+
if (row.protection === 'told')
|
|
199
|
+
return glyphIcon(MODE_SVG.tell, 'sand', label('fl.mode.told'));
|
|
200
|
+
if (row.protection === 'unknown')
|
|
201
|
+
return glyphIcon('?', 'grey', label('fl.mode.unknown'));
|
|
202
|
+
if (row.protection === 'na') {
|
|
203
|
+
if (key === undefined)
|
|
204
|
+
return '<span class="fl-plain">' + label('fl.mode.na') + '</span>';
|
|
205
|
+
// Quieter than Protect it (button.ts: light for "Protect it", an outline for the rest): nothing is wrong with the file.
|
|
206
|
+
return '<span class="fl-prot" data-protect-open="' + key + '">' +
|
|
207
|
+
pill({ label: label(protectLabel(row)), tone: 'outline', size: 'sm', href: '#protect-' + key, attributes: opener('protect-' + key) + ' data-row-control' }) + '</span>' + made;
|
|
208
|
+
}
|
|
209
|
+
const now = glyphIcon('!', 'coral', label('fl.mode.no'));
|
|
210
|
+
if (key === undefined)
|
|
211
|
+
return now;
|
|
212
|
+
return '<span class="fl-prot" data-protect-open="' + key + '">' + now +
|
|
213
|
+
pill({ label: label(protectLabel(row)), tone: 'light', size: 'sm', href: '#protect-' + key, attributes: opener('protect-' + key) + ' data-row-control' }) + '</span>' + made;
|
|
214
|
+
}
|
|
215
|
+
/** "Protect it →" for a private file, "Make it private →" for an everyday one. */
|
|
216
|
+
function protectLabel(row) {
|
|
217
|
+
return row.protection === 'na' ? 'fl.makePrivate' : 'fl.protect';
|
|
218
|
+
}
|
|
219
|
+
function actionCell(row) {
|
|
220
|
+
const label = (id) => inLanguages((t) => t(id));
|
|
221
|
+
if (row.item === undefined)
|
|
222
|
+
return '<span class="fl-act fl-act-none">' + label('fl.act.none') + '</span>';
|
|
223
|
+
const fixed = row.group === 'fixed';
|
|
224
|
+
return '<a class="fl-act fl-act-fix" href="#' + fixId(row.item) + '"' + opener(fixId(row.item)) + ' data-row-control data-files-fix="' + row.item + '"' + (fixed ? ' hidden' : '') + '>' + label('fl.act.fix') + '</a>' +
|
|
225
|
+
'<span class="fl-act fl-act-fixed" data-files-fixed="' + row.item + '"' + (fixed ? '' : ' hidden') + '>' + label('fl.act.fixed') + '</span>';
|
|
226
|
+
}
|
|
227
|
+
/** P37: a file with nothing on the to-do list - what the AI did, whether it is protected, and what to do. */
|
|
228
|
+
function fileWindow(row, key, protectKeys, names) {
|
|
229
|
+
const id = 'file-' + key;
|
|
230
|
+
const label = (k) => inLanguages((t) => t(k));
|
|
231
|
+
const did = row.private
|
|
232
|
+
? 'fl.w.did.' + row.access
|
|
233
|
+
: row.access === 'changed' ? 'fl.w.did.changed' : row.access === 'stopped' ? 'fl.w.did.everydayStopped' : 'fl.w.did.everydayRead';
|
|
234
|
+
const next = nextOf(row);
|
|
235
|
+
const protectKey = protectKeys.get(row.path);
|
|
236
|
+
// Each answer carries its colour's glyph, so the state is seen before it is read (guidelines §9.3): what the AI did
|
|
237
|
+
// in the row's own look, only a private file in colour; nothing on this window is ever a thing to do.
|
|
238
|
+
const reach = LOOKS[LOOK[row.access === 'changed' ? 'read' : row.access]];
|
|
239
|
+
const glyphs = [
|
|
240
|
+
[reach.glyph, row.private ? reach.tone : 'grey'],
|
|
241
|
+
PROTECTED[row.protection],
|
|
242
|
+
[LOOKS.none.glyph, 'grey'],
|
|
243
|
+
];
|
|
244
|
+
const fact = (at, question, answer) => {
|
|
245
|
+
const [glyph, tone] = glyphs[at];
|
|
246
|
+
return '<div class="fw-row"><span class="fw-glyph fw-' + tone + '" aria-hidden="true">' + glyph + '</span>' +
|
|
247
|
+
'<div><div class="fw-q">' + label(question) + '</div><div class="fw-a">' + label(answer) + '</div></div></div>';
|
|
248
|
+
};
|
|
249
|
+
return popup({
|
|
250
|
+
id,
|
|
251
|
+
size: 'small',
|
|
252
|
+
labelledBy: id + '-title',
|
|
253
|
+
body: '<div class="fw"><div class="fw-top"><div class="fw-id"><h2 class="fw-title" id="' + id + '-title">' + label(row.kind) + '</h2>' +
|
|
254
|
+
'<span class="fl-chip" title="' + e(row.path) + '">' + e(names(row.path)) + '</span></div>' +
|
|
255
|
+
closeButton(labelAttributes((t) => t('app.close')) + CLOSES, 'sm') + '</div>' +
|
|
256
|
+
'<div class="fw-facts">' + fact(0, 'fl.w.did', did) + fact(1, 'fl.w.prot', 'fl.w.prot.' + row.protection) + fact(2, 'fl.w.next', next) + '</div></div>' +
|
|
257
|
+
popupFoot('', pill({ label: label('app.close'), tone: 'outline', size: 'md', button: true, attributes: CLOSES }) +
|
|
258
|
+
(protectKey === undefined ? '' : '<span data-protect-open="' + protectKey + '">' +
|
|
259
|
+
pill({ label: label(protectLabel(row)), tone: row.protection === 'na' ? 'outline' : 'light', size: 'md', href: '#protect-' + protectKey, attributes: opener('protect-' + protectKey) }) + '</span>'), true),
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* P34: the filters, applied to the rows as the person changes them; the counts follow a file marked done or protected.
|
|
264
|
+
* Each Files view works within its own box, so a page may hold more than one: the report holds its own, and the
|
|
265
|
+
* Conversations page shows a report's in a window (`for-people-who-build-with-ai.md` F58) and starts it through
|
|
266
|
+
* `window.agentwhyFiles(box)` once it is in place. A view already started is left alone.
|
|
267
|
+
*/
|
|
268
|
+
export const FILES_SCRIPT = String.raw `
|
|
269
|
+
(() => {
|
|
270
|
+
const started = new WeakSet();
|
|
271
|
+
const start = (table) => {
|
|
272
|
+
if (started.has(table)) return;
|
|
273
|
+
started.add(table);
|
|
274
|
+
const box = table.closest('.fl') || document;
|
|
275
|
+
const rows = [...table.querySelectorAll('[data-file-key]')];
|
|
276
|
+
const search = box.querySelector('[data-files-search]');
|
|
277
|
+
const state = { group: 'all', did: 'any', prot: 'any', text: '' };
|
|
278
|
+
const apply = () => {
|
|
279
|
+
let shown = 0;
|
|
280
|
+
rows.forEach((row) => {
|
|
281
|
+
const on = (state.group === 'all' || row.dataset.group === state.group) && (state.did === 'any' || row.dataset.did === state.did) &&
|
|
282
|
+
(state.prot === 'any' || row.dataset.prot === state.prot) && (state.text === '' || row.dataset.search.includes(state.text));
|
|
283
|
+
row.hidden = !on;
|
|
284
|
+
if (on) shown += 1;
|
|
285
|
+
});
|
|
286
|
+
table.querySelectorAll('[data-files-tier]').forEach((heading) => {
|
|
287
|
+
heading.hidden = !rows.some((row) => !row.hidden && row.dataset.tier === heading.dataset.filesTier);
|
|
288
|
+
});
|
|
289
|
+
box.querySelectorAll('[data-files-shown]').forEach((element) => { element.textContent = String(shown); });
|
|
290
|
+
const empty = table.querySelector('.dt-empty');
|
|
291
|
+
if (empty) empty.hidden = shown !== 0;
|
|
292
|
+
box.querySelectorAll('[data-files-group]').forEach((button) => {
|
|
293
|
+
const on = button.dataset.filesGroup === state.group;
|
|
294
|
+
button.classList.toggle('fl-on', on);
|
|
295
|
+
button.setAttribute('aria-pressed', String(on));
|
|
296
|
+
});
|
|
297
|
+
['fix', 'fixed'].forEach((group) => box.querySelectorAll('[data-files-count="' + group + '"]').forEach((element) => {
|
|
298
|
+
element.textContent = String(rows.filter((row) => row.dataset.group === group).length);
|
|
299
|
+
}));
|
|
300
|
+
box.querySelectorAll('[data-files-did]').forEach((select) => { select.value = state.did; });
|
|
301
|
+
box.querySelectorAll('[data-files-prot]').forEach((select) => { select.value = state.prot; });
|
|
302
|
+
const clear = box.querySelector('[data-files-clear]');
|
|
303
|
+
if (clear) clear.hidden = state.group === 'all' && state.did === 'any' && state.prot === 'any' && state.text === '';
|
|
304
|
+
};
|
|
305
|
+
if (search) search.addEventListener('input', () => { state.text = search.value.trim().toLowerCase(); apply(); });
|
|
306
|
+
box.addEventListener('click', (event) => {
|
|
307
|
+
const group = event.target.closest('[data-files-group]');
|
|
308
|
+
if (group) { state.group = group.dataset.filesGroup; apply(); return; }
|
|
309
|
+
if (event.target.closest('[data-files-clear]')) {
|
|
310
|
+
Object.assign(state, { group: 'all', did: 'any', prot: 'any', text: '' });
|
|
311
|
+
if (search) search.value = '';
|
|
312
|
+
apply();
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
box.addEventListener('change', (event) => {
|
|
316
|
+
if (event.target.matches('[data-files-did]')) { state.did = event.target.value; apply(); }
|
|
317
|
+
if (event.target.matches('[data-files-prot]')) { state.prot = event.target.value; apply(); }
|
|
318
|
+
});
|
|
319
|
+
document.addEventListener('files-changed', apply);
|
|
320
|
+
apply();
|
|
321
|
+
};
|
|
322
|
+
window.agentwhyFiles = (scope) => scope.querySelectorAll('[data-files-table]').forEach(start);
|
|
323
|
+
window.agentwhyFiles(document);
|
|
324
|
+
})();
|
|
325
|
+
`;
|
|
326
|
+
/*
|
|
327
|
+
* The heading of each part - read, only its name seen, the rest - reads as a title and stays at the top of the window
|
|
328
|
+
* while its rows scroll under it (the maintainer, 2026-09-28), on the report and in the Conversations window alike. A
|
|
329
|
+
* table that can scroll sideways is a scroll box of its own, which nothing inside can stick to the window through; so
|
|
330
|
+
* only where the table fits its width does it clip instead of scroll, and in a narrow window it keeps scrolling
|
|
331
|
+
* sideways, its headings in place (guidelines §4 "File table").
|
|
332
|
+
*/
|
|
333
|
+
export const FILES_VIEW_STYLE = String.raw `
|
|
334
|
+
.fl{max-width:1100px;margin:0 auto;container:files/inline-size}
|
|
335
|
+
.fl .dt-group{position:sticky;top:0;z-index:3;padding:13px 20px;font-size:16px;font-weight:650;letter-spacing:0;color:var(--text)}
|
|
336
|
+
.fl .dt-group-cell{gap:10px}
|
|
337
|
+
.fl .dt-group-dot{width:9px;height:9px}
|
|
338
|
+
.fl .dt-group-count{font-size:14.5px}
|
|
339
|
+
.fl .dt-row a,.fl .dt-row button{scroll-margin-top:64px}
|
|
340
|
+
@container files (min-width:982px){.fl .dt{overflow:clip}}
|
|
341
|
+
.fl .hero{margin-bottom:28px}
|
|
342
|
+
.fl .hero-fact,.fl .hero-action{font-size:34px;line-height:1.15}
|
|
343
|
+
.fl .hero-lead{font-size:16px;max-width:560px}
|
|
344
|
+
.fl-clean .hero-action{color:var(--mint)}
|
|
345
|
+
.fl-filters{flex-direction:column;gap:12px;margin-bottom:18px}
|
|
346
|
+
.js .fl-filters.js-only{display:flex}
|
|
347
|
+
.fl-row{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
|
|
348
|
+
.fl-row>.i18n{max-width:100%}.fl-row .ls{max-width:100%}.fl-row .ls-select{min-width:0}
|
|
349
|
+
.fl-search{flex:1 1 220px;min-width:0;background:var(--card);border:1px solid var(--white-10);border-radius:999px;padding:9px 16px;color:var(--text);font:inherit;font-size:14px;outline:none}
|
|
350
|
+
.fl-search:focus-visible{border-color:var(--coral-50)}
|
|
351
|
+
.fl-pills{display:flex;gap:8px;flex-wrap:wrap}
|
|
352
|
+
.fl-pill{display:flex;align-items:center;gap:8px;border-radius:999px;padding:7px 14px;font:inherit;font-size:14px;font-weight:500;cursor:pointer;border:1px solid var(--white-12);background:transparent;color:var(--text-soft)}
|
|
353
|
+
.fl-pill.fl-on{background:var(--text);color:var(--bg);border-color:var(--text)}
|
|
354
|
+
.fl-count{opacity:.7}
|
|
355
|
+
.fl-clear{font-size:14px;font-weight:600;padding:8px}.fl-clear[hidden]{display:none}
|
|
356
|
+
.fl-kind{display:block;font-size:15px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
357
|
+
.fl-chip{display:inline-flex;margin-top:6px;font-family:var(--mono);font-size:13.5px;font-weight:500;color:var(--text);background:var(--white-07);border:1px solid var(--white-10);border-radius:6px;padding:2px 7px;white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis}
|
|
358
|
+
.fl-plain{font-size:13.5px;font-weight:600;color:var(--text-2)}
|
|
359
|
+
.fl-prot{display:flex;align-items:center;gap:10px;flex-wrap:nowrap}
|
|
360
|
+
.fl-prot[hidden],[data-protected][hidden]{display:none}
|
|
361
|
+
.fw-glyph svg{width:13px;height:13px}
|
|
362
|
+
[data-row-control]{position:relative;z-index:2}
|
|
363
|
+
.fl-act{font-size:13.5px;font-weight:600;white-space:nowrap}.fl-act[hidden]{display:none}
|
|
364
|
+
.fl-act-fix{color:var(--coral-text)}.fl-act-fixed{color:var(--mint)}.fl-act-none{color:var(--text-3)}
|
|
365
|
+
.fl-note{margin:12px 4px 0;font-size:13px;color:var(--text-3)}
|
|
366
|
+
.fl-names{margin-top:24px}.fl-names .fold-body>.dt{margin-top:0}
|
|
367
|
+
.fw{padding:24px 28px 26px}
|
|
368
|
+
.fw-top{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:20px}
|
|
369
|
+
.fw-id{min-width:0}
|
|
370
|
+
.fw-title{margin:0;font-size:24px;line-height:1.2;letter-spacing:-0.015em;font-weight:650;color:var(--text)}
|
|
371
|
+
.fw .fl-chip{margin-top:10px}
|
|
372
|
+
.fw-facts{border-radius:14px;border:1px solid var(--white-09);background:var(--raised)}
|
|
373
|
+
.fw-row{display:grid;grid-template-columns:26px minmax(0,1fr);gap:14px;padding:16px 18px;border-top:1px solid var(--white-06)}
|
|
374
|
+
.fw-row:first-child{border-top:none}
|
|
375
|
+
.fw-glyph{width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:700}
|
|
376
|
+
.fw-coral{background:var(--coral-16);color:var(--coral-text)}.fw-amber{background:var(--amber-16);color:var(--amber)}
|
|
377
|
+
.fw-mint{background:var(--mint-14);color:var(--mint)}.fw-sand{background:var(--sand-16);color:var(--sand)}.fw-blue{background:var(--blue-16);color:var(--blue)}.fw-grey{background:var(--white-06);color:var(--text-2)}
|
|
378
|
+
.fw-q{font-size:13px;font-weight:600;color:var(--text-3);line-height:1.3;margin:4px 0 4px}
|
|
379
|
+
.fw-a{font-size:15px;line-height:1.5;color:var(--text);text-wrap:pretty}
|
|
380
|
+
@media (max-width:640px){.fw{padding:20px 18px 22px}.fw-title{font-size:21px}.fw-row{padding:14px}}
|
|
381
|
+
`;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { matchesGlob } from '../../../core/policy/glob.js';
|
|
2
|
+
import { helperViews } from './helpers.js';
|
|
3
|
+
import { nameOf, ruleKey } from './item-names.js';
|
|
4
|
+
import { toDoItems } from './to-do.js';
|
|
5
|
+
const REACH = { read: 'read', unknown: 'unknown', named: 'name', stopped: 'stopped' };
|
|
6
|
+
const STRENGTH = ['read', 'unknown', 'name', 'stopped', 'changed'];
|
|
7
|
+
export function fileRows(report, items, done, denied) {
|
|
8
|
+
const patternOf = new Map(report.findings.map((finding) => [finding.path, finding.pattern]));
|
|
9
|
+
const reached = new Map();
|
|
10
|
+
const note = (path, access) => {
|
|
11
|
+
const known = reached.get(path);
|
|
12
|
+
if (known === undefined || STRENGTH.indexOf(access) < STRENGTH.indexOf(known.access))
|
|
13
|
+
reached.set(path, { path, access });
|
|
14
|
+
};
|
|
15
|
+
// A file on the to-do list had its contents reach an agent, whichever way the record says it did.
|
|
16
|
+
for (const item of items)
|
|
17
|
+
note(item.path, 'read');
|
|
18
|
+
for (const view of helperViews(report))
|
|
19
|
+
for (const file of view.files)
|
|
20
|
+
note(file.path, REACH[file.reach]);
|
|
21
|
+
const told = new Set(report.findings.filter((finding) => finding.told === true).map((finding) => finding.path));
|
|
22
|
+
const protectionOf = (path) => {
|
|
23
|
+
if (denied === undefined)
|
|
24
|
+
return told.has(path) ? 'told' : 'unknown';
|
|
25
|
+
const forms = [path, path + '/'];
|
|
26
|
+
if (denied.some((pattern) => forms.some((form) => matchesGlob(form, pattern))))
|
|
27
|
+
return 'yes';
|
|
28
|
+
return told.has(path) ? 'told' : 'no';
|
|
29
|
+
};
|
|
30
|
+
const privateRows = [...reached.values()].map(({ path, access }) => {
|
|
31
|
+
const at = items.findIndex((item) => item.path === path);
|
|
32
|
+
return {
|
|
33
|
+
path,
|
|
34
|
+
private: true,
|
|
35
|
+
access,
|
|
36
|
+
protection: protectionOf(path),
|
|
37
|
+
group: at < 0 ? 'none' : done.has(path) ? 'fixed' : 'fix',
|
|
38
|
+
...(at < 0 ? {} : { item: at }),
|
|
39
|
+
kind: ruleKey(patternOf.get(path)) ?? 'rp.item.private',
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
const rank = (row) => (row.group === 'fix' ? 0 : row.group === 'fixed' ? 1 : 2);
|
|
43
|
+
privateRows.sort((a, b) => rank(a) - rank(b) || (a.item ?? Infinity) - (b.item ?? Infinity) || STRENGTH.indexOf(a.access) - STRENGTH.indexOf(b.access));
|
|
44
|
+
const everydayRows = report.everydayFiles.filter((file) => !reached.has(file.path)).map((file) => ({
|
|
45
|
+
path: file.path,
|
|
46
|
+
private: false,
|
|
47
|
+
access: file.how === 'changed' ? 'changed' : file.how === 'stopped' ? 'stopped' : 'read',
|
|
48
|
+
protection: 'na',
|
|
49
|
+
group: 'none',
|
|
50
|
+
kind: kindOfName(nameOf(file.path)),
|
|
51
|
+
}));
|
|
52
|
+
return [...privateRows, ...everydayRows];
|
|
53
|
+
}
|
|
54
|
+
/** A private file the AI only saw the name of: nothing shows it opened it, or that it exists. */
|
|
55
|
+
export function onlyNamed(row) {
|
|
56
|
+
return row.private && row.access === 'name';
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* How many files the Files tab lists, as the report's sidebar counts them: every row but a name only seen. Marks and
|
|
60
|
+
* rules change a row's group and protection, never whether it is a row, so none is needed to count them.
|
|
61
|
+
*/
|
|
62
|
+
export function listedFiles(report) {
|
|
63
|
+
return fileRows(report, toDoItems(report), new Set(), undefined).filter((row) => !onlyNamed(row)).length;
|
|
64
|
+
}
|
|
65
|
+
const SOURCE = /\.(ts|tsx|js|jsx|mjs|cjs|py|go|rb|rs|java|kt|swift|c|h|cpp|hpp|cs|php|sh|vue|svelte|css|scss|html|sql)$/i;
|
|
66
|
+
/** P33's fixed table: what an everyday file is, from its name alone. */
|
|
67
|
+
export function kindOfName(name) {
|
|
68
|
+
if (/^(AGENTS|CLAUDE)\.md$/i.test(name))
|
|
69
|
+
return 'fl.kind.aiNotes';
|
|
70
|
+
if (/\.(md|txt)$/i.test(name))
|
|
71
|
+
return 'fl.kind.notes';
|
|
72
|
+
if (/\.(json|ya?ml|toml)$/i.test(name) || name.startsWith('.'))
|
|
73
|
+
return 'fl.kind.settings';
|
|
74
|
+
if (SOURCE.test(name))
|
|
75
|
+
return 'fl.kind.code';
|
|
76
|
+
return 'fl.kind.file';
|
|
77
|
+
}
|