From d5d03cfd6b8f489fafb5fe0d64acefe52c3991b7 Mon Sep 17 00:00:00 2001 From: Quorafind Date: Tue, 7 Apr 2026 10:44:03 +0800 Subject: [PATCH] docs(v10): self-contained worktree briefs for Phase 1-4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Splits the v10 Phase 1-4 work into 5 self-contained briefs in .v10-worktrees/, one per worktree. Each brief is meant to be handed to a single agent or developer: worktree-a-banners.md — Phase 1 deprecation banners (parallel with B) worktree-b-archiver.md — Phase 1 Archiver pure functions (parallel with A) worktree-c-readonly.md — Phase 2 read-only mode + 10.0.0-beta.1 cut worktree-d-cliff.md — Phase 3 the cliff (5 sub-PRs: D.2 → D.1 → D.3 → D.4 → D.5) worktree-e-cleanup.md — Phase 4 cleanup + calendar-sync v0.1.0 release Each brief includes: - Setup commands (git worktree add, branch off, npm install) - Files to modify and files to create - Numbered task list with calendar estimates - Definition of Done (per worktree) - Conflicts to watch (cross-worktree) - Open questions affecting THIS worktree (subset of the 5 main-plan questions) - "Don't do these things" guardrails The 5 main-plan open questions have been resolved with sensible defaults (documented in .v10-worktrees/README.md). User can override before any worktree commits to a particular answer; most decisions don't kick in until Worktree D, giving a 3-4 week runway. Phase 0 deferred items (TaskView.ts deletion, settings-migration.ts fold) are explicitly assigned to Worktree D sub-PRs (D.4 and D.2 respectively), with full resolution paths in PHASE0_DEFERRED.md. WORKTREE_PLAN.md updated with a header pointer to the new briefs and preserved as the umbrella overview. --- .v10-worktrees/README.md | 88 +++++ .v10-worktrees/worktree-a-banners.md | 234 +++++++++++++ .v10-worktrees/worktree-b-archiver.md | 291 ++++++++++++++++ .v10-worktrees/worktree-c-readonly.md | 233 +++++++++++++ .v10-worktrees/worktree-d-cliff.md | 459 ++++++++++++++++++++++++++ .v10-worktrees/worktree-e-cleanup.md | 308 +++++++++++++++++ WORKTREE_PLAN.md | 13 + 7 files changed, 1626 insertions(+) create mode 100644 .v10-worktrees/README.md create mode 100644 .v10-worktrees/worktree-a-banners.md create mode 100644 .v10-worktrees/worktree-b-archiver.md create mode 100644 .v10-worktrees/worktree-c-readonly.md create mode 100644 .v10-worktrees/worktree-d-cliff.md create mode 100644 .v10-worktrees/worktree-e-cleanup.md diff --git a/.v10-worktrees/README.md b/.v10-worktrees/README.md new file mode 100644 index 00000000..7bf64ad0 --- /dev/null +++ b/.v10-worktrees/README.md @@ -0,0 +1,88 @@ +# Task Genius v10 — Worktree Briefs + +This directory holds **self-contained briefs** for the 5 worktrees that +execute v10 Phase 1-4. Each brief is meant to be handed to a single agent +(or developer) who will create a worktree, do the work, and merge. + +The full v10 plan lives at `~/.claude/plans/dynamic-mixing-pie.md` (in the +user's Claude config). Each brief here references the main plan but is +written to be readable on its own — an agent picking up brief D should not +need to read the entire v10 plan to start working. + +## The 5 worktrees + +| # | Brief | Phase | Branch | Calendar | Depends on | +|---|---|---|---|---|---| +| **A** | [worktree-a-banners.md](./worktree-a-banners.md) | 1 (9.14.0) | `refactor/v10-phase1-banners` | ~1 wk | Phase 0 (✅ done) | +| **B** | [worktree-b-archiver.md](./worktree-b-archiver.md) | 1 (9.14.0) | `refactor/v10-phase1-archiver` | ~1 wk | Phase 0 (✅ done) | +| **C** | [worktree-c-readonly.md](./worktree-c-readonly.md) | 2 (9.15.0) | `refactor/v10-phase2-readonly` | ~1 wk | A merged to master | +| **D** | [worktree-d-cliff.md](./worktree-d-cliff.md) | 3 (10.0.0) | `refactor/v10-phase3-cliff` | ~1 wk | C merged to master | +| **E** | [worktree-e-cleanup.md](./worktree-e-cleanup.md) | 4 (10.0.1) | `refactor/v10-phase4-cleanup` | ~1 wk | D merged to master | + +## How to spawn agents + +**Parallel start (recommended):** spawn agents A and B simultaneously, both +branched off `refactor/v10-phase0`. They modify disjoint files. Once A merges +to master, spawn C. Then D after C, then E after D. + +**Solo execution:** the single-developer path is `A → B → C → D.2 → D.1 → D.3 +→ D.4 → D.5 → E`. The worktree split is informational; you can use one working +tree if you prefer. + +## Phase 0 status (the ground each worktree stands on) + +Phase 0 is **complete** on `refactor/v10-phase0`. 6 commits, 71 new passing +tests, 10 of 12 DoD items checked. The 2 deferred items (delete TaskView.ts, +fold settings-migration.ts into the registry) are documented in +[../PHASE0_DEFERRED.md](../PHASE0_DEFERRED.md) and explicitly assigned to +worktree D sub-PRs (D.4 and D.2 respectively). + +Phase 0 commits on `refactor/v10-phase0`: +- `dd3fe89a` — W0 test infrastructure (buildOrchestrator + InMemoryStorage + localforage mock) +- `1de55f4c` — W2/W2-bis/W3 (onunload race fixed, rebuild last-resort, worker timeouts) +- `fe4c976f` — W4 (typed cache scope map + invariants checker + LocalStorageCache version fix) +- `12481c17` — W1 (MigrationRegistry with version-keyed tombstones) +- `d583e967` — W5 (critical-path integration tests: roundtrip / settingsChange / cache invariants sequence) +- `e90fc537` — Phase 0 docs (PHASE0_DEFERRED.md, WORKTREE_PLAN.md) + +## Decisions resolved (defaults — user can override before any worktree commits) + +The 5 open questions from the main plan have been answered with sensible +defaults so worktrees can start without waiting on more decisions: + +1. **Deprecation list:** ship exactly the 14 features listed in the main plan + (Workflow, Habit, Reward, Timer, Gantt, Quadrant, Timeline Sidebar, + File-as-Task, Holiday detector, Electron quick-capture, 4 quick-capture + modal variants, Working-On view, Flagged view, Habit view). Pull-back can + happen at sub-PR review time. + +2. **Sub-plugin commitment:** YES, 4 new repos + (`task-genius-workflow`, `task-genius-habits`, `task-genius-timer`, + `task-genius-calendar-sync`). Each is small (~3-6k LOC). They share the + same tooling as the main plugin; the boundary is "share vault files, + nothing else" (no DataflowOrchestrator coupling). + +3. **Default hotkeys:** SHIP the 5 proposed bindings + (`Mod+Shift+T` capture, `Mod+Shift+G` open view, `Mod+Shift+I` inbox, + `Mod+Shift+F` forecast, `Mod+Alt+P` priority, `Mod+Enter` mark done on + task line). Document in CHANGELOG that v10 sets defaults for the first + time. Users can opt out via Obsidian's hotkey settings. + +4. **Cliff version:** 9.14 → 9.15 → 10.0 over 4 weeks (the original + proposal). Faster is better; the deprecation period exists to give beta + testers time, not as a UX runway. + +5. **Beta tester recruitment:** pin a GitHub Discussion explicitly recruiting + testers. Don't depend on a pre-existing pool. The Discussion goes up the + day Worktree A starts; recruitment runs in parallel with banner work. + +If the user wants to override any of these, they can do so before the +relevant worktree commits to a particular answer — most decisions come into +play in Worktree D (Phase 3), so the runway is ~3-4 weeks. + +## See also + +- [`../PHASE0_DEFERRED.md`](../PHASE0_DEFERRED.md) — the 2 W6 items deferred from Phase 0 +- [`../WORKTREE_PLAN.md`](../WORKTREE_PLAN.md) — the original umbrella worktree plan (this directory subsumes it; WORKTREE_PLAN.md kept for reference) +- [`../PLAN.md`](../PLAN.md) — the original v10 widgets requirements doc (predates this refactor effort) +- `~/.claude/plans/dynamic-mixing-pie.md` — the full v10 refactor plan (in the user's Claude config) diff --git a/.v10-worktrees/worktree-a-banners.md b/.v10-worktrees/worktree-a-banners.md new file mode 100644 index 00000000..cd6e0c73 --- /dev/null +++ b/.v10-worktrees/worktree-a-banners.md @@ -0,0 +1,234 @@ +# Worktree A — Phase 1 Deprecation Banners (9.14.0) + +## What you're doing + +Task Genius is being slimmed down for v10 (~95k LOC → ~40k LOC). Phase 1 is +the **announce + soft warning** week: deprecated settings tabs get a yellow +banner, the changelog modal auto-opens once on first launch of 9.14.0, and +nothing actually breaks for users yet. This is the gentle on-ramp. + +Your worktree is one of two Phase 1 worktrees that run **in parallel**: +- **Worktree A (this one)** — UI banners + changelog modal (user-facing) +- **Worktree B** — Archiver pure functions (infrastructure for Phase 3) + +A and B touch disjoint files. Both branch off `refactor/v10-phase0`. + +## Phase 0 ground + +You're branching off `refactor/v10-phase0` (already merged-quality, 6 commits, +71 new tests). Phase 0 added the MigrationRegistry, fixed lifecycle hazards, +added cache guardrails, and shipped integration test infrastructure. None of +that affects your work directly — you're touching settings UI files, not +dataflow. + +## Setup + +```bash +# From the main repo root +git fetch +git worktree add ../tg-phase1-banners refactor/v10-phase0 +cd ../tg-phase1-banners +git checkout -b refactor/v10-phase1-banners + +# Verify the integration tests pass on this branch +npm install +npm test -- --testPathPattern="integration/" +# Expect: 70+ passing in the integration namespace +``` + +## Files you'll create + +- `src/components/features/settings/components/DeprecationBanner.ts` — new component (~60 LOC) +- `src/common/deprecation-messages.ts` — centralized i18n strings (~80 LOC) + +## Files you'll modify (14 deprecated tabs + supporting files) + +The 14 deprecated tabs each get a one-line `DeprecationBanner` injection at +the top of their `renderXxxSettingsTab()` function: + +1. `src/components/features/settings/tabs/WorkflowSettingsTab.ts` → "Workflows move to `task-genius-workflow` in v10" +2. `src/components/features/settings/tabs/HabitSettingsTab.ts` → "Habits move to `task-genius-habits`" +3. `src/components/features/settings/tabs/RewardSettingsTab.ts` → "Rewards move to `task-genius-habits`" +4. `src/components/features/settings/tabs/TaskTimerSettingsTab.ts` → "Timer moves to `task-genius-timer`" +5. `src/components/features/settings/tabs/TimelineSidebarSettingsTab.ts` → "Timeline Sidebar removed in v10. Forecast view replaces it." +6. `src/components/features/settings/tabs/IcsSettingsTab.ts` (OAuth/CalDAV section only — read-only ICS stays in main plugin) → "OAuth/CalDAV moves to `task-genius-calendar-sync`" +7. `src/components/features/settings/tabs/IndexSettingsTab.ts` (file-as-task source section) → "File-as-Task source removed in v10" +8. `src/components/features/settings/tabs/DesktopIntegrationSettingsTab.ts` (electron-quick-capture window section) → "Electron quick-capture window removed in v10" +9-12. Sections within the views tab: Gantt, Quadrant, Habit view, Working-On view, Flagged view (5 view-config entries deprecated) +13. Holiday detector toggle (find via `grep -r "holiday-detector" src/components/features/settings/`) +14. AboutSettingsTab — gets a "Deprecations" collapsible at the top + +Plus: +- `src/components/features/settings/index.ts` — export the new banner component +- `src/managers/changelog-manager.ts` — wire to auto-open the v10 announcement on 9.14.0 first launch +- `src/translations/locale/en.ts` — add new strings for banner copy + +## Tasks (in order) + +### Task 1 — Build the DeprecationBanner component (~½ day) + +`src/components/features/settings/components/DeprecationBanner.ts`: + +```ts +export interface DeprecationBannerProps { + tabId: string; + replacementText: string; // e.g. "Workflows move to task-genius-workflow" + exportLabel?: string; // e.g. "Export this section now" + exportAction?: () => Promise | void; + learnMoreUrl?: string; + // Phase 2 will add: readOnly?: boolean +} + +export function renderDeprecationBanner( + containerEl: HTMLElement, + props: DeprecationBannerProps, +): void { + // Yellow background, alert icon, message text, optional Export button, + // optional "Learn more" link. ~60 LOC. CSS class .tg-deprecation-banner. +} +``` + +Add CSS in `src/styles/setting.scss` (or wherever the existing settings styles +live — grep `.task-genius-setting`). + +### Task 2 — Centralize the strings (~½ day) + +`src/common/deprecation-messages.ts`: + +```ts +export const DEPRECATION_MESSAGES = { + workflow: { + bannerText: "Workflows move to the task-genius-workflow plugin in v10. ...", + exportLabel: "Export workflows now", + learnMoreUrl: "https://github.com/.../discussions/...", + }, + habit: { ... }, + // ... 14 total entries +} as const; +``` + +This becomes the single source of truth so locales translate one set of +strings, not 14 spread across tabs. Phase 2 will add more keys here. + +### Task 3 — Wire banners into 14 tabs (~1.5 days) + +For each of the 14 tab files, add a one-line `renderDeprecationBanner(containerEl, ...)` +call at the top of the render function (before any existing content). The +tab continues to function normally; the banner is purely additive. + +For tabs that have a deprecated **section** (not the whole tab) — IcsSettingsTab, +IndexSettingsTab, DesktopIntegrationSettingsTab — render the banner above the +deprecated section, not the whole tab. + +The "Export this section now" button calls a stub from Worktree B's Archiver: + +```ts +import { archiveWorkflows } from "@/migration/v10/Archiver"; // from Worktree B + +exportAction: async () => { + const result = await archiveWorkflows(plugin); + // For Phase 1 we just write to vault — Phase 3 wraps in transactional migration + for (const [path, content] of result.files) { + await plugin.app.vault.create(path, content); + } + new Notice(`Archived ${result.files.size} files to Task Genius Archive/`); +}, +``` + +**Coordination with Worktree B:** if B hasn't merged yet, stub the import as +`async () => { new Notice("Export coming soon"); }` and add a TODO. Do not +block on B. + +### Task 4 — AboutSettingsTab "Deprecations" panel (~½ day) + +`src/components/features/settings/tabs/AboutSettingsTab.ts` — add a collapsible +section at the top of the tab listing all 14 deprecations with one global +"Export everything" button. The button calls all 7 archive functions in +sequence (or sequentially with a progress notice if you want to be fancy). + +### Task 5 — Auto-open v10 announcement on 9.14.0 first launch (~½ day) + +`src/managers/changelog-manager.ts` already auto-opens on version change. +Verify the existing logic and add a one-time announcement modal for 9.14.0 +that links to the pinned GitHub Discussion. Body content goes in +`src/translations/locale/en.ts` (a new key like `v10AnnouncementBody`). + +### Task 6 — Update CHANGELOG.md and create the GitHub Discussion (~½ day, out of repo) + +- Add a `## 9.14.0` section to CHANGELOG.md announcing the v10 deprecations +- Create a pinned GitHub Discussion titled **"Task Genius v10: what's changing + and how to prepare"** with the TL;DR table from the main plan, the archive + folder explanation, sub-plugin install instructions, and an FAQ section +- Pin a thread for beta tester recruitment + +## Definition of Done + +| # | Criterion | How to verify | +|---|---|---| +| 1 | All 14 deprecated tabs/sections show banners in real-vault smoke test | Manual: open Settings, visit each, confirm banner is at the top | +| 2 | Each banner's "Export this section" button creates files in `/Task Genius Archive/
/` | Manual: click each export button, verify the folder appears | +| 3 | Changelog modal auto-opens once on 9.14.0 first launch | Manual: bump manifest.json to 9.14.0, reload plugin, verify modal opens; reload again, verify it does NOT open | +| 4 | AboutSettingsTab has a "Deprecations" collapsible at the top with a global "Export everything" button | Manual | +| 5 | No regression in existing tab rendering (all 25 tabs still render their existing content) | Manual + `npm test` | +| 6 | New strings only in `en.ts`; locale fallback handles other languages | Code review | +| 7 | TypeScript build clean (`npm run build`) | Auto | +| 8 | Phase 0 integration tests still pass | `npm test -- --testPathPattern="integration/"` | +| 9 | CHANGELOG.md updated, GitHub Discussion pinned | Manual | + +## Conflicts to watch + +- **Worktree C (Phase 2)** will modify the same 14 tab files to add read-only + mode. **C cannot start until A is merged to master.** Don't try to run them + in parallel. +- **Worktree D.1 (Phase 3)** will DELETE most of these tabs. The banners get + removed in Phase 3. That's expected — your work is the bridge that gives + users 4 weeks of warning before the deletion. + +## Open questions that affect THIS worktree + +The v10 plan has 5 open questions; defaults are documented in +[`./README.md`](./README.md). The two that touch your work: + +- **Q1 — Deprecation list:** the 14 features listed above are the default. If + the user pulls any back, your task list shrinks accordingly. Wait for + user confirmation if you're about to ship a banner for a feature they + changed their mind about. +- **Q5 — Beta tester recruitment:** the GitHub Discussion goes up when your + worktree starts. If the user doesn't have a tester pool, the Discussion + recruits explicitly. + +The other 3 (sub-plugin commitment, hotkey policy, cliff version) don't +affect this worktree — they kick in for Worktree C and D. + +## Useful existing utilities to reuse + +- `src/managers/changelog-manager.ts` — already supports auto-open on version change (Task 5) +- `src/components/features/changelog/` — ChangelogView component (re-use for the announcement) +- `src/translations/helper.ts` — `t()` translation helper +- The existing `Setting()` chain pattern from any tab file is your model for adding the banner above existing settings + +## Don't do these things + +- **Don't delete any tabs.** Phase 3 owns deletions. Banners are additive only. +- **Don't make any tab read-only.** That's Phase 2 / Worktree C. +- **Don't wire the banners' export action through MigrationRegistry.** That's + Phase 3 / Worktree D.5. For Phase 1, the export is a direct call to the + Archiver function (which Worktree B is building in parallel). +- **Don't touch the dataflow layer.** Your changes are 100% UI. +- **Don't translate strings to non-English locales.** Just `en.ts`. The locale + prune script in Phase 4 (Worktree E) handles parity. +- **Don't migrate any callers off `Orchestrator.onSettingsChange(scopes[])` to + the typed `onSettingsFieldsChanged(fields[])`.** Leave that for Phase 1+ + feature work as features are touched. Your worktree shouldn't even import + the Orchestrator. + +## When you're done + +```bash +# From your worktree +git push origin refactor/v10-phase1-banners +gh pr create --base master --title "feat(settings): deprecation banners (Phase 1, Worktree A)" +``` + +After merge, signal that **Worktree C is unblocked** (it depends on A's +merge to master). diff --git a/.v10-worktrees/worktree-b-archiver.md b/.v10-worktrees/worktree-b-archiver.md new file mode 100644 index 00000000..482ac623 --- /dev/null +++ b/.v10-worktrees/worktree-b-archiver.md @@ -0,0 +1,291 @@ +# Worktree B — Phase 1 Archiver Pure Functions (9.14.0) + +## What you're doing + +Task Genius is being slimmed down for v10. When users upgrade to 10.0.0, +their persistent data for deprecated features (workflows, habits, rewards, +etc.) gets archived to a vault folder so they don't lose it. The archive +folder is also where extracted sub-plugins look for "previous data" on first +install. + +Your job is to build the **pure functions** that produce the archive — the +serialization logic — without any wiring to the UI or the migration system. +That wiring is Phase 3 / Worktree D.5. + +You're running **in parallel with Worktree A** (banners). A modifies UI files, +B modifies new infrastructure files. Zero conflict. + +## Phase 0 ground + +You're branching off `refactor/v10-phase0` (already merged-quality, 6 commits). +Phase 0 added the MigrationRegistry which Phase 3 will use to wrap your +archiver functions in atomic migration steps. You don't need to touch the +registry yourself. + +## Setup + +```bash +git fetch +git worktree add ../tg-phase1-archiver refactor/v10-phase0 +cd ../tg-phase1-archiver +git checkout -b refactor/v10-phase1-archiver + +npm install +npm test -- --testPathPattern="integration/" +# Expect: 70+ passing +``` + +## Files you'll create + +- `src/migration/v10/Archiver.ts` — 7 pure archive functions (~300 LOC) +- `src/migration/v10/index.ts` — barrel export +- `src/migration/v10/types.ts` — shared types (`ArchiveSection`, etc.) +- `src/__tests__/migration/v10/Archiver.test.ts` — fixture-based tests (~250 LOC) +- `src/__tests__/migration/v10/__fixtures__/realistic-settings.ts` — sample settings shapes for the 7 sections + +## Files you will NOT touch + +- `src/index.ts` (Worktree D wires the archiver into onload) +- `src/utils/migration/MigrationRegistry.ts` (Worktree D adds the v10-archive step) +- Any settings tab files (Worktree A injects the export buttons that *call* your functions) +- The DataflowOrchestrator (no dataflow concerns here) + +## Tasks (in order) + +### Task 1 — Define the contract (~½ day) + +`src/migration/v10/types.ts`: + +```ts +/** + * The result of one archive function. Pure data — no I/O happens inside the + * function. The caller is responsible for actually writing files via vault. + */ +export interface ArchiveSection { + /** Section name, e.g. "workflows", "habits", "timer". */ + section: string; + /** Files to write, keyed by relative path under /Task Genius Archive/ */ + files: Map; + /** Human-readable summary for the migration confirmation modal. */ + summary: string; + /** Optional structured count for the modal: {workflows: 47, habits: 12} */ + itemCount: number; +} + +export interface ArchiveManifest { + version: string; // plugin version that produced this archive + exportedAt: number; // unix epoch ms + sections: Array<{ + section: string; + itemCount: number; + files: string[]; // relative paths + }>; +} +``` + +### Task 2 — Implement the 7 archive functions (~3-4 days) + +`src/migration/v10/Archiver.ts`: + +```ts +import type TaskProgressBarPlugin from "@/index"; +import type { ArchiveSection } from "./types"; + +export async function archiveWorkflows( + plugin: TaskProgressBarPlugin, +): Promise { + const workflows = plugin.settings.workflow?.definitions ?? []; + const files = new Map(); + + // workflows.json — raw shape, round-trippable + files.set("workflows/workflows.json", JSON.stringify( + { version: "v10-archive-1", definitions: workflows }, + null, + 2, + )); + + // workflows.md — human-readable summary, one workflow per H2 + const md = renderWorkflowsMarkdown(workflows); + files.set("workflows/workflows.md", md); + + return { + section: "workflows", + files, + summary: `${workflows.length} workflow definition${workflows.length === 1 ? "" : "s"}`, + itemCount: workflows.length, + }; +} + +// ... 6 more functions +``` + +The 7 functions to implement (each takes `plugin` and returns an `ArchiveSection`): + +1. **`archiveWorkflows`** — reads `plugin.settings.workflow.definitions`. Output: `workflows/workflows.json` + `workflows/workflows.md`. +2. **`archiveHabits`** — reads `plugin.settings.habit.habits` (array). Output: `habits/habits.json` + `habits/habits.md`. Each habit gets a markdown section with type, schedule, and history if present. +3. **`archiveRewards`** — reads `plugin.settings.rewards.rewardItems` and `occurrenceLevels`. Output: `rewards/rewards.json` + `rewards/rewards.md`. +4. **`archiveTimerData`** — reads `plugin.settings.taskTimer` config + any in-memory `timerManager` state if accessible. Output: `timer/timer-data.json` + `timer/timer-summary.md`. Note: timer state may also live in localStorage; check `src/services/timer-export-service.ts` for the existing export shape and reuse it. +5. **`archiveCalDavSources`** — reads `plugin.settings.icsIntegration.sources` AND OAuth provider configs. **CRITICAL: strip OAuth tokens** before serializing. Output: `calendar-sync/caldav-sources.json` (URLs + names only). +6. **`archiveRemovedViews`** — reads `plugin.settings.viewConfiguration[]` and filters to entries whose ID is in `["gantt", "quadrant", "habit", "working-on", "flagged"]`. Output: `views/removed-views.json` (per-view filterRules + sort + visibility). +7. **`archiveOrphans`** — catch-all: reads any settings keys that don't have a dedicated archiver and aren't in the v10 keep-list. Output: `orphan-settings.json`. This is the safety net for "we deprecated something we forgot to write a function for." + +Plus a top-level orchestrator: + +```ts +export async function archiveAll( + plugin: TaskProgressBarPlugin, +): Promise<{ sections: ArchiveSection[]; manifest: ArchiveManifest }> { + const sections = await Promise.all([ + archiveWorkflows(plugin), + archiveHabits(plugin), + archiveRewards(plugin), + archiveTimerData(plugin), + archiveCalDavSources(plugin), + archiveRemovedViews(plugin), + archiveOrphans(plugin), + ]); + + const manifest: ArchiveManifest = { + version: plugin.manifest.version, + exportedAt: Date.now(), + sections: sections.map((s) => ({ + section: s.section, + itemCount: s.itemCount, + files: [...s.files.keys()], + })), + }; + + return { sections, manifest }; +} +``` + +### Task 3 — Build realistic test fixtures (~½ day) + +`src/__tests__/migration/v10/__fixtures__/realistic-settings.ts`: + +```ts +export const settingsWith47Workflows: Partial = { + workflow: { + enableWorkflow: true, + definitions: [/* 47 realistic workflow shapes */], + timestampFormat: "YYYY-MM-DD HH:mm", + autoAddTimestamp: true, + calculateSpentTime: false, + }, +}; + +export const settingsWith12Habits: Partial = { + habit: { + enableHabits: true, + habits: [/* 12 mixed daily/count/scheduled/mapping habits */], + }, +}; + +// ... fixtures for the other 5 sections +``` + +These fixtures double as documentation for what realistic v9 user data looks +like. Phase 3's migration confirmation modal will use the same shapes for its +"X workflows, Y habits" copy. + +### Task 4 — Test fixtures end-to-end (~1 day) + +`src/__tests__/migration/v10/Archiver.test.ts`: + +```ts +import { archiveWorkflows, archiveAll } from "@/migration/v10/Archiver"; +import { settingsWith47Workflows, ... } from "./__fixtures__/realistic-settings"; + +describe("Archiver (Phase 1 Worktree B)", () => { + it("archiveWorkflows produces expected files for 47 workflows", async () => { + const plugin = makeFakePlugin({ settings: settingsWith47Workflows }); + const result = await archiveWorkflows(plugin); + expect(result.itemCount).toBe(47); + expect(result.files.has("workflows/workflows.json")).toBe(true); + expect(result.files.has("workflows/workflows.md")).toBe(true); + const json = JSON.parse(result.files.get("workflows/workflows.json")!); + expect(json.definitions).toHaveLength(47); + }); + + // ... 1 test per section + 1 for archiveAll +}); +``` + +`makeFakePlugin` is a tiny helper — just `{ settings, manifest: {version: "9.14.0"} }`. +You don't need a full plugin instance. + +## Definition of Done + +| # | Criterion | How to verify | +|---|---|---| +| 1 | All 7 archive functions return correct shapes for known inputs | `npm test -- --testPathPattern="migration/v10/Archiver"` | +| 2 | `archiveAll` orchestrator produces a valid manifest | Test asserts manifest shape | +| 3 | OAuth tokens are stripped from `archiveCalDavSources` output | Test asserts no `accessToken`/`refreshToken` keys in JSON | +| 4 | Each section has both a JSON (round-trippable) and markdown (human) representation, where applicable | Test asserts both files exist | +| 5 | Functions are pure: no `vault.create`, no `localforage` calls, no `app.workspace.trigger` | Code review | +| 6 | TypeScript build clean (`npm run build`) | Auto | +| 7 | Phase 0 integration tests still pass | `npm test -- --testPathPattern="integration/"` | +| 8 | NOT wired into MigrationRegistry yet | Code review (no edits to `src/utils/migration/`) | + +## Coordination with Worktree A + +Worktree A's banner export buttons need to call your functions. Provide a +clean import surface: + +```ts +// from src/migration/v10/index.ts +export { archiveWorkflows, archiveHabits, /* ... */, archiveAll } from "./Archiver"; +export type { ArchiveSection, ArchiveManifest } from "./types"; +``` + +Worktree A imports from `@/migration/v10`. If A starts before B, A stubs the +export action with a TODO; once B merges, A removes the stub. **This is a +soft dependency** — A and B are independent worktrees. + +## Conflicts to watch + +**None.** Worktree B touches only new files in `src/migration/v10/` and +`src/__tests__/migration/v10/`. No existing code is modified. + +The only file you write outside that namespace is potentially nothing — even +the orchestrator export goes through `src/migration/v10/index.ts`. + +## Open questions that affect THIS worktree + +- **Q2 — Sub-plugin commitment:** the default is YES, 4 sub-plugins. If the + user changes their mind and wants to delete a feature outright (no sub-plugin + migration), you can SKIP the corresponding archive function — there's no + point archiving data nobody will ever consume. Wait for confirmation if this + changes before you ship `archiveTimerData` etc. + +The other 4 questions don't affect this worktree. + +## Useful existing utilities + +- `src/services/timer-export-service.ts` — already exports timer data to JSON. You can probably import its serialization logic for `archiveTimerData`. +- `src/components/features/quick-capture/modals/QuickCaptureModalWithSwitch.ts` (line ~1006) — has the existing settings shape for quick-capture, useful reference for `archiveOrphans`. +- `src/common/setting-definition.ts` (line ~995, `DEFAULT_SETTINGS`) — list of every settings field, useful for `archiveOrphans` exclusion list. + +## Don't do these things + +- **Don't write to the vault.** Pure functions only. Phase 3 / Worktree D.5 + handles I/O via the migration registry. +- **Don't import obsidian's `Notice`, `Modal`, or `App`.** Your functions take + a plugin instance and return data. Nothing more. +- **Don't add dependencies.** Use plain JSON.stringify / template strings. +- **Don't OVERLY pretty-print the markdown.** A simple `# {section} {N}` + followed by `## {item.name}` for each item is fine. The markdown is a + fallback view; the JSON is the source of truth for sub-plugin importers. +- **Don't try to make the archive "diff-friendly".** Phase 3 is one-shot; + there's no need to support incremental archives. + +## When you're done + +```bash +git push origin refactor/v10-phase1-archiver +gh pr create --base master --title "feat(migration): v10 Archiver pure functions (Phase 1, Worktree B)" +``` + +After merge, Worktree A can remove its stub imports if it shipped with one. +Worktree D.5 (Phase 3 confirmation modal) will wire your `archiveAll` into +the MigrationRegistry as the `v10-archive` step. diff --git a/.v10-worktrees/worktree-c-readonly.md b/.v10-worktrees/worktree-c-readonly.md new file mode 100644 index 00000000..e2f20767 --- /dev/null +++ b/.v10-worktrees/worktree-c-readonly.md @@ -0,0 +1,233 @@ +# Worktree C — Phase 2 Read-Only Mode + Beta (9.15.0) + +## What you're doing + +Phase 1 (Worktrees A + B) shipped 9.14.0 with deprecation banners. Phase 2 is +the **hard warning** week: deprecated settings tabs become read-only (inputs +disabled, only the Export button works), deprecated commands fire a one-shot +Notice on first use per session, and v10 enters beta via BRAT. + +This is the last stop before the cliff. After your worktree merges and ships +9.15.0, the beta channel gets 10.0.0-beta.1 and a ~5 day soak period. + +## Phase 0 + Phase 1 ground + +You depend on **Worktree A merged to master**. Verify before starting: + +```bash +git fetch +git log master --oneline | grep "deprecation banners" +# Expect: "feat(settings): deprecation banners (Phase 1, Worktree A)" present +``` + +If not present, **do not start.** Worktree C cannot run in parallel with A — +you'll fight for the same 14 settings tab files. + +Worktree B (Archiver) can be merged or pending; you only need its functions +for the export buttons (which are already wired by Worktree A). + +## Setup + +```bash +git fetch +git worktree add ../tg-phase2-readonly master +cd ../tg-phase2-readonly +git checkout -b refactor/v10-phase2-readonly + +npm install +npm test -- --testPathPattern="integration/" +# Expect: 70+ passing +``` + +## Files you'll modify + +The same 14 deprecated tab files Worktree A injected banners into. You're +adding a `readOnly` mode to each one: + +1-14. All `src/components/features/settings/tabs/{Workflow,Habit,Reward,TaskTimer,TimelineSidebar,Ics,Index,DesktopIntegration,About}SettingsTab.ts` (and the 5 view-config sections) + +Plus: +- `src/components/features/settings/components/DeprecationBanner.ts` (banner copy update) +- `src/common/deprecation-messages.ts` (add Notice strings for commands) +- `src/index.ts` (wrap deprecated commands with one-shot Notice) +- `src/managers/changelog-manager.ts` (10.0.0-beta.1 announcement modal) +- `manifest-beta.json` (bump to 10.0.0-beta.1) + +## Tasks (in order) + +### Task 1 — Add `readOnly` mode to DeprecationBanner (~½ day) + +Extend the banner component (from Worktree A): + +```ts +export interface DeprecationBannerProps { + // ... existing fields from Phase 1 + readOnly?: boolean; // NEW +} +``` + +When `readOnly: true`, the banner copy upgrades from "moves to X in v10" to +"**read-only — export now**" and the "Export" button gets primary button +styling. Visual: same yellow background, but more urgent affordance. + +Update CSS in `src/styles/setting.scss` for the new state. + +### Task 2 — Disable inputs in 14 deprecated tabs (~2 days) + +For each tab/section, walk the `Setting()` chains and call `.setDisabled(true)` +on each input when the tab is in read-only mode. The `Export` button stays +enabled. Add a `disabled` prop or a flag at the top of each render function. + +Pattern: + +```ts +// Before +new Setting(containerEl) + .setName("Enable workflows") + .addToggle(t => t.setValue(plugin.settings.workflow.enableWorkflow) + .onChange(async v => { ... })); + +// After (Phase 2) +const readOnly = true; // hardcoded — Phase 3 deletes the tab entirely +new Setting(containerEl) + .setName("Enable workflows") + .addToggle(t => t.setValue(plugin.settings.workflow.enableWorkflow) + .setDisabled(readOnly) + .onChange(async v => { if (readOnly) return; ... })); +``` + +Pass the `renderDeprecationBanner` call `{readOnly: true, ...}`. + +For sectioned tabs (Ics, Index, DesktopIntegration), only the deprecated +sections become read-only — the rest of the tab stays interactive. + +### Task 3 — Wrap deprecated commands with first-use Notice (~1 day) + +`src/index.ts` — for each command that targets a deprecated feature, wrap the +existing callback with a one-shot Notice: + +```ts +// New helper at the top of registerCommands or in a small util +const _deprecationWarned: Record = {}; +function warnDeprecatedOnce(commandId: string, message: string): void { + if (_deprecationWarned[commandId]) return; + _deprecationWarned[commandId] = true; + new Notice(message, 6000); +} + +// Wrap each deprecated command's callback +this.addCommand({ + id: "create-quick-workflow", + name: t("Create Quick Workflow"), + editorCallback: async (editor, ctx) => { + warnDeprecatedOnce( + "create-quick-workflow", + t("This command is removed in v10. Install task-genius-workflow."), + ); + // existing logic still runs + return createQuickWorkflowCommand(plugin, editor, ctx); + }, +}); +``` + +The 11 deprecated commands to wrap: +- 6 workflow commands from `src/commands/workflowCommands.ts` +- 5 task-timer commands (find via `grep -l "task-timer-" src/index.ts`) +- 1 reindex-habits command + +Memory is per-session (cleared on plugin reload). Don't store in settings. + +### Task 4 — Update Notice strings in deprecation-messages.ts (~½ day) + +Add new keys for each command-level Notice. Centralize so locales translate +once. + +### Task 5 — Sub-plugin v0.1.0 release coordination (out of repo, ~1 day) + +This is the part that touches OTHER repos: + +- `task-genius-workflow` v0.1.0 — release with a **one-time bootstrap importer** + that reads from main plugin's live `data.json` (not yet from `Task Genius + Archive/`, since 9.15 hasn't archived anything yet) +- `task-genius-habits` v0.1.0 — same pattern +- `task-genius-timer` v0.1.0 — same pattern +- **`task-genius-calendar-sync` is HELD** — riskiest one (OAuth tokens), + ships in Phase 4 (Worktree E) + +Each sub-plugin's bootstrap importer logs which fields it imported and writes +a marker `/.imported-from-main-plugin` so it doesn't +double-import on next load. + +The sub-plugin repos don't exist yet — Worktree C creates them. Use the +main plugin's tooling (esbuild config, jest config, manifest format) as a +template. + +### Task 6 — Cut 10.0.0-beta.1 (~½ day) + +`manifest-beta.json` — bump to `10.0.0-beta.1`. Worktree D will own the +actual 10.0.0 work; this commit just opens the beta channel so testers can +opt in early. + +`src/managers/changelog-manager.ts` — add a beta-only announcement: "v10 +beta is here. Migration modal will appear on first launch — please test on +a backup vault first." + +## Definition of Done + +| # | Criterion | How to verify | +|---|---|---| +| 1 | All 14 deprecated tabs/sections show inputs as disabled | Manual: open Settings, try to toggle anything in Workflows tab — should be grayed out | +| 2 | Export buttons in each tab still functional | Manual: click each export button, verify archive folder updates | +| 3 | Banner copy updated to "read-only — export now" | Manual visual check | +| 4 | Each deprecated command fires a Notice on first use per session | Manual: invoke `Create Quick Workflow` twice — Notice once, second time silent | +| 5 | Notice memory clears on plugin reload | Manual: reload plugin, invoke command again — Notice fires again | +| 6 | 3 sub-plugins (workflow, habits, timer) released to community plugins or BRAT | Out of repo — verify by installing fresh and confirming bootstrap importer runs | +| 7 | 10.0.0-beta.1 published via BRAT | `manifest-beta.json` shows `10.0.0-beta.1`, BRAT installs it, real beta tester confirms it loads | +| 8 | TypeScript build clean | `npm run build` | +| 9 | Phase 0 integration tests still pass | `npm test -- --testPathPattern="integration/"` | +| 10 | No regression in non-deprecated tabs | Manual: open General/Tasks/Views, edit a setting, verify it persists | + +## Conflicts to watch + +- **Worktree D (Phase 3)** will DELETE the 14 tabs you're modifying. Same as + the A→D conflict — Phase 3 starts after Phase 2 merges, no overlap. +- **Worktree B (Archiver)** — your Export buttons call Worktree B's functions. + If B hasn't merged, the buttons remain stubbed (Worktree A's stubs from + Phase 1). Don't block on B; it'll be ready by the time you finish. + +## Open questions that affect THIS worktree + +- **Q4 — Cliff version (4 weeks vs 8 weeks):** the default is 4 weeks. If the + user wants 8, your worktree gets a longer beta soak (10.0.0-beta.1 stays in + the field for ~2 weeks instead of ~5 days). The work itself doesn't change. +- **Q5 — Beta tester recruitment:** Worktree A pinned the GitHub Discussion. + By the time you start, recruitment should have produced ~5-10 testers. If + it hasn't, push the discussion harder before cutting beta. + +## Useful existing utilities + +- The Obsidian `Setting` class' `.setDisabled(true)` method — works on every + input type (toggle, text, dropdown, slider, button) +- `Notice` from obsidian — your one-shot Notice helper wraps this +- `manifest-beta.json` — already exists, just bump the version field + +## Don't do these things + +- **Don't delete any tabs.** Worktree D owns deletions. +- **Don't modify the dataflow layer.** All your changes are UI + command callbacks. +- **Don't make the Notice persistent across sessions.** Per-session is the + contract — users who reload the plugin should see the warning again. +- **Don't ship a 10.0.0 manifest.** Only `manifest-beta.json` gets bumped. + `manifest.json` stays at `9.15.0`. +- **Don't translate Notice strings to non-English locales.** Worktree E's + locale prune handles parity. + +## When you're done + +```bash +git push origin refactor/v10-phase2-readonly +gh pr create --base master --title "feat(settings): read-only deprecated tabs + first-use command notice (Phase 2, Worktree C)" +``` + +After merge, **Worktree D is unblocked**. Tag `9.15.0` and cut +`10.0.0-beta.1` via BRAT. The 5-day beta soak begins. diff --git a/.v10-worktrees/worktree-d-cliff.md b/.v10-worktrees/worktree-d-cliff.md new file mode 100644 index 00000000..0b8babe9 --- /dev/null +++ b/.v10-worktrees/worktree-d-cliff.md @@ -0,0 +1,459 @@ +# Worktree D — Phase 3 Cliff (10.0.0) + +## What you're doing + +This is **the cliff**. Everything Phase 1 + Phase 2 warned about, you actually +do. Settings tabs go from 25 to 7. Commands go from 43 to 16 with default +hotkeys. Quick-capture modals go from 5 to 1. Views go from 15 to 5 core + 3 +widget-only. Onboarding goes from 36 files to 5. Roughly 50% of the plugin's +LOC gets deleted. The migration confirmation modal runs on first launch and +archives every deprecated feature's persistent data to `/Task Genius +Archive/`. + +This is also the largest worktree by far. It's split into **5 sub-PRs** that +land sequentially on the worktree branch. You can run them as 5 separate +commits or 5 separate Sub-PRs against the worktree branch — whichever fits +your workflow. + +## Phase 0/1/2 ground + +You depend on **Worktree C merged to master**. Verify before starting: + +```bash +git fetch +git log master --oneline | head -10 +# Expect: "feat(settings): read-only deprecated tabs..." (Worktree C) is the most recent v10 commit +# Expect: Worktree A (banners) and Worktree B (Archiver) commits are also present +``` + +The Phase 0 deferred items from `PHASE0_DEFERRED.md` are picked up here: +- **Item 1 (delete `src/pages/TaskView.ts`)** → assigned to **D.4** +- **Item 2 (fold `src/utils/settings-migration.ts` into the registry)** → assigned to **D.2** + +Read [`../PHASE0_DEFERRED.md`](../PHASE0_DEFERRED.md) before starting either +sub-PR for the resolution paths. + +## Setup + +```bash +git fetch +git worktree add ../tg-phase3-cliff master +cd ../tg-phase3-cliff +git checkout -b refactor/v10-phase3-cliff + +npm install +npm test -- --testPathPattern="integration/" +# Expect: 70+ passing +``` + +## The 5 sub-PRs + +Each sub-PR lands on `refactor/v10-phase3-cliff`. They MUST land in this +order due to `src/index.ts` conflicts: + +``` +D.2 (commands) → D.1 (settings tabs) → D.3 (quick capture) → D.4 (views + deletions) → D.5 (confirmation modal) +``` + +D.2 must be first because it owns the bulk of the `src/index.ts` rewrite. +D.5 must be last because it depends on every other sub-PR being stable. + +--- + +### D.2 — Command palette + hotkeys (43 → 16) + +**Why first:** owns the largest stretch of `src/index.ts`. Other sub-PRs +rebase onto it. + +**Files:** +- `src/index.ts` (command registration block — major rewrite) +- `src/commands/*.ts` (delete: `completedTaskMover.ts`, `sortTaskCommands.ts`, `taskCycleCommands.ts`, `taskMover.ts`, `workflowCommands.ts`) +- `src/commands/v10/` (new directory) — 16 new consolidated command files + +**Plus PHASE 0 DEFERRED Item 2** — fold `src/utils/settings-migration.ts` +into the registry. Resolution path: +1. Move `repairStatusCycles`, `validateStatusCycle`, `sortCyclesByPriority`, `findDuplicateCycleIds` → `src/utils/status-cycle-resolver.ts` (already exists) +2. Inline `migrateToMultiCycle` body into `src/utils/migration/steps/legacy-bundle-0.ts` (no longer imported) +3. Remove the W1 fallback in `src/index.ts:2003-2010` (the registry has atomic semantics — fallback is dead defense) +4. Delete `src/utils/settings-migration.ts` +5. Verify `npm test` and `npm run build` + +**The 16 new commands** (renaming + consolidation map from main plan §3.4): + +| New ID | Old IDs absorbed | Default hotkey | +|---|---|---| +| `tg:capture` | `quick-capture`, `minimal-quick-capture`, `toggle-quick-capture`, `toggle-quick-capture-globally`, `quick-file-create` | `Mod+Shift+T` | +| `tg:capture-here` | (new) | — | +| `tg:mark-done` | `cycle-task-status-forward` (when on task line) | `Mod+Enter` (task line) | +| `tg:mark-cycle` | `cycle-task-status-forward`, `cycle-task-status-backward` | — | +| `tg:set-priority` | all 12 priority commands collapsed into one picker | `Mod+Alt+P` | +| `tg:remove-priority` | `remove-priority` | — | +| `tg:open-view` | `open-task-genius-view` | `Mod+Shift+G` | +| `tg:open-inbox` | (new) | `Mod+Shift+I` | +| `tg:open-forecast` | (new) | `Mod+Shift+F` | +| `tg:open-review` | (new) | — | +| `tg:move-tasks` | all 6 task-mover commands → one picker for scope | — | +| `tg:sort-tasks` | `sort-tasks-by-due-date`, `sort-tasks-in-entire-document` | — | +| `tg:reindex` | `force-reindex-tasks` (and removes `reindex-habits`) | — | +| `tg:open-settings` | `open-task-genius-settings-modal` | — | +| `tg:open-archive` | (new — reveals `Task Genius Archive/` in file explorer) | — | +| `tg:setup` | `open-task-genius-setup` | — | + +**Removed entirely:** `open-timeline-sidebar-view`, `open-task-genius-changelog` +(auto-opens on version change), 5× `task-timer-*`, 6× `workflow-*`. The 11 +auto-move commands collapse into a setting toggle in the Tasks tab — **not in +the palette at all**. + +**Backward compatibility:** keep old command IDs as aliases for **one version +only** (10.0.0). Drop in 10.0.1 via Worktree E. This preserves manually-bound +hotkeys for surviving commands during the upgrade. + +**Discovery:** after the migration modal (D.5), show a one-screen "What +changed" sheet listing the 5 default hotkeys, the 4 picker collapses, and +the sub-plugin pointers. Use the existing `ChangelogManager` modal infrastructure. + +**DoD subset:** `npm test`, `npm run build`, all 16 new commands appear in +the palette with the new names, manually-bound hotkeys for surviving commands +still work via aliases. + +--- + +### D.1 — Settings tab rewrite (25 → 7) + +**Files:** +- `src/components/features/settings/SettingsModal.ts` (`renderTabContent` switch — 25 cases → 7) +- `src/components/features/settings/tabs/*` (delete 14, rewrite 7) +- `src/components/features/settings/index.ts` (exports) +- `src/components/features/settings/components/DeprecationBanner.ts` (delete — banners are gone in v10) +- `src/common/deprecation-messages.ts` (delete) +- `src/utils/ObsidianUriHandler.ts:117` (switch to redirect map) +- `src/utils/uri-tab-redirects.ts` (new) +- `src/migration/v10/TabIdMap.ts` (new) +- All `src/components/features/settings/tabs/{Workflow,Habit,Reward,TaskTimer,TimelineSidebar}*.ts` (delete) + +**The 7 new tabs:** + +| # | New tab | Absorbs old tabs | +|---|---|---| +| 1 | **General** | `index`, `file-filter`, `interface` (parts) | +| 2 | **Capture** | `quick-capture`, `time-parsing`, `date-priority` (parts) | +| 3 | **Tasks** | `progress-bar`, `task-status`, `task-handler`, `date-priority` (parts) | +| 4 | **Views** | `view-settings`, `calendar-views`, `task-filter` | +| 5 | **Projects & Tags** | `project` | +| 6 | **Integrations** | `ics` (read-only only), `mcp-integration`, `bases-support`, `workspaces`, `desktop-integration` | +| 7 | **About** | `about`, `beta-test` + "Open archive folder", import/export, tombstones list | + +**Deleted tabs (no merge):** `workflow`, `habit`, `reward`, `task-timer`, +`timeline-sidebar`. Their content was archived in D.5. + +**URI redirect map:** `src/utils/uri-tab-redirects.ts` — see main plan §3.8 +for the full table. Existing URI bookmarks pointing to deprecated tabs land +on `about#archived-X` with a Notice explaining where the data went. + +**DoD subset:** Settings opens in ≤500ms. All 7 tabs render valid content on +an empty vault. Existing URI bookmarks still work (manual smoke test). + +--- + +### D.3 — Quick capture modal consolidation (5 → 1) + +**Files:** +- `src/components/features/quick-capture/modals/{QuickCaptureModal,MinimalQuickCaptureModal,MinimalQuickCaptureModalWithSwitch,BaseQuickCaptureModal}.ts` (delete) +- `src/components/features/quick-capture/modals/QuickCaptureModalWithSwitch.ts` → rename to `QuickCaptureModal.ts` +- New `Mode` strip UI inside the survivor (Full / Minimal / Daily) +- `src/utils/migration/steps/v10-quick-capture-modes.ts` (new — registers as a tombstone+transform) +- `src/index.ts` (command callback updates — `tg:capture` opens the unified modal) + +**Three modes inside one modal:** + +``` +┌─────────────────────────────────────┐ +│ [● Full] [Minimal] [Daily] [×] │ ← mode strip +├─────────────────────────────────────┤ +│ ▌ Task content... │ ← always: text input, autofocus +│ │ +│ ─── Below this line shown in Full ──│ +│ Project ▾ Tags ▾ Priority ▾ │ +│ Due ▾ Start ▾ Scheduled ▾ │ +│ Target file: │ +│ Append / Prepend / Replace ▾ │ +│ [Cancel] [Capture ↵] │ +└─────────────────────────────────────┘ +``` + +**Settings migration step `v10-quick-capture-modes`:** +```ts +// Old: separate command bound to MinimalQuickCaptureModalWithSwitch +// Old: lastUsedMode tracked per modal class +plugin.settings.quickCapture.mode = mapMode(plugin.settings.quickCapture.lastUsedMode); +delete plugin.settings.quickCapture.lastUsedMode; +delete plugin.settings.quickCapture.minimalModeSettings; // fields merged up one level +``` + +Known degradation: users who configured different file targets for full vs +minimal lose that distinction — call out in changelog. + +**DoD subset:** capture flow works in all 3 modes, settings migration handles +existing `lastUsedMode` correctly, default hotkey (`Mod+Shift+T`) opens the +modal. + +--- + +### D.4 — View consolidation + onboarding compression + deletions + +**This is the biggest sub-PR by LOC.** It also picks up Phase 0 deferred +Item 1 (delete `src/pages/TaskView.ts`). + +**Files (deletion sweep):** +- `src/components/features/{gantt,quadrant,habit}/*` (delete entire dirs — except keep a small `QuadrantWidgetView.ts` for codeblock embedding) +- `src/components/features/timeline-sidebar/*` (delete) +- `src/components/features/onboarding/**` (delete 31 of 36 files, add 4 simplified) +- `src/managers/{habit-manager,reward-manager,timer-manager,electron-quick-capture}.ts` (delete) +- `src/services/{timer-export-service,timer-format-service,timer-metadata-service}.ts` (delete) +- `src/managers/calendar-auth-manager.ts` (delete — moves to calendar-sync sub-plugin) +- `src/providers/*` (delete entire dir → calendar-sync sub-plugin) +- `src/parsers/holiday-detector.ts` (delete) +- `src/dataflow/sources/FileSource.ts` (delete) +- `src/editor-extensions/workflow/*` (delete entire dir) +- `src/editor-extensions/date-time/task-timer.ts` (delete) +- `src/pages/TaskView.ts` (delete after porting dirty changes — see PHASE0_DEFERRED.md Item 1) + +**Files (additions):** +- `src/widgets/registerWidgets.ts` (add TableWidget, QuadrantWidget) +- `src/widgets/views/TableWidgetView.ts` (new, port from `src/components/features/table/`) +- `src/widgets/views/QuadrantWidgetView.ts` (new, ~200 LOC — codeblock embedding only) +- `src/migration/v10/ViewMigration.ts` (new) +- `src/utils/migration/steps/v10-view-cleanup.ts` (new — tombstone for removed views) +- `src/common/setting-definition.ts` (`viewConfiguration` defaults: 15 → 5) +- `src/components/features/onboarding/steps/{WelcomeStep,CaptureStep,ViewsStep,DoneStep}.ts` (new — 4 simplified onboarding steps) + +**View consolidation (15 → 5 core + 3 widget-only):** + +Core (live in FluentTaskView sidebar): `inbox`, `forecast`, `projects`, `tags`, `review` + +Widget-only (no sidebar entry, codeblock + `tg:open-view` picker only): `calendar`, `kanban`, `table` + +Removed: `gantt`, `quadrant`, `habit`, `working-on`, `flagged` + +**Phase 0 deferred Item 1 (port TaskView.ts changes to FluentTaskView):** + +The user has uncommitted modifications in `src/pages/TaskView.ts` adding +multi-cycle support to the "switch status" context menu. Before deleting +TaskView.ts: + +1. Read the dirty diff (`git diff src/pages/TaskView.ts`). The relevant block + is the "switch status" submenu builder around line ~1263-1440. +2. Find the equivalent location in `src/pages/FluentTaskView.ts` and port the + multi-cycle logic. The new code reuses these helpers from + `src/utils/status-cycle-resolver.ts`: + - `findApplicableCycles(currentMark, statusCycles)` + - `getAllStatusNames` + - `getNextStatusPrimary` + - `getAllStatusMarks` +3. Move `TASK_VIEW_TYPE` constant from `src/pages/TaskView.ts` to a new file + `src/common/view-types.ts` (stale leaves in user vaults still need to be + detached on next load — see `src/index.ts:1825` and `:2116`). +4. Update import sites of `TASK_VIEW_TYPE`: + - `src/index.ts:72` (also remove the `TaskView` symbol from this import) + - `src/components/features/fluent/FluentIntegration.ts:13` +5. Delete the `instanceof TaskView` block at `src/index.ts:2119` — unreachable + since the class is no longer registered. +6. Delete `src/pages/TaskView.ts`. +7. Run typecheck + integration suite. + +**Migration step `v10-view-cleanup`** (`src/migration/v10/ViewMigration.ts`): +```ts +const REMOVED = ["gantt", "quadrant", "habit", "working-on", "flagged"]; +const DEMOTED = ["calendar", "kanban", "table"]; + +// 1. Snapshot removed view configs into Archive/views/removed-views.json (Worktree B's archiver) +// 2. For removed views with non-default filterRules, create a saved filter preset +// on the closest core view (working-on → inbox preset, flagged → forecast preset) +// 3. Strip removed entries from plugin.settings.viewConfiguration +// 4. For demoted views, set type:"widget" and remove from FluentTaskView sidebar list +// 5. Walk plugin.settings.workspaces.byId[*].settings.fluentActiveViewId; replace any removed-view ID with "inbox" +// 6. Walk plugin.settings.workspaces.byId[*].settings.hiddenModules and prune removed IDs +``` + +**Steps 5 + 6 are the WORKSPACE_ONLY_KEYS trap** — workspaces in +`plugin.settings.workspaces.byId[*]` must be cleaned in the same migration +step or workspaces will boot to a broken view. + +**Onboarding compression (36 → 5 files):** +``` +src/components/features/onboarding/ +├── OnboardingView.ts ← view shell (kept, slimmed) +├── OnboardingController.ts ← state machine (kept, simplified to 4 steps) +├── steps/ +│ ├── WelcomeStep.ts ← 1. Welcome + import-from-archive prompt +│ ├── CaptureStep.ts ← 2. Pick target file, hotkey hint, sample capture +│ ├── ViewsStep.ts ← 3. Pick which of 5 core views to show +│ └── DoneStep.ts ← 4. "You're ready" + docs link +└── ui/Layout.ts ← shared step layout (kept, simplified) +``` +Delete every `Fluent*Step.ts`, `UserLevelStep`, `ModeSelectionStep`, +`ConfigPreviewStep`, `SettingsCheckStep`, `PlacementStep`, `IntroStep`, +`TaskGuideStep`, all of `steps/intro/`, `steps/guide/`, `steps/preview/`, +`previews/`, `TaskCreationGuide.ts`. **No more Beginner/Advanced/Power +branching** — one linear flow. + +**DoD subset:** all 5 core views render with an empty vault, all workspaces +boot to a valid `fluentActiveViewId`, onboarding completes in ≤4 steps, +LOC reduction visible (`find src/ -name "*.ts" | xargs wc -l` should be +notably lower). + +--- + +### D.5 — Migration confirmation modal + +**Files:** +- `src/migration/v10/ConfirmationModal.ts` (new) +- `src/utils/migration/steps/v10-archive.ts` (new — wraps Worktree B's `archiveAll`) +- `src/index.ts` (first-launch detection in onload) + +**The migration confirmation modal:** + +On first launch of 10.0.0, BEFORE any view renders, show a blocking modal: + +``` +┌────────────────────────────────────────────┐ +│ Task Genius is upgrading to v10. │ +│ │ +│ The following will be archived: │ +│ • 47 workflows → Task Genius Archive/ │ +│ workflows/ │ +│ • 12 habits → habits/ │ +│ • 3 ICS sources → calendar-sync/ │ +│ • 5 custom views → views/ │ +│ │ +│ Archive folder: [Task Genius Archive ] │ +│ │ +│ [Cancel & rollback to v9] [Preview] │ +│ [Apply ▶] │ +└────────────────────────────────────────────┘ +``` + +Driven by `MigrationRegistry.run(settings, {dryRun: true})` for the Preview +button, then `dryRun: false` on Apply. Cancel exits Obsidian without +persisting (leaves `data.json` untouched, instructions on how to revert). + +**Wire `archiveAll` (from Worktree B) into the registry as `v10-archive`:** + +```ts +// src/utils/migration/steps/v10-archive.ts +import { archiveAll } from "@/migration/v10/Archiver"; +import type { MigrationStep } from "../MigrationRegistry"; + +export const v10ArchiveStep: MigrationStep = { + id: "v10.0.0-archive", + targetVersion: "10.0.0", + kind: "transform", + description: "Archive deprecated feature data to /Task Genius Archive/", + apply: async (settings, ctx) => { + // The migration is two-part: + // 1. Run archiveAll() to compute the archive contents + // 2. Have the modal write them to the vault (since the registry is pure) + // The "writing" is done by the ConfirmationModal in apply phase, NOT here. + // This step's job is just to mark that the archive happened. + return { changed: true, details: ["v10 archive scheduled"] }; + }, +}; +``` + +**Beta vs stable behavior:** in `10.0.0-beta.X`, the modal defaults to +"preview only, do not apply" — user must explicitly click Apply. In stable +`10.0.0`, Apply is the primary button. + +**DoD subset:** the §3.10 acceptance test from the main plan — the "single +hardest test": + +> A user upgrades from 9.13.1 with: 47 workflows, 12 habits, 3 ICS sources, +> 2 OAuth calendars, 5 custom views, 3 workspaces, all 25 settings tabs touched +> at least once. After upgrading to 10.0.0, they: +> 1. See the migration modal within 3 seconds. +> 2. Click Apply. +> 3. See their Inbox. +> 4. Capture a task with `Mod+Shift+T`. +> 5. Mark it done. +> 6. Open `Task Genius Archive/` and see all their data. +> +> If any of those six steps requires reading docs, opening Settings, or +> restarting Obsidian — **it's not done.** + +--- + +## Definition of Done (worktree-level) + +| # | Criterion | How to verify | +|---|---|---| +| 1 | The §3.10 acceptance test from the main plan | Manual smoke on a real vault | +| 2 | First-time user enables plugin → first captured task in ≤60 seconds, ≤5 clicks | Manual on a fresh vault | +| 3 | Onboarding completes in ≤4 steps, ≤90 seconds | Manual | +| 4 | Settings opens in ≤500ms | Performance tab in dev tools | +| 5 | All workspaces boot to a valid `fluentActiveViewId` (no removed view IDs) | `git grep -l "removed view" src/__tests__` | +| 6 | All custom hotkeys for surviving commands still work | Manual | +| 7 | URI bookmarks pointing to deprecated tabs land somewhere reasonable with a Notice | Manual: navigate to `obsidian://task-genius?action=settings&tab=workflow` | +| 8 | No console errors during migration | `src/__tests__/migration/v10-migration.test.ts` | +| 9 | Main plugin LOC ≤ 42k (target 40k, ceiling 42k) | `find src/ -name "*.ts" -not -path "*__tests__*" -not -path "*__mocks__*" \| xargs wc -l \| tail -1` | +| 10 | 0 references to deleted modules | `git grep "from.*workflow"`, `git grep "from.*habit-manager"`, etc. — all should be empty in main plugin | +| 11 | All 5 core views render with an empty vault | Manual | +| 12 | All 16 commands appear in palette with new names | Manual | +| 13 | Phase 0 integration tests still pass | `npm test -- --testPathPattern="integration/"` | +| 14 | TypeScript build clean | `npm run build` | + +## Conflicts within Worktree D + +D.1-D.4 each touch `src/index.ts` differently: +- D.1 changes settings tab routing +- D.2 rewrites commands +- D.3 changes quick-capture commands +- D.4 deletes timer/workflow commands + +**Sequence them: D.2 first (it owns the command block), then D.1, D.3, D.4 +in any order, then D.5 last.** + +## Open questions that affect THIS worktree + +- **Q1 — Deprecation list:** if the user pulls anything back, the corresponding + D.4 deletion gets skipped. Confirm before D.4 starts. +- **Q3 — Default hotkeys:** the 5 defaults (`Mod+Shift+T`, etc.) are baked + into D.2. If the user wants different bindings or no defaults, change at + the top of D.2. +- **Q4 — Cliff version:** 4-week vs 8-week runway only affects WHEN you + start (after C merges, plus the beta soak period). Doesn't change scope. + +## Useful existing utilities + +- `src/managers/changelog-manager.ts` — for the "What changed" first-run sheet +- `src/utils/migration/MigrationRegistry.ts` (Phase 0) — already supports + atomic + dry-run, just add new steps +- `src/dataflow/cache/scope-map.ts` (Phase 0) — typed scope map for the + settings consolidation; D.1 should migrate the settings tab callers to + `onSettingsFieldsChanged()` as it rewrites them +- `src/widgets/core/BaseWidgetView.ts` — base for new TableWidgetView and + QuadrantWidgetView +- `src/widgets/codeblock/WidgetCodeBlockProcessor.ts` — codeblock embedding, + no changes needed + +## Don't do these things + +- **Don't ship without the migration confirmation modal.** D.5 is mandatory. + The whole point of Phase 0/1/2 was to set up the safety net for D.5 — it's + the user's only protection against data loss. +- **Don't keep `legacy` flags.** v10 is the cliff. No `enableV9Compatibility` + toggles. +- **Don't translate strings to non-English locales.** Worktree E's locale + prune handles parity. +- **Don't release `task-genius-calendar-sync` v0.1.0** — that's Worktree E. + Calendar sync is the riskiest sub-plugin (OAuth tokens) and gets held until + 10.0.1 for an extra week of soak. + +## When you're done + +```bash +git push origin refactor/v10-phase3-cliff +gh pr create --base master --title "feat: v10 cliff - 16 commands, 7 settings tabs, 5 core views (Phase 3, Worktree D)" +``` + +After merge, **Worktree E is unblocked**. Tag `10.0.0`. The cleanup phase +begins. diff --git a/.v10-worktrees/worktree-e-cleanup.md b/.v10-worktrees/worktree-e-cleanup.md new file mode 100644 index 00000000..a0a72ba0 --- /dev/null +++ b/.v10-worktrees/worktree-e-cleanup.md @@ -0,0 +1,308 @@ +# Worktree E — Phase 4 Cleanup (10.0.1) + +## What you're doing + +The cliff is behind us — 10.0.0 shipped with the migration confirmation modal, +the new 7-tab settings UI, the 16-command palette, the 5 core views, and +~50% of the LOC deleted. Worktree E is the **cleanup pass** that: + +- Removes the migration code itself (its job is done) +- Drops the one-version command-ID aliases that Worktree D shipped for + backward compatibility +- Prunes orphan locale keys +- Releases `task-genius-calendar-sync` v0.1.0 (the riskiest sub-plugin, held + back from Phase 2 for an extra week of soak) + +This is the smallest worktree by LOC. It's mostly bookkeeping with one +sub-plugin release coordination. + +## Phase 0/1/2/3 ground + +You depend on **Worktree D merged to master**. Verify before starting: + +```bash +git fetch +git log master --oneline | head -5 +# Expect: "feat: v10 cliff..." (Worktree D) is the most recent commit +git tag | grep "10.0.0$" +# Expect: 10.0.0 tag exists +``` + +Beta soak should have run for ~5 days minimum after `10.0.0-beta.1` was cut +in Phase 2. If real users on the beta channel are reporting bugs, FIX THOSE +FIRST before starting Worktree E — your work is post-stability cleanup, not +emergency response. + +## Setup + +```bash +git fetch +git worktree add ../tg-phase4-cleanup master +cd ../tg-phase4-cleanup +git checkout -b refactor/v10-phase4-cleanup + +npm install +npm test -- --testPathPattern="integration/" +# Expect: 70+ passing +``` + +## Files you'll modify + +- `src/migration/v10/Archiver.ts` (delete — its job is done, archive folder lives in user vaults forever) +- `src/migration/v10/index.ts` (update exports) +- `src/utils/migration/steps/v10-archive.ts` → tombstone-only marker +- `src/utils/migration/steps/v10-view-cleanup.ts` → tombstone marker +- `src/index.ts` (drop one-version command aliases that D.2 shipped) +- `src/__tests__/migration/v10/` (delete the Archiver tests since the source is gone) + +## Files you'll create + +- `scripts/prune-locale-orphans.mjs` (new — one-shot script) +- `src/__tests__/locale-parity.test.ts` (new — CI guard against regressions) + +## Tasks (in order) + +### Task 1 — Tombstone the migration code (~½ day) + +The `v10-archive` and `v10-view-cleanup` migration steps did their job in +10.0.0. They should now become **no-op tombstones** that just record "already +applied" via `_meta.lastMigratedVersion`. The actual archive logic in +`src/migration/v10/Archiver.ts` is no longer needed. + +For each of the two steps: + +```ts +// Before (10.0.0) +export const v10ArchiveStep: MigrationStep = { + id: "v10.0.0-archive", + targetVersion: "10.0.0", + kind: "transform", + description: "...", + apply: async (settings, ctx) => { /* real work */ }, +}; + +// After (10.0.1) +export const v10ArchiveStep: MigrationStep = { + id: "v10.0.0-archive", + targetVersion: "10.0.0", + kind: "tombstone", // changed from "transform" + description: "Archive migration applied in 10.0.0 (now no-op)", + apply: () => ({ changed: false, details: ["already applied"] }), +}; +``` + +The reason to keep the step at all (instead of deleting it) is that users +upgrading from 9.x DIRECTLY to 10.0.1 (skipping 10.0.0) need the registry to +recognize the version slot. With a tombstone marker, the registry sees +`fromVersion < 10.0.0 < toVersion = 10.0.1` and runs the step — which now +no-ops. Without the marker, fresh-install users would also be fine, but +upgrading users wouldn't have a migration record at the right version. + +Then delete `src/migration/v10/Archiver.ts` and its tests: + +```bash +rm src/migration/v10/Archiver.ts +rm -rf src/__tests__/migration/v10/ +``` + +Update `src/migration/v10/index.ts` to remove the Archiver exports. + +### Task 2 — Drop one-version command aliases (~½ day) + +Worktree D.2 kept old command IDs as aliases for one version (10.0.0) to +preserve manually-bound hotkeys. Now drop them: + +```bash +git grep -n "addCommand.*id:.*['\"]old-command-id['\"]" src/index.ts +# Find the alias registrations and delete them +``` + +The aliases were: +- `quick-capture` → aliased to `tg:capture` +- `cycle-task-status-forward` → aliased to `tg:mark-cycle` +- ... etc., one alias per surviving command + +These are documented in the D.2 sub-PR commit history. Read that commit to +see the full alias list. + +Add a CHANGELOG entry: "Removed v9 command aliases. If you bound hotkeys to +old command IDs, rebind them to the v10 equivalents (see CHANGELOG 10.0.0)." + +### Task 3 — Locale prune script (~½ day) + +`scripts/prune-locale-orphans.mjs`: + +```js +#!/usr/bin/env node +/** + * Prune locale orphans: delete keys in non-en locale files that don't + * exist in en.ts. Run manually before tagging 10.0.1. + */ +import * as fs from "node:fs/promises"; +import * as path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const localeDir = path.join(__dirname, "..", "src", "translations", "locale"); + +const en = await import(path.join(localeDir, "en.ts")); +const enKeys = new Set(Object.keys(en.default)); + +const files = await fs.readdir(localeDir); +for (const file of files) { + if (file === "en.ts" || !file.endsWith(".ts")) continue; + // ... parse, prune, write back +} + +console.log(`Pruned orphan keys from ${files.length - 1} non-en locales`); +``` + +Run it: + +```bash +node scripts/prune-locale-orphans.mjs +``` + +This is a ONE-SHOT script. Don't add it to npm scripts or CI. The author +runs it manually when locale orphans accumulate. + +### Task 4 — Locale parity Jest test (~½ day) + +`src/__tests__/locale-parity.test.ts` — a tiny ratchet test that asserts +every key in `en.ts` exists in every other locale file. New strings added +to `en.ts` are allowed to be missing in other locales (they fall back to +en) — this only fails if a locale file has EXTRA keys that don't exist in +en. + +Wait, that's wrong direction. Re-think: + +- `en.ts` is the canonical superset +- Other locales should be SUBSETS of `en.ts` (missing translations fall back to en) +- If a non-en locale has a key that en doesn't, that's an orphan — assert it doesn't happen + +```ts +import en from "@/translations/locale/en"; +import zhCn from "@/translations/locale/zh-cn"; +import zhTw from "@/translations/locale/zh-tw"; +import ja from "@/translations/locale/ja"; +import ru from "@/translations/locale/ru"; +import uk from "@/translations/locale/uk"; +import ptBr from "@/translations/locale/pt-br"; +import enGb from "@/translations/locale/en-gb"; + +const enKeys = new Set(Object.keys(en)); + +describe("locale parity (W4 cleanup)", () => { + test.each([ + ["zh-cn", zhCn], + ["zh-tw", zhTw], + ["ja", ja], + ["ru", ru], + ["uk", uk], + ["pt-br", ptBr], + ["en-gb", enGb], + ])("%s has no orphan keys not in en.ts", (name, locale) => { + const orphans = Object.keys(locale).filter((k) => !enKeys.has(k)); + expect(orphans).toEqual([]); + }); +}); +``` + +This is the **automated** complement to the manual prune script. The script +runs occasionally; the test runs every PR. + +### Task 5 — Release `task-genius-calendar-sync` v0.1.0 (~2 days, mostly out of repo) + +This is the riskiest sub-plugin — OAuth tokens, token refresh, CalDAV write +operations. It was held back from Phase 2 for an extra week of soak after +v10.0.0 ships. + +Tasks: +1. Create the new repo `task-genius-calendar-sync` (copy main plugin's tooling) +2. Migrate `src/providers/*`, `src/managers/calendar-auth-manager.ts` from the + main plugin (which deleted them in Worktree D.4) +3. Add a one-time importer that reads from `/Task Genius Archive/calendar-sync/caldav-sources.json` +4. Test with a real Google Calendar account (out of repo) +5. Release v0.1.0 to community plugins (or BRAT) +6. Pin a "calendar sync available" announcement to the GitHub Discussion + +This task is largely external to the main plugin repo. The main-plugin side +is just verifying nothing reads from the deleted provider files (`git grep`). + +### Task 6 — Bump version + tag (~10 minutes) + +```bash +# In the main plugin repo +# Bump manifest.json from 10.0.0 to 10.0.1 +# Bump versions.json (the Obsidian plugin version map) +# Commit +git tag v10.0.1 +git push origin v10.0.1 +``` + +## Definition of Done + +| # | Criterion | How to verify | +|---|---|---| +| 1 | `src/migration/v10/Archiver.ts` deleted | File doesn't exist; `git grep "Archiver"` returns no production matches | +| 2 | Both v10 migration steps are tombstones (no-op) | Code review | +| 3 | One-version command aliases removed from `src/index.ts` | `git grep "alias.*10.0.0"` returns nothing | +| 4 | Locale prune script exists and runs without error | `node scripts/prune-locale-orphans.mjs` exits 0 | +| 5 | Locale parity Jest test exists and passes | `npm test -- --testPathPattern="locale-parity"` | +| 6 | `task-genius-calendar-sync` v0.1.0 published | Out of repo; check community plugins or BRAT | +| 7 | `manifest.json` is `10.0.1` | File contents | +| 8 | TypeScript build clean | `npm run build` | +| 9 | All Phase 0 + Phase 3 integration tests still pass | `npm test -- --testPathPattern="integration/"` | +| 10 | No deleted-module references | `git grep "from.*workflow"`, `git grep "from.*habit-manager"`, `git grep "from.*timer-manager"`, `git grep "from.*calendar-auth"` — all empty | +| 11 | Main plugin LOC ≤ 42k (still hitting the v10 ceiling) | `find src/ -name "*.ts" -not -path "*__tests__*" -not -path "*__mocks__*" \| xargs wc -l \| tail -1` | + +## Conflicts to watch + +**None.** By the time Worktree E starts, Phase 3 is merged and stable. No +other worktrees are in flight. + +## Open questions that affect THIS worktree + +- **Q2 — Sub-plugin commitment:** if the user changed their mind about + `task-genius-calendar-sync` (e.g. wants to delete OAuth/CalDAV outright + instead of extracting), Task 5 gets skipped. Confirm before starting. + +The other 4 questions are settled by the time you reach Phase 4. + +## Useful existing utilities + +- `src/utils/migration/MigrationRegistry.ts` — already supports `kind: "tombstone"` (Phase 0) +- `src/translations/locale/*.ts` — existing locale files; the prune script + walks them +- `src/translations/helper.ts` — `t()` translation helper + +## Don't do these things + +- **Don't delete the migration steps entirely.** They become tombstones, not + deletions. Tombstones preserve the version slot for skip-version upgrades. +- **Don't translate orphan strings before pruning.** The prune script + determines which strings are orphans by comparing to en.ts. Translate AFTER + the prune, not before. +- **Don't add the prune script to CI or npm scripts.** It's a one-shot tool; + the author runs it manually. +- **Don't ship `task-genius-calendar-sync` without testing OAuth refresh on + a real account.** This is the highest-risk sub-plugin; an untested + refresh-token bug = users locked out of their calendars. +- **Don't bump the major version.** 10.0.1 is a patch release; 10.1.0 is + reserved for the first feature release post-cliff. + +## When you're done + +```bash +git push origin refactor/v10-phase4-cleanup +gh pr create --base master --title "chore: v10 cleanup - tombstones, locale prune, calendar-sync release (Phase 4, Worktree E)" +``` + +After merge, tag `v10.0.1` and the v10 refactor effort is COMPLETE. The +plugin is at ~40k LOC, the user has 5 core views + 16 commands + 7 settings +tabs + 1 quick-capture modal + a 4-step onboarding, and 4 sub-plugins are +available for users who want the deprecated features back. + +Update CHANGELOG.md with a final summary entry and consider writing a blog +post / GitHub release note explaining the 6-week journey for users who +weren't in the loop. diff --git a/WORKTREE_PLAN.md b/WORKTREE_PLAN.md index 22bfcd21..8a00c6a8 100644 --- a/WORKTREE_PLAN.md +++ b/WORKTREE_PLAN.md @@ -1,5 +1,18 @@ # Task Genius v10 — Phase 1-4 Worktree Split +> **Update (2026-04-07):** the 5 worktrees described below have each been +> split into a self-contained brief in [`./.v10-worktrees/`](./.v10-worktrees/). +> Hand each brief to one agent / developer. This file remains as the umbrella +> overview; individual briefs have the actionable instructions. +> +> | Worktree | Brief | +> |---|---| +> | A — banners | [`.v10-worktrees/worktree-a-banners.md`](./.v10-worktrees/worktree-a-banners.md) | +> | B — Archiver | [`.v10-worktrees/worktree-b-archiver.md`](./.v10-worktrees/worktree-b-archiver.md) | +> | C — read-only | [`.v10-worktrees/worktree-c-readonly.md`](./.v10-worktrees/worktree-c-readonly.md) | +> | D — cliff cluster | [`.v10-worktrees/worktree-d-cliff.md`](./.v10-worktrees/worktree-d-cliff.md) | +> | E — cleanup | [`.v10-worktrees/worktree-e-cleanup.md`](./.v10-worktrees/worktree-e-cleanup.md) | + Operational follow-up to the v10 refactor plan (`~/.claude/plans/dynamic-mixing-pie.md`). That document is the source of truth for **what** to do in each phase. This document is the source of truth