From 09b5fa610e678fa3727c4b425751026bee51b3a4 Mon Sep 17 00:00:00 2001 From: Kris Braun Date: Thu, 27 Aug 2026 23:51:52 -0400 Subject: [PATCH] Remove the Today and goal tool surfaces from the Plot tool These tools are retired. The Plot tool no longer exposes a Today snapshot or per-user goals, and the `@plotday/twister/goal` entry point is gone. Removed from the public SDK surface: - `TodayAccess` and `GoalAccess` permission enums, and the `today` / `goals` entries in `Plot.Options`. - `getTodayItems()`, `updateTodayItem()`, `getTodayThreadId()`. - `createGoal()`, `getGoals()`, `updateGoal()`, `archiveGoal()`. - The `TodayItem`, `TodayItemSection`, and `TodayItemKind` types, and the `Note.todayItem` field (with its `NewNote` omit entry). - The `@plotday/twister/goal` export and its `Goal`, `NewGoal`, `GoalUpdate`, `GoalStatus`, and `GoalCadence` types. Twists that declared `today` or `goals` access should drop those declarations and any calls to the corresponding methods. The thread `type` value `"goal"` is a display sub-type and is unaffected. Co-Authored-By: Claude Opus 5 --- .changeset/remove-today-and-goal-tools.md | 5 + twister/package.json | 5 - twister/src/goal.ts | 69 ------------ twister/src/index.ts | 1 - twister/src/plot.today-item.test-d.ts | 11 -- twister/src/plot.ts | 57 +--------- twister/src/tools/plot.ts | 129 ---------------------- 7 files changed, 6 insertions(+), 271 deletions(-) create mode 100644 .changeset/remove-today-and-goal-tools.md delete mode 100644 twister/src/goal.ts delete mode 100644 twister/src/plot.today-item.test-d.ts diff --git a/.changeset/remove-today-and-goal-tools.md b/.changeset/remove-today-and-goal-tools.md new file mode 100644 index 00000000..25e86339 --- /dev/null +++ b/.changeset/remove-today-and-goal-tools.md @@ -0,0 +1,5 @@ +--- +"@plotday/twister": major +--- + +Removed: the Today and goal surfaces from the Plot tool. The `TodayAccess` and `GoalAccess` permission enums are gone, along with the `today` and `goals` entries in `Plot.Options`, the `getTodayItems()`, `updateTodayItem()`, and `getTodayThreadId()` methods, the `createGoal()`, `getGoals()`, `updateGoal()`, and `archiveGoal()` methods, the `TodayItem`, `TodayItemSection`, and `TodayItemKind` types, the `Note.todayItem` field, and the `@plotday/twister/goal` entry point with its `Goal`, `NewGoal`, `GoalUpdate`, `GoalStatus`, and `GoalCadence` types. To upgrade, drop `today` and `goals` from your `build(Plot, { ... })` options and remove any calls to those methods; a twist that stored per-user intentions through goals can keep them in its own state with `this.set` / `this.get`. Note that the thread `type` value `"goal"` is unaffected — it is a display sub-type and remains available. diff --git a/twister/package.json b/twister/package.json index 83cf9830..62f68334 100644 --- a/twister/package.json +++ b/twister/package.json @@ -40,11 +40,6 @@ "types": "./dist/schedule.d.ts", "default": "./dist/schedule.js" }, - "./goal": { - "@plotday/connector": "./src/goal.ts", - "types": "./dist/goal.d.ts", - "default": "./dist/goal.js" - }, "./tag": { "@plotday/connector": "./src/tag.ts", "types": "./dist/tag.d.ts", diff --git a/twister/src/goal.ts b/twister/src/goal.ts deleted file mode 100644 index 456a7f70..00000000 --- a/twister/src/goal.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * @fileoverview - * Goal entity types. - * - * Goals are per-user, cross-cutting intentions — "ship the feature by - * Friday", "3 hours a week on leads" — that Plot uses to shape each day's - * priorities. They are structured agent memory, readable and writable by - * twists with the `Plot.Options.goals` permission and read server-side by - * Plot's day-planning pipeline. Goals are strictly per-user; there is no - * sharing. - * - * Types follow the Twister entity standard: required fields plain, nullable - * fields `| null` (never optional), and New* / Update* types use `Partial<>` - * so omitted (`undefined`) fields are distinguishable from explicitly - * cleared (`null`) ones. - */ - -import { type Uuid } from "./utils/uuid"; - -/** - * Lifecycle status of a goal. - * - `active`: live; shapes day planning. - * - `completed`: achieved. - * - `dropped`: cancelled by the user, kept for memory ("cancel my goal - * to…" sets this — goals are never hard-deleted). - */ -export type GoalStatus = "active" | "completed" | "dropped"; - -/** - * Recurring effort budget for a goal, e.g. "3 hours a week on leads" → - * `{ hours: 3, per: "week" }`. - */ -export type GoalCadence = { - /** Hours of effort per period. */ - hours: number; - /** The period the hours apply to. */ - per: "day" | "week" | "month"; -}; - -/** - * A per-user goal. - */ -export type Goal = { - /** Unique identifier for the goal */ - id: Uuid; - /** Short imperative, e.g. "Ship the Today feature" */ - title: string; - /** Freeform elaboration / agent notes */ - details: string | null; - /** Lifecycle status */ - status: GoalStatus; - /** Deadline intent as an ISO date (YYYY-MM-DD): "by end of week" */ - targetDate: string | null; - /** Planned work day as an ISO date (YYYY-MM-DD): "I'll work on it Friday" */ - scheduledOn: string | null; - /** Recurring effort budget */ - cadence: GoalCadence | null; - /** Linked focus id, or null when the goal isn't tied to a focus */ - focusId: Uuid | null; -}; - -/** Type for creating a new goal: `title` is required, all else optional. */ -export type NewGoal = Pick & Partial>; - -/** - * Type for partially updating a goal: `id` is required; omitted fields are - * left unchanged, `null` clears a nullable field. - */ -export type GoalUpdate = Pick & Partial>; diff --git a/twister/src/index.ts b/twister/src/index.ts index c3182e70..f46d0c60 100644 --- a/twister/src/index.ts +++ b/twister/src/index.ts @@ -2,7 +2,6 @@ export * from "./twist"; export * from "./connector"; export * from "./plot"; export * from "./schedule"; -export * from "./goal"; export * from "./tag"; export * from "./tool"; export { diff --git a/twister/src/plot.today-item.test-d.ts b/twister/src/plot.today-item.test-d.ts deleted file mode 100644 index 73c696f1..00000000 --- a/twister/src/plot.today-item.test-d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { describe, expectTypeOf, it } from "vitest"; -import type { Note, NewNote } from "./plot"; - -describe("Note.todayItem", () => { - it("is a required { id } | null field on Note", () => { - expectTypeOf().toEqualTypeOf<{ id: Note["id"] } | null>(); - }); - it("is NOT settable on NewNote", () => { - expectTypeOf().not.toHaveProperty("todayItem"); - }); -}); diff --git a/twister/src/plot.ts b/twister/src/plot.ts index 5c8f0105..5725ed17 100644 --- a/twister/src/plot.ts +++ b/twister/src/plot.ts @@ -771,15 +771,6 @@ export type Note = ThreadCommon & { actions: Array | null; /** The note this is a reply to, or null if not a reply */ reNote: { id: Uuid } | null; - /** - * The Today-item context this note was composed against, via the Today - * thread's pin affordance (pin an item to discuss it), or null. Mutually - * exclusive with `reNote` and a forward snapshot — a note is at most one - * of a reply, a forward, or a Today-item reference. Read-only from a - * twist's perspective: only the Plot app sets it, when the user pins a - * Today item and sends a message in the Today thread. - */ - todayItem: { id: Uuid } | null; /** * Contacts who can see this note, or null if the note inherits thread visibility. * When set (even to []), the note is private to the listed contacts plus the creator. @@ -837,7 +828,7 @@ export type Note = ThreadCommon & { export type NewNote = Partial< Omit< Note, - "author" | "thread" | "tags" | "reactions" | "mentions" | "accessContacts" | "recipients" | "id" | "key" | "reNote" | "todayItem" | "tagActors" + "author" | "thread" | "tags" | "reactions" | "mentions" | "accessContacts" | "recipients" | "id" | "key" | "reNote" | "tagActors" > > & ({ id: Uuid } | { key: string } | {}) & { @@ -1662,49 +1653,3 @@ export type PlanOperation = focusTitle: string; changes: Partial>; }; - -/** - * Section of the user's Today snapshot an item belongs to. - * - "priorities": the day's top items (to-dos, events, urgent threads, goals) - * - "updates": important information pulled from unread threads - */ -export type TodayItemSection = "priorities" | "updates"; - -/** - * The kind of a Today snapshot item. Determines check-off affordances and - * how the item links back to threads/goals. - */ -export type TodayItemKind = "todo" | "event" | "urgent" | "goal" | "update"; - -/** - * One item in the user's Today snapshot — the pre-generated, per-day list - * of priorities and updates. Items are server-composed; twists read them - * via {@link Plot.getTodayItems} and adjust them (rank / checked / - * dismissed) via {@link Plot.updateTodayItem}. All other fields are - * server-authored and read-only from the SDK. - */ -export type TodayItem = { - id: Uuid; - /** The user-local day this item belongs to, as an ISO date ("YYYY-MM-DD"). */ - day: string; - section: TodayItemSection; - kind: TodayItemKind; - /** Order within the section, ascending (lower rank renders higher). */ - rank: number; - /** The item line, consolidated where appropriate. */ - title: string; - /** 1–2 sentence support text, mainly for "updates" items. */ - detail: string | null; - /** Linked threads; the first is the primary open target. May be empty (e.g. goal items). */ - threadIds: Uuid[]; - /** The focus this item is labeled with, if any. */ - focusId: Uuid | null; - /** The goal this item derives from, if any. */ - goalId: Uuid | null; - /** Event start (events only). */ - startsAt: Date | string | null; - /** Event end (events only). */ - endsAt: Date | string | null; - /** When the user checked this item off, or null if unchecked. */ - checkedAt: Date | string | null; -}; diff --git a/twister/src/tools/plot.ts b/twister/src/tools/plot.ts index 7e283058..c72b45bb 100644 --- a/twister/src/tools/plot.ts +++ b/twister/src/tools/plot.ts @@ -16,19 +16,12 @@ import { type PlanOperation, type Focus, type FocusUpdate, - type TodayItem, Uuid, } from ".."; import { type Schedule, type NewSchedule, } from "../schedule"; -import { - type Goal, - type GoalStatus, - type GoalUpdate, - type NewGoal, -} from "../goal"; import type { Callback } from "./callbacks"; export enum ThreadAccess { @@ -78,26 +71,6 @@ export enum LinkAccess { Full, } -export enum GoalAccess { - /** Read the owner's goals. */ - Read, - /** - * Read, create, update, and archive the owner's goals. - * All Read permissions. - */ - Manage, -} - -export enum TodayAccess { - /** Read the user's Today snapshot items and Today-thread id. */ - Read, - /** - * Read + adjust Today items: re-rank within a section, check items off, - * and dismiss items from the snapshot. Includes all Read permissions. - */ - Manage, -} - /** * Intent handler for thread mentions. * Defines how the twist should respond when mentioned in a thread. @@ -350,20 +323,6 @@ export abstract class Plot extends ITool { contact?: { access?: ContactAccess; }; - /** - * Enable goal operations. Goals are per-user intentions ("ship X by - * Friday", "3 hours a week on leads") that shape Plot's day planning. - */ - goals?: { - access: GoalAccess; - }; - /** - * Access to the user's Today snapshot (per-day priorities/updates items - * and the persistent Today chat thread id). - */ - today?: { - access: TodayAccess; - }; /** Enable semantic search across notes and links owned by the twist's user. */ search?: true; /** @@ -682,56 +641,6 @@ export abstract class Plot extends ITool { // eslint-disable-next-line @typescript-eslint/no-unused-vars abstract getSchedules(threadId: Uuid): Promise; - /** - * Creates a new goal for the twist owner. - * - * Requires `goals: { access: GoalAccess.Manage }`. - * - * @param goal - The goal data to create (`title` required) - * @returns Promise resolving to the created goal - */ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - abstract createGoal(goal: NewGoal): Promise; - - /** - * Lists the twist owner's goals (archived goals are excluded). - * - * Requires `goals: { access: GoalAccess.Read }` (or Manage). - * - * @param filter - Optional status filter - * @returns Promise resolving to the matching goals - */ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - abstract getGoals(filter?: { status?: GoalStatus }): Promise; - - /** - * Partially updates an existing goal. Omitted fields are left unchanged; - * `null` clears a nullable field. Setting `status: "completed"` records - * the completion time server-side; moving away from `completed` clears it. - * - * Requires `goals: { access: GoalAccess.Manage }`. - * - * @param update - The goal update containing the ID and fields to change - * @returns Promise resolving to the updated goal - * @throws Error if the goal does not exist - */ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - abstract updateGoal(update: GoalUpdate): Promise; - - /** - * Archives a goal (soft delete — the row is kept server-side as agent - * memory; goals are never hard-deleted). Prefer - * `updateGoal({ id, status: "dropped" })` for "cancel my goal", which - * keeps it visible in goal listings. - * - * Requires `goals: { access: GoalAccess.Manage }`. - * - * @param id - The goal id to archive - * @throws Error if the goal does not exist - */ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - abstract archiveGoal(id: Uuid): Promise; - /** * Reads a focus's agent memory — the facts Plot has been told about that * focus. Entries whose date is long past are excluded; a recently overdue @@ -778,44 +687,6 @@ export abstract class Plot extends ITool { */ abstract getBriefs(): Promise; - /** - * Lists the user's current Today snapshot: all non-archived items for the - * latest generated day, ordered by section ("priorities" first) then rank. - * - * Requires `today` access ({@link TodayAccess.Read} or higher). - * - * @returns Promise resolving to the current Today items (may be empty) - */ - abstract getTodayItems(): Promise; - - /** - * Adjusts one Today item. Only the provided fields change: - * - `rank` reorders the item within its section (ascending; lower is higher) - * - `checked: true` stamps the item's checked state; `false` clears it - * - `dismissed: true` removes the item from the snapshot (archives it) - * - * Requires {@link TodayAccess.Manage}. - * - * @param update - The item id plus the fields to change - * @returns Promise that resolves when the update is complete - * @throws Error if the item does not exist or belongs to another user - */ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - abstract updateTodayItem(update: { - id: Uuid; - rank?: number; - checked?: boolean; - dismissed?: boolean; - }): Promise; - - /** - * Returns the id of the user's persistent Today chat thread, or null if - * it has not been created yet (first snapshot generation pending). - * - * Requires `today` access ({@link TodayAccess.Read} or higher). - */ - abstract getTodayThreadId(): Promise; - /** * Retrieves links from connected source channels. *