feat: record_directive — the PM's ledger in pm-state (P4, completes Reginald)
The last agent tool. When the PM states standing intent ("pilots come first"),
Reginald logs it verbatim to an append-only JSONL ledger in the pm-state repo —
a directive is intent; its effects still land through propose_change. This
completes Reginald's tool surface: query_project · propose_change · capture_work
· record_directive.
core (@commitea/core):
- directives/record-directive-v0: schema (kind/quote/target/params/rationale +
id/ts/status), serialize/parseDirectiveLog (ts-ordered, seq computed on read,
corrupt lines skipped), appendDirective (concatenation merge), toDirectiveInput.
- RECORD_DIRECTIVE_TOOL + system prompt update ("log standing intent; never claim
a change is applied").
- gitea client: getFile/putFile (contents API, base64-agnostic) for the pm-state repo.
app:
- main: a pm-state client (same token, `commitea-pm-state` repo — the purity
split, D4); appendDirectiveEntry (read→append→write, id/ts stamped here),
readDirectives. model:chat executes record_directive; pmstate:directives reads
the ledger. Degrades cleanly when the pm-state repo is absent.
- Directives screen shows the real ledger when present, the fixture demo otherwise.
Note: the pm-state repo isn't created yet — my token lacks write:user (repo
creation). Create `commitea-pm-state` (private) to activate the live path; all the
code + tests are in place. Override with COMMITEA_PMSTATE_REPO.
Verified: 116 core tests green (8 directive + 2 contents-API added), desktop
typecheck clean, 14 fixture e2e green. Gated live test: the real gemma-4-26b calls
record_directive for "pilots come first" (logs intent, doesn't claim to apply it);
the append/read + POST/PUT contents paths are unit-tested.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,35 @@ export function DirectivesScreen() {
|
||||
const [pending, setPending] = React.useState<DirectivePending | null>(DIRECTIVES.pending)
|
||||
const [entries, setEntries] = React.useState<DirectiveEntry[]>(DIRECTIVES.entries)
|
||||
|
||||
// Real ledger from the pm-state repo, when it exists — else the fixture demo.
|
||||
React.useEffect(() => {
|
||||
let alive = true
|
||||
window.commitea.pmstate
|
||||
.directives()
|
||||
.then((r) => {
|
||||
if (!alive || !r.ok || r.directives.length === 0) return
|
||||
setPending(null)
|
||||
setEntries(
|
||||
r.directives
|
||||
.slice()
|
||||
.reverse()
|
||||
.map((d) => ({
|
||||
seq: d.seq,
|
||||
who: 'You',
|
||||
when: new Date(d.ts).toLocaleDateString(),
|
||||
what: d.quote,
|
||||
why: d.rationale ?? '',
|
||||
status: d.status === 'accepted' ? 'applied' : d.status === 'withdrawn' ? 'withdrawn' : 'superseded',
|
||||
consequence: '',
|
||||
})),
|
||||
)
|
||||
})
|
||||
.catch(() => {})
|
||||
return () => {
|
||||
alive = false
|
||||
}
|
||||
}, [])
|
||||
|
||||
const resolve = (status: string) => {
|
||||
setEntries((e) => [{
|
||||
seq: pending!.seq, who: pending!.who, when: pending!.when, what: pending!.what, why: 'pilot demo on the 14th',
|
||||
|
||||
12
apps/desktop/src/renderer/src/global.d.ts
vendored
12
apps/desktop/src/renderer/src/global.d.ts
vendored
@@ -4,6 +4,7 @@ import type {
|
||||
ChatMessage,
|
||||
CaptureProposal,
|
||||
DependencyEdge,
|
||||
DirectiveRecord,
|
||||
GiteaIssue,
|
||||
GiteaMilestone,
|
||||
IssueChange,
|
||||
@@ -55,12 +56,23 @@ export interface ModelBridge {
|
||||
capture(braindump: string): Promise<CaptureResult>
|
||||
}
|
||||
|
||||
/** The result of reading the directive ledger. */
|
||||
export type DirectivesResult =
|
||||
| { ok: false; reason: 'unconfigured' | 'error'; message?: string }
|
||||
| { ok: true; directives: DirectiveRecord[] }
|
||||
|
||||
/** The pm-state bridge (machine-derived state) exposed by the preload over IPC. */
|
||||
export interface PmStateBridge {
|
||||
directives(): Promise<DirectivesResult>
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
commitea: {
|
||||
platform: string
|
||||
gitea: GiteaBridge
|
||||
model: ModelBridge
|
||||
pmstate: PmStateBridge
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user