claude-code-session-manager 0.76.0 → 0.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{AgentLibrary-CBx9l4zN.js → AgentLibrary-B2ie8bbw.js} +2 -2
- package/dist/assets/{DataModel-Bf0EIE_t.js → DataModel-BIJPYw32.js} +1 -1
- package/dist/assets/{History-CpdtWhC8.js → History-CeY6dk9S.js} +2 -2
- package/dist/assets/{Hooks-DyUbMDmg.js → Hooks-BFH2ocKg.js} +2 -2
- package/dist/assets/{HostBilko-By-wIpry.js → HostBilko-36gj9wLz.js} +1 -1
- package/dist/assets/{Library-CQmo4QVC.js → Library-C-hBct39.js} +1 -1
- package/dist/assets/{ListDetail-BQMd6NOm.js → ListDetail-CNq64VWV.js} +1 -1
- package/dist/assets/{MarkdownEditor-DEp43FXX.js → MarkdownEditor-Bh3qt5-1.js} +1 -1
- package/dist/assets/{McpServers-CLarzwqA.js → McpServers-DpGN0oyz.js} +1 -1
- package/dist/assets/{Memory-B0sCdIy1.js → Memory-D59hUjC4.js} +6 -6
- package/dist/assets/{Panel-BhWPVOCD.js → Panel-DCgbaoci.js} +1 -1
- package/dist/assets/{Permissions-Ddlq8T_O.js → Permissions-DAmQ0DYV.js} +2 -2
- package/dist/assets/{Plugins-D2oA_2Jl.js → Plugins-Dyfgn6Is.js} +2 -2
- package/dist/assets/{ProvenanceBadge-DgAgavUM.js → ProvenanceBadge-BiYhPO1U.js} +1 -1
- package/dist/assets/SaveBar-RV7B6sOh.js +1 -0
- package/dist/assets/Scheduler-BPaNqx1b.js +14 -0
- package/dist/assets/{ScopeSwitcher-C_zWEtIl.js → ScopeSwitcher-P4mdLGNU.js} +1 -1
- package/dist/assets/{Settings-2Vx3X5SI.js → Settings-BL4vf5aX.js} +1 -1
- package/dist/assets/{SkillReferenceGraph-BDEUjlTQ.js → SkillReferenceGraph-BRBDyi1_.js} +1 -1
- package/dist/assets/{Skills-Cmrz_LeN.js → Skills-BV08gDUH.js} +2 -2
- package/dist/assets/{SystemPrompt-DVA1eYDP.js → SystemPrompt-CLftSsDw.js} +1 -1
- package/dist/assets/TagLibrary-Bp8jGsd5.js +1 -0
- package/dist/assets/{TiptapBody-DmPc3amD.js → TiptapBody-jCpuB6E5.js} +1 -1
- package/dist/assets/{Toggle-zfd5LJkK.js → Toggle-D2paA1xf.js} +1 -1
- package/dist/assets/{index-B_4PNh9T.js → index-BDRSqBl3.js} +175 -175
- package/dist/assets/{index-DIjnPkRN.css → index-CYhdtisq.css} +1 -1
- package/dist/assets/{settingsSchema-B9es6fdA.js → settingsSchema-6IOLjZZN.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +8 -2
- package/plugins/session-manager-dev/skills/develop/standards.md +1 -1
- package/scripts/project-pages-logic/dist/logic.cjs +4709 -0
- package/scripts/render-project-pages/dist/renderer.cjs +18900 -0
- package/scripts/render-project-pages.cjs +70 -0
- package/scripts/scheduler-mcp-server.cjs +115 -1
- package/scripts/validate-project-pages-summary.cjs +62 -0
- package/src/main/__tests__/agentModelResolve.test.cjs +66 -0
- package/src/main/__tests__/health-delegation-chain.test.cjs +2 -1
- package/src/main/__tests__/prdAgentType.test.cjs +103 -0
- package/src/main/__tests__/prdCreate.test.cjs +138 -0
- package/src/main/__tests__/prdFrontmatterAgentType.test.cjs +117 -0
- package/src/main/__tests__/prdFrontmatterQuietMachine.test.cjs +108 -0
- package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +485 -0
- package/src/main/__tests__/projectPages.test.cjs +73 -1
- package/src/main/__tests__/rcaReport.test.cjs +54 -0
- package/src/main/__tests__/runVerify.test.cjs +94 -0
- package/src/main/__tests__/scheduler-autofix-select.test.cjs +43 -0
- package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +103 -0
- package/src/main/__tests__/scheduler-effective-concurrency.test.cjs +10 -0
- package/src/main/__tests__/scheduler-foreign-wip-manifest.test.cjs +78 -0
- package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +242 -0
- package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +31 -0
- package/src/main/__tests__/scheduler-launch-failure.test.cjs +201 -0
- package/src/main/__tests__/scheduler-leftover-fields.test.cjs +52 -0
- package/src/main/__tests__/scheduler-looks-done.test.cjs +241 -0
- package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +135 -0
- package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +222 -0
- package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +147 -0
- package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +212 -0
- package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +194 -0
- package/src/main/__tests__/seedAgentPersonas.test.cjs +75 -14
- package/src/main/config.cjs +4 -1
- package/src/main/index.cjs +8 -1
- package/src/main/ipcSchemas.cjs +51 -0
- package/src/main/lib/__tests__/childWithLog.test.cjs +78 -0
- package/src/main/lib/__tests__/delegationReadiness.test.cjs +152 -2
- package/src/main/lib/__tests__/epicWorktreeMint.test.cjs +4 -2
- package/src/main/lib/__tests__/fixChainDepth.test.cjs +40 -0
- package/src/main/lib/__tests__/gitWorktree.test.cjs +277 -4
- package/src/main/lib/__tests__/gitWorktreeSalvageDelta.test.cjs +153 -0
- package/src/main/lib/__tests__/jobWorktree.test.cjs +5 -3
- package/src/main/lib/__tests__/landedSinceRun.test.cjs +73 -0
- package/src/main/lib/__tests__/launchFailure.test.cjs +220 -0
- package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +1 -0
- package/src/main/lib/__tests__/opsOwnership.test.cjs +7 -0
- package/src/main/lib/__tests__/prdDeclaredPaths.test.cjs +82 -0
- package/src/main/lib/__tests__/queueHealth.test.cjs +58 -0
- package/src/main/lib/__tests__/quietMachineLease.test.cjs +39 -0
- package/src/main/lib/__tests__/reaperHelpers.test.cjs +22 -1
- package/src/main/lib/__tests__/schedulerBatchLaunchHold.test.cjs +125 -0
- package/src/main/lib/__tests__/schedulerBatchQuietMachine.test.cjs +109 -0
- package/src/main/lib/__tests__/schedulerMcpServerHeadlessRefusal.test.cjs +71 -0
- package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +350 -0
- package/src/main/lib/agentModelResolve.cjs +58 -0
- package/src/main/lib/childWithLog.cjs +40 -5
- package/src/main/lib/claudeBin.cjs +54 -1
- package/src/main/lib/definitionOfDone.cjs +3 -2
- package/src/main/lib/delegationReadiness.cjs +115 -9
- package/src/main/lib/epicWorktreeMint.cjs +5 -2
- package/src/main/lib/fixChainDepth.cjs +45 -0
- package/src/main/lib/gitWorktree.cjs +464 -19
- package/src/main/lib/jobWorktree.cjs +1 -0
- package/src/main/lib/landedSinceRun.cjs +55 -0
- package/src/main/lib/launchFailure.cjs +357 -0
- package/src/main/lib/mcpToolCatalog.cjs +87 -2
- package/src/main/lib/opsOwnership.cjs +12 -0
- package/src/main/lib/prdAgentType.cjs +84 -0
- package/src/main/lib/prdCreate.cjs +57 -1
- package/src/main/lib/prdDeclaredPaths.cjs +70 -0
- package/src/main/lib/prdFrontmatter.cjs +17 -3
- package/src/main/lib/projectHomeAdminRoutes.cjs +402 -0
- package/src/main/lib/projectPageSummarySchema.cjs +181 -0
- package/src/main/lib/queueHealth.cjs +38 -0
- package/src/main/lib/queueStore.cjs +9 -2
- package/src/main/lib/quietMachineLease.cjs +48 -0
- package/src/main/lib/rcaReport.cjs +53 -3
- package/src/main/lib/reaperHelpers.cjs +18 -1
- package/src/main/lib/scheduleJobSchema.cjs +31 -0
- package/src/main/lib/scheduleJobTransitions.cjs +6 -2
- package/src/main/lib/schedulerBatch.cjs +133 -29
- package/src/main/lib/schedulerConfig.cjs +19 -0
- package/src/main/projectPages.cjs +160 -2
- package/src/main/runVerify.cjs +50 -9
- package/src/main/scheduler/prdParser.cjs +18 -1
- package/src/main/scheduler.cjs +1371 -97
- package/src/main/seedAgentPersonas.cjs +62 -21
- package/src/main/templates/project-pages-catalog.json +741 -0
- package/src/main/templates/project-pages-pipeline.md +417 -0
- package/src/preload/api.d.ts +118 -2
- package/src/preload/index.cjs +7 -0
- package/src/seed/agents/project-home-builder.md +59 -0
- package/dist/assets/SaveBar-Qvc4Ek-H.js +0 -1
- package/dist/assets/Scheduler-BmYJvNzK.js +0 -14
- package/dist/assets/TagLibrary-DYJGAKZu.js +0 -1
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
# Project Pages pipeline — architecture spec
|
|
2
|
+
|
|
3
|
+
Canonical design for the "Project Page" feature: Project Home generates 5
|
|
4
|
+
static HTML pages per project (**Home**, Marketing Landing, Feature
|
|
5
|
+
Description, Architecture Overview, **Brief**) from a fixed component
|
|
6
|
+
library, plus a never-generated "About these templates" view explaining the
|
|
7
|
+
five lenses and where to hand-edit them. This is the design source of truth
|
|
8
|
+
for the four `project_home_*` MCP tools (`project_home_get_contract`,
|
|
9
|
+
`project_home_validate_summary`, `project_home_render`, `project_home_status`,
|
|
10
|
+
served over the app's admin routes, PRD 1089) that actually drive a
|
|
11
|
+
`project-home-builder` Epic's session — edit here, not in the tool
|
|
12
|
+
implementations, when the design changes.
|
|
13
|
+
|
|
14
|
+
**Correction, PRD "project-home-portable-persona":** generation is no longer
|
|
15
|
+
grounded by pointing a session at this file (or any other repo-relative
|
|
16
|
+
path) directly. This spec stopped being something a builder Epic reads —
|
|
17
|
+
neither the seeded `project-home-builder` persona
|
|
18
|
+
(`src/seed/agents/project-home-builder.md`, delivered to
|
|
19
|
+
`~/.claude/agents/`) nor the `project-home-builder` Epic tag's grounding
|
|
20
|
+
prompt (`src/renderer/lib/agentTagDefs.ts`) names a repo path anymore, because
|
|
21
|
+
a builder Epic can run against a project that never had this repo checked
|
|
22
|
+
out (the npm-installed case). Instead, both now point a session at the
|
|
23
|
+
`project_home_get_contract` MCP tool as the FIRST call of the run — its
|
|
24
|
+
response is a fully self-contained protocol + schema + catalog payload
|
|
25
|
+
computed from this spec (see "Epic tag" below). This file remains the
|
|
26
|
+
design source of truth for whoever implements or changes the MCP tools
|
|
27
|
+
themselves; it is no longer read at generation time by the builder Epic.
|
|
28
|
+
session-manager's own repo keeps a lean project-local overlay,
|
|
29
|
+
`.claude/agents/project-home-builder.md`, that adds only session-manager-
|
|
30
|
+
specific historical context (the saved design-mock library) on top of the
|
|
31
|
+
seeded persona's real protocol — see that file.
|
|
32
|
+
|
|
33
|
+
**Correction, 2026-08-02:** the original spec shipped 3 lenses
|
|
34
|
+
(marketing/feature/architecture) only, with Project Home's own live Brief
|
|
35
|
+
dashboard staying a separate, hand-built React view above the generated
|
|
36
|
+
block. The human then asked for the Brief's own content to be available as a
|
|
37
|
+
4th generated template too ("Home") — same component-library/summary/picks
|
|
38
|
+
pipeline as the other three, reusing `identity`/`stats`/`pillars` (already
|
|
39
|
+
in `ProjectPageSummary`, no schema change needed) rather than the live
|
|
40
|
+
Epic-queue data the React Brief shows (that stays live-only; a static page
|
|
41
|
+
can't show "what's running right now" truthfully). The live Brief dashboard
|
|
42
|
+
above the Project Pages block is unchanged and still the primary live view —
|
|
43
|
+
Home is an *additional* static snapshot, not a replacement for it.
|
|
44
|
+
|
|
45
|
+
**Correction, 2026-08-03 (Epic "Project Home Layout"):** the 2026-08-02
|
|
46
|
+
correction above is now itself superseded. Project Home is no longer a
|
|
47
|
+
hand-built React page with a Project Pages viewer embedded at the bottom —
|
|
48
|
+
its primary content area IS the generated `home` document, hosted at a fixed
|
|
49
|
+
path, with a shipped default so a brand-new project is never empty. The
|
|
50
|
+
live Brief dashboard's synthesized fields (purpose/what/areas/scope/
|
|
51
|
+
conventions) become their own 5th generated lens, `brief`, rather than a
|
|
52
|
+
separate hand-built React block stack — see "Project Home is a hosted
|
|
53
|
+
document, not a React page" below for the full design, and Stage 4 for how
|
|
54
|
+
the display changes. `PhNow`/`PhOpenQuestions` (live Epic-queue and
|
|
55
|
+
open-question state) are the one part of the old React page that stays
|
|
56
|
+
live React, per the same "a static page can't show what's running right now
|
|
57
|
+
truthfully" reasoning the 2026-08-02 correction already established for
|
|
58
|
+
Epic-queue data.
|
|
59
|
+
|
|
60
|
+
## Project Home is a hosted document, not a React page
|
|
61
|
+
|
|
62
|
+
- Project Home's main content area renders a generated, self-contained
|
|
63
|
+
static HTML document, displayed via the same sandboxed
|
|
64
|
+
`<iframe sandbox="allow-same-origin" srcDoc={html} />` mechanism Stage 4
|
|
65
|
+
already uses for the other lenses — Project Home does not recompose this
|
|
66
|
+
content live in its own React tree.
|
|
67
|
+
- That document lives at a **fixed path**,
|
|
68
|
+
`session-manager-operations/project-pages/output/home.html` — this is what
|
|
69
|
+
the app always reads for Project Home's main view, regardless of whether
|
|
70
|
+
it was just generated or is days old.
|
|
71
|
+
- Session-manager **ships a default `home.html`** baked into the app build
|
|
72
|
+
(not per-project state — see "Storage / ownership" below). A brand-new
|
|
73
|
+
project with no generated output still renders a real page, never an
|
|
74
|
+
empty state.
|
|
75
|
+
- The only way that document is replaced is the **"Generate My Project
|
|
76
|
+
Home"** action, which creates (or resumes) an Epic tagged
|
|
77
|
+
`project-home-builder`, bound to the `project-home-builder` agent — reusing
|
|
78
|
+
the exact Epic-creation mechanism `ProjectPagesSection.tsx`'s
|
|
79
|
+
`findActiveBuilderEpic` + `composeEpicIntake` already implement for
|
|
80
|
+
"Generate Now" today (see Stage 4). Never an inline function call, never a
|
|
81
|
+
main-process `claude -p` spawn — same non-negotiable Stage 1 already
|
|
82
|
+
states for `summary.json`.
|
|
83
|
+
|
|
84
|
+
## Inputs (as specified by the human, 2026-08-01, extended 2026-08-02, 2026-08-03)
|
|
85
|
+
|
|
86
|
+
1. **Component Library** — fixed, ships with the app. Source design for the
|
|
87
|
+
original 3 lenses saved at
|
|
88
|
+
`session-manager-operations/design-mocks/project-pages-component-library/`
|
|
89
|
+
(read its `README.md` first) — the `home` lens has no saved design mock;
|
|
90
|
+
it was authored directly in
|
|
91
|
+
`src/renderer/lib/projectPages/library/homeSlots.tsx` reusing the same
|
|
92
|
+
`PageLensDef` shape and the marketing lens's `identity`/`stats`/`pillars`
|
|
93
|
+
fields, styled as an internal dashboard rather than an outward pitch. The
|
|
94
|
+
`brief` lens likewise has no saved design mock — it is authored directly
|
|
95
|
+
against `ProjectBrief`'s own fields (see "Stage 1" below for the exact
|
|
96
|
+
source-field mapping), styled as a straightforward read of what the
|
|
97
|
+
project is, what it does, and its conventions, rather than a pitch or a
|
|
98
|
+
dashboard.
|
|
99
|
+
Shape: 5 lenses (`home` / `marketing` / `feature` / `architecture` /
|
|
100
|
+
`brief`), each a stack of **slots**, each slot 2-4 **variant** components,
|
|
101
|
+
each lens shipping named **presets** (fixed slot→variant picks) plus a
|
|
102
|
+
"custom" override state.
|
|
103
|
+
2. **Project summary** — a JSON computed per project (see schema below).
|
|
104
|
+
3. **Summary → component mapping** — picks the best-fitting variant per slot
|
|
105
|
+
(and/or a whole preset) from the summary's content, then renders.
|
|
106
|
+
|
|
107
|
+
## Non-negotiables from the human's instructions
|
|
108
|
+
|
|
109
|
+
- Output **MUST be static HTML** — 5 files, one per lens. Project Home does
|
|
110
|
+
not recompose the pages live in its own React tree; it hosts pre-rendered
|
|
111
|
+
HTML. This is what "guaranteed to render" means: the generated artifact is
|
|
112
|
+
immune to the app's own React/Tailwind version ever drifting under it.
|
|
113
|
+
- Before the first "Generate My Project Home" run, Project Home renders the
|
|
114
|
+
**shipped default `home.html`** (see "Project Home is a hosted document,
|
|
115
|
+
not a React page" above) — no placeholder/fake content ever, and no
|
|
116
|
+
fabricated per-project claims in the default either (see Stage 4's
|
|
117
|
+
"Shipped default" subsection).
|
|
118
|
+
- Generation is not a bare function call — it runs as an Epic of a
|
|
119
|
+
**new type, `project-home-builder`**, so grounding, objective and output
|
|
120
|
+
are pinned before the agent starts (see "Epic tag" below), the same way
|
|
121
|
+
every other unit of work in this app is an Epic (CLAUDE.md's TAB/EPIC
|
|
122
|
+
domain model).
|
|
123
|
+
- The agent doing the generation is a **registered local agent**
|
|
124
|
+
(`.claude/agents/project-home-builder.md`), not an ad hoc prompt.
|
|
125
|
+
- Never fabricate content. Every field in the summary must trace to
|
|
126
|
+
something concrete (an Epic goal, a file/dir, a CLAUDE.md convention, a
|
|
127
|
+
git log entry) — same rule already enforced for `project-brief`, and now
|
|
128
|
+
also the rule governing the shipped default `home.html`'s copy.
|
|
129
|
+
|
|
130
|
+
## Stage 0 — Component Library (build-time asset, already captured)
|
|
131
|
+
|
|
132
|
+
Port `design-mocks/project-pages-component-library/source/*.jsx` into real
|
|
133
|
+
`.tsx` under `src/renderer/lib/projectPages/library/` (or a sibling location
|
|
134
|
+
a PRD should decide precisely). Precompile with esbuild into a pure
|
|
135
|
+
function:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
renderProjectPages(summary: ProjectPageSummary, picks: ProjectPagePicks)
|
|
139
|
+
=> { home: string; marketing: string; feature: string; architecture: string; brief: string }
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Each string is a **fully self-contained HTML document** — inline CSS, fonts
|
|
143
|
+
self-hosted as local assets bundled with the app (never fetched from Google
|
|
144
|
+
Fonts at generation time — this is the same "no network egress" principle
|
|
145
|
+
the design library's own `PROJ.arch.principles` already states). No runtime
|
|
146
|
+
JSX transform, no CDN script tags, no in-browser Babel (the source bundle
|
|
147
|
+
uses browser-side Babel for its own live-preview tool; that is NOT the
|
|
148
|
+
shipped renderer).
|
|
149
|
+
|
|
150
|
+
## Stage 1 — Project Summary (`ProjectPageSummary`, computed per project)
|
|
151
|
+
|
|
152
|
+
New schema, a strict superset of the existing `ProjectBrief`
|
|
153
|
+
(`session-manager-operations/project-brief/`, `purpose/what/areas/scope/
|
|
154
|
+
conventions` only). Build incrementally on top of an already-generated
|
|
155
|
+
Brief rather than re-reading the repo from scratch:
|
|
156
|
+
|
|
157
|
+
- `identity`: name, tagline, oneLine, claim, sub, install command — derived
|
|
158
|
+
from `package.json` + Brief's `purpose`.
|
|
159
|
+
- `stats[]`, `pillars[]` — derived from Brief's `areas` (file counts, heat,
|
|
160
|
+
notes become pillar copy).
|
|
161
|
+
- `feature` (ONE deep-dive) — derived from the most-active open Epic
|
|
162
|
+
(highest `heat`/most recent scope entries): name, problem/solution framed
|
|
163
|
+
from that Epic's goal + its scope-timeline entries, steps from its PRD
|
|
164
|
+
chain if one exists.
|
|
165
|
+
- `architecture` — layers/modules from Brief's `areas` + their `epic`
|
|
166
|
+
ownership; decisions from Brief's `scope` entries tagged `decided`; risks
|
|
167
|
+
are the one field with no clean Brief source — leave empty rather than
|
|
168
|
+
invent, or optionally source from open `discussion`-tagged Epics.
|
|
169
|
+
- `brief` — the `brief` lens's source fields, read directly off
|
|
170
|
+
`ProjectBrief` (`session-manager-operations/project-brief/brief.json`)
|
|
171
|
+
with no reshaping: `purpose` (string), `what[]`, `areas[]`, `scope[]`,
|
|
172
|
+
`conventions[]`. This is the generated form of what the live React Brief
|
|
173
|
+
used to render by hand (`PhWhat`/`PhAreas`/`PhScope`/`PhConventions`) —
|
|
174
|
+
the `brief` lens's slots map one-to-one to these four array fields plus
|
|
175
|
+
the `purpose` string; a later PRD implementing the lens should not need to
|
|
176
|
+
invent any additional source data. `brief.json`'s `pins` (per-block
|
|
177
|
+
edit-pins) still apply at the Brief-authoring layer (Stage 1, before this
|
|
178
|
+
mapping) — the `brief` lens renders whatever `brief.json` currently holds,
|
|
179
|
+
pinned or not, same as every other summary field here.
|
|
180
|
+
- `quotes[]` — **do not fabricate testimonials**. Either omit entirely
|
|
181
|
+
(proof-strip variants that need a quote simply aren't selectable) or wire
|
|
182
|
+
a future opt-in source (e.g. GitHub issue comments) — out of scope for v1.
|
|
183
|
+
|
|
184
|
+
Written to `session-manager-operations/project-pages/summary.json`.
|
|
185
|
+
|
|
186
|
+
**Correction vs. an earlier draft of this spec:** this is NOT a
|
|
187
|
+
`projectBrief.refresh`-style main-process-orchestrated `claude -p` spawn.
|
|
188
|
+
Per the human's explicit instruction, generation runs as a
|
|
189
|
+
`project-home-builder`-tagged **Epic** — an ordinary Chat/Terminal claude
|
|
190
|
+
session grounded by that tag's `initialPromptTemplate` (`agentTagDefs.ts`),
|
|
191
|
+
which drives the session to call the `project_home_get_contract` MCP tool
|
|
192
|
+
first and follow the protocol it returns (see the correction note at the top
|
|
193
|
+
of this file). That session reads `brief.json` and the repo directly
|
|
194
|
+
(Read/Grep/Bash tools) and composes `summary.json` itself, then writes it
|
|
195
|
+
via `project_home_render` (not a raw Write-tool file write — see Stage 3).
|
|
196
|
+
There is no separate nested `claude -p` call and no new main-process IPC for
|
|
197
|
+
synthesis beyond the four `project_home_*` admin-routed tools themselves.
|
|
198
|
+
Cost-gating is inherent: it only runs when a human clicks **"Generate My
|
|
199
|
+
Project Home"** (which creates/resumes the Epic), same discipline as any
|
|
200
|
+
other Epic. `brief.json` itself is still produced by
|
|
201
|
+
`projectBrief.refresh`'s existing main-process-orchestrated mechanism — that
|
|
202
|
+
mechanism is unchanged and stays, because `brief.json` remains an *input* to
|
|
203
|
+
Stage 1, read by the `project-home-builder` Epic session same as any other
|
|
204
|
+
repo file. What changes is only that `projectBrief.refresh` no longer has
|
|
205
|
+
its own dedicated user-facing button — see Stage 4's "One action, not two"
|
|
206
|
+
subsection.
|
|
207
|
+
|
|
208
|
+
## Stage 2 — Summary → component mapping (selection)
|
|
209
|
+
|
|
210
|
+
**Reversed 2026-08-03 (Epic "Project Home Layout"): there is no separate
|
|
211
|
+
deterministic selection stage.** The `project-home-builder` agent itself
|
|
212
|
+
picks each slot's variant, by reasoning over its composed summary against
|
|
213
|
+
the component library's own variant notes — the same class of step as
|
|
214
|
+
Stage 1's summary authoring, not a distinct machine-checkable predicate
|
|
215
|
+
scorer. Concretely: for each lens, for each slot, the agent reads the
|
|
216
|
+
candidate variants' prose `note`/description — served to it directly in
|
|
217
|
+
`project_home_get_contract`'s catalog response, sourced server-side from
|
|
218
|
+
`src/renderer/lib/projectPages/library/*.tsx` so the agent never needs to
|
|
219
|
+
read that source itself (e.g. "Needs a real quote.", "Needs a strong
|
|
220
|
+
screenshot.") — and judges which variant genuinely fits this project's
|
|
221
|
+
summary content, then passes the resulting picks to `project_home_render` —
|
|
222
|
+
no intermediate predicate language, no scorer script.
|
|
223
|
+
|
|
224
|
+
Output persisted to `session-manager-operations/project-pages/picks.json`
|
|
225
|
+
in the same shape as before (`Record<lensId, Record<slotId, variantId>>`),
|
|
226
|
+
plus a top-level `schemaVersion` field (see "Stale-picks migration" below).
|
|
227
|
+
**The 'respect existing hand-picks unless explicit start-over' rule is
|
|
228
|
+
unchanged and still what keeps selection stable across regenerates**: a
|
|
229
|
+
project's picks are judged once (or on an explicit reset request) and then
|
|
230
|
+
persisted like `project-brief`'s pinned blocks, so moving selection from a
|
|
231
|
+
script to agent judgment does not reintroduce per-regenerate
|
|
232
|
+
nondeterminism — the agent must not silently overwrite it (mirrors
|
|
233
|
+
`project-brief`'s per-block `pins`, but per-slot-pick here instead of
|
|
234
|
+
per-paragraph-text).
|
|
235
|
+
|
|
236
|
+
**Stale-picks migration (found 2026-08-03).** Today's on-disk
|
|
237
|
+
`picks.json` was written by the now-deleted deterministic scorer
|
|
238
|
+
(`selectionPredicates.ts`, retired by PRD 958) — every existing project's
|
|
239
|
+
picks are preset-`v1` defaults, not real judgment. The 'preserve existing
|
|
240
|
+
hand-picks on regenerate' rule above would otherwise grandfather these in
|
|
241
|
+
forever, silently defeating agent-owned selection for every project that
|
|
242
|
+
already has a `picks.json`. Decided: `picks.json` carries
|
|
243
|
+
`schemaVersion: 1` for scorer-era files (files with no `schemaVersion`
|
|
244
|
+
field at all are treated as `schemaVersion: 1` — the scorer never wrote
|
|
245
|
+
one) and `schemaVersion: 2` once written by the agent or hand-edited by a
|
|
246
|
+
human. On the first `project-home-builder` Epic run after this change, the
|
|
247
|
+
agent checks `picks.json`'s `schemaVersion`: if `1` (or absent), the
|
|
248
|
+
existing picks are **non-authoritative** — the agent re-judges every slot
|
|
249
|
+
from scratch (ignoring the stale values, not merging with them) and writes
|
|
250
|
+
the result back as `schemaVersion: 2`. Every later run treats a
|
|
251
|
+
`schemaVersion: 2` file as real hand/agent judgment and follows the normal
|
|
252
|
+
'preserve unless explicit start-over' rule. This re-judgment happens
|
|
253
|
+
exactly once per project, not on every run — `schemaVersion` is the marker
|
|
254
|
+
that prevents repeating it.
|
|
255
|
+
|
|
256
|
+
## Stage 3 — Render
|
|
257
|
+
|
|
258
|
+
`renderProjectPages(summary, picks)` → 5 HTML strings. Write to
|
|
259
|
+
`session-manager-operations/project-pages/output/{home,marketing,feature,
|
|
260
|
+
architecture,brief}.html` plus a `manifest.json` (`generatedAt`, `model`,
|
|
261
|
+
`summarySynthesizedAt`, and a drift flag vs. the Brief's own
|
|
262
|
+
`synthesizedAt` — same drift-chip idea `project-brief` already uses).
|
|
263
|
+
`output/home.html` is the fixed path Project Home's main view reads (see
|
|
264
|
+
"Project Home is a hosted document, not a React page" above) — it is
|
|
265
|
+
written by this same single render pass as the other four lenses, not by a
|
|
266
|
+
separate mechanism.
|
|
267
|
+
|
|
268
|
+
## Stage 4 — Project Home display
|
|
269
|
+
|
|
270
|
+
- **No empty state for the main view.** With a shipped default `home.html`
|
|
271
|
+
(see "Project Home is a hosted document, not a React page" above), Project
|
|
272
|
+
Home's main content area always has something real to show — either the
|
|
273
|
+
shipped default or a project-generated document. What the UI must surface
|
|
274
|
+
instead is **provenance**: a chip stating whether the currently-displayed
|
|
275
|
+
`home.html` is the shipped default or a generated document, and if
|
|
276
|
+
generated, when (`manifest.json`'s `generatedAt`). The **"Generate My
|
|
277
|
+
Project Home"** action is always available regardless of which state is
|
|
278
|
+
showing.
|
|
279
|
+
- **Shipped default `home.html`** is a **build-time asset**, not per-project
|
|
280
|
+
state — it ships baked into the app bundle (same "ships with the app"
|
|
281
|
+
status as the component library in Stage 0), not written into any
|
|
282
|
+
project's `session-manager-operations/`. It must be honest about being a
|
|
283
|
+
default: its copy describes what Project Home is in general and prompts
|
|
284
|
+
the reader to press "Generate My Project Home" — it must **not** contain
|
|
285
|
+
fabricated project-specific content (name, stats, claims about this
|
|
286
|
+
particular repo), per this spec's existing never-fabricate rule. The app
|
|
287
|
+
falls back to this shipped asset whenever a project's own
|
|
288
|
+
`output/home.html` is absent; once a project has generated its own, that
|
|
289
|
+
file (at the fixed per-project path) takes over and the shipped default is
|
|
290
|
+
never shown again for that project.
|
|
291
|
+
- **"Generate My Project Home"** click creates (or resumes) an Epic tagged
|
|
292
|
+
`project-home-builder` in the active project and sends it the tag's
|
|
293
|
+
grounding prompt (see Epic tag below) as the opening message — the Epic
|
|
294
|
+
IS the unit of work, same as every other Epic in this app. This reuses
|
|
295
|
+
the exact mechanism `ProjectPagesSection.tsx`'s `findActiveBuilderEpic` +
|
|
296
|
+
`composeEpicIntake` already implement today (there under the "Generate
|
|
297
|
+
Now"/"Regenerate" names) — no new Epic-creation code path, only a rename
|
|
298
|
+
and a widened trigger surface (see "One action, not two" below).
|
|
299
|
+
- **One action, not two.** Today there are two competing CTAs: "Refresh
|
|
300
|
+
brief" (regenerates `brief.json` for the old hand-built React blocks) and
|
|
301
|
+
"Generate Now"/"Regenerate" (regenerates the Project Pages HTML). These
|
|
302
|
+
**consolidate into the single "Generate My Project Home" action**, because
|
|
303
|
+
the Brief's content is now one of the five generated lenses (`brief`) —
|
|
304
|
+
there is no longer a separate live-React consumer of `brief.json` that
|
|
305
|
+
needs its own refresh trigger. `brief.json` itself, and the
|
|
306
|
+
`projectBrief.refresh` mechanism that writes it, are unchanged and still
|
|
307
|
+
needed — `brief.json` is still an *input* to Stage 1 (see Stage 1's
|
|
308
|
+
correction note above) — it simply stops being exposed as its own
|
|
309
|
+
user-facing button. "Generate My Project Home" is responsible for
|
|
310
|
+
ensuring `brief.json` is fresh enough before it runs Stages 1-3 (e.g.
|
|
311
|
+
invoking `projectBrief.refresh` itself as a first step, or the
|
|
312
|
+
`project-home-builder` agent reading `brief.json` and refreshing it
|
|
313
|
+
in-session if stale) — the exact mechanics of that call are an
|
|
314
|
+
implementation detail for the PRD that wires the button, not specified
|
|
315
|
+
further here.
|
|
316
|
+
- Once a project has generated its own `output/*.html`, Project Home renders
|
|
317
|
+
the 5 pages via a sandboxed
|
|
318
|
+
`<iframe sandbox="allow-same-origin" srcDoc={html} />`, toggled by lens
|
|
319
|
+
(Home / Marketing / Feature / Architecture / Brief) — never re-parsed into
|
|
320
|
+
the app's own React tree. The main Project Home view defaults to the
|
|
321
|
+
`home` lens; the other four remain reachable the same way
|
|
322
|
+
`ProjectPagesSection.tsx` exposes them today.
|
|
323
|
+
- **`PhNow` and `PhOpenQuestions` stay live React**, rendered as a thin strip
|
|
324
|
+
**above** the hosted HTML document (default or generated) rather than
|
|
325
|
+
folded into any generated lens. Reason: they show live state — "what is
|
|
326
|
+
in flight" (the live Epic queue) and "waiting on you" (live unresolved
|
|
327
|
+
questions) — and injecting live data into a generated static document
|
|
328
|
+
would violate this spec's own non-negotiable that the generated artifact
|
|
329
|
+
is "self-contained static HTML, immune to the app's own React/Tailwind
|
|
330
|
+
drift" (see "Non-negotiables" above): a document that embeds live data
|
|
331
|
+
stops being self-contained the moment that data changes underneath it.
|
|
332
|
+
This is the same reasoning the 2026-08-02 correction already applied to
|
|
333
|
+
the old React Brief's Epic-queue data — carried forward unchanged, just
|
|
334
|
+
now scoped to two specific components instead of the whole page.
|
|
335
|
+
- A 6th tab, **"About these templates,"** is always reachable (even before
|
|
336
|
+
the first "Generate My Project Home") and is never part of
|
|
337
|
+
`output/*.html` — it's static explainer copy
|
|
338
|
+
(`ProjectPagesLibraryExplainer` in `ProjectPagesSection.tsx`) naming the 5
|
|
339
|
+
lenses, their source slot files, and the 3 real on-disk paths a human
|
|
340
|
+
would touch to change what gets generated:
|
|
341
|
+
`project-pages/summary.json` (the computed inputs), `project-pages/
|
|
342
|
+
picks.json` (per-project, per-slot overrides — hand-edit a pick here and
|
|
343
|
+
regenerating preserves it, since the `project-home-builder` agent respects
|
|
344
|
+
existing picks unless explicitly told to start over, same rule Stage 2
|
|
345
|
+
already had — see Stage 2's schema-version note for the one-time
|
|
346
|
+
exception), and `src/renderer/lib/projectPages/library/` (the component
|
|
347
|
+
library itself, shared across every project — editing it is a code
|
|
348
|
+
change, not a per-project override).
|
|
349
|
+
|
|
350
|
+
## Storage / ownership
|
|
351
|
+
|
|
352
|
+
**Correction, PRD 1089/1090 (`project_home_*` MCP tools):** the write path
|
|
353
|
+
described in an earlier draft of this section — a builder Epic's own `Write`
|
|
354
|
+
tool writing `summary.json`/`picks.json`/`output/*.html` directly, with no
|
|
355
|
+
`OWNERS` entry needed because no main-process code was involved — is
|
|
356
|
+
superseded. `project_home_render` now writes those files via the app's
|
|
357
|
+
admin API, which IS main-process code going through `config.cjs`'s write
|
|
358
|
+
helpers. `project-pages` is therefore now listed in `OWNERS`
|
|
359
|
+
(`src/main/lib/opsOwnership.cjs`), owned by `project-home`, scoped to the
|
|
360
|
+
app's admin render route only (per CLAUDE.md's domain-model law) — see
|
|
361
|
+
`project-pages/README.md` for the exact split. A builder Epic's own direct
|
|
362
|
+
Write-tool authoring of anything under `project-pages/` (as opposed to going
|
|
363
|
+
through `project_home_render`) stays ungoverned/unsupported; the sanctioned
|
|
364
|
+
path for a builder Epic is always the MCP tool, never a raw file write.
|
|
365
|
+
|
|
366
|
+
The concurrency concern is real but bounded a different way: "Generate My
|
|
367
|
+
Project Home" must check for an already-active `project-home-builder` Epic
|
|
368
|
+
for this project and **resume/focus it** instead of creating a second one —
|
|
369
|
+
the same "refuse a live session" guard pattern `deleteEpic` already uses
|
|
370
|
+
elsewhere — rather than relying on filesystem-level write arbitration.
|
|
371
|
+
|
|
372
|
+
The **shipped default `home.html`** is a different storage class again: it
|
|
373
|
+
is packaged with the app build itself (e.g. under the renderer's own static
|
|
374
|
+
assets, resolved at runtime the same way other build-time-baked assets are)
|
|
375
|
+
— it is never written to, or read from, any project's
|
|
376
|
+
`session-manager-operations/` tree, and carries no per-project state at all.
|
|
377
|
+
It is not part of `project-pages/` and is not a candidate for an `OWNERS`
|
|
378
|
+
entry.
|
|
379
|
+
|
|
380
|
+
Add `session-manager-operations/project-pages/README.md` once the first
|
|
381
|
+
file lands, documenting the shape (matching `design-mocks/`'s and
|
|
382
|
+
`HUMAN_LEARN/`'s own READMEs, not an `OWNERS` namespace README).
|
|
383
|
+
|
|
384
|
+
## Epic tag: `project-home-builder`
|
|
385
|
+
|
|
386
|
+
Added to `src/renderer/lib/tagLibrary.ts` (`EpicTag` union + `TAG_LIBRARY`
|
|
387
|
+
entry) and `src/renderer/lib/agentTagDefs.ts` (`AGENT_TAG_DEFS` entry with
|
|
388
|
+
an `initialPromptTemplate` that grounds the session): call
|
|
389
|
+
`project_home_get_contract` first — its response IS the protocol, the
|
|
390
|
+
schemas, and the catalog, entirely self-contained — then follow it through
|
|
391
|
+
`project_home_validate_summary` → `project_home_render` →
|
|
392
|
+
`project_home_status`. The template names no repo-relative path (this is
|
|
393
|
+
what makes generation work on a machine with only the npm package
|
|
394
|
+
installed) and explicitly instructs the session to report and stop, never
|
|
395
|
+
build pipeline infrastructure, if the contract tool is unavailable or
|
|
396
|
+
errors. Deliberately **not**
|
|
397
|
+
added to `AGENT_TAG_DEFS`'s `AGENT_TAG_ORDER` yet — same precedent as the
|
|
398
|
+
existing `build` tag ("no UI surface to create a build-tagged Epic exists
|
|
399
|
+
yet"): the creation surface (the "Generate My Project Home" button) is
|
|
400
|
+
itself one of the PRDs building this feature, so it adds the tag to
|
|
401
|
+
`AGENT_TAG_ORDER` at the same time it wires the button, rather than exposing
|
|
402
|
+
a half-built creation path in the New Epic composer before that button
|
|
403
|
+
exists.
|
|
404
|
+
|
|
405
|
+
## Screenshots
|
|
406
|
+
|
|
407
|
+
Several variants need real app screenshots (`FvShot` placeholders in the
|
|
408
|
+
saved library). Reuse the existing `blog-for-project-feature` skill's real-
|
|
409
|
+
capture pipeline rather than building a second one — out of scope for the
|
|
410
|
+
first PRD chain; ship with the honest placeholder pattern until wired.
|
|
411
|
+
|
|
412
|
+
## Explicit non-goals for v1
|
|
413
|
+
|
|
414
|
+
- No installable "design pack" packaging (Stage 0 ships baked into the app;
|
|
415
|
+
making it swappable is a later roadmap item, not part of this build).
|
|
416
|
+
- No automatic/background regeneration — manual trigger only, same
|
|
417
|
+
cost-discipline as `project-brief`.
|
package/src/preload/api.d.ts
CHANGED
|
@@ -461,6 +461,11 @@ export interface ScheduleJob {
|
|
|
461
461
|
finishedAt: string | null;
|
|
462
462
|
exitCode: number | null;
|
|
463
463
|
error: string | null;
|
|
464
|
+
/** Structured terminal-outcome label set alongside `error` (never replacing
|
|
465
|
+
* it) so a reader can tell "the gate ran and went red" (failed) apart from
|
|
466
|
+
* "the gate never got to run" (never_ran) — reaperHelpers.cjs's
|
|
467
|
+
* mapOutcomeToGateOutcome (PRD 1109). */
|
|
468
|
+
gateOutcome?: 'passed' | 'failed' | 'never_ran' | 'unknown';
|
|
464
469
|
/** Claude session UUID passed via `--session-id`. Set when the job spawns
|
|
465
470
|
* and persisted across queue reloads so the renderer can find the JSONL
|
|
466
471
|
* transcript even after restart. */
|
|
@@ -500,6 +505,62 @@ export interface ScheduleJob {
|
|
|
500
505
|
* change be reviewed after the fact instead of only inferred from a
|
|
501
506
|
* heartbeat count. */
|
|
502
507
|
statusHistory?: ScheduleJobStatusHistoryEntry[];
|
|
508
|
+
/** Opt-in PRD frontmatter flag (PRD 1107): dispatched only when zero other
|
|
509
|
+
* jobs are running machine-wide, and holds an exclusive lease over the
|
|
510
|
+
* whole session-slot pool for its run — no other job dispatches while it
|
|
511
|
+
* is running. For timing-sensitive acceptance criteria (frame time,
|
|
512
|
+
* performance fences) that need to trust their own numbers. */
|
|
513
|
+
quietMachine?: boolean;
|
|
514
|
+
/** True when a `quietMachine` job was dispatched anyway after waiting past
|
|
515
|
+
* the configurable quiet-wait interval without the machine going quiet —
|
|
516
|
+
* tells a reader its measurements ran under contention. */
|
|
517
|
+
quietLeaseDegraded?: boolean;
|
|
518
|
+
/** Process-group survivors childWithLog.cjs's sweepChildProcessGroup found
|
|
519
|
+
* still alive right before sweeping them (PRD 1110). [] in the normal
|
|
520
|
+
* case — a non-empty array means the job backgrounded work that outlived
|
|
521
|
+
* it and had to be reaped; the job's `status` is unaffected. */
|
|
522
|
+
leakedDescendants?: LeakedDescendant[];
|
|
523
|
+
/** Path to a patch file (`<slug>.uncommitted.patch` in the run dir)
|
|
524
|
+
* salvaging this job's uncommitted worktree/in-place diff before it was
|
|
525
|
+
* lost — set whenever the commit-guard's worktree or in-place salvage
|
|
526
|
+
* pass produced one (PRD 1098). */
|
|
527
|
+
salvagePatch?: string | null;
|
|
528
|
+
/** Why a pending row is not being dispatched this tick (worktree cap, launch circuit breaker). */
|
|
529
|
+
heldReason?: string;
|
|
530
|
+
/** Set when this row's last dispatch never got a model turn (issue #11): the
|
|
531
|
+
* API's own message, and how many times in a row it has happened. Cleared
|
|
532
|
+
* by the next run that finalizes. */
|
|
533
|
+
launchFailure?: {
|
|
534
|
+
kind: ScheduleLaunchFailureKind;
|
|
535
|
+
httpStatus: number | null;
|
|
536
|
+
message: string;
|
|
537
|
+
at: string;
|
|
538
|
+
runId: string | null;
|
|
539
|
+
count: number;
|
|
540
|
+
mitigationApplied: boolean;
|
|
541
|
+
};
|
|
542
|
+
/** Closed-set outcome taxonomy stamped at finalize: 'completed',
|
|
543
|
+
* 'impl_failed:exit_N', 'signal_kill', 'signal_kill_with_commit',
|
|
544
|
+
* 'verifier:<verdict>', 'worktree_integration_failed', 'launch_failure:<kind>'. */
|
|
545
|
+
terminalReason?: string;
|
|
546
|
+
/** The newly-dirty paths a terminal run left uncommitted, diffed against
|
|
547
|
+
* the pre-run baseline — set on EVERY terminal outcome that left dirt
|
|
548
|
+
* (completed/failed/needs_review alike, not just the exit=0 commit-guard
|
|
549
|
+
* path), deleted when the run left nothing. Capped at 50 entries;
|
|
550
|
+
* `leftoverCount` carries the true total and `leftoverPathsTruncated` is
|
|
551
|
+
* set when the list was cut. Lets the queue row show e.g. "left 4 files
|
|
552
|
+
* uncommitted" on a bare `failed` row, distinguishing it from one that
|
|
553
|
+
* left nothing. */
|
|
554
|
+
leftoverPaths?: string[];
|
|
555
|
+
leftoverCount?: number;
|
|
556
|
+
leftoverPathsTruncated?: boolean;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
export interface LeakedDescendant {
|
|
560
|
+
pid: number;
|
|
561
|
+
pcpu: number;
|
|
562
|
+
etimes: number;
|
|
563
|
+
comm: string;
|
|
503
564
|
}
|
|
504
565
|
|
|
505
566
|
export interface ScheduleJobStatusHistoryEntry {
|
|
@@ -593,8 +654,51 @@ export interface SchedulePollHealth {
|
|
|
593
654
|
/** One `pending` job held by an unsatisfied dependency, and which dep. */
|
|
594
655
|
export interface ScheduleJobHold {
|
|
595
656
|
slug: string;
|
|
596
|
-
|
|
597
|
-
|
|
657
|
+
/** The dependency slug holding this row, or null for a non-dependency hold (launch circuit breaker). */
|
|
658
|
+
dep: string | null;
|
|
659
|
+
depStatus: string | null;
|
|
660
|
+
/** Human-readable hold reason when `dep` is null. */
|
|
661
|
+
reason?: string | null;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/** Why a headless run never got a model turn (lib/launchFailure.cjs, issue #11). */
|
|
665
|
+
export type ScheduleLaunchFailureKind =
|
|
666
|
+
| 'model_config_rejected'
|
|
667
|
+
| 'bad_request'
|
|
668
|
+
| 'auth_failed'
|
|
669
|
+
| 'model_not_found'
|
|
670
|
+
| 'api_overloaded'
|
|
671
|
+
| 'api_error';
|
|
672
|
+
|
|
673
|
+
/** One persona's open launch circuit breaker. Keyed by the PRD `agentType` (or 'default' / 'investigation'). */
|
|
674
|
+
export interface ScheduleLaunchBlock {
|
|
675
|
+
kind: ScheduleLaunchFailureKind;
|
|
676
|
+
httpStatus: number | null;
|
|
677
|
+
/** The API's own message, verbatim (bounded). */
|
|
678
|
+
message: string;
|
|
679
|
+
/** Operator-facing explanation + the action that clears it. */
|
|
680
|
+
hint: string;
|
|
681
|
+
since: string;
|
|
682
|
+
lastAt: string;
|
|
683
|
+
/** ISO time of the next half-open probe; null = exhausted (waits for a CLI version change or Retry). */
|
|
684
|
+
until: string | null;
|
|
685
|
+
attempts: number;
|
|
686
|
+
exhausted: boolean;
|
|
687
|
+
claudeVersion: string | null;
|
|
688
|
+
lastSlug: string | null;
|
|
689
|
+
lastRunId: string | null;
|
|
690
|
+
mitigationEnv: Record<string, string> | null;
|
|
691
|
+
mitigationApplied: boolean;
|
|
692
|
+
probing: { slug: string; at: string } | null;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/** Degraded-mode env a persona is currently launching with (e.g. thinking disabled for an outdated CLI). */
|
|
696
|
+
export interface ScheduleLaunchMitigation {
|
|
697
|
+
kind: ScheduleLaunchFailureKind;
|
|
698
|
+
env: Record<string, string>;
|
|
699
|
+
since: string;
|
|
700
|
+
claudeVersion: string | null;
|
|
701
|
+
hint: string;
|
|
598
702
|
}
|
|
599
703
|
|
|
600
704
|
/** Outcome of the scheduler's last tick — why the batch was (or wasn't) fired.
|
|
@@ -641,6 +745,10 @@ export interface ScheduleStateSnapshot {
|
|
|
641
745
|
nextReset: string | null;
|
|
642
746
|
/** Set when scheduler self-paused (rate-limit detected). null when running normally. */
|
|
643
747
|
paused: SchedulePauseInfo | null;
|
|
748
|
+
/** Launch circuit breakers currently open, keyed by persona. Empty when every persona can launch. */
|
|
749
|
+
launchBlocks?: Record<string, ScheduleLaunchBlock>;
|
|
750
|
+
/** Degraded-mode launch env in force per persona. Empty when nothing is degraded. */
|
|
751
|
+
launchMitigations?: Record<string, ScheduleLaunchMitigation>;
|
|
644
752
|
/** Latest five_hour utilization percent (0–100) cached from billing.fetchUsage. null if unknown. */
|
|
645
753
|
utilization: number | null;
|
|
646
754
|
/** Poll health — last billing poll result; used to detect stale utilization. */
|
|
@@ -1647,6 +1755,12 @@ export interface SessionManagerAPI {
|
|
|
1647
1755
|
projectPages: {
|
|
1648
1756
|
/** Read output/*.html + manifest.json (or `{output: null}` if none exist yet). Never fires an LLM call. */
|
|
1649
1757
|
get: (cwd: string) => Promise<ProjectPagesGetResult>;
|
|
1758
|
+
/** Start pushing `onChanged` events for this cwd's output dir. Refcounted per cwd; `ok:false` (reason 'ephemeral'|'invalid-cwd') means no live updates are possible, not an error. */
|
|
1759
|
+
watch: (cwd: string) => Promise<{ ok: boolean; reason?: 'ephemeral' | 'invalid-cwd' }>;
|
|
1760
|
+
/** Stop pushing `onChanged` events for this cwd — must be paired 1:1 with a prior `watch` call. */
|
|
1761
|
+
unwatch: (cwd: string) => Promise<{ ok: boolean }>;
|
|
1762
|
+
/** Fires whenever a watched cwd's project-pages output dir changes, carrying the freshly recomputed output. */
|
|
1763
|
+
onChanged: (handler: (payload: { cwd: string; output: ProjectPagesOutput | null }) => void) => () => void;
|
|
1650
1764
|
};
|
|
1651
1765
|
bilkoHost: {
|
|
1652
1766
|
/** Read compatibility-gate inputs + any existing bundle/publish state. Never fires an LLM call. */
|
|
@@ -1832,6 +1946,7 @@ export interface PromptSessionsCreateWorktreeResult {
|
|
|
1832
1946
|
branch: string;
|
|
1833
1947
|
baseCwd: string;
|
|
1834
1948
|
status: 'active' | 'needs_merge_resolution' | 'merged' | 'disabled';
|
|
1949
|
+
carriedPaths?: string[];
|
|
1835
1950
|
}
|
|
1836
1951
|
|
|
1837
1952
|
// ─────────────────────────────────── PromptSessions merge-to-main (main-side integrateEpicBranch)
|
|
@@ -1840,6 +1955,7 @@ export interface PromptSessionsMergeToMainPayload {
|
|
|
1840
1955
|
epicId: string;
|
|
1841
1956
|
branch: string;
|
|
1842
1957
|
dir: string;
|
|
1958
|
+
carriedPaths?: string[];
|
|
1843
1959
|
}
|
|
1844
1960
|
|
|
1845
1961
|
export interface PromptSessionsMergeToMainResult {
|
package/src/preload/index.cjs
CHANGED
|
@@ -304,6 +304,13 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
304
304
|
},
|
|
305
305
|
projectPages: {
|
|
306
306
|
get: (cwd) => ipcRenderer.invoke('project-pages:get', { cwd }),
|
|
307
|
+
watch: (cwd) => ipcRenderer.invoke('project-pages:watch', { cwd }),
|
|
308
|
+
unwatch: (cwd) => ipcRenderer.invoke('project-pages:unwatch', { cwd }),
|
|
309
|
+
onChanged: (handler) => {
|
|
310
|
+
const listener = (_e, payload) => handler(payload);
|
|
311
|
+
ipcRenderer.on('project-pages:changed', listener);
|
|
312
|
+
return () => ipcRenderer.removeListener('project-pages:changed', listener);
|
|
313
|
+
},
|
|
307
314
|
},
|
|
308
315
|
bilkoHost: {
|
|
309
316
|
get: (cwd) => ipcRenderer.invoke('bilko-host:get', { cwd }),
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: project-home-builder
|
|
3
|
+
description: Generates a project's 5 static Project Page HTML files (Home / Marketing Landing / Feature Description / Architecture Overview / Brief) by following the session-manager app's own MCP contract for the pipeline — portable to any machine with the app installed, no source-repo paths required.
|
|
4
|
+
tools: Read, Grep, Glob, Bash, Write, Edit
|
|
5
|
+
title: Project Pages — Builder
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the project-home-builder. Your whole job is to generate a project's Project Home pages by
|
|
9
|
+
following the exact protocol the session-manager app hands you over MCP — never by re-deriving the
|
|
10
|
+
pipeline from a repo you may not have, and never by inventing content.
|
|
11
|
+
|
|
12
|
+
## Ground on the live contract, every run
|
|
13
|
+
|
|
14
|
+
1. Call `project_home_get_contract` FIRST, before composing or reading anything else. It returns
|
|
15
|
+
everything you need: the operating protocol, the `ProjectPageSummary`/`ProjectPagePicks` JSON
|
|
16
|
+
schemas, the full component catalog for every lens (which slots exist, which variants are
|
|
17
|
+
available per slot, and each variant's own selection notes), the exact output paths, and the
|
|
18
|
+
full pipeline spec text.
|
|
19
|
+
2. Follow the protocol the contract response describes. It is the single source of truth for this
|
|
20
|
+
run — do not fall back to a remembered or assumed version of the pipeline shape.
|
|
21
|
+
3. If `project_home_get_contract` is unavailable, errors, or the MCP tools it depends on
|
|
22
|
+
(`project_home_validate_summary`, `project_home_render`, `project_home_status`) are not present
|
|
23
|
+
in this session's toolset: **report that plainly and stop.** Do not attempt to build, script, or
|
|
24
|
+
hand-roll any part of the pipeline yourself, and do not treat the missing contract as a coding
|
|
25
|
+
task for this Epic. The pipeline is owned by the session-manager app, not by the target project.
|
|
26
|
+
|
|
27
|
+
## Hard rules
|
|
28
|
+
|
|
29
|
+
- **Never fabricate.** Every field of the summary you author must trace to something concrete about
|
|
30
|
+
the real project: an Epic goal, a source file/dir, a documented convention, a git log entry, or an
|
|
31
|
+
existing project brief. An omitted field beats an invented one, every time — no invented stats, no
|
|
32
|
+
invented testimonials/quotes, no invented screenshots.
|
|
33
|
+
- **Author the summary from real evidence.** Read the target project itself (its repo tree, its git
|
|
34
|
+
history, its own docs/brief, its active Epics) to build the `ProjectPageSummary` the contract's
|
|
35
|
+
schema describes — the contract gives you the shape, not the content.
|
|
36
|
+
- **Validate before you render.** Call `project_home_validate_summary` with your composed summary
|
|
37
|
+
and fix every returned `{field, message}` error, re-validating until it reports `valid: true`.
|
|
38
|
+
Don't skip straight to rendering an unvalidated summary.
|
|
39
|
+
- **Choose picks from the returned catalog only.** For every lens/slot the contract's catalog lists,
|
|
40
|
+
pick the one variant that genuinely fits this project's summary content, using the catalog's own
|
|
41
|
+
per-variant notes — never a variant name you assumed instead of one the catalog actually offered.
|
|
42
|
+
- **Respect existing picks on a regenerate.** If the project already has picks for a slot, keep them
|
|
43
|
+
unless this run was explicitly asked to start over — same spirit as any other pinned-content
|
|
44
|
+
regenerate.
|
|
45
|
+
- **Cost-gated, manual only.** This is a real-cost pass. Run it once per explicit "Generate" /
|
|
46
|
+
"Regenerate" request — never automatically, never in a loop.
|
|
47
|
+
|
|
48
|
+
## Protocol
|
|
49
|
+
|
|
50
|
+
1. `project_home_get_contract` — read its protocol, schemas, and catalog before anything else.
|
|
51
|
+
2. Gather real evidence about the target project and compose a `ProjectPageSummary` matching the
|
|
52
|
+
contract's schema.
|
|
53
|
+
3. `project_home_validate_summary` with that summary — fix and repeat until `valid: true`.
|
|
54
|
+
4. Choose one variant per lens/slot from the contract's catalog, forming a `ProjectPagePicks` object
|
|
55
|
+
in the shape the contract specifies.
|
|
56
|
+
5. `project_home_render` with the validated summary and the picks — this is the only write path;
|
|
57
|
+
it re-validates server-side and writes nothing on schema failure.
|
|
58
|
+
6. `project_home_status` — confirm the expected files now exist with a fresh `generatedAt`, and
|
|
59
|
+
report what was generated.
|