diff --git a/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx b/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx index ed93cab0..0213c923 100644 --- a/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx +++ b/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx @@ -11,6 +11,7 @@ import type { ChatMessage } from '../Chat/types'; import { categoryFromParam, commandHqListPath, commandHqSessionPath } from './command-hq-routes'; import { useCommandHqCategories, useCommandHqCommander, useCommandHqCommanderActions } from './useCommandHq'; import { formatCommanderCost, formatTokens } from './format'; +import { NEW_COMMANDER_GUIDE } from './newCommanderGuide'; // Right panel of the /command-hq workspace. Three states, chosen by the URL alone (no channel — panels // read the route directly, per `docs/navigation-audit.md`): @@ -32,6 +33,37 @@ function EmptyState() { ); } +/** + * The instructions shown in an empty new-commander pane. + * + * Deliberately plain and deliberately unfinished — see `newCommanderGuide.ts`. A `provisional` section + * carries a visible marker so a guide that is still being written cannot be mistaken for one that is done, + * which matters because this ships on every deploy whether the copy is ready or not. + */ +const NewCommanderGuide = () => ( +
+
+ {NEW_COMMANDER_GUIDE.map((section) => ( +
+

+ {section.title} + {section.provisional && ( + + draft + + )} +

+ {section.body.map((paragraph) => ( +

+ {paragraph} +

+ ))} +
+ ))} +
+
+); + /** * A commander started in THIS pane, and it keeps the same live chat for as long as the pane is open. * @@ -103,6 +135,9 @@ function NewCommander({ `useEmbeddableChat(params)` builds the manager from these props, and `manager.context` is what the composer reads to decide whether to offer "exit and hand back, then re-arm". Passing it to the hook and not to the component left that radio hidden inside a commander — the one place it exists for. */} + {/* Before the first message, the pane explains itself. `EmbeddableChat`'s own empty state is "Send a + message to start", which is true and tells a first-time user nothing about what to send. */} + {chat.messages.length === 0 && } ); diff --git a/src/workspaces/officerdev/src/apps/CommandHQ/newCommanderGuide.ts b/src/workspaces/officerdev/src/apps/CommandHQ/newCommanderGuide.ts new file mode 100644 index 00000000..4f8335ef --- /dev/null +++ b/src/workspaces/officerdev/src/apps/CommandHQ/newCommanderGuide.ts @@ -0,0 +1,50 @@ +/* + What the pane says before a new commander has been spoken to. + + ── Why this is data, and why it is a skeleton ── + + The creation flow is being rebuilt. Starting a commander currently means knowing to open the background-job + dialog and arm a watcher from it, which is not discoverable and reads as configuration when it is really + just "talk to it" — so the dialog stops being the way in, and this pane explains the way in instead. + + The copy is NOT written yet, by agreement: the instructions have to describe a flow that does not exist + yet, and writing them before the flow is decided produces text that is wrong in a way nobody notices. + What is here is the structure plus the parts that are already TRUE regardless of what the flow becomes — + what a commander is, and that it begins as an ordinary conversation. + + Sections marked `provisional` render with a visible marker, so a half-written guide cannot ship looking + finished. Removing the flag is the last step of writing one, not a formatting choice. +*/ + +export type GuideSection = { + title: string; + /** One paragraph per entry. Kept as an array so a section can grow without touching the renderer. */ + body: string[]; + /** True until the copy is settled. Renders a marker; the whole point is that it is visible. */ + provisional?: boolean; +}; + +export const NEW_COMMANDER_GUIDE: GuideSection[] = [ + { + title: 'What a commander is', + body: [ + 'An agent that keeps working when you are not here — it waits for something to happen, acts on it, and reports back.', + 'It is an ordinary conversation. You start by telling it what to watch for and what to do about it, in your own words.', + ], + }, + { + title: 'Starting one', + provisional: true, + body: [ + 'Describe the job here, as you would to anybody. Say what it should watch, where, and what to do when it fires.', + 'TODO: the concrete steps, once the creation flow is settled. This replaces "open the background-job dialog and arm a watcher", which nobody could be expected to guess.', + ], + }, + { + title: 'While it runs', + provisional: true, + body: [ + 'TODO: what the owner sees — where its cost shows, how to read what its spawned agents are doing, and how to stop it.', + ], + }, +];