@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,100 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { FileAccessError } from '../../../ports/file-access-error.js';
|
|
3
|
+
import { LAYOUT, parseSubagentFileName } from '../contract/layout.js';
|
|
4
|
+
import { PROJECTS_DIRECTORY, matchesProject, projectDirectoryName } from '../contract/projects.js';
|
|
5
|
+
/**
|
|
6
|
+
* Lists the sessions Claude Code has kept for a project, so that using the tool does not require typing a path
|
|
7
|
+
* that looks like `~/.claude/projects/-Users-someone-Projects-app/<uuid>`.
|
|
8
|
+
*
|
|
9
|
+
* Nothing inside a session is read here: only names, modification times and how many index files each has.
|
|
10
|
+
*/
|
|
11
|
+
export class ClaudeCodeSessionCatalogue {
|
|
12
|
+
#directories;
|
|
13
|
+
#home;
|
|
14
|
+
constructor(directories, home) {
|
|
15
|
+
this.#directories = directories;
|
|
16
|
+
this.#home = home;
|
|
17
|
+
}
|
|
18
|
+
async list(workingDirectory) {
|
|
19
|
+
const root = join(this.#home, ...PROJECTS_DIRECTORY);
|
|
20
|
+
const directory = await this.#directoryFor(root, workingDirectory);
|
|
21
|
+
let entries;
|
|
22
|
+
try {
|
|
23
|
+
entries = await this.#directories.list(directory);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (!(error instanceof FileAccessError))
|
|
27
|
+
throw error;
|
|
28
|
+
// Not found is an answer, not a failure: this project may simply never have been worked on here.
|
|
29
|
+
return { directory, found: false, searched: [{ provider: 'claude-code', directory, found: false }], sessions: [] };
|
|
30
|
+
}
|
|
31
|
+
const sessions = await Promise.all(entries
|
|
32
|
+
.filter((entry) => entry.kind === 'file' && entry.name.endsWith(LAYOUT.transcriptSuffix))
|
|
33
|
+
.map((entry) => this.#summarise(directory, entry.name)));
|
|
34
|
+
return {
|
|
35
|
+
directory,
|
|
36
|
+
found: true,
|
|
37
|
+
searched: [{ provider: 'claude-code', directory, found: true }],
|
|
38
|
+
sessions: sessions.sort((a, b) => b.modifiedAt - a.modifiedAt),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The encoded name first, because it costs nothing when it is right. When it is not - and the rule is
|
|
43
|
+
* inferred from examples, so it will not always be - the stored directories are compared against the working
|
|
44
|
+
* directory instead of trusting the guess.
|
|
45
|
+
*/
|
|
46
|
+
async #directoryFor(root, workingDirectory) {
|
|
47
|
+
const derived = join(root, projectDirectoryName(workingDirectory));
|
|
48
|
+
try {
|
|
49
|
+
if ((await this.#directories.kindOf(derived)) === 'directory')
|
|
50
|
+
return derived;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (!(error instanceof FileAccessError))
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const stored = await this.#directories.list(root);
|
|
58
|
+
const match = stored.find((entry) => entry.kind === 'directory' && matchesProject(entry.name, workingDirectory));
|
|
59
|
+
return match === undefined ? derived : join(root, match.name);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (!(error instanceof FileAccessError))
|
|
63
|
+
throw error;
|
|
64
|
+
return derived;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async #summarise(directory, fileName) {
|
|
68
|
+
const id = fileName.slice(0, -LAYOUT.transcriptSuffix.length);
|
|
69
|
+
const path = join(directory, id);
|
|
70
|
+
return {
|
|
71
|
+
id,
|
|
72
|
+
path,
|
|
73
|
+
modifiedAt: await this.#modifiedAt(join(directory, fileName)),
|
|
74
|
+
delegations: await this.#delegations(join(path, LAYOUT.subagentsDir)),
|
|
75
|
+
provider: 'claude-code',
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
async #modifiedAt(path) {
|
|
79
|
+
try {
|
|
80
|
+
return await this.#directories.modifiedAt(path);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (!(error instanceof FileAccessError))
|
|
84
|
+
throw error;
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** Counted from the index files, which is the one thing that says a session delegated at all. */
|
|
89
|
+
async #delegations(subagents) {
|
|
90
|
+
try {
|
|
91
|
+
const entries = await this.#directories.list(subagents);
|
|
92
|
+
return entries.filter((entry) => parseSubagentFileName(entry.name)?.kind === 'meta').length;
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (!(error instanceof FileAccessError))
|
|
96
|
+
throw error;
|
|
97
|
+
return 0;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { basename, join, resolve } from 'node:path';
|
|
2
|
+
import { FileAccessError } from '../../../ports/file-access-error.js';
|
|
3
|
+
import { byString } from '../../../shared/compare.js';
|
|
4
|
+
import { LAYOUT } from '../contract/layout.js';
|
|
5
|
+
import { CONTRACT_VERSION } from '../contract/version.js';
|
|
6
|
+
import { pairSubagentFiles, splitToolResults } from './session-entries.js';
|
|
7
|
+
export class ClaudeCodeSessionDiscovery {
|
|
8
|
+
#directories;
|
|
9
|
+
constructor(directories) {
|
|
10
|
+
this.#directories = directories;
|
|
11
|
+
}
|
|
12
|
+
async discover(input) {
|
|
13
|
+
const target = resolve(input);
|
|
14
|
+
const sessionDir = target.endsWith(LAYOUT.transcriptSuffix)
|
|
15
|
+
? target.slice(0, -LAYOUT.transcriptSuffix.length)
|
|
16
|
+
: target;
|
|
17
|
+
const [mainTranscript, subagentsListing, toolResultsListing] = await Promise.all([
|
|
18
|
+
this.#presence(sessionDir + LAYOUT.transcriptSuffix, 'file'),
|
|
19
|
+
this.#list(join(sessionDir, LAYOUT.subagentsDir)),
|
|
20
|
+
this.#list(join(sessionDir, LAYOUT.toolResultsDir)),
|
|
21
|
+
]);
|
|
22
|
+
const subagents = pairSubagentFiles(subagentsListing);
|
|
23
|
+
const toolResults = splitToolResults(toolResultsListing);
|
|
24
|
+
return {
|
|
25
|
+
contractVersion: CONTRACT_VERSION,
|
|
26
|
+
sessionId: basename(sessionDir),
|
|
27
|
+
mainTranscript,
|
|
28
|
+
subagentsDir: subagentsListing.presence,
|
|
29
|
+
subagents: subagents.sources,
|
|
30
|
+
toolResultsDir: toolResultsListing.presence,
|
|
31
|
+
toolResultFiles: toolResults.files,
|
|
32
|
+
unrecognised: [...subagents.unrecognised, ...toolResults.unrecognised].sort(byString),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async #presence(path, expected) {
|
|
36
|
+
try {
|
|
37
|
+
const kind = await this.#directories.kindOf(path);
|
|
38
|
+
return kind === expected ? { present: true, path } : { present: false, path, reason: 'wrong-kind' };
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
if (error instanceof FileAccessError)
|
|
42
|
+
return { present: false, path, reason: error.failure };
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// A directory counts as present only once it has been listed: it can exist and still refuse to be read.
|
|
47
|
+
async #list(path) {
|
|
48
|
+
const found = await this.#presence(path, 'directory');
|
|
49
|
+
if (!found.present)
|
|
50
|
+
return { presence: found, entries: [] };
|
|
51
|
+
try {
|
|
52
|
+
return { presence: found, entries: await this.#directories.list(path) };
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (error instanceof FileAccessError) {
|
|
56
|
+
return { presence: { present: false, path, reason: error.failure }, entries: [] };
|
|
57
|
+
}
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { FileAccessError } from '../../../ports/file-access-error.js';
|
|
2
|
+
import { LAYOUT } from '../contract/layout.js';
|
|
3
|
+
import { SESSION_TITLE } from '../contract/session-title.js';
|
|
4
|
+
import { recognitionIn } from './transcript-tail.js';
|
|
5
|
+
/**
|
|
6
|
+
* Reads what a person recognises a session by from the end of its transcript, in one read: the title Claude Code gave
|
|
7
|
+
* it, handed over only once it has passed the redactor, and which way into Claude Code it was held
|
|
8
|
+
* (`.ai/specs/2026-09-27-which-project.md` V4). Nothing else in the transcript is looked at, and nothing is kept.
|
|
9
|
+
*/
|
|
10
|
+
export class ClaudeCodeSessionTitles {
|
|
11
|
+
#dependencies;
|
|
12
|
+
constructor(dependencies) {
|
|
13
|
+
this.#dependencies = dependencies;
|
|
14
|
+
}
|
|
15
|
+
async recognise(session) {
|
|
16
|
+
const { transcripts, redactor } = this.#dependencies;
|
|
17
|
+
let tail;
|
|
18
|
+
try {
|
|
19
|
+
tail = await transcripts.readTail(session.path + LAYOUT.transcriptSuffix, SESSION_TITLE.tailBytes);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (!(error instanceof FileAccessError))
|
|
23
|
+
throw error;
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
return recognitionIn(tail, redactor);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { byString } from '../../../shared/compare.js';
|
|
3
|
+
import { LAYOUT, isToolResultFileName, parseSubagentFileName, subagentFileName } from '../contract/layout.js';
|
|
4
|
+
export function pairSubagentFiles(listing) {
|
|
5
|
+
const found = new Map();
|
|
6
|
+
const unrecognised = [];
|
|
7
|
+
for (const entry of listing.entries) {
|
|
8
|
+
const parsed = entry.kind === 'file' ? parseSubagentFileName(entry.name) : undefined;
|
|
9
|
+
if (parsed === undefined) {
|
|
10
|
+
unrecognised.push(join(LAYOUT.subagentsDir, entry.name));
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
const seen = found.get(parsed.fileId) ?? { transcript: false, meta: false };
|
|
14
|
+
seen[parsed.kind] = true;
|
|
15
|
+
found.set(parsed.fileId, seen);
|
|
16
|
+
}
|
|
17
|
+
const dir = listing.presence.path;
|
|
18
|
+
const sources = [...found]
|
|
19
|
+
.sort(([a], [b]) => byString(a, b))
|
|
20
|
+
.map(([fileId, seen]) => ({
|
|
21
|
+
fileId,
|
|
22
|
+
transcript: listed(dir, subagentFileName(fileId, 'transcript'), seen.transcript),
|
|
23
|
+
meta: listed(dir, subagentFileName(fileId, 'meta'), seen.meta),
|
|
24
|
+
}));
|
|
25
|
+
return { sources, unrecognised };
|
|
26
|
+
}
|
|
27
|
+
export function splitToolResults(listing) {
|
|
28
|
+
const files = [];
|
|
29
|
+
const unrecognised = [];
|
|
30
|
+
for (const entry of listing.entries) {
|
|
31
|
+
if (entry.kind === 'file' && isToolResultFileName(entry.name))
|
|
32
|
+
files.push(entry.name);
|
|
33
|
+
else
|
|
34
|
+
unrecognised.push(join(LAYOUT.toolResultsDir, entry.name));
|
|
35
|
+
}
|
|
36
|
+
return { files: files.sort(byString), unrecognised };
|
|
37
|
+
}
|
|
38
|
+
function listed(dir, name, isPresent) {
|
|
39
|
+
const path = join(dir, name);
|
|
40
|
+
return isPresent ? { present: true, path } : { present: false, path, reason: 'not-found' };
|
|
41
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { parseJsonObject } from '../../../shared/json.js';
|
|
2
|
+
import { oneLine } from '../../../shared/printable.js';
|
|
3
|
+
import { ENTRY_POINT_VALUES } from '../contract/entry-points.js';
|
|
4
|
+
import { FIELDS } from '../contract/fields.js';
|
|
5
|
+
import { SESSION_TITLE } from '../contract/session-title.js';
|
|
6
|
+
/*
|
|
7
|
+
* What the end of a transcript says about the session, read from the text `FileTailReader` hands over. The rules are
|
|
8
|
+
* the same for every part: a record ends at `\n` alone (lesson L010); the first line of a tail is usually cut and the
|
|
9
|
+
* last may still be being written (L008), so a line that does not parse is not a record; and a field counts only on the
|
|
10
|
+
* record itself, never as text quoted inside another record - a prompt that pastes one (L009). A megabyte of tool
|
|
11
|
+
* results is not parsed line by line: a line is parsed only where it names the field it is searched for.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* What a person recognises the session by (`which-project.md` V4): its latest title, only once it has passed the
|
|
15
|
+
* redactor, and which way into Claude Code it was held.
|
|
16
|
+
*/
|
|
17
|
+
export function recognitionIn(tail, redactor) {
|
|
18
|
+
const title = lastTitleIn(tail);
|
|
19
|
+
const entryPoint = lastEntryPointIn(tail);
|
|
20
|
+
return {
|
|
21
|
+
...(title === undefined ? {} : { title: redactor.scan(title) }),
|
|
22
|
+
...(entryPoint === undefined ? {} : { entryPoint }),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** The session's latest title, as one line of plain words: its last `ai-title` record. */
|
|
26
|
+
export function lastTitleIn(tail) {
|
|
27
|
+
for (const record of recordsFromTheEnd(tail, SESSION_TITLE.lineType)) {
|
|
28
|
+
if (record[FIELDS.lineType] !== SESSION_TITLE.lineType)
|
|
29
|
+
continue;
|
|
30
|
+
const title = record[SESSION_TITLE.field];
|
|
31
|
+
if (typeof title !== 'string')
|
|
32
|
+
continue;
|
|
33
|
+
const shown = oneLine(title);
|
|
34
|
+
if (shown !== '')
|
|
35
|
+
return shown;
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Which way into Claude Code the session was started by, from the last record that says so (`entry-points.ts`). A
|
|
41
|
+
* value the contract does not list is `unknown`; a tail with no such record says nothing.
|
|
42
|
+
*/
|
|
43
|
+
export function lastEntryPointIn(tail) {
|
|
44
|
+
for (const record of recordsFromTheEnd(tail, keyOf(FIELDS.entryPoint))) {
|
|
45
|
+
const value = record[FIELDS.entryPoint];
|
|
46
|
+
if (typeof value !== 'string')
|
|
47
|
+
continue;
|
|
48
|
+
const known = Object.keys(ENTRY_POINT_VALUES).find((kind) => ENTRY_POINT_VALUES[kind] === value);
|
|
49
|
+
return known ?? 'unknown';
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The latest working directory the tail's records carry that `accept` takes. One session can carry more than one
|
|
55
|
+
* (contract v12, 14 of 244 tails): which of them names the project is the caller's to decide by the project's directory,
|
|
56
|
+
* so the latest is never taken on its own. The search stops at the first taken, since nearly every record carries one.
|
|
57
|
+
*/
|
|
58
|
+
export function workingDirectoryIn(tail, accept) {
|
|
59
|
+
for (const record of recordsFromTheEnd(tail, keyOf(FIELDS.workingDirectory))) {
|
|
60
|
+
const value = record[FIELDS.workingDirectory];
|
|
61
|
+
if (typeof value === 'string' && value !== '' && accept(value))
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
/** The tail's whole records, the last first, among the lines holding `mark` - a cheap filter before any parse. */
|
|
67
|
+
function* recordsFromTheEnd(tail, mark) {
|
|
68
|
+
const lines = tail.split('\n');
|
|
69
|
+
for (let at = lines.length - 1; at >= 0; at -= 1) {
|
|
70
|
+
const line = lines[at] ?? '';
|
|
71
|
+
if (!line.includes(mark))
|
|
72
|
+
continue;
|
|
73
|
+
const record = parseJsonObject(line);
|
|
74
|
+
if (record !== undefined)
|
|
75
|
+
yield record;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** A field's name as a record writes it, quoted: `"cwd"`, which a path or a word in the text rarely is. */
|
|
79
|
+
function keyOf(field) {
|
|
80
|
+
return `"${field}"`;
|
|
81
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { MAIN_AGENT_TYPE } from '../../../core/agent.js';
|
|
2
|
+
import { correlate } from '../../../core/correlation/correlate.js';
|
|
3
|
+
import { agentSource, mainSource } from '../../../core/evidence.js';
|
|
4
|
+
import { FileAccessError } from '../../../ports/file-access-error.js';
|
|
5
|
+
import { parseJsonObject } from '../../../shared/json.js';
|
|
6
|
+
import { FIELDS } from '../contract/fields.js';
|
|
7
|
+
import { readDelegationIndex } from './delegation-index.js';
|
|
8
|
+
import { callsIn, delegationTextIn, deliveriesIn, handbackIn, isDelegation, messagesIn, resultsIn } from './transcript-scan.js';
|
|
9
|
+
/**
|
|
10
|
+
* Reads a Claude Code session into the core's model. Everything format-specific stops here: what a record holds
|
|
11
|
+
* comes from the contract, and what belongs with what comes from `correlate`.
|
|
12
|
+
*/
|
|
13
|
+
export class ClaudeCodeSessionSource {
|
|
14
|
+
#discovery;
|
|
15
|
+
#files;
|
|
16
|
+
constructor(dependencies) {
|
|
17
|
+
this.#discovery = dependencies.discovery;
|
|
18
|
+
this.#files = dependencies.files;
|
|
19
|
+
}
|
|
20
|
+
async read(input) {
|
|
21
|
+
return correlate(await this.#collect(await this.#discovery.discover(input)));
|
|
22
|
+
}
|
|
23
|
+
async #collect(session) {
|
|
24
|
+
const collected = {
|
|
25
|
+
agents: [{ id: session.sessionId, type: MAIN_AGENT_TYPE, depth: 0 }],
|
|
26
|
+
calls: [],
|
|
27
|
+
results: [],
|
|
28
|
+
delegations: [],
|
|
29
|
+
delegationIndex: [],
|
|
30
|
+
messages: [],
|
|
31
|
+
deliveredReports: [],
|
|
32
|
+
gaps: [],
|
|
33
|
+
workingDirectories: new Set(),
|
|
34
|
+
spilledFiles: new Set(session.toolResultFiles),
|
|
35
|
+
// Absent is normal - a session that spilled nothing has no such directory. Present but unusable is not.
|
|
36
|
+
spilledFilesKnown: session.toolResultsDir.present || session.toolResultsDir.reason === 'not-found',
|
|
37
|
+
};
|
|
38
|
+
if (!collected.spilledFilesKnown)
|
|
39
|
+
collected.gaps.push({ kind: 'source-missing' });
|
|
40
|
+
if (session.mainTranscript.present) {
|
|
41
|
+
await this.#scan(session.mainTranscript.path, session.sessionId, mainSource(), collected);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Not just a missing source: without the main transcript there is no session to report on.
|
|
45
|
+
collected.gaps.push({ kind: 'session-missing' });
|
|
46
|
+
}
|
|
47
|
+
for (const subagent of session.subagents) {
|
|
48
|
+
await this.#collectSubagent(subagent, collected);
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
sessionId: session.sessionId,
|
|
52
|
+
provider: 'claude-code',
|
|
53
|
+
agents: collected.agents,
|
|
54
|
+
calls: collected.calls,
|
|
55
|
+
results: collected.results,
|
|
56
|
+
delegations: collected.delegations,
|
|
57
|
+
delegationIndex: collected.delegationIndex,
|
|
58
|
+
messages: collected.messages,
|
|
59
|
+
deliveredReports: collected.deliveredReports,
|
|
60
|
+
workingDirectories: [...collected.workingDirectories],
|
|
61
|
+
// Claude Code records none of these apart from what is above: said as none, never left out
|
|
62
|
+
// (`2026-09-27-what-codex-wrote.md` §4.G). Its capabilities are those its contract measured, not declared per file.
|
|
63
|
+
agentReports: [],
|
|
64
|
+
followUps: [],
|
|
65
|
+
followUpIndex: [],
|
|
66
|
+
turns: [],
|
|
67
|
+
reviews: [],
|
|
68
|
+
contexts: [],
|
|
69
|
+
deliveries: [],
|
|
70
|
+
capabilities: [],
|
|
71
|
+
gaps: collected.gaps,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async #collectSubagent(subagent, collected) {
|
|
75
|
+
const agentId = subagent.fileId;
|
|
76
|
+
const entry = subagent.meta.present ? await this.#readIndexEntry(subagent.meta.path, agentId, collected) : undefined;
|
|
77
|
+
if (!subagent.meta.present)
|
|
78
|
+
collected.gaps.push({ kind: 'source-missing', agentId });
|
|
79
|
+
collected.agents.push({
|
|
80
|
+
id: agentId,
|
|
81
|
+
...(entry?.requestedType === undefined ? {} : { type: entry.requestedType }),
|
|
82
|
+
...(entry?.depth === undefined ? {} : { depth: entry.depth }),
|
|
83
|
+
...(entry?.callId === undefined ? {} : { startedBy: entry.callId }),
|
|
84
|
+
});
|
|
85
|
+
if (entry?.callId !== undefined) {
|
|
86
|
+
collected.delegationIndex.push({
|
|
87
|
+
callId: entry.callId,
|
|
88
|
+
agentId,
|
|
89
|
+
...(entry.requestedType === undefined ? {} : { requestedType: entry.requestedType }),
|
|
90
|
+
...(entry.depth === undefined ? {} : { depth: entry.depth }),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (subagent.transcript.present) {
|
|
94
|
+
await this.#scan(subagent.transcript.path, agentId, agentSource(agentId), collected, entry?.callId);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// The delegation still happened; only its actions are unknown. Saying "no actions" beats dropping it.
|
|
98
|
+
collected.gaps.push({ kind: 'source-missing', agentId });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async #readIndexEntry(path, agentId, collected) {
|
|
102
|
+
let text;
|
|
103
|
+
try {
|
|
104
|
+
text = await this.#files.readText(path);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
if (!(error instanceof FileAccessError))
|
|
108
|
+
throw error;
|
|
109
|
+
collected.gaps.push({ kind: 'source-missing', agentId });
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
const entry = readDelegationIndex(text);
|
|
113
|
+
if (entry === undefined)
|
|
114
|
+
collected.gaps.push({ kind: 'record-damaged', agentId });
|
|
115
|
+
return entry;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* `answers` is the delegation this transcript belongs to, when it is a subagent's. A report handed back through
|
|
119
|
+
* a call names no delegation of its own (D9), so this is the join: the words answer the call that started the
|
|
120
|
+
* agent whose transcript they are on.
|
|
121
|
+
*/
|
|
122
|
+
async #scan(path, agentId, source, collected, answers) {
|
|
123
|
+
let record = 0;
|
|
124
|
+
let sequence = 0;
|
|
125
|
+
try {
|
|
126
|
+
for await (const raw of this.#files.readLines(path)) {
|
|
127
|
+
if (raw.trim() === '')
|
|
128
|
+
continue;
|
|
129
|
+
record += 1;
|
|
130
|
+
const json = parseJsonObject(raw);
|
|
131
|
+
if (json === undefined) {
|
|
132
|
+
collected.gaps.push({ kind: 'record-damaged', agentId });
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const workingDirectory = json[FIELDS.workingDirectory];
|
|
136
|
+
if (typeof workingDirectory === 'string')
|
|
137
|
+
collected.workingDirectories.add(workingDirectory);
|
|
138
|
+
// When the line was written, for display only: a value that does not parse is no time, never a guessed one.
|
|
139
|
+
const stamp = json[FIELDS.recordedAt];
|
|
140
|
+
const at = typeof stamp === 'string' ? Date.parse(stamp) : Number.NaN;
|
|
141
|
+
const evidence = { source, record, ...(Number.isFinite(at) ? { at } : {}) };
|
|
142
|
+
for (const call of callsIn(json)) {
|
|
143
|
+
sequence += 1;
|
|
144
|
+
collected.calls.push({
|
|
145
|
+
id: call.id,
|
|
146
|
+
agentId,
|
|
147
|
+
sequence,
|
|
148
|
+
toolName: call.toolName,
|
|
149
|
+
input: call.input,
|
|
150
|
+
targets: call.targets,
|
|
151
|
+
commands: call.commands,
|
|
152
|
+
resultShape: call.resultShape,
|
|
153
|
+
toolKnown: call.toolKnown,
|
|
154
|
+
...(call.written === undefined ? {} : { written: call.written }),
|
|
155
|
+
...(call.printsMatches === true ? { printsMatches: true } : {}),
|
|
156
|
+
evidence,
|
|
157
|
+
});
|
|
158
|
+
if (isDelegation(call)) {
|
|
159
|
+
collected.delegations.push({ callId: call.id, parentAgentId: agentId, ...delegationTextIn(call), evidence });
|
|
160
|
+
}
|
|
161
|
+
const handback = handbackIn(call);
|
|
162
|
+
if (handback !== undefined && answers !== undefined) {
|
|
163
|
+
collected.deliveredReports.push({ callId: answers, content: handback, evidence });
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// A text or reasoning block is read whole: nothing of it is held back by the record.
|
|
167
|
+
for (const message of messagesIn(json))
|
|
168
|
+
collected.messages.push({ agentId, ...message, completeness: 'complete', evidence });
|
|
169
|
+
for (const delivery of deliveriesIn(json)) {
|
|
170
|
+
collected.deliveredReports.push({ callId: delivery.callId, content: delivery.text, evidence });
|
|
171
|
+
}
|
|
172
|
+
const scanned = resultsIn(json);
|
|
173
|
+
for (const result of scanned.results) {
|
|
174
|
+
const missing = collected.spilledFilesKnown && result.spilledFiles.some((name) => !collected.spilledFiles.has(name));
|
|
175
|
+
collected.results.push({
|
|
176
|
+
callId: result.callId,
|
|
177
|
+
...(result.content === undefined ? {} : { content: result.content }),
|
|
178
|
+
...(result.denial === undefined ? {} : { denial: result.denial }),
|
|
179
|
+
...(missing ? { spilledResultMissing: true } : {}),
|
|
180
|
+
...(scanned.denialUnattributed ? { attributionAmbiguous: true } : {}),
|
|
181
|
+
...(result.launchNotice === true ? { launchNotice: true } : {}),
|
|
182
|
+
// A tool_result is the message the calling agent's model was handed, so it is that stage, whole as recorded. A
|
|
183
|
+
// spilled result keeps its own notice and gap, as before.
|
|
184
|
+
stage: 'model',
|
|
185
|
+
completeness: 'complete',
|
|
186
|
+
evidence,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
if (!(error instanceof FileAccessError))
|
|
193
|
+
throw error;
|
|
194
|
+
collected.gaps.push({ kind: 'source-missing', agentId });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { parseJsonObject } from '../../../shared/json.js';
|
|
2
|
+
import { META_FIELD } from '../contract/fields.js';
|
|
3
|
+
export function readDelegationIndex(text) {
|
|
4
|
+
const meta = parseJsonObject(text);
|
|
5
|
+
if (meta === undefined)
|
|
6
|
+
return undefined;
|
|
7
|
+
const callId = meta[META_FIELD.toolUseId];
|
|
8
|
+
const requestedType = meta[META_FIELD.agentType];
|
|
9
|
+
const depth = meta[META_FIELD.spawnDepth];
|
|
10
|
+
return {
|
|
11
|
+
...(typeof callId === 'string' ? { callId } : {}),
|
|
12
|
+
...(typeof requestedType === 'string' ? { requestedType } : {}),
|
|
13
|
+
...(typeof depth === 'number' ? { depth } : {}),
|
|
14
|
+
};
|
|
15
|
+
}
|