mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
p2 rewritten by the Chord v2 authoring rules (decision "App authoring rules confirmed by the p2 audit"), in four parts merged together: - core: session lifecycle (relocate, clone, fork, archive) and search rebuild are persisted jobs on a new server store; Sessions v6 with client-chosen ids and visible operations; Retry answers with the worker's real outcome; workers push branch, subagent and status state to the server; roots take the method's ctx. - services: models, envs, ports, login, mcp, logs, sharing and voice follow external state (self.follow, followNative) instead of copy loops; methods answer after their state commits; presence from host.references. - chat: chat mode, artifacts and prompt resources follow Durable and native state; shell commands are Chord jobs (shellId is the requestId); status pushed before send and stop answer; race-free draft claim. - ui: optimistic updates on web (useOptimistic) and terminal (TuiScope.optimistic, extended in Chord with a reducer and a pending flag), pending states for long work, visible rollback, load waterfalls removed; merged with the one composer and immediate first send (ccff9876e) and the folder + button (5a31a6d5f). docs/optimistic-ui.md describes the pattern.
66 lines
1.9 KiB
TypeScript
66 lines
1.9 KiB
TypeScript
// The owner's sheet for a `/tree` branch's label (docs/tree.md): a new label, or for conversation 1 the session title.
|
|
import { Sheet } from "@p2/app/v1/web";
|
|
import { useState } from "react";
|
|
import { PREVIEW_LENGTH } from "../tree/contract.ts";
|
|
|
|
/**
|
|
* Renames a branch; `label` null shows `title` (conversation 1's default), and only conversation 1 may go back to it.
|
|
* Saving closes the sheet: the row shows the new label while the rename is in flight.
|
|
*/
|
|
export function BranchSheet({
|
|
title,
|
|
conversation,
|
|
label,
|
|
onSave,
|
|
onClose,
|
|
}: {
|
|
/** The session title, what a null label shows. */
|
|
title: string;
|
|
conversation: number;
|
|
label: string | null;
|
|
onSave: (label: string | null) => void;
|
|
onClose: () => void;
|
|
}) {
|
|
const [draft, setDraft] = useState(label ?? title);
|
|
const next = draft.replace(/\s+/g, " ").trim();
|
|
const resettable = conversation === 1;
|
|
const unchanged = next === (label ?? title);
|
|
const save = (value: string | null) => {
|
|
onSave(value);
|
|
onClose();
|
|
};
|
|
return (
|
|
<Sheet title="Branch name" onClose={onClose}>
|
|
<form
|
|
className="stack"
|
|
onSubmit={(event) => {
|
|
event.preventDefault();
|
|
if (!unchanged && (next || resettable)) save(next || null);
|
|
}}
|
|
>
|
|
<label className="field">
|
|
<span className="label">Label in the sidebar and /tree</span>
|
|
<input
|
|
className="input"
|
|
value={draft}
|
|
maxLength={PREVIEW_LENGTH}
|
|
onChange={(event) => setDraft(event.target.value)}
|
|
/>
|
|
</label>
|
|
{resettable && (
|
|
<p className="muted small">The first branch shows the session title until it gets a label of its own.</p>
|
|
)}
|
|
<div className="inline-form">
|
|
<button type="submit" className="button" disabled={unchanged || (!next && !resettable)}>
|
|
Save
|
|
</button>
|
|
{resettable && label !== null && (
|
|
<button type="button" className="text-action" onClick={() => save(null)}>
|
|
Use the session title
|
|
</button>
|
|
)}
|
|
</div>
|
|
</form>
|
|
</Sheet>
|
|
);
|
|
}
|