a new commander pane explains itself, in skeleton
Starting a commander currently means knowing to open the background-job dialog and arm a watcher from it. That is not discoverable, and it reads as configuration when the real answer is "talk to it" — so the dialog stops being the way in, and the pane explains the way in instead. EmbeddableChat's own empty state is "Send a message to start". True, and it tells a first-time user nothing about what to send. The copy is NOT written, by agreement: the instructions have to describe a flow that does not exist yet, and writing them first produces text that is wrong in a way nobody notices. What is here is the structure, plus the parts already true whatever the flow becomes — what a commander is, and that it begins as an ordinary conversation. Sections carry a `provisional` flag that renders a visible "draft" marker. That is the load-bearing detail: this ships on every deploy whether the copy is ready or not, so a half-written guide must not be able to look finished. Clearing the flag is the last step of writing a section, not a formatting choice. Data rather than JSX, so filling it in later is editing one array instead of hunting through markup — the same shape as the shortcuts registry. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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 = () => (
|
||||
<div className="shrink-0 overflow-y-auto border-b border-border px-5 py-4">
|
||||
<div className="mx-auto flex max-w-2xl flex-col gap-4">
|
||||
{NEW_COMMANDER_GUIDE.map((section) => (
|
||||
<section key={section.title}>
|
||||
<h3 className="flex items-center gap-2 text-sm font-semibold text-foreground">
|
||||
{section.title}
|
||||
{section.provisional && (
|
||||
<span className="rounded bg-warning/15 px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-warning">
|
||||
draft
|
||||
</span>
|
||||
)}
|
||||
</h3>
|
||||
{section.body.map((paragraph) => (
|
||||
<p key={paragraph} className="mt-1 text-sm leading-relaxed text-muted-foreground">
|
||||
{paragraph}
|
||||
</p>
|
||||
))}
|
||||
</section>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
/**
|
||||
* 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 && <NewCommanderGuide />}
|
||||
<EmbeddableChat chat={chat} sessionId={undefined} context="command-hq" className="min-h-0 flex-1" />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -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.',
|
||||
],
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user