@songsid/agend 2.3.0-beta.8 → 2.3.0
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/README.md +16 -8
- package/README.zh-TW.md +16 -8
- package/dist/adapter-world.js.map +1 -1
- package/dist/agend-home.d.ts +5 -0
- package/dist/agend-home.js +7 -0
- package/dist/agend-home.js.map +1 -0
- package/dist/agent-cli-instructions.md +9 -2
- package/dist/agent-cli.js +44 -0
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.d.ts +9 -0
- package/dist/agent-endpoint.js +23 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-file-read.js +1 -1
- package/dist/agent-file-read.js.map +1 -1
- package/dist/agent-whats-new.d.ts +16 -0
- package/dist/agent-whats-new.js +54 -11
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/apply-job.js.map +1 -1
- package/dist/atomic-write.js.map +1 -1
- package/dist/auth-api.d.ts +12 -0
- package/dist/auth-api.js +77 -22
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/authority-state.d.ts +4 -0
- package/dist/authority/authority-state.js +17 -8
- package/dist/authority/authority-state.js.map +1 -1
- package/dist/authority/session-authorizations.js.map +1 -1
- package/dist/authority/web-authority.d.ts +16 -8
- package/dist/authority/web-authority.js +19 -5
- package/dist/authority/web-authority.js.map +1 -1
- package/dist/backend/antigravity.d.ts +2 -2
- package/dist/backend/antigravity.js +2 -1
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-code.js +13 -4
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-metadata.d.ts +8 -0
- package/dist/backend/codex-metadata.js +74 -17
- package/dist/backend/codex-metadata.js.map +1 -1
- package/dist/backend/codex-package.d.ts +30 -0
- package/dist/backend/codex-package.js +133 -0
- package/dist/backend/codex-package.js.map +1 -0
- package/dist/backend/codex-session-lookup.js.map +1 -1
- package/dist/backend/codex.d.ts +2 -0
- package/dist/backend/codex.js +25 -5
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/credential-profile.d.ts +2 -0
- package/dist/backend/credential-profile.js +2 -0
- package/dist/backend/credential-profile.js.map +1 -1
- package/dist/backend/effort-metadata.js.map +1 -1
- package/dist/backend/grok.js +58 -3
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro-engine-ledger.js.map +1 -1
- package/dist/backend/kiro-kas-store.js.map +1 -1
- package/dist/backend/kiro-v2-store.js.map +1 -1
- package/dist/backend/kiro-v3-identity.js.map +1 -1
- package/dist/backend/kiro.d.ts +9 -1
- package/dist/backend/kiro.js +102 -1
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/launch-effort.js.map +1 -1
- package/dist/backend/mock.js.map +1 -1
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/opencode-permission.js +1 -1
- package/dist/backend/opencode-permission.js.map +1 -1
- package/dist/backend/opencode.js +2 -1
- package/dist/backend/opencode.js.map +1 -1
- package/dist/backend/session-signals.js.map +1 -1
- package/dist/backend-availability.js.map +1 -1
- package/dist/backend-command.d.ts +2 -0
- package/dist/backend-command.js +3 -1
- package/dist/backend-command.js.map +1 -1
- package/dist/backend-outage.js.map +1 -1
- package/dist/binary-probe.js +1 -1
- package/dist/binary-probe.js.map +1 -1
- package/dist/bug-report-cli.d.ts +30 -0
- package/dist/bug-report-cli.js +139 -0
- package/dist/bug-report-cli.js.map +1 -0
- package/dist/bug-report.d.ts +47 -0
- package/dist/bug-report.js +137 -0
- package/dist/bug-report.js.map +1 -0
- package/dist/bundled-skills.d.ts +18 -0
- package/dist/bundled-skills.js +38 -0
- package/dist/bundled-skills.js.map +1 -0
- package/dist/cache-service.js +1 -1
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/adapters/discord-client-retirement.d.ts +5 -0
- package/dist/channel/adapters/discord-client-retirement.js +57 -0
- package/dist/channel/adapters/discord-client-retirement.js.map +1 -0
- package/dist/channel/adapters/discord.d.ts +4 -0
- package/dist/channel/adapters/discord.js +57 -12
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +6 -0
- package/dist/channel/adapters/telegram.js +54 -14
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-server.js +21 -4
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/channel/mcp-tools.d.ts +3 -1
- package/dist/channel/mcp-tools.js +43 -6
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/message-queue.js.map +1 -1
- package/dist/channel/sticker-download.js.map +1 -1
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/child-process.d.ts +21 -0
- package/dist/child-process.js +54 -0
- package/dist/child-process.js.map +1 -0
- package/dist/classic-channel-manager.js +3 -2
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli-entry.js.map +1 -1
- package/dist/cli-flags.js.map +1 -1
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +443 -311
- package/dist/cli.js.map +1 -1
- package/dist/command-table.d.ts +1 -1
- package/dist/command-table.js +1 -1
- package/dist/command-table.js.map +1 -1
- package/dist/compact-watch.js.map +1 -1
- package/dist/completion-install.js.map +1 -1
- package/dist/completion.js.map +1 -1
- package/dist/config-validator.d.ts +6 -0
- package/dist/config-validator.js +81 -8
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +15 -3
- package/dist/config.js +41 -10
- package/dist/config.js.map +1 -1
- package/dist/connection-secrets.js.map +1 -1
- package/dist/context-guardian.js.map +1 -1
- package/dist/coredump-filter.js.map +1 -1
- package/dist/cpu-profile.js.map +1 -1
- package/dist/cross-instance-envelope.js.map +1 -1
- package/dist/cross-instance-notice.d.ts +7 -0
- package/dist/cross-instance-notice.js +10 -0
- package/dist/cross-instance-notice.js.map +1 -1
- package/dist/daemon.d.ts +39 -1
- package/dist/daemon.js +234 -15
- package/dist/daemon.js.map +1 -1
- package/dist/daily-summary.js.map +1 -1
- package/dist/darwin-memory.js +1 -1
- package/dist/darwin-memory.js.map +1 -1
- package/dist/dashboard-live.d.ts +8 -0
- package/dist/dashboard-live.js +35 -0
- package/dist/dashboard-live.js.map +1 -0
- package/dist/dashboard-permissions.d.ts +69 -0
- package/dist/dashboard-permissions.js +138 -0
- package/dist/dashboard-permissions.js.map +1 -0
- package/dist/decision-list.d.ts +25 -0
- package/dist/decision-list.js +30 -0
- package/dist/decision-list.js.map +1 -0
- package/dist/delivery-consumed-watch.js.map +1 -1
- package/dist/delivery-outbox.js +5 -0
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/delivery-outbox.test.js.map +1 -1
- package/dist/delivery-reconciliation.test.js.map +1 -1
- package/dist/diagnostic-redaction.d.ts +10 -0
- package/dist/diagnostic-redaction.js +167 -0
- package/dist/diagnostic-redaction.js.map +1 -0
- package/dist/doctor.d.ts +8 -0
- package/dist/doctor.js +52 -0
- package/dist/doctor.js.map +1 -1
- package/dist/e2e-isolation.js.map +1 -1
- package/dist/event-log.js.map +1 -1
- package/dist/export-import.js +7 -5
- package/dist/export-import.js.map +1 -1
- package/dist/fleet-control-audit.js.map +1 -1
- package/dist/fleet-label.js.map +1 -1
- package/dist/fleet-level-config.d.ts +1 -1
- package/dist/fleet-level-config.js +2 -0
- package/dist/fleet-level-config.js.map +1 -1
- package/dist/fleet-lock.js +3 -2
- package/dist/fleet-lock.js.map +1 -1
- package/dist/fleet-manager.d.ts +258 -15
- package/dist/fleet-manager.js +1605 -304
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-process-handlers.d.ts +18 -0
- package/dist/fleet-process-handlers.js +70 -0
- package/dist/fleet-process-handlers.js.map +1 -0
- package/dist/fleet-startup.d.ts +14 -0
- package/dist/fleet-startup.js +30 -0
- package/dist/fleet-startup.js.map +1 -0
- package/dist/fleet-traffic.d.ts +36 -0
- package/dist/fleet-traffic.js +100 -0
- package/dist/fleet-traffic.js.map +1 -1
- package/dist/forged-envelope-scan.d.ts +0 -20
- package/dist/forged-envelope-scan.js +3 -2
- package/dist/forged-envelope-scan.js.map +1 -1
- package/dist/full-restart.d.ts +5 -5
- package/dist/full-restart.js +5 -5
- package/dist/full-restart.js.map +1 -1
- package/dist/general-knowledge/skills/bug-report/SKILL.md +31 -0
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +52 -11
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +5 -1
- package/dist/general-knowledge/skills/fleet-config/SKILL.md +3 -1
- package/dist/general-knowledge/skills/fleet-restart/SKILL.md +8 -9
- package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
- package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
- package/dist/general-knowledge/skills/scheduling/SKILL.md +4 -0
- package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +321 -0
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +28 -4
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +553 -0
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +170 -35
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
- package/dist/general-knowledge/steering/core-rules.md +1 -1
- package/dist/host-memory.js.map +1 -1
- package/dist/idle-gate-log.d.ts +19 -0
- package/dist/idle-gate-log.js +15 -0
- package/dist/idle-gate-log.js.map +1 -0
- package/dist/instance-config-impact.js +25 -4
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +10 -1
- package/dist/instance-lifecycle.js +86 -25
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.d.ts +12 -6
- package/dist/instructions.js +19 -10
- package/dist/instructions.js.map +1 -1
- package/dist/kiro-compact-pane.js.map +1 -1
- package/dist/kiro-db-reader.js.map +1 -1
- package/dist/kiro-engine-status.js.map +1 -1
- package/dist/kiro-log-gate.js.map +1 -1
- package/dist/kiro-transcript-lane.js.map +1 -1
- package/dist/locale.js +428 -20
- package/dist/locale.js.map +1 -1
- package/dist/log-service.js.map +1 -1
- package/dist/log-steps.d.ts +1 -0
- package/dist/log-steps.js +15 -0
- package/dist/log-steps.js.map +1 -1
- package/dist/logger.js +3 -2
- package/dist/logger.js.map +1 -1
- package/dist/login-controller.d.ts +45 -0
- package/dist/login-controller.js +101 -5
- package/dist/login-controller.js.map +1 -1
- package/dist/login-flows.js +1 -1
- package/dist/login-manager.js.map +1 -1
- package/dist/login-shell.js +3 -1
- package/dist/login-shell.js.map +1 -1
- package/dist/ls-attach-resolve.d.ts +96 -0
- package/dist/ls-attach-resolve.js +180 -0
- package/dist/ls-attach-resolve.js.map +1 -0
- package/dist/ls-rows.d.ts +12 -0
- package/dist/ls-rows.js +83 -4
- package/dist/ls-rows.js.map +1 -1
- package/dist/memory-pressure.js.map +1 -1
- package/dist/muse-usage-relay.js.map +1 -1
- package/dist/needs-you-hub.d.ts +98 -1
- package/dist/needs-you-hub.js +313 -44
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you-live.d.ts +5 -2
- package/dist/needs-you-live.js +6 -3
- package/dist/needs-you-live.js.map +1 -1
- package/dist/needs-you.d.ts +68 -3
- package/dist/needs-you.js +38 -4
- package/dist/needs-you.js.map +1 -1
- package/dist/network-family.js.map +1 -1
- package/dist/operator-control-paths.js +3 -4
- package/dist/operator-control-paths.js.map +1 -1
- package/dist/outbound-handlers.d.ts +3 -0
- package/dist/outbound-handlers.js +76 -19
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +112 -64
- package/dist/outbound-schemas.js +39 -12
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/outbox-open-error.js.map +1 -1
- package/dist/pane-context-cache.js.map +1 -1
- package/dist/paths.js.map +1 -1
- package/dist/private-dir.js.map +1 -1
- package/dist/probe-worker-pool.js.map +1 -1
- package/dist/profile-control.js.map +1 -1
- package/dist/prompt-file-ref.js.map +1 -1
- package/dist/provider-probe.js.map +1 -1
- package/dist/provider-secret-registry.d.ts +5 -3
- package/dist/provider-secret-registry.js +8 -2
- package/dist/provider-secret-registry.js.map +1 -1
- package/dist/public-link-auto-open.d.ts +32 -0
- package/dist/public-link-auto-open.js +86 -0
- package/dist/public-link-auto-open.js.map +1 -0
- package/dist/public-link-owner.d.ts +10 -0
- package/dist/public-link-owner.js +36 -0
- package/dist/public-link-owner.js.map +1 -0
- package/dist/public-link-progress.d.ts +12 -1
- package/dist/public-link-progress.js +5 -10
- package/dist/public-link-progress.js.map +1 -1
- package/dist/public-preview.js.map +1 -1
- package/dist/public-tunnel-config.d.ts +11 -0
- package/dist/public-tunnel-config.js +68 -0
- package/dist/public-tunnel-config.js.map +1 -0
- package/dist/public-web-gateway.d.ts +2 -0
- package/dist/public-web-gateway.js +19 -6
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +48 -3
- package/dist/public-web-link.js +177 -51
- package/dist/public-web-link.js.map +1 -1
- package/dist/quickstart-api.d.ts +9 -0
- package/dist/quickstart-api.js +82 -0
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.d.ts +5 -0
- package/dist/quickstart.js +40 -25
- package/dist/quickstart.js.map +1 -1
- package/dist/reply-buttons-controller.js.map +1 -1
- package/dist/reply-dedup.js.map +1 -1
- package/dist/resource-report.js +1 -1
- package/dist/resource-report.js.map +1 -1
- package/dist/restart-guard.js.map +1 -1
- package/dist/restart-progress.d.ts +80 -1
- package/dist/restart-progress.js +306 -21
- package/dist/restart-progress.js.map +1 -1
- package/dist/rollout-index.js.map +1 -1
- package/dist/runtime-cpu-profile.js.map +1 -1
- package/dist/scheduler/db.d.ts +40 -13
- package/dist/scheduler/db.js +123 -89
- package/dist/scheduler/db.js.map +1 -1
- package/dist/scheduler/scheduler.js.map +1 -1
- package/dist/scheduler/task-board-text.d.ts +26 -0
- package/dist/scheduler/task-board-text.js +140 -0
- package/dist/scheduler/task-board-text.js.map +1 -0
- package/dist/scheduler/task-board.d.ts +730 -0
- package/dist/scheduler/task-board.js +2179 -0
- package/dist/scheduler/task-board.js.map +1 -0
- package/dist/scheduler/types.d.ts +6 -1
- package/dist/sd-notify.js +2 -1
- package/dist/sd-notify.js.map +1 -1
- package/dist/search/search-docs.d.ts +58 -0
- package/dist/search/search-docs.js +63 -0
- package/dist/search/search-docs.js.map +1 -0
- package/dist/search/search-index.d.ts +141 -0
- package/dist/search/search-index.js +440 -0
- package/dist/search/search-index.js.map +1 -0
- package/dist/search/search-store.d.ts +122 -0
- package/dist/search/search-store.js +236 -0
- package/dist/search/search-store.js.map +1 -0
- package/dist/search/search-worker.d.ts +1 -0
- package/dist/search/search-worker.js +163 -0
- package/dist/search/search-worker.js.map +1 -0
- package/dist/secret-file.js.map +1 -1
- package/dist/secret-store.d.ts +2 -0
- package/dist/secret-store.js +21 -0
- package/dist/secret-store.js.map +1 -1
- package/dist/service-installer.d.ts +75 -0
- package/dist/service-installer.js +206 -0
- package/dist/service-installer.js.map +1 -1
- package/dist/service-owner.d.ts +44 -0
- package/dist/service-owner.js +48 -0
- package/dist/service-owner.js.map +1 -0
- package/dist/service-plan.d.ts +39 -2
- package/dist/service-plan.js +188 -6
- package/dist/service-plan.js.map +1 -1
- package/dist/session-oom.d.ts +21 -0
- package/dist/session-oom.js +139 -0
- package/dist/session-oom.js.map +1 -0
- package/dist/settings-api.d.ts +13 -0
- package/dist/settings-api.js +73 -12
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-baseline.js.map +1 -1
- package/dist/settings-change.d.ts +5 -0
- package/dist/settings-change.js +167 -6
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-confirmation.d.ts +9 -1
- package/dist/settings-confirmation.js +18 -8
- package/dist/settings-confirmation.js.map +1 -1
- package/dist/settings-control.js +2 -1
- package/dist/settings-control.js.map +1 -1
- package/dist/settings-effect.js +29 -4
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.d.ts +13 -0
- package/dist/settings-http-confirmation.js +15 -3
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/settings-instance-patch.js +13 -1
- package/dist/settings-instance-patch.js.map +1 -1
- package/dist/settings-request-capability.d.ts +4 -1
- package/dist/settings-request-capability.js +11 -3
- package/dist/settings-request-capability.js.map +1 -1
- package/dist/settings-transaction.js.map +1 -1
- package/dist/setup-auth.d.ts +1 -0
- package/dist/setup-auth.js +2 -1
- package/dist/setup-auth.js.map +1 -1
- package/dist/setup-form.d.ts +1 -1
- package/dist/setup-form.js +23 -7
- package/dist/setup-form.js.map +1 -1
- package/dist/setup-host.d.ts +6 -1
- package/dist/setup-host.js +15 -4
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-wizard.js +6 -3
- package/dist/setup-wizard.js.map +1 -1
- package/dist/spawn-gate.d.ts +5 -0
- package/dist/spawn-gate.js +28 -8
- package/dist/spawn-gate.js.map +1 -1
- package/dist/start-attempt.d.ts +1 -0
- package/dist/start-attempt.js +18 -0
- package/dist/start-attempt.js.map +1 -0
- package/dist/start-failure-notice.d.ts +4 -0
- package/dist/start-failure-notice.js +20 -0
- package/dist/start-failure-notice.js.map +1 -0
- package/dist/start-failure.d.ts +147 -0
- package/dist/start-failure.js +281 -0
- package/dist/start-failure.js.map +1 -0
- package/dist/startup-memory-deadline.d.ts +23 -0
- package/dist/startup-memory-deadline.js +55 -0
- package/dist/startup-memory-deadline.js.map +1 -0
- package/dist/statusline-watcher.js.map +1 -1
- package/dist/storm-window.js.map +1 -1
- package/dist/systemd-peer-bus.js.map +1 -1
- package/dist/target-queue-worker.js.map +1 -1
- package/dist/task-board-summary.d.ts +101 -0
- package/dist/task-board-summary.js +177 -0
- package/dist/task-board-summary.js.map +1 -0
- package/dist/task-board-tool.d.ts +25 -0
- package/dist/task-board-tool.js +155 -0
- package/dist/task-board-tool.js.map +1 -0
- package/dist/task-board-waker.d.ts +51 -0
- package/dist/task-board-waker.js +141 -0
- package/dist/task-board-waker.js.map +1 -0
- package/dist/tips.js.map +1 -1
- package/dist/tmux-control.js +1 -1
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-exec-helper.d.ts +104 -0
- package/dist/tmux-exec-helper.js +412 -0
- package/dist/tmux-exec-helper.js.map +1 -0
- package/dist/tmux-manager.d.ts +1 -0
- package/dist/tmux-manager.js +29 -13
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tmux-read.js +2 -2
- package/dist/tmux-read.js.map +1 -1
- package/dist/tool-permissions.js +9 -42
- package/dist/tool-permissions.js.map +1 -1
- package/dist/tool-progress.js.map +1 -1
- package/dist/topic-archiver.js.map +1 -1
- package/dist/topic-commands.d.ts +13 -0
- package/dist/topic-commands.js +56 -33
- package/dist/topic-commands.js.map +1 -1
- package/dist/topic-link.js.map +1 -1
- package/dist/transcript-delta-reader.js.map +1 -1
- package/dist/transcript-jsonl.js.map +1 -1
- package/dist/transcript-monitor.js +5 -0
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-sources.d.ts +2 -0
- package/dist/transcript-sources.js +4 -0
- package/dist/transcript-sources.js.map +1 -1
- package/dist/tunnel/cloudflared-install.js +3 -1
- package/dist/tunnel/cloudflared-install.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +7 -16
- package/dist/tunnel/cloudflared.js +100 -13
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/lease.js +3 -2
- package/dist/tunnel/lease.js.map +1 -1
- package/dist/tunnel/manager.js.map +1 -1
- package/dist/tunnel/named-diagnostics.d.ts +13 -0
- package/dist/tunnel/named-diagnostics.js +52 -0
- package/dist/tunnel/named-diagnostics.js.map +1 -0
- package/dist/tunnel/public-fetch.js.map +1 -1
- package/dist/tunnel/purpose-lane.js.map +1 -1
- package/dist/tunnel/types.d.ts +4 -1
- package/dist/tunnel/types.js.map +1 -1
- package/dist/types.d.ts +55 -2
- package/dist/ui/app-effects.js +27 -5
- package/dist/ui/app.html +2 -0
- package/dist/ui/backend-signin.js +297 -0
- package/dist/ui/chat-effects.js +15 -7
- package/dist/ui/chat-msg-actions.js +176 -0
- package/dist/ui/chat-render.js +67 -20
- package/dist/ui/chat-store.js +218 -48
- package/dist/ui/chat-strings.js +42 -10
- package/dist/ui/chat-thread.js +249 -23
- package/dist/ui/effect-trial-controller.js +13 -8
- package/dist/ui/effect-trial-offer.js +2 -31
- package/dist/ui/effects-waker.js +2 -0
- package/dist/ui/fleet-canvas-layout.js +13 -4
- package/dist/ui/fleet-canvas.js +120 -43
- package/dist/ui/fleet-office-editor.js +149 -0
- package/dist/ui/fleet-office-model.js +358 -0
- package/dist/ui/fleet-office-pack.js +199 -0
- package/dist/ui/fleet-office-skin.js +474 -0
- package/dist/ui/fleet-office-store.js +49 -0
- package/dist/ui/fleet-office-zones.js +177 -0
- package/dist/ui/fleet-office.js +434 -0
- package/dist/ui/fleet-org.js +21 -8
- package/dist/ui/fleet-route-scene.js +272 -0
- package/dist/ui/fleet-route-worker.js +21 -0
- package/dist/ui/fleet-route.js +88 -0
- package/dist/ui/fleet-task-card.js +436 -0
- package/dist/ui/fleet-task-common.js +482 -0
- package/dist/ui/fleet-task-work.js +107 -0
- package/dist/ui/fleet-tasks.js +569 -0
- package/dist/ui/fleet-traffic.js +227 -45
- package/dist/ui/fleet-usage.js +36 -2
- package/dist/ui/guest-refused.html +41 -0
- package/dist/ui/icons/icon-192.png +0 -0
- package/dist/ui/icons/icon-512.png +0 -0
- package/dist/ui/image-lightbox.js +45 -1
- package/dist/ui/image-zoom.js +242 -0
- package/dist/ui/panel-chat.js +282 -89
- package/dist/ui/panel-details.js +2 -0
- package/dist/ui/panel-fleet.js +32 -71
- package/dist/ui/panel-needs.js +23 -6
- package/dist/ui/panel-settings.js +158 -32
- package/dist/ui/preview-panel.js +2 -1
- package/dist/ui/search-dialog.js +350 -0
- package/dist/ui/settings-appearance.js +170 -10
- package/dist/ui/settings-apply.js +3 -3
- package/dist/ui/settings-confirm.js +7 -2
- package/dist/ui/settings-dialogs.js +46 -21
- package/dist/ui/settings-discord.js +6 -2
- package/dist/ui/settings-guests.js +2 -1
- package/dist/ui/settings-learn.js +1 -0
- package/dist/ui/settings-model.js +51 -18
- package/dist/ui/settings-mods.js +8 -3
- package/dist/ui/settings-owner-effects.js +6 -4
- package/dist/ui/settings-strings.js +180 -6
- package/dist/ui/settings-token.js +3 -1
- package/dist/ui/settings-web-authority.js +13 -5
- package/dist/ui/settings-wizard.js +13 -7
- package/dist/ui/shared/agend-auth.js +3 -1
- package/dist/ui/shared/app-i18n.js +12 -5
- package/dist/ui/shared/app-needs.js +2 -2
- package/dist/ui/shared/app-prefs.js +15 -0
- package/dist/ui/shared/app-route.js +18 -0
- package/dist/ui/shared/app-shell.js +172 -28
- package/dist/ui/shared/app-store.js +3 -2
- package/dist/ui/shared/app-stream.js +7 -2
- package/dist/ui/shared/app-themes.js +116 -1
- package/dist/ui/shared/app.css +681 -54
- package/dist/ui/shared/app.js +9 -1
- package/dist/ui/shared/card-strings.js +4 -0
- package/dist/ui/shared/effect-app-runtime.js +7 -5
- package/dist/ui/shared/effect-chat-runtime.js +2 -7
- package/dist/ui/shared/effect-cursor.js +3 -2
- package/dist/ui/shared/effect-display-metadata.js +39 -0
- package/dist/ui/shared/effect-owner-source.js +8 -1
- package/dist/ui/shared/effect-policy.js +2 -2
- package/dist/ui/shared/effect-registry.js +30 -11
- package/dist/ui/shared/effect-runtime-loader.js +3 -1
- package/dist/ui/shared/effect-stock-snapshot.js +9 -0
- package/dist/ui/shared/effect-stock-trust.js +40 -9
- package/dist/ui/shared/effect-trial-source.js +1 -1
- package/dist/ui/shared/effect-trial-stage.js +27 -21
- package/dist/ui/shared/effect-trial.css +1 -1
- package/dist/ui/shared/feature-flags.js +127 -0
- package/dist/ui/shared/guest-refused.js +35 -0
- package/dist/ui/shared/header-tools.js +2 -2
- package/dist/ui/shared/identity-card.js +26 -8
- package/dist/ui/shared/identity-color.js +17 -10
- package/dist/ui/shared/instance-nav.js +183 -28
- package/dist/ui/shared/owner-css.js +30 -1
- package/dist/ui/shared/panel-view.js +14 -29
- package/dist/ui/shared/text-undo.js +210 -0
- package/dist/ui/shared/tokens.css +13 -3
- package/dist/ui/shared/ui-dialog.js +5 -4
- package/dist/ui/shared/ui-icons.js +4 -0
- package/dist/ui/shared/ui-menu.js +20 -7
- package/dist/ui/shared/ui-toast.js +16 -3
- package/dist/ui/shared/usage-dialog.js +206 -16
- package/dist/ui/shared/view-strings.js +68 -4
- package/dist/ui/shared/web-authorize.js +50 -1
- package/dist/ui/signin.html +2 -0
- package/dist/ui/web-terminal/terminal.css +4 -4
- package/dist/ui/web-terminal/terminal.html +10 -10
- package/dist/ui/web-terminal/terminal.js +58 -12
- package/dist/update-check.js.map +1 -1
- package/dist/update-dispatch.js +1 -1
- package/dist/update-dispatch.js.map +1 -1
- package/dist/update-install.js.map +1 -1
- package/dist/update-launch.d.ts +10 -1
- package/dist/update-launch.js +39 -14
- package/dist/update-launch.js.map +1 -1
- package/dist/update-marker.js.map +1 -1
- package/dist/update-preflight.js +1 -1
- package/dist/update-preflight.js.map +1 -1
- package/dist/update-progress.d.ts +3 -1
- package/dist/update-progress.js +3 -1
- package/dist/update-progress.js.map +1 -1
- package/dist/usage/format-rich.js +6 -3
- package/dist/usage/format-rich.js.map +1 -1
- package/dist/usage/i18n-keys.d.ts +1 -1
- package/dist/usage/i18n-keys.js +2 -1
- package/dist/usage/i18n-keys.js.map +1 -1
- package/dist/usage/i18n.d.ts +13 -1
- package/dist/usage/i18n.js +29 -0
- package/dist/usage/i18n.js.map +1 -1
- package/dist/usage/providers.d.ts +89 -2
- package/dist/usage/providers.js +247 -41
- package/dist/usage/providers.js.map +1 -1
- package/dist/usage/statusline-usage.js.map +1 -1
- package/dist/usage/usage-api.d.ts +5 -1
- package/dist/usage/usage-api.js +185 -58
- package/dist/usage/usage-api.js.map +1 -1
- package/dist/usage-report.js.map +1 -1
- package/dist/usage-rollup.js +1 -1
- package/dist/usage-rollup.js.map +1 -1
- package/dist/user-systemd.d.ts +24 -0
- package/dist/user-systemd.js +75 -0
- package/dist/user-systemd.js.map +1 -0
- package/dist/view-api.d.ts +7 -0
- package/dist/view-api.js +16 -4
- package/dist/view-api.js.map +1 -1
- package/dist/wake-coordinator.js.map +1 -1
- package/dist/web-ambient.js +9 -2
- package/dist/web-ambient.js.map +1 -1
- package/dist/web-api.d.ts +58 -10
- package/dist/web-api.js +1104 -71
- package/dist/web-api.js.map +1 -1
- package/dist/web-app-icon-worker.d.ts +1 -0
- package/dist/web-app-icon-worker.js +16 -0
- package/dist/web-app-icon-worker.js.map +1 -0
- package/dist/web-app-icon.d.ts +109 -0
- package/dist/web-app-icon.js +257 -0
- package/dist/web-app-icon.js.map +1 -0
- package/dist/web-appearance-policy.js.map +1 -1
- package/dist/web-appearance-tools.d.ts +1 -0
- package/dist/web-appearance-tools.js +7 -3
- package/dist/web-appearance-tools.js.map +1 -1
- package/dist/web-appearance-view.js.map +1 -1
- package/dist/web-appearance.d.ts +4 -10
- package/dist/web-appearance.js +7 -4
- package/dist/web-appearance.js.map +1 -1
- package/dist/web-auth.d.ts +8 -4
- package/dist/web-auth.js +33 -21
- package/dist/web-auth.js.map +1 -1
- package/dist/web-backend-login.d.ts +130 -0
- package/dist/web-backend-login.js +225 -0
- package/dist/web-backend-login.js.map +1 -0
- package/dist/web-card.js.map +1 -1
- package/dist/web-channel-echo.js.map +1 -1
- package/dist/web-chat-history.d.ts +118 -8
- package/dist/web-chat-history.js +220 -25
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-commands.d.ts +5 -1
- package/dist/web-commands.js +1 -1
- package/dist/web-commands.js.map +1 -1
- package/dist/web-cookie-names.d.ts +5 -0
- package/dist/web-cookie-names.js +12 -0
- package/dist/web-cookie-names.js.map +1 -0
- package/dist/web-effect-bundle.d.ts +2 -2
- package/dist/web-effect-library.js.map +1 -1
- package/dist/web-effect-playback.js.map +1 -1
- package/dist/web-effect-profiles.d.ts +16 -16
- package/dist/web-effect-profiles.js +3 -2
- package/dist/web-effect-profiles.js.map +1 -1
- package/dist/web-effect-service.js.map +1 -1
- package/dist/web-effect-tools.js.map +1 -1
- package/dist/web-effect-trials.js.map +1 -1
- package/dist/web-effect-upload.js.map +1 -1
- package/dist/web-effect.d.ts +6 -6
- package/dist/web-effect.js.map +1 -1
- package/dist/web-experimental-http.d.ts +2 -0
- package/dist/web-experimental-http.js +12 -0
- package/dist/web-experimental-http.js.map +1 -0
- package/dist/web-experimental.d.ts +11 -0
- package/dist/web-experimental.js +49 -0
- package/dist/web-experimental.js.map +1 -0
- package/dist/web-guest-access.d.ts +4 -2
- package/dist/web-guest-access.js +22 -10
- package/dist/web-guest-access.js.map +1 -1
- package/dist/web-guest-rooms.js.map +1 -1
- package/dist/web-host-guard.d.ts +11 -0
- package/dist/web-host-guard.js +11 -0
- package/dist/web-host-guard.js.map +1 -1
- package/dist/web-icons.d.ts +33 -1
- package/dist/web-icons.js +83 -11
- package/dist/web-icons.js.map +1 -1
- package/dist/web-identity-color.js.map +1 -1
- package/dist/web-image-meta.d.ts +13 -0
- package/dist/web-image-meta.js +62 -0
- package/dist/web-image-meta.js.map +1 -1
- package/dist/web-images.js.map +1 -1
- package/dist/web-libavoid.d.ts +14 -0
- package/dist/web-libavoid.js +46 -0
- package/dist/web-libavoid.js.map +1 -0
- package/dist/web-login.js.map +1 -1
- package/dist/web-mentions.js.map +1 -1
- package/dist/web-mod-agent.js.map +1 -1
- package/dist/web-mod-store.d.ts +2 -0
- package/dist/web-mod-store.js +10 -0
- package/dist/web-mod-store.js.map +1 -1
- package/dist/web-office-store.d.ts +104 -0
- package/dist/web-office-store.js +236 -0
- package/dist/web-office-store.js.map +1 -0
- package/dist/web-owner-css-store.d.ts +44 -1
- package/dist/web-owner-css-store.js +70 -9
- package/dist/web-owner-css-store.js.map +1 -1
- package/dist/web-owner-css.js.map +1 -1
- package/dist/web-png.d.ts +33 -0
- package/dist/web-png.js +329 -0
- package/dist/web-png.js.map +1 -0
- package/dist/web-prefs.d.ts +6 -0
- package/dist/web-prefs.js +29 -3
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +2 -0
- package/dist/web-preview.js +2 -0
- package/dist/web-preview.js.map +1 -1
- package/dist/web-profile.js.map +1 -1
- package/dist/web-reactions.d.ts +35 -0
- package/dist/web-reactions.js +47 -0
- package/dist/web-reactions.js.map +1 -0
- package/dist/web-request-context.d.ts +5 -0
- package/dist/web-request-context.js.map +1 -1
- package/dist/web-returning-device.d.ts +4 -2
- package/dist/web-returning-device.js +13 -6
- package/dist/web-returning-device.js.map +1 -1
- package/dist/web-schedules.js.map +1 -1
- package/dist/web-send-dedupe.d.ts +36 -0
- package/dist/web-send-dedupe.js +69 -0
- package/dist/web-send-dedupe.js.map +1 -0
- package/dist/web-session-authorization.js.map +1 -1
- package/dist/web-session.js +1 -1
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +3 -1
- package/dist/web-settings-patch.js +11 -5
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-settings-tools.d.ts +6 -0
- package/dist/web-settings-tools.js +52 -17
- package/dist/web-settings-tools.js.map +1 -1
- package/dist/web-terminal-http.js +15 -2
- package/dist/web-terminal-http.js.map +1 -1
- package/dist/web-terminal.js +1 -1
- package/dist/web-terminal.js.map +1 -1
- package/dist/web-theme-store.d.ts +2 -2
- package/dist/web-theme-store.js +6 -3
- package/dist/web-theme-store.js.map +1 -1
- package/dist/web-theme.d.ts +29 -0
- package/dist/web-theme.js +89 -1
- package/dist/web-theme.js.map +1 -1
- package/dist/web-upload.d.ts +18 -1
- package/dist/web-upload.js +45 -7
- package/dist/web-upload.js.map +1 -1
- package/dist/web-widget.js.map +1 -1
- package/dist/webhook-emitter.js.map +1 -1
- package/dist/windows-shortcuts.d.ts +78 -0
- package/dist/windows-shortcuts.js +203 -0
- package/dist/windows-shortcuts.js.map +1 -0
- package/dist/workflow-templates/default.md +4 -1
- package/dist/ws-server.js.map +1 -1
- package/dist/yaml-shared-nodes.d.ts +25 -0
- package/dist/yaml-shared-nodes.js +185 -0
- package/dist/yaml-shared-nodes.js.map +1 -0
- package/launcher/agend-install.cjs +828 -0
- package/launcher/install-admission.cjs +4 -39
- package/launcher/postinstall.cjs +14 -12
- package/launcher/private-home.cjs +43 -0
- package/package.json +16 -13
- package/scripts/preinstall-guard.cjs +2 -5
- package/templates/windows-shortcuts.ps1 +181 -0
- package/launcher/old-updater-note.cjs +0 -48
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
// One card of the task board (Fleet › Tasks), in the app's dialog: every field editable in place, the checklist, the
|
|
2
|
+
// moves the person makes (confirm, send back, answer, move, cancel, reopen), its sub tasks, and its comments, progress
|
|
3
|
+
// log and history. Edits carry the version they started from, so saving over an agent's newer write is caught (409):
|
|
4
|
+
// the dialog then shows the newer card with the draft still open, and saving again overwrites on purpose.
|
|
5
|
+
import { html, useEffect, useLayoutEffect, useRef, useState } from "/assets/app-html.js";
|
|
6
|
+
import { t, register } from "/assets/app-i18n.js";
|
|
7
|
+
import { appStore, useStore } from "/assets/app-store.js";
|
|
8
|
+
import { Dialog } from "/assets/ui-dialog.js";
|
|
9
|
+
import { Icon } from "/assets/ui-icons.js";
|
|
10
|
+
import { toast } from "/assets/ui-toast.js";
|
|
11
|
+
import { StatusPill, Who, answerBlocked, askText, boardApi, currentWork, errorText, followsSubs, moveCard, notesForPeople, relTime, wrapUpText } from "./fleet-task-common.js";
|
|
12
|
+
|
|
13
|
+
register("taskcard", {
|
|
14
|
+
en: {
|
|
15
|
+
loading: "Loading…", missing: "There is no card {0}", version: "v{0}", copyLink: "Copy this card's link", linkCopied: "Link copied",
|
|
16
|
+
conflict: "{0} changed while you were editing. The newer card is shown and your edit is still open — save again to overwrite it.",
|
|
17
|
+
moveTo: "Move to…", moveLabel: "Change the status", followsSubs: "It has sub tasks: its status follows them",
|
|
18
|
+
reopen: "Reopen", cancelCard: "Cancel this card", confirmMain: "Confirm the main task",
|
|
19
|
+
assignee: "Assignee", nobody: "Unassigned", unassign: "(unassign)", other: "Other…", otherTitle: "Assign to another instance", otherLabel: "The instance's name",
|
|
20
|
+
change: "Change…", project: "Project", priority: "Priority", size: "Size", review: "Your confirmation", reviewBox: "Stop at review for my confirmation",
|
|
21
|
+
reviewOn: "Stops at review for your confirmation", reviewOff: "Finishes without your confirmation",
|
|
22
|
+
parent: "Main task", deps: "Waits for", none: "None", edit: "Edit", depsTitle: "What {0} waits for", depsLabel: "Card numbers to finish first, separated by commas or spaces (empty: nothing)",
|
|
23
|
+
depWaiting: "Not done yet", depDone: "Done", opened: "Opened by {0} {1} · changed {2}",
|
|
24
|
+
blockedReason: "Blocked on", goal: "Goal", goalHint: "Why, and what done looks like", scope: "Scope", scopeHint: "In: … / Out: …",
|
|
25
|
+
definition: "Definition of done", acceptance: "Acceptance", context: "Context", contextHint: "Paths, related cards, decisions already made",
|
|
26
|
+
state: "State", stateHint: "Done / next / watch out (the assignee keeps it current)", result: "Result", resultHint: "Which files changed and how it was checked",
|
|
27
|
+
empty: "(empty — click to edit)", clickToEdit: "Click to edit", ctrlEnter: "Ctrl+Enter saves", save: "Save", cancel: "Cancel",
|
|
28
|
+
checklistEmpty: "(none yet — click to add)", editList: "Edit the list", onePerLine: "One per line; an item whose text changes is unchecked again", items: "{0}/{1} items",
|
|
29
|
+
subs: "Sub tasks ({0})", quickAdd: "New sub task: type a title and press Enter (small work needs no split)",
|
|
30
|
+
tabComments: "Comments {0}", tabLog: "Progress log {0}", tabHistory: "History", noComments: "No comments yet", noLog: "No progress log yet",
|
|
31
|
+
rejectTag: "Sent back", approveTag: "Confirmed", commentTo: "Comment to {0} (Ctrl+Enter sends)", commentHint: "Comment (Ctrl+Enter sends)", send: "Send",
|
|
32
|
+
evCreated: "opened it", evMoved: "{0} → {1}", evAuto: " (automatic)", evAssigned: "assignee {0} → {1}", evUpdated: "changed {0}", evCommented: "commented", evLogged: "log: {0}",
|
|
33
|
+
fTitle: "title", fGoal: "goal", fScope: "scope", fContext: "context", fState: "state", fResult: "result", fBlockedReason: "blocked reason", fSize: "size",
|
|
34
|
+
fPriority: "priority", fNeedsReview: "needs review", fDependsOn: "dependencies", fAcceptance: "acceptance", fProjectId: "project",
|
|
35
|
+
position: "Position", moveUp: "Move up", moveDown: "Move down",
|
|
36
|
+
dispatcher: "Dispatched by", dispatcherHint: "A blocked card's question goes to them first", dispatcherMe: "Me", dispatcherNone: "Nobody",
|
|
37
|
+
dispatcherPerson: "{0} (a person)", now: "Now", nowNone: "No sub task in progress", fDispatcher: "dispatcher",
|
|
38
|
+
},
|
|
39
|
+
"zh-TW": {
|
|
40
|
+
loading: "載入中…", missing: "找不到 {0}", version: "v{0}", copyLink: "複製這張卡的連結", linkCopied: "已複製連結",
|
|
41
|
+
conflict: "{0} 在你編輯時被改過了。已載入最新內容,你的修改還在,再存一次就會覆蓋。",
|
|
42
|
+
moveTo: "移到…", moveLabel: "改狀態", followsSubs: "有子任務,狀態會跟著子任務自動變化",
|
|
43
|
+
reopen: "重新打開", cancelCard: "取消這張卡", confirmMain: "確認主任務",
|
|
44
|
+
assignee: "負責人", nobody: "沒人負責", unassign: "(不指派)", other: "其他…", otherTitle: "指派給其他 instance", otherLabel: "instance 名稱",
|
|
45
|
+
change: "改…", project: "專案", priority: "優先度", size: "大小", review: "你確認", reviewBox: "做完要停在待確認,等我確認",
|
|
46
|
+
reviewOn: "做完會停在待確認,等你確認", reviewOff: "做完直接完成,不等你確認",
|
|
47
|
+
parent: "主任務", deps: "相依", none: "沒有", edit: "編輯", depsTitle: "{0} 的相依", depsLabel: "要先完成的卡號,用逗號或空白分開(留空=沒有相依)",
|
|
48
|
+
depWaiting: "還沒完成", depDone: "已完成", opened: "{0} 開的・{1}・最後更新 {2}",
|
|
49
|
+
blockedReason: "卡住原因", goal: "目標", goalHint: "為什麼做、做完是什麼樣子", scope: "範圍", scopeHint: "做:…/不做:…",
|
|
50
|
+
definition: "完成定義", acceptance: "驗收條件", context: "背景", contextHint: "檔案路徑、相關卡號、已經做的決定",
|
|
51
|
+
state: "目前狀態", stateHint: "已完成/下一步/注意(負責人會隨時覆寫)", result: "產出", resultHint: "改了哪些檔案、怎麼驗證",
|
|
52
|
+
empty: "(未填,點一下編輯)", clickToEdit: "點一下編輯", ctrlEnter: "Ctrl+Enter 儲存", save: "儲存", cancel: "取消",
|
|
53
|
+
checklistEmpty: "(還沒有,點一下新增)", editList: "編輯清單", onePerLine: "一行一項;改了文字的項目會變回沒勾", items: "{0}/{1} 項",
|
|
54
|
+
subs: "子任務({0})", quickAdd: "新增子任務:輸入標題後按 Enter(小事可以不拆)",
|
|
55
|
+
tabComments: "留言 {0}", tabLog: "進度紀錄 {0}", tabHistory: "變更歷史", noComments: "還沒有留言", noLog: "還沒有進度紀錄",
|
|
56
|
+
rejectTag: "退回", approveTag: "確認", commentTo: "留言給 {0}(Ctrl+Enter 送出)", commentHint: "留言(Ctrl+Enter 送出)", send: "送出",
|
|
57
|
+
evCreated: "開卡", evMoved: "{0}→{1}", evAuto: "(自動)", evAssigned: "負責人 {0}→{1}", evUpdated: "修改{0}", evCommented: "留言", evLogged: "紀錄:{0}",
|
|
58
|
+
fTitle: "標題", fGoal: "目標", fScope: "範圍", fContext: "背景", fState: "目前狀態", fResult: "產出", fBlockedReason: "卡住原因", fSize: "大小",
|
|
59
|
+
fPriority: "優先度", fNeedsReview: "需要確認", fDependsOn: "相依", fAcceptance: "驗收條件", fProjectId: "專案",
|
|
60
|
+
position: "位置", moveUp: "往上移", moveDown: "往下移",
|
|
61
|
+
dispatcher: "派工", dispatcherHint: "卡住要決定的事會先通知派工者", dispatcherMe: "我", dispatcherNone: "(沒有)",
|
|
62
|
+
dispatcherPerson: "{0}(人)", now: "目前", nowNone: "沒有正在進行的子任務", fDispatcher: "派工者",
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const MOVES = ["open", "claimed", "blocked", "review", "done"];
|
|
67
|
+
const LIMIT = { title: 100, goal: 300, scope: 600, context: 1000, state: 500, result: 1000, blockedReason: 400, acceptanceItems: 10 };
|
|
68
|
+
|
|
69
|
+
/** One history line, without who and when. */
|
|
70
|
+
export function describeEvent(ev) {
|
|
71
|
+
const d = ev.data || {};
|
|
72
|
+
switch (ev.type) {
|
|
73
|
+
case "created": return t("taskcard.evCreated");
|
|
74
|
+
case "moved": return `${t("taskcard.evMoved", t(`tasks.${d.from}`), t(`tasks.${d.to}`))}${d.auto ? t("taskcard.evAuto") : ""}${d.reason ? `: ${d.reason}` : ""}`;
|
|
75
|
+
case "assigned": return t("taskcard.evAssigned", d.from || "—", d.to || "—");
|
|
76
|
+
case "updated": return t("taskcard.evUpdated", Object.keys(d.changes || {}).map((k) => fieldName(k)).join(", "));
|
|
77
|
+
case "commented": return t("taskcard.evCommented");
|
|
78
|
+
case "logged": return t("taskcard.evLogged", d.text || "");
|
|
79
|
+
default: return ev.type;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const fieldName = (k) => { const key = `taskcard.f${k[0].toUpperCase()}${k.slice(1)}`; const s = t(key); return s === key ? k : s; };
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* `writable`: false over the public link (the card is shown, nothing on it changes). `place`: up and down in its column,
|
|
86
|
+
* for touch and keyboard (null when it cannot move).
|
|
87
|
+
*/
|
|
88
|
+
export function CardDialog({ id, tick, projects, writable = true, place = null, onClose, onOpen, reloadBoard }) {
|
|
89
|
+
const { instances } = useStore(appStore);
|
|
90
|
+
const [detail, setDetail] = useState(null);
|
|
91
|
+
const [missing, setMissing] = useState(false);
|
|
92
|
+
const [tab, setTab] = useState("comments");
|
|
93
|
+
const seq = useRef(0);
|
|
94
|
+
|
|
95
|
+
async function load() {
|
|
96
|
+
const mine = ++seq.current;
|
|
97
|
+
try {
|
|
98
|
+
const d = await boardApi.card(id);
|
|
99
|
+
if (mine === seq.current) { setDetail(d); setMissing(false); }
|
|
100
|
+
} catch (err) {
|
|
101
|
+
if (mine !== seq.current) return;
|
|
102
|
+
if (err.status === 404 || err.status === 400) setMissing(true);
|
|
103
|
+
else toast(errorText(err), false);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
useEffect(() => { void load(); }, [id, tick]);
|
|
107
|
+
|
|
108
|
+
/** A write and what follows: its notes, the card and the board read again. Resolves "ok", "conflict" or "error". */
|
|
109
|
+
async function run(fn) {
|
|
110
|
+
try {
|
|
111
|
+
const r = await fn();
|
|
112
|
+
for (const n of notesForPeople(r && r.notes)) toast(n);
|
|
113
|
+
await load();
|
|
114
|
+
reloadBoard();
|
|
115
|
+
return "ok";
|
|
116
|
+
} catch (err) {
|
|
117
|
+
const conflict = err.status === 409;
|
|
118
|
+
toast(conflict ? t("taskcard.conflict", id) : errorText(err), false);
|
|
119
|
+
if (conflict) await load();
|
|
120
|
+
return conflict ? "conflict" : "error";
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/** A move from this dialog: one at a time (claimed before the first await), then the card and the board read again. */
|
|
124
|
+
const moving = useRef(false);
|
|
125
|
+
const [busy, setBusy] = useState(false);
|
|
126
|
+
async function moved(start) {
|
|
127
|
+
if (moving.current) return;
|
|
128
|
+
moving.current = true;
|
|
129
|
+
setBusy(true);
|
|
130
|
+
try { const r = await start(); if (r) { await load(); reloadBoard(); } }
|
|
131
|
+
finally { moving.current = false; setBusy(false); }
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (missing || !detail) {
|
|
135
|
+
return html`<${Dialog} title=${id} onClose=${onClose} wide drawer><p class="muted">${missing ? t("taskcard.missing", id) : t("taskcard.loading")}</p></${Dialog}>`;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const { card, parent, children } = detail;
|
|
139
|
+
const isMain = card.kind === "main";
|
|
140
|
+
const derived = followsSubs(card);
|
|
141
|
+
const finished = card.status === "done" || card.status === "cancelled";
|
|
142
|
+
/** `version` guards against overwriting a newer card; null skips it (text typed after a conflict was shown). */
|
|
143
|
+
const save = (patch, version = card.version) => run(() => boardApi.update(card.id, version === null ? patch : { ...patch, version }));
|
|
144
|
+
const names = [...new Set([...instances.map((i) => i.name), card.assignee].filter(Boolean))].sort();
|
|
145
|
+
|
|
146
|
+
async function chooseAssignee(value) {
|
|
147
|
+
if (value === "\u0000other") {
|
|
148
|
+
const name = await askText({ title: t("taskcard.otherTitle"), label: t("taskcard.otherLabel"), required: true });
|
|
149
|
+
if (name) await save({ assignee: name }, null);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
await save({ assignee: value === "\u0000none" ? null : value });
|
|
153
|
+
}
|
|
154
|
+
async function chooseDispatcher(value) {
|
|
155
|
+
await save({ dispatcher: value === "\u0000none" ? null : value === "\u0000me" ? { kind: "person" } : { kind: "instance", name: value } });
|
|
156
|
+
}
|
|
157
|
+
async function editDeps() {
|
|
158
|
+
const text = await askText({ title: t("taskcard.depsTitle", card.id), label: t("taskcard.depsLabel"), initial: card.dependsOn.join(", ") });
|
|
159
|
+
if (text !== null) await save({ dependsOn: text.split(/[\s,,、]+/).filter(Boolean) }, null);
|
|
160
|
+
}
|
|
161
|
+
function copyLink() {
|
|
162
|
+
try {
|
|
163
|
+
const u = new URL(globalThis.location.href);
|
|
164
|
+
u.searchParams.set("card", card.id);
|
|
165
|
+
void navigator.clipboard?.writeText(u.toString()).then(() => toast(t("taskcard.linkCopied")));
|
|
166
|
+
} catch { /* no clipboard */ }
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return html`<${Dialog} title=${`${card.id} · ${t(`tasks.${card.kind}`)}`} onClose=${onClose} wide drawer label=${`${card.id} ${card.title}`}>
|
|
170
|
+
<div class="tc">
|
|
171
|
+
<div class="tc-head">
|
|
172
|
+
${writable ? html`<${InlineTitle} value=${card.title} version=${card.version} onSave=${(title, base) => save({ title }, base)} />` : html`<h3 class="tc-title">${card.title}</h3>`}
|
|
173
|
+
<span class="muted tc-ver">${t("taskcard.version", card.version)}</span>
|
|
174
|
+
<button type="button" class="icon-btn" title=${t("taskcard.copyLink")} aria-label=${t("taskcard.copyLink")} onClick=${copyLink}><${Icon} name="copy" size=${16} /></button>
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
<div class="tc-actions">
|
|
178
|
+
<${StatusPill} status=${card.status} />
|
|
179
|
+
${writable ? html`
|
|
180
|
+
${card.status === "review" ? html`
|
|
181
|
+
<button type="button" class="btn btn-primary btn-sm" disabled=${busy} onClick=${() => moved(() => moveCard(card, "done"))}><${Icon} name="check" size=${14} />${isMain ? t("taskcard.confirmMain") : t("tasks.confirm")}</button>
|
|
182
|
+
<button type="button" class="btn btn-sm" disabled=${busy} onClick=${() => moved(() => moveCard(card, "claimed"))}>${t("tasks.sendBack")}</button>
|
|
183
|
+
${wrapUpText(card) ? html`<span class="tc-hint wrapup">${t("tasks.wrapLine", wrapUpText(card))}</span>` : null}` : null}
|
|
184
|
+
${card.status === "blocked" ? html`<button type="button" class="btn btn-primary btn-sm" disabled=${busy} onClick=${() => moved(() => answerBlocked(card))}>${t("tasks.answer")}</button>` : null}
|
|
185
|
+
${!derived && !finished ? html`<select class="tb-select" value="" aria-label=${t("taskcard.moveLabel")} onChange=${(e) => { const to = e.target.value; e.target.value = ""; if (to) void moved(() => moveCard(card, to)); }} disabled=${busy}>
|
|
186
|
+
<option value="">${t("taskcard.moveTo")}</option>
|
|
187
|
+
${MOVES.filter((s) => s !== card.status).map((s) => html`<option key=${s} value=${s}>${t(`tasks.${s}`)}</option>`)}</select>` : null}
|
|
188
|
+
${derived && !finished && card.status !== "blocked" ? html`<button type="button" class="btn btn-sm" disabled=${busy} onClick=${() => moved(() => moveCard(card, "blocked"))}>${t("tasks.block")}</button>` : null}
|
|
189
|
+
${derived && !finished ? html`<span class="muted tc-hint">${t("taskcard.followsSubs")}</span>` : null}
|
|
190
|
+
<span class="tb-grow"></span>
|
|
191
|
+
${finished
|
|
192
|
+
? html`<button type="button" class="btn btn-ghost btn-sm" disabled=${busy} onClick=${() => moved(() => moveCard(card, card.status === "done" ? "claimed" : "open"))}><${Icon} name="restart" size=${14} />${t("taskcard.reopen")}</button>`
|
|
193
|
+
: html`<button type="button" class="btn btn-ghost btn-sm danger" disabled=${busy} onClick=${() => moved(() => moveCard(card, "cancelled"))}>${t("taskcard.cancelCard")}</button>`}` : null}
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<dl class="tc-meta">
|
|
197
|
+
<dt>${t("taskcard.assignee")}</dt>
|
|
198
|
+
<dd><${Who} name=${card.assignee} empty=${t("taskcard.nobody")} />
|
|
199
|
+
${writable ? html`<select class="tb-select" value="\u0000pick" aria-label=${t("taskcard.assignee")} onChange=${(e) => { const v = e.target.value; e.target.value = "\u0000pick"; void chooseAssignee(v); }}>
|
|
200
|
+
<option value="\u0000pick" disabled hidden>${t("taskcard.change")}</option>
|
|
201
|
+
${card.assignee ? html`<option value="\u0000none">${t("taskcard.unassign")}</option>` : null}
|
|
202
|
+
${names.filter((n) => n !== card.assignee).map((n) => html`<option key=${n} value=${n}>${n}</option>`)}
|
|
203
|
+
<option value="\u0000other">${t("taskcard.other")}</option>
|
|
204
|
+
</select>` : null}</dd>
|
|
205
|
+
${isMain && children.length ? html`<dt>${t("taskcard.now")}</dt><dd>${(() => {
|
|
206
|
+
const now = currentWork(card, children);
|
|
207
|
+
if (!now) return html`<span class="muted">${card.status === "review" ? t("tasks.review") : t("taskcard.nowNone")}</span>`;
|
|
208
|
+
return now.cards.map((c) => html`<button key=${c.id} type="button" class="tc-now" onClick=${() => onOpen(c.id)} title=${c.title}>
|
|
209
|
+
<span class=${`tb-now-label st-${now.tone}`}>${t(now.label)}</span><span class="tb-code">${c.id}</span><span class="tc-child-title">${c.title}</span>
|
|
210
|
+
<${Who} name=${c.assignee} empty=${t("tasks.nobody")} /></button>`);
|
|
211
|
+
})()}</dd>` : null}
|
|
212
|
+
<dt>${t("taskcard.dispatcher")}</dt>
|
|
213
|
+
<dd><span class="tb-who" title=${t("taskcard.dispatcherHint")}>${!card.dispatcher ? t("taskcard.dispatcherNone")
|
|
214
|
+
: card.dispatcher.kind === "person" ? t("taskcard.dispatcherPerson", card.dispatcher.name) : card.dispatcher.name}</span>
|
|
215
|
+
${writable ? html`<select class="tb-select" value="\u0000pick" aria-label=${t("taskcard.dispatcher")} title=${t("taskcard.dispatcherHint")} onChange=${(e) => { const v = e.target.value; e.target.value = "\u0000pick"; void chooseDispatcher(v); }}>
|
|
216
|
+
<option value="\u0000pick" disabled hidden>${t("taskcard.change")}</option>
|
|
217
|
+
<option value="\u0000me">${t("taskcard.dispatcherMe")}</option>
|
|
218
|
+
${card.dispatcher ? html`<option value="\u0000none">${t("taskcard.dispatcherNone")}</option>` : null}
|
|
219
|
+
${names.filter((n) => !(card.dispatcher && card.dispatcher.kind === "instance" && card.dispatcher.name === n)).map((n) => html`<option key=${n} value=${n}>${n}</option>`)}
|
|
220
|
+
</select>` : null}</dd>
|
|
221
|
+
${isMain ? html`<dt>${t("taskcard.project")}</dt>
|
|
222
|
+
<dd>${writable ? html`<select class="tb-select" value=${card.projectId === null ? "" : String(card.projectId)} aria-label=${t("taskcard.project")}
|
|
223
|
+
onChange=${(e) => void save({ projectId: e.target.value === "" ? null : Number(e.target.value) })}>
|
|
224
|
+
<option value="">${t("tasks.noProject")}</option>
|
|
225
|
+
${projects.filter((p) => !p.archived || p.id === card.projectId).map((p) => html`<option key=${p.id} value=${String(p.id)}>${p.name}</option>`)}
|
|
226
|
+
</select>` : html`<span class="tc-value">${card.projectId === null ? t("tasks.noProject") : (projects.find((p) => p.id === card.projectId) || {}).name || "—"}</span>`}</dd>` : null}
|
|
227
|
+
<dt>${t("taskcard.priority")}</dt>
|
|
228
|
+
<dd>${writable ? html`<select class="tb-select" value=${card.priority} aria-label=${t("taskcard.priority")} onChange=${(e) => void save({ priority: e.target.value })}>
|
|
229
|
+
${["urgent", "high", "normal", "low"].map((p) => html`<option key=${p} value=${p}>${t(`tasks.${p}`)}</option>`)}</select>`
|
|
230
|
+
: html`<span class="tc-value">${t(`tasks.${card.priority}`)}</span>`}</dd>
|
|
231
|
+
<dt>${t("taskcard.size")}</dt>
|
|
232
|
+
<dd>${writable ? html`<select class="tb-select" value=${card.size || ""} aria-label=${t("taskcard.size")} onChange=${(e) => void save({ size: e.target.value || null })}>
|
|
233
|
+
<option value="">${t("tasks.sizeNone")}</option>${["S", "M", "L"].map((s) => html`<option key=${s} value=${s}>${t(`tasks.size${s}`)}</option>`)}</select>`
|
|
234
|
+
: html`<span class="tc-value">${card.size ? t(`tasks.size${card.size}`) : t("tasks.sizeNone")}</span>`}</dd>
|
|
235
|
+
<dt>${t("taskcard.review")}</dt>
|
|
236
|
+
<dd>${writable ? html`<label class="tb-check"><input type="checkbox" checked=${card.needsReview} onChange=${(e) => void save({ needsReview: e.target.checked })} />${t("taskcard.reviewBox")}</label>`
|
|
237
|
+
// #2299: read-only (the public link): the values as text, not controls that look usable and are not.
|
|
238
|
+
: html`<span class="tc-value">${t(card.needsReview ? "taskcard.reviewOn" : "taskcard.reviewOff")}</span>`}</dd>
|
|
239
|
+
${parent ? html`<dt>${t("taskcard.parent")}</dt><dd><button type="button" class="tb-link" onClick=${() => onOpen(parent.id)}><span class="tb-code">${parent.id}</span> ${parent.title}</button></dd>` : null}
|
|
240
|
+
<dt>${t("taskcard.deps")}</dt>
|
|
241
|
+
<dd>${card.dependsOn.length ? card.dependsOn.map((d) => html`<button key=${d} type="button" class=${`tc-dep${card.unmetDeps.includes(d) ? " waiting" : ""}`}
|
|
242
|
+
title=${card.unmetDeps.includes(d) ? t("taskcard.depWaiting") : t("taskcard.depDone")} onClick=${() => onOpen(d)}>${d}</button>`) : html`<span class="muted">${t("taskcard.none")}</span>`}
|
|
243
|
+
${writable ? html`<button type="button" class="btn btn-ghost btn-sm" onClick=${editDeps}>${t("taskcard.edit")}</button>` : null}</dd>
|
|
244
|
+
${place && (place.up || place.down) ? html`<dt>${t("taskcard.position")}</dt>
|
|
245
|
+
<dd><button type="button" class="btn btn-ghost btn-sm" disabled=${!place.up} aria-label=${t("taskcard.moveUp")} title=${t("taskcard.moveUp")} onClick=${place.up}><${Icon} name="up" size=${16} /></button>
|
|
246
|
+
<button type="button" class="btn btn-ghost btn-sm" disabled=${!place.down} aria-label=${t("taskcard.moveDown")} title=${t("taskcard.moveDown")} onClick=${place.down}><${Icon} name="down" size=${16} /></button></dd>` : null}
|
|
247
|
+
<dt></dt>
|
|
248
|
+
<dd class="muted">${t("taskcard.opened", card.createdBy, relTime(card.createdAt), relTime(card.updatedAt))}</dd>
|
|
249
|
+
</dl>
|
|
250
|
+
|
|
251
|
+
${card.status === "blocked" ? html`<${Field} title=${t("taskcard.blockedReason")} tone="blocked">
|
|
252
|
+
<${EditableText} readOnly=${!writable} value=${card.blockedReason} limit=${LIMIT.blockedReason} version=${card.version} onSave=${(v, base) => save({ blockedReason: v }, base)} /></${Field}>` : null}
|
|
253
|
+
<${Field} title=${t("taskcard.goal")}><${EditableText} readOnly=${!writable} value=${card.goal} limit=${LIMIT.goal} version=${card.version} placeholder=${t("taskcard.goalHint")} onSave=${(v, base) => save({ goal: v }, base)} /></${Field}>
|
|
254
|
+
${isMain ? html`<${Field} title=${t("taskcard.scope")}><${EditableText} readOnly=${!writable} value=${card.scope} limit=${LIMIT.scope} version=${card.version} placeholder=${t("taskcard.scopeHint")} onSave=${(v, base) => save({ scope: v }, base)} /></${Field}>` : null}
|
|
255
|
+
<${Field} title=${isMain ? t("taskcard.definition") : t("taskcard.acceptance")}>
|
|
256
|
+
<${Checklist} card=${card} readOnly=${!writable} onToggle=${(n, done) => save(done ? { check: [n] } : { uncheck: [n] })} onReplace=${(items, base) => save({ acceptance: items }, base)} /></${Field}>
|
|
257
|
+
<${Field} title=${t("taskcard.context")}><${EditableText} readOnly=${!writable} value=${card.context} limit=${LIMIT.context} version=${card.version} placeholder=${t("taskcard.contextHint")} onSave=${(v, base) => save({ context: v }, base)} /></${Field}>
|
|
258
|
+
<${Field} title=${t("taskcard.state")}><${EditableText} readOnly=${!writable} value=${card.state} limit=${LIMIT.state} version=${card.version} placeholder=${t("taskcard.stateHint")} onSave=${(v, base) => save({ state: v }, base)} /></${Field}>
|
|
259
|
+
<${Field} title=${t("taskcard.result")}><${EditableText} readOnly=${!writable} value=${card.result} limit=${LIMIT.result} version=${card.version} placeholder=${t("taskcard.resultHint")} onSave=${(v, base) => save({ result: v }, base)} /></${Field}>
|
|
260
|
+
|
|
261
|
+
${isMain ? html`<${Field} title=${t("taskcard.subs", children.length)}>
|
|
262
|
+
${children.length ? html`<ul class="tc-children">${children.map((c) => html`<li key=${c.id}><button type="button" onClick=${() => onOpen(c.id)}>
|
|
263
|
+
<${StatusPill} status=${c.status} /><span class="tb-code">${c.id}</span><span class="tc-child-title">${c.title}</span><span class="tb-who">${c.assignee || ""}</span></button></li>`)}</ul>` : null}
|
|
264
|
+
${finished || !writable ? null : html`<${QuickAdd} placeholder=${t("taskcard.quickAdd")} onAdd=${(title) => run(() => boardApi.create({ parent: card.id, title }))} />`}
|
|
265
|
+
</${Field}>` : null}
|
|
266
|
+
|
|
267
|
+
<div class="seg tc-tabs" role="tablist">
|
|
268
|
+
${[["comments", t("taskcard.tabComments", detail.comments.length)], ["log", t("taskcard.tabLog", detail.logs.length)], ["history", t("taskcard.tabHistory")]].map(([k, label]) =>
|
|
269
|
+
html`<button key=${k} type="button" role="tab" aria-selected=${tab === k ? "true" : "false"} class=${`seg-item${tab === k ? " active" : ""}`} onClick=${() => setTab(k)}>${label}</button>`)}
|
|
270
|
+
</div>
|
|
271
|
+
${tab === "comments" ? html`<${Comments} entries=${detail.comments} card=${card} writable=${writable} onSend=${(text) => run(() => boardApi.update(card.id, { comment: text }))} />` : null}
|
|
272
|
+
${tab === "log" ? html`<ul class="tc-feed">${detail.logs.length ? detail.logs.map((e) => html`<li key=${e.id}><span class="muted">${relTime(e.at)}</span> <b>${e.author}</b> ${e.text}</li>`)
|
|
273
|
+
: html`<li class="muted">${t("taskcard.noLog")}</li>`}</ul>` : null}
|
|
274
|
+
${tab === "history" ? html`<ul class="tc-feed">${[...detail.history].reverse().map((ev) => html`<li key=${ev.id}><span class="muted">${relTime(ev.at)}</span> <b>${ev.actor}</b> ${describeEvent(ev)}</li>`)}</ul>` : null}
|
|
275
|
+
</div>
|
|
276
|
+
</${Dialog}>`;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function Field({ title, tone, children }) {
|
|
280
|
+
return html`<section class=${`tc-field${tone ? ` tone-${tone}` : ""}`}><h3>${title}</h3>${children}</section>`;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Which version an edit started from: a save sends it, so an agent's newer write is caught (409). After a conflict
|
|
285
|
+
* the next save of the same draft overwrites on purpose (null: no check).
|
|
286
|
+
*/
|
|
287
|
+
function useEditBase(version) {
|
|
288
|
+
const [base, setBase] = useState(version);
|
|
289
|
+
return {
|
|
290
|
+
start: () => setBase(version),
|
|
291
|
+
current: () => (base === undefined ? version : base),
|
|
292
|
+
afterSave: (outcome) => { if (outcome === "conflict") setBase(null); },
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/** Focus moves into an edit box as it opens (before the next key: Esc must reach the box, not the dialog). */
|
|
297
|
+
function useAutoFocus(open) {
|
|
298
|
+
const ref = useRef(null);
|
|
299
|
+
useLayoutEffect(() => { if (open && ref.current) ref.current.focus(); }, [open]);
|
|
300
|
+
return ref;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Esc leaves the edit, not the dialog. */
|
|
304
|
+
function escapeEdit(e, cancel) {
|
|
305
|
+
if (e.key !== "Escape") return false;
|
|
306
|
+
e.preventDefault();
|
|
307
|
+
e.stopPropagation();
|
|
308
|
+
cancel();
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function InlineTitle({ value, version, onSave }) {
|
|
313
|
+
const [draft, setDraft] = useState(null);
|
|
314
|
+
const base = useEditBase(version);
|
|
315
|
+
const ref = useAutoFocus(draft !== null);
|
|
316
|
+
if (draft === null) {
|
|
317
|
+
return html`<button type="button" class="tc-title" title=${t("taskcard.clickToEdit")} onClick=${() => { setDraft(value); base.start(); }}>${value}</button>`;
|
|
318
|
+
}
|
|
319
|
+
const commit = async () => {
|
|
320
|
+
const v = draft.trim();
|
|
321
|
+
if (!v || v === value) { setDraft(null); return; }
|
|
322
|
+
const outcome = await onSave(v, base.current());
|
|
323
|
+
base.afterSave(outcome);
|
|
324
|
+
if (outcome === "ok") setDraft(null);
|
|
325
|
+
};
|
|
326
|
+
return html`<input class="tc-title-input" value=${draft} maxlength=${LIMIT.title} ref=${ref}
|
|
327
|
+
onInput=${(e) => setDraft(e.target.value)} onBlur=${() => void commit()}
|
|
328
|
+
onKeyDown=${(e) => { if (escapeEdit(e, () => setDraft(null))) return; if (e.key === "Enter") { e.preventDefault(); void commit(); } }} />`;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function EditableText({ value, limit, placeholder, version, readOnly = false, onSave }) {
|
|
332
|
+
const [draft, setDraft] = useState(null);
|
|
333
|
+
const [saving, setSaving] = useState(false);
|
|
334
|
+
const base = useEditBase(version);
|
|
335
|
+
const ref = useAutoFocus(draft !== null);
|
|
336
|
+
if (readOnly) return html`<p class=${`tc-text${value ? "" : " empty"}`}>${value || "—"}</p>`;
|
|
337
|
+
if (draft === null) {
|
|
338
|
+
return html`<button type="button" class=${`tc-text${value ? "" : " empty"}`} title=${t("taskcard.clickToEdit")} onClick=${() => { setDraft(value); base.start(); }}>${value || placeholder || t("taskcard.empty")}</button>`;
|
|
339
|
+
}
|
|
340
|
+
const length = [...draft].length;
|
|
341
|
+
const submit = async () => {
|
|
342
|
+
if (saving) return;
|
|
343
|
+
setSaving(true);
|
|
344
|
+
const outcome = await onSave(draft.trim(), base.current());
|
|
345
|
+
setSaving(false);
|
|
346
|
+
base.afterSave(outcome);
|
|
347
|
+
if (outcome === "ok") setDraft(null);
|
|
348
|
+
};
|
|
349
|
+
return html`<div class="tc-edit">
|
|
350
|
+
<textarea rows=${Math.min(10, Math.max(3, draft.split("\n").length + 1))} value=${draft} ref=${ref}
|
|
351
|
+
onInput=${(e) => setDraft(e.target.value)}
|
|
352
|
+
onKeyDown=${(e) => { if (escapeEdit(e, () => setDraft(null))) return; if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) { e.preventDefault(); void submit(); } }}></textarea>
|
|
353
|
+
<div class="tc-edit-bar">
|
|
354
|
+
<span class=${`tc-counter${length > limit ? " over" : ""}`}>${length}/${limit}</span>
|
|
355
|
+
<span class="muted">${t("taskcard.ctrlEnter")}</span>
|
|
356
|
+
<span class="tb-grow"></span>
|
|
357
|
+
<button type="button" class="btn btn-sm" onClick=${() => setDraft(null)}>${t("taskcard.cancel")}</button>
|
|
358
|
+
<button type="button" class="btn btn-primary btn-sm" disabled=${saving || length > limit} onClick=${submit}>${t("taskcard.save")}</button>
|
|
359
|
+
</div></div>`;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function Checklist({ card, readOnly = false, onToggle, onReplace }) {
|
|
363
|
+
const [draft, setDraft] = useState(null);
|
|
364
|
+
// One tick at a time: each sends the version it saw, so a second tick before the first is saved would be refused.
|
|
365
|
+
// The tick being saved shows as asked meanwhile (the box does not flick back until the card is read again).
|
|
366
|
+
const [ticking, setTicking] = useState(null);
|
|
367
|
+
const tick = async (n, done) => { setTicking({ n, done }); try { await onToggle(n, done); } finally { setTicking(null); } };
|
|
368
|
+
const base = useEditBase(card.version);
|
|
369
|
+
const ref = useAutoFocus(draft !== null);
|
|
370
|
+
const start = (text) => { setDraft(text); base.start(); };
|
|
371
|
+
if (draft !== null) {
|
|
372
|
+
const items = draft.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
373
|
+
const save = async () => {
|
|
374
|
+
const outcome = await onReplace(items, base.current());
|
|
375
|
+
base.afterSave(outcome);
|
|
376
|
+
if (outcome === "ok") setDraft(null);
|
|
377
|
+
};
|
|
378
|
+
return html`<div class="tc-edit">
|
|
379
|
+
<textarea rows=${Math.max(3, items.length + 1)} value=${draft} ref=${ref}
|
|
380
|
+
onInput=${(e) => setDraft(e.target.value)}
|
|
381
|
+
onKeyDown=${(e) => { if (escapeEdit(e, () => setDraft(null))) return; if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) { e.preventDefault(); void save(); } }}></textarea>
|
|
382
|
+
<div class="tc-edit-bar">
|
|
383
|
+
<span class=${`tc-counter${items.length > LIMIT.acceptanceItems ? " over" : ""}`}>${t("taskcard.items", items.length, LIMIT.acceptanceItems)}</span>
|
|
384
|
+
<span class="muted">${t("taskcard.onePerLine")}</span>
|
|
385
|
+
<span class="tb-grow"></span>
|
|
386
|
+
<button type="button" class="btn btn-sm" onClick=${() => setDraft(null)}>${t("taskcard.cancel")}</button>
|
|
387
|
+
<button type="button" class="btn btn-primary btn-sm" disabled=${items.length > LIMIT.acceptanceItems} onClick=${save}>${t("taskcard.save")}</button>
|
|
388
|
+
</div></div>`;
|
|
389
|
+
}
|
|
390
|
+
if (!card.acceptance.length) return readOnly ? html`<p class="tc-text empty">—</p>` : html`<button type="button" class="tc-text empty" onClick=${() => start("")}>${t("taskcard.checklistEmpty")}</button>`;
|
|
391
|
+
return html`<ul class="tc-checklist">${card.acceptance.map((a, i) => html`<li key=${`${i}-${a.text}`}><label class="tb-check">
|
|
392
|
+
<input type="checkbox" checked=${ticking && ticking.n === i + 1 ? ticking.done : a.done} disabled=${readOnly || !!ticking} onChange=${() => void tick(i + 1, !a.done)} /><span class=${a.done ? "done" : ""}>${a.text}</span></label></li>`)}</ul>
|
|
393
|
+
${readOnly ? null : html`<button type="button" class="btn btn-ghost btn-sm" onClick=${() => start(card.acceptance.map((a) => a.text).join("\n"))}>${t("taskcard.editList")}</button>`}`;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function QuickAdd({ placeholder, onAdd }) {
|
|
397
|
+
const [title, setTitle] = useState("");
|
|
398
|
+
const busy = useRef(false);
|
|
399
|
+
return html`<input class="tc-quick-add" value=${title} placeholder=${placeholder} aria-label=${placeholder} maxlength=${LIMIT.title}
|
|
400
|
+
onInput=${(e) => setTitle(e.target.value)}
|
|
401
|
+
onKeyDown=${async (e) => {
|
|
402
|
+
if (e.key !== "Enter" || !title.trim() || busy.current) return;
|
|
403
|
+
e.preventDefault();
|
|
404
|
+
busy.current = true;
|
|
405
|
+
if ((await onAdd(title.trim())) === "ok") setTitle("");
|
|
406
|
+
busy.current = false;
|
|
407
|
+
}} />`;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function Comments({ entries, card, writable = true, onSend }) {
|
|
411
|
+
const [text, setText] = useState("");
|
|
412
|
+
const [sending, setSending] = useState(false);
|
|
413
|
+
const busy = useRef(false);
|
|
414
|
+
const send = async () => {
|
|
415
|
+
if (!text.trim() || busy.current) return;
|
|
416
|
+
busy.current = true;
|
|
417
|
+
setSending(true);
|
|
418
|
+
if ((await onSend(text.trim())) === "ok") setText("");
|
|
419
|
+
setSending(false);
|
|
420
|
+
busy.current = false;
|
|
421
|
+
};
|
|
422
|
+
return html`<div class="tc-comments">
|
|
423
|
+
${entries.length ? null : html`<p class="muted">${t("taskcard.noComments")}</p>`}
|
|
424
|
+
${entries.map((e) => html`<div key=${e.id} class=${`tc-comment${e.authorKind === "person" ? " person" : ""}`}>
|
|
425
|
+
<div class="tc-comment-head"><b>${e.author}</b>
|
|
426
|
+
${e.kind === "reject" ? html`<span class="tb-tag st-blocked">${t("taskcard.rejectTag")}</span>` : null}
|
|
427
|
+
${e.kind === "approve" ? html`<span class="tb-tag st-done">${t("taskcard.approveTag")}</span>` : null}
|
|
428
|
+
<span class="muted">${relTime(e.at)}</span></div>
|
|
429
|
+
<div class="tc-comment-body">${e.text}</div></div>`)}
|
|
430
|
+
${writable ? html`<div class="tc-composer">
|
|
431
|
+
<textarea rows="2" value=${text} placeholder=${card.assignee ? t("taskcard.commentTo", card.assignee) : t("taskcard.commentHint")} aria-label=${t("taskcard.commentHint")}
|
|
432
|
+
onInput=${(e) => setText(e.target.value)}
|
|
433
|
+
onKeyDown=${(e) => { if (e.key === "Escape") { e.preventDefault(); e.stopPropagation(); e.currentTarget.blur(); return; } if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) { e.preventDefault(); void send(); } }}></textarea>
|
|
434
|
+
<button type="button" class="btn btn-primary btn-sm" disabled=${sending || !text.trim()} onClick=${send}>${t("taskcard.send")}</button>
|
|
435
|
+
</div>` : null}</div>`;
|
|
436
|
+
}
|