@deskwork/studio 0.18.0 → 0.19.1

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.
@@ -1,28 +1,34 @@
1
1
  /**
2
2
  * Studio dashboard page — `/dev/editorial-studio`.
3
3
  *
4
- * Pipeline-redesign Task 34. The dashboard renders eight stage
5
- * sections — Ideas PlannedOutliningDrafting Final
6
- * Published, plus Blocked and Cancelled — backed by sidecar reads
7
- * under `<projectRoot>/.deskwork/entries/*.json`. Each row carries
8
- * the entry's iteration count for its current stage and a
9
- * reviewState badge so an operator can see at a glance where each
10
- * entry sits without opening it.
4
+ * The dashboard renders eight stage sections — Ideas → Planned →
5
+ * OutliningDraftingFinalPublished, plus Blocked and
6
+ * Cancelled — backed by sidecar reads under
7
+ * `<projectRoot>/.deskwork/entries/*.json`, with a Distribution
8
+ * placeholder pinned at the end. Each row carries the entry's slug,
9
+ * title, updated-at timestamp, and stage-gated verb buttons that
10
+ * clipboard-copy `/deskwork:<verb> <slug>` (THESIS Consequence 2 —
11
+ * the studio routes commands; skills do the work). On phone (≤600px)
12
+ * each stage section is collapsed by default and fronted by a tile
13
+ * (see Compact-1 in DESIGN-STANDARDS.md); on desktop everything is
14
+ * expanded with the existing `<h2 class="er-section-head">` heading
15
+ * carrying the stage name.
11
16
  *
12
- * Replaces the legacy calendar.md + workflow store rendering. The
13
- * scaffold (folio, masthead, filter strip, layout) is preserved so
14
- * existing CSS keeps working.
17
+ * Per DESKWORK-STATE-MACHINE.md (Commandment III), reviewState is
18
+ * RETIRED. Rows do NOT carry per-stage iteration counts or
19
+ * reviewState badges; that legacy "at-a-glance" surfacing was
20
+ * removed in v0.19.
15
21
  *
16
22
  * The renderer's data flow:
17
23
  * 1. loadDashboardData reads every sidecar and groups by stage.
18
- * 2. Each of the eight stages renders via `renderStageSection`.
19
- * 3. The Distribution placeholder pins beneath the stage sections.
24
+ * 2. Each stage renders via `renderStageSection`.
25
+ * 3. The Distribution placeholder renders below the stage sections.
26
+ * 4. The mobile-only Compose chrome (FAB + slide-up sheet) renders
27
+ * at the page tail; CSS hides it on desktop.
20
28
  *
21
- * The legacy export `renderDashboard` stays server.ts wires it as
22
- * the page handler. The `getIndex` parameter is preserved for
23
- * signature compatibility with the override resolver in server.ts;
24
- * the new dashboard does not currently consume it (sidecars are the
25
- * data source, not the on-disk content tree).
29
+ * `getIndex` is preserved for signature compatibility with the
30
+ * override resolver in server.ts; the dashboard does not consume it
31
+ * (sidecars are the data source, not the on-disk content tree).
26
32
  */
27
33
  import { html, unsafe } from "./html.js";
28
34
  import { layout } from "./layout.js";
@@ -30,7 +36,6 @@ import { renderEditorialFolio } from "./chrome.js";
30
36
  import { loadDashboardData, DASHBOARD_STAGE_ORDER } from "./dashboard/data.js";
31
37
  import { renderStageSection, renderDistributionPlaceholder, } from "./dashboard/section.js";
32
38
  import { renderHeader, renderFilterStrip } from "./dashboard/header.js";
33
- import { renderPressQueue } from "./dashboard/press-queue.js";
34
39
  /**
35
40
  * Render the studio dashboard. Async because sidecar reads hit disk;
36
41
  * the route handler in server.ts awaits the result before sending it.
@@ -45,19 +50,20 @@ export async function renderDashboard(ctx, getIndex) {
45
50
  const bucket = data.byStage.get(stage) ?? [];
46
51
  return renderStageSection(stage, bucket, defaultSite).__raw;
47
52
  }).join('\n');
53
+ // The press queue (right-rail on desktop) was removed in v0.19
54
+ // per DESKWORK-STATE-MACHINE.md Commandment III — its primary
55
+ // purpose was surfacing review-state, which is RETIRED. The
56
+ // archive entry at docs/studio-design/ACCEPTED/2026-05-09-press-queue-removed/
57
+ // captures the rationale.
48
58
  const body = html `
49
59
  ${renderEditorialFolio('dashboard', 'press-check')}
50
60
  ${renderHeader(data, ctx.projectRoot, now)}
51
61
  <main class="er-container">
52
62
  ${renderFilterStrip()}
53
- <div class="er-layout">
54
- <div>
55
- ${unsafe(stageSections)}
56
- ${renderDistributionPlaceholder()}
57
- </div>
58
- ${renderPressQueue(data.entries, defaultSite, now)}
59
- </div>
63
+ ${unsafe(stageSections)}
64
+ ${renderDistributionPlaceholder()}
60
65
  </main>
66
+ ${renderComposeChrome()}
61
67
  <div class="er-toast" data-toast hidden></div>
62
68
  <div class="er-poll-indicator" data-poll>auto-refresh · 10s</div>`;
63
69
  return layout({
@@ -66,10 +72,84 @@ export async function renderDashboard(ctx, getIndex) {
66
72
  '/static/css/editorial-review.css',
67
73
  '/static/css/editorial-nav.css',
68
74
  '/static/css/editorial-studio.css',
75
+ '/static/css/dashboard-mobile.css',
69
76
  ],
70
77
  bodyAttrs: 'data-review-ui="studio"',
71
78
  bodyHtml: body,
72
79
  scriptModules: ['editorial-studio-client'],
73
80
  });
74
81
  }
82
+ /**
83
+ * Mobile-only Compose chrome — a floating "+ Compose" chip at bottom-right
84
+ * and a slide-up sheet listing creation verbs. The chip and sheet are
85
+ * `display: none` on desktop (see dashboard-mobile.css); on phone the
86
+ * chip is the operator's primary path to /deskwork:add, /deskwork:ingest,
87
+ * and /deskwork:shortform-start.
88
+ *
89
+ * Each verb card is a `<button data-compose-verb data-copy="...">`. The
90
+ * client-side controller in `dashboard/compose-chip.ts` handles the
91
+ * clipboard write via copyOrShowFallback (THESIS Consequence 2 — agent
92
+ * does the work; the studio routes intent). We deliberately do NOT use
93
+ * the existing `.er-copy-btn` class on these buttons because that class
94
+ * triggers a textContent swap on success, which would clobber the rich
95
+ * verb-card markup; the compose-chip controller handles feedback via a
96
+ * `.is-copied` class instead.
97
+ */
98
+ function renderComposeChrome() {
99
+ return unsafe(html `
100
+ <button class="er-compose-fab" data-compose-fab type="button" aria-controls="er-compose-sheet" aria-expanded="false">
101
+ <span class="er-compose-fab-glyph" aria-hidden="true">+</span>
102
+ <span class="er-compose-fab-label">Compose</span>
103
+ </button>
104
+ <section
105
+ class="er-compose-sheet"
106
+ id="er-compose-sheet"
107
+ data-compose-sheet
108
+ hidden
109
+ role="dialog"
110
+ aria-modal="false"
111
+ aria-label="Compose creation verbs"
112
+ >
113
+ <div class="er-compose-scrim" data-compose-scrim></div>
114
+ <div class="er-compose-panel">
115
+ <button class="er-compose-handle" data-compose-handle type="button" aria-label="Drag to dismiss compose sheet">
116
+ <span class="er-compose-handle-bar" aria-hidden="true"></span>
117
+ </button>
118
+ <header class="er-compose-head">
119
+ <span class="er-compose-kicker">+ Compose · creation verbs</span>
120
+ <span class="er-compose-meta">tap copies the command</span>
121
+ <button class="er-compose-close" data-compose-close type="button" aria-label="Close compose sheet">×</button>
122
+ </header>
123
+ <div class="er-compose-body">
124
+ <button class="er-compose-verb" data-compose-verb data-copy="/deskwork:add" type="button">
125
+ <span class="er-compose-verb-head">
126
+ <span class="er-compose-verb-glyph" aria-hidden="true">+</span>
127
+ <span class="er-compose-verb-name">New idea</span>
128
+ <span class="er-compose-verb-cmd">/deskwork:add</span>
129
+ </span>
130
+ <span class="er-compose-verb-desc">Capture a new pitch as an Ideas-stage entry. Scaffolds an idea.md with sidecar; the agent picks up from there.</span>
131
+ <span class="er-compose-verb-foot">tap → clipboard · paste in Claude Code</span>
132
+ </button>
133
+ <button class="er-compose-verb" data-compose-verb data-copy="/deskwork:ingest" type="button">
134
+ <span class="er-compose-verb-head">
135
+ <span class="er-compose-verb-glyph" aria-hidden="true">⤓</span>
136
+ <span class="er-compose-verb-name">Ingest existing</span>
137
+ <span class="er-compose-verb-cmd">/deskwork:ingest</span>
138
+ </span>
139
+ <span class="er-compose-verb-desc">Backfill markdown that already exists on disk. Walks files / globs, derives slug + state + date, and (after dry-run) writes calendar rows.</span>
140
+ <span class="er-compose-verb-foot">tap → clipboard · paste in Claude Code</span>
141
+ </button>
142
+ <button class="er-compose-verb" data-compose-verb data-copy="/deskwork:shortform-start" type="button">
143
+ <span class="er-compose-verb-head">
144
+ <span class="er-compose-verb-glyph" aria-hidden="true">⊜</span>
145
+ <span class="er-compose-verb-name">Shortform start</span>
146
+ <span class="er-compose-verb-cmd">/deskwork:shortform-start</span>
147
+ </span>
148
+ <span class="er-compose-verb-desc">Start a LinkedIn / Reddit / YouTube / Instagram draft for a Published or Drafting entry. Same review pipeline as longform.</span>
149
+ <span class="er-compose-verb-foot">tap → clipboard · paste in Claude Code</span>
150
+ </button>
151
+ </div>
152
+ </div>
153
+ </section>`);
154
+ }
75
155
  //# sourceMappingURL=dashboard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/pages/dashboard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EACL,kBAAkB,EAClB,6BAA6B,GAC9B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAW9D;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAkB,EAClB,QAA+B;IAE/B,iEAAiE;IACjE,KAAK,QAAQ,CAAC;IAEd,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IAE7C,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;IAC3C,MAAM,aAAa,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACxD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7C,OAAO,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC;IAC9D,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,IAAI,GAAG,IAAI,CAAA;IACf,oBAAoB,CAAC,WAAW,EAAE,aAAa,CAAC;IAChD,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC;;MAEtC,iBAAiB,EAAE;;;UAGf,MAAM,CAAC,aAAa,CAAC;UACrB,6BAA6B,EAAE;;QAEjC,gBAAgB,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC;;;;oEAIY,CAAC;IAEnE,OAAO,MAAM,CAAC;QACZ,KAAK,EAAE,mBAAmB;QAC1B,QAAQ,EAAE;YACR,kCAAkC;YAClC,+BAA+B;YAC/B,kCAAkC;SACnC;QACD,SAAS,EAAE,yBAAyB;QACpC,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,CAAC,yBAAyB,CAAC;KAC3C,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/pages/dashboard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EACL,kBAAkB,EAClB,6BAA6B,GAC9B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAWxE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAkB,EAClB,QAA+B;IAE/B,iEAAiE;IACjE,KAAK,QAAQ,CAAC;IAEd,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IAE7C,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;IAC3C,MAAM,aAAa,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACxD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7C,OAAO,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC;IAC9D,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,+DAA+D;IAC/D,8DAA8D;IAC9D,4DAA4D;IAC5D,+EAA+E;IAC/E,0BAA0B;IAC1B,MAAM,IAAI,GAAG,IAAI,CAAA;IACf,oBAAoB,CAAC,WAAW,EAAE,aAAa,CAAC;IAChD,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC;;MAEtC,iBAAiB,EAAE;MACnB,MAAM,CAAC,aAAa,CAAC;MACrB,6BAA6B,EAAE;;IAEjC,mBAAmB,EAAE;;oEAE2C,CAAC;IAEnE,OAAO,MAAM,CAAC;QACZ,KAAK,EAAE,mBAAmB;QAC1B,QAAQ,EAAE;YACR,kCAAkC;YAClC,+BAA+B;YAC/B,kCAAkC;YAClC,kCAAkC;SACnC;QACD,SAAS,EAAE,yBAAyB;QACpC,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,CAAC,yBAAyB,CAAC;KAC3C,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,SAAS,mBAAmB;IAC1B,OAAO,MAAM,CAAC,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAsDP,CAAC,CAAC;AACf,CAAC"}
@@ -1,32 +1,38 @@
1
1
  /**
2
2
  * Studio dashboard page — `/dev/editorial-studio`.
3
3
  *
4
- * Pipeline-redesign Task 34. The dashboard renders eight stage
5
- * sections — Ideas PlannedOutliningDrafting Final
6
- * Published, plus Blocked and Cancelled — backed by sidecar reads
7
- * under `<projectRoot>/.deskwork/entries/*.json`. Each row carries
8
- * the entry's iteration count for its current stage and a
9
- * reviewState badge so an operator can see at a glance where each
10
- * entry sits without opening it.
4
+ * The dashboard renders eight stage sections — Ideas → Planned →
5
+ * OutliningDraftingFinalPublished, plus Blocked and
6
+ * Cancelled — backed by sidecar reads under
7
+ * `<projectRoot>/.deskwork/entries/*.json`, with a Distribution
8
+ * placeholder pinned at the end. Each row carries the entry's slug,
9
+ * title, updated-at timestamp, and stage-gated verb buttons that
10
+ * clipboard-copy `/deskwork:<verb> <slug>` (THESIS Consequence 2 —
11
+ * the studio routes commands; skills do the work). On phone (≤600px)
12
+ * each stage section is collapsed by default and fronted by a tile
13
+ * (see Compact-1 in DESIGN-STANDARDS.md); on desktop everything is
14
+ * expanded with the existing `<h2 class="er-section-head">` heading
15
+ * carrying the stage name.
11
16
  *
12
- * Replaces the legacy calendar.md + workflow store rendering. The
13
- * scaffold (folio, masthead, filter strip, layout) is preserved so
14
- * existing CSS keeps working.
17
+ * Per DESKWORK-STATE-MACHINE.md (Commandment III), reviewState is
18
+ * RETIRED. Rows do NOT carry per-stage iteration counts or
19
+ * reviewState badges; that legacy "at-a-glance" surfacing was
20
+ * removed in v0.19.
15
21
  *
16
22
  * The renderer's data flow:
17
23
  * 1. loadDashboardData reads every sidecar and groups by stage.
18
- * 2. Each of the eight stages renders via `renderStageSection`.
19
- * 3. The Distribution placeholder pins beneath the stage sections.
24
+ * 2. Each stage renders via `renderStageSection`.
25
+ * 3. The Distribution placeholder renders below the stage sections.
26
+ * 4. The mobile-only Compose chrome (FAB + slide-up sheet) renders
27
+ * at the page tail; CSS hides it on desktop.
20
28
  *
21
- * The legacy export `renderDashboard` stays server.ts wires it as
22
- * the page handler. The `getIndex` parameter is preserved for
23
- * signature compatibility with the override resolver in server.ts;
24
- * the new dashboard does not currently consume it (sidecars are the
25
- * data source, not the on-disk content tree).
29
+ * `getIndex` is preserved for signature compatibility with the
30
+ * override resolver in server.ts; the dashboard does not consume it
31
+ * (sidecars are the data source, not the on-disk content tree).
26
32
  */
27
33
 
28
34
  import type { StudioContext } from '../routes/api.ts';
29
- import { html, unsafe } from './html.ts';
35
+ import { html, unsafe, type RawHtml } from './html.ts';
30
36
  import { layout } from './layout.ts';
31
37
  import { renderEditorialFolio } from './chrome.ts';
32
38
  import { loadDashboardData, DASHBOARD_STAGE_ORDER } from './dashboard/data.ts';
@@ -35,7 +41,6 @@ import {
35
41
  renderDistributionPlaceholder,
36
42
  } from './dashboard/section.ts';
37
43
  import { renderHeader, renderFilterStrip } from './dashboard/header.ts';
38
- import { renderPressQueue } from './dashboard/press-queue.ts';
39
44
  import type { ContentIndex } from '@deskwork/core/content-index';
40
45
 
41
46
  /**
@@ -66,19 +71,20 @@ export async function renderDashboard(
66
71
  return renderStageSection(stage, bucket, defaultSite).__raw;
67
72
  }).join('\n');
68
73
 
74
+ // The press queue (right-rail on desktop) was removed in v0.19
75
+ // per DESKWORK-STATE-MACHINE.md Commandment III — its primary
76
+ // purpose was surfacing review-state, which is RETIRED. The
77
+ // archive entry at docs/studio-design/ACCEPTED/2026-05-09-press-queue-removed/
78
+ // captures the rationale.
69
79
  const body = html`
70
80
  ${renderEditorialFolio('dashboard', 'press-check')}
71
81
  ${renderHeader(data, ctx.projectRoot, now)}
72
82
  <main class="er-container">
73
83
  ${renderFilterStrip()}
74
- <div class="er-layout">
75
- <div>
76
- ${unsafe(stageSections)}
77
- ${renderDistributionPlaceholder()}
78
- </div>
79
- ${renderPressQueue(data.entries, defaultSite, now)}
80
- </div>
84
+ ${unsafe(stageSections)}
85
+ ${renderDistributionPlaceholder()}
81
86
  </main>
87
+ ${renderComposeChrome()}
82
88
  <div class="er-toast" data-toast hidden></div>
83
89
  <div class="er-poll-indicator" data-poll>auto-refresh · 10s</div>`;
84
90
 
@@ -88,9 +94,84 @@ export async function renderDashboard(
88
94
  '/static/css/editorial-review.css',
89
95
  '/static/css/editorial-nav.css',
90
96
  '/static/css/editorial-studio.css',
97
+ '/static/css/dashboard-mobile.css',
91
98
  ],
92
99
  bodyAttrs: 'data-review-ui="studio"',
93
100
  bodyHtml: body,
94
101
  scriptModules: ['editorial-studio-client'],
95
102
  });
96
103
  }
104
+
105
+ /**
106
+ * Mobile-only Compose chrome — a floating "+ Compose" chip at bottom-right
107
+ * and a slide-up sheet listing creation verbs. The chip and sheet are
108
+ * `display: none` on desktop (see dashboard-mobile.css); on phone the
109
+ * chip is the operator's primary path to /deskwork:add, /deskwork:ingest,
110
+ * and /deskwork:shortform-start.
111
+ *
112
+ * Each verb card is a `<button data-compose-verb data-copy="...">`. The
113
+ * client-side controller in `dashboard/compose-chip.ts` handles the
114
+ * clipboard write via copyOrShowFallback (THESIS Consequence 2 — agent
115
+ * does the work; the studio routes intent). We deliberately do NOT use
116
+ * the existing `.er-copy-btn` class on these buttons because that class
117
+ * triggers a textContent swap on success, which would clobber the rich
118
+ * verb-card markup; the compose-chip controller handles feedback via a
119
+ * `.is-copied` class instead.
120
+ */
121
+ function renderComposeChrome(): RawHtml {
122
+ return unsafe(html`
123
+ <button class="er-compose-fab" data-compose-fab type="button" aria-controls="er-compose-sheet" aria-expanded="false">
124
+ <span class="er-compose-fab-glyph" aria-hidden="true">+</span>
125
+ <span class="er-compose-fab-label">Compose</span>
126
+ </button>
127
+ <section
128
+ class="er-compose-sheet"
129
+ id="er-compose-sheet"
130
+ data-compose-sheet
131
+ hidden
132
+ role="dialog"
133
+ aria-modal="false"
134
+ aria-label="Compose creation verbs"
135
+ >
136
+ <div class="er-compose-scrim" data-compose-scrim></div>
137
+ <div class="er-compose-panel">
138
+ <button class="er-compose-handle" data-compose-handle type="button" aria-label="Drag to dismiss compose sheet">
139
+ <span class="er-compose-handle-bar" aria-hidden="true"></span>
140
+ </button>
141
+ <header class="er-compose-head">
142
+ <span class="er-compose-kicker">+ Compose · creation verbs</span>
143
+ <span class="er-compose-meta">tap copies the command</span>
144
+ <button class="er-compose-close" data-compose-close type="button" aria-label="Close compose sheet">×</button>
145
+ </header>
146
+ <div class="er-compose-body">
147
+ <button class="er-compose-verb" data-compose-verb data-copy="/deskwork:add" type="button">
148
+ <span class="er-compose-verb-head">
149
+ <span class="er-compose-verb-glyph" aria-hidden="true">+</span>
150
+ <span class="er-compose-verb-name">New idea</span>
151
+ <span class="er-compose-verb-cmd">/deskwork:add</span>
152
+ </span>
153
+ <span class="er-compose-verb-desc">Capture a new pitch as an Ideas-stage entry. Scaffolds an idea.md with sidecar; the agent picks up from there.</span>
154
+ <span class="er-compose-verb-foot">tap → clipboard · paste in Claude Code</span>
155
+ </button>
156
+ <button class="er-compose-verb" data-compose-verb data-copy="/deskwork:ingest" type="button">
157
+ <span class="er-compose-verb-head">
158
+ <span class="er-compose-verb-glyph" aria-hidden="true">⤓</span>
159
+ <span class="er-compose-verb-name">Ingest existing</span>
160
+ <span class="er-compose-verb-cmd">/deskwork:ingest</span>
161
+ </span>
162
+ <span class="er-compose-verb-desc">Backfill markdown that already exists on disk. Walks files / globs, derives slug + state + date, and (after dry-run) writes calendar rows.</span>
163
+ <span class="er-compose-verb-foot">tap → clipboard · paste in Claude Code</span>
164
+ </button>
165
+ <button class="er-compose-verb" data-compose-verb data-copy="/deskwork:shortform-start" type="button">
166
+ <span class="er-compose-verb-head">
167
+ <span class="er-compose-verb-glyph" aria-hidden="true">⊜</span>
168
+ <span class="er-compose-verb-name">Shortform start</span>
169
+ <span class="er-compose-verb-cmd">/deskwork:shortform-start</span>
170
+ </span>
171
+ <span class="er-compose-verb-desc">Start a LinkedIn / Reddit / YouTube / Instagram draft for a Published or Drafting entry. Same review pipeline as longform.</span>
172
+ <span class="er-compose-verb-foot">tap → clipboard · paste in Claude Code</span>
173
+ </button>
174
+ </div>
175
+ </div>
176
+ </section>`);
177
+ }
@@ -241,7 +241,7 @@ function renderStudioSection() {
241
241
  <div class="eh-panel">
242
242
  <p class="eh-panel-head">Secondary surfaces</p>
243
243
  <h4>Entry review</h4>
244
- <p><code>/dev/editorial-review/entry/&lt;uuid&gt;</code>. The current-stage artifact (idea.md, plan.md, outline.md, or index.md) renders inside the review surface. Select text for a margin note; double-click anywhere to edit the markdown in place. The fixed strip's Approve / Iterate / (Reject — disabled, see <a href="https://github.com/audiocontrol-org/deskwork/issues/173">#173</a>) buttons COPY the corresponding skill command (<code>/deskwork:approve &lt;slug&gt;</code>, etc.) to your clipboard — paste into a Claude Code chat to run. The skill reads marginalia, applies editorial judgment, edits the file (when iterating), advances state. The review is keyed by entry uuid, not workflow id.</p>
244
+ <p><code>/dev/editorial-review/entry/&lt;uuid&gt;</code>. The current-stage artifact (idea.md, plan.md, outline.md, or index.md) renders inside the review surface. Select text for a margin note; double-click anywhere to edit the markdown in place. The fixed strip's Approve / Iterate / (Reject — disabled, see <a href="https://github.com/audiocontrol-org/deskwork/issues/173">#173</a>) buttons COPY the corresponding skill command (<code>/deskwork:approve &lt;slug&gt;</code>, etc.) to your clipboard — paste into a Claude Code chat to run. The skill reads marginalia, applies editorial judgment, edits the file (iterate), or graduates the entry to the next pipeline stage (approve). Iterate is stage-gated — only available on Ideas / Planned / Outlining / Drafting; Final locks content. The review is keyed by entry uuid, not workflow id.</p>
245
245
  <h4>Shortform review</h4>
246
246
  <p><code>/dev/editorial-review-shortform</code>. Cards grouped by platform. Each card has a version header, an editable textarea, and save · approve · iterate · reject controls.</p>
247
247
  <h4>Keyboard</h4>
@@ -259,7 +259,7 @@ function renderStudioSection(): RawHtml {
259
259
  <div class="eh-panel">
260
260
  <p class="eh-panel-head">Secondary surfaces</p>
261
261
  <h4>Entry review</h4>
262
- <p><code>/dev/editorial-review/entry/&lt;uuid&gt;</code>. The current-stage artifact (idea.md, plan.md, outline.md, or index.md) renders inside the review surface. Select text for a margin note; double-click anywhere to edit the markdown in place. The fixed strip's Approve / Iterate / (Reject — disabled, see <a href="https://github.com/audiocontrol-org/deskwork/issues/173">#173</a>) buttons COPY the corresponding skill command (<code>/deskwork:approve &lt;slug&gt;</code>, etc.) to your clipboard — paste into a Claude Code chat to run. The skill reads marginalia, applies editorial judgment, edits the file (when iterating), advances state. The review is keyed by entry uuid, not workflow id.</p>
262
+ <p><code>/dev/editorial-review/entry/&lt;uuid&gt;</code>. The current-stage artifact (idea.md, plan.md, outline.md, or index.md) renders inside the review surface. Select text for a margin note; double-click anywhere to edit the markdown in place. The fixed strip's Approve / Iterate / (Reject — disabled, see <a href="https://github.com/audiocontrol-org/deskwork/issues/173">#173</a>) buttons COPY the corresponding skill command (<code>/deskwork:approve &lt;slug&gt;</code>, etc.) to your clipboard — paste into a Claude Code chat to run. The skill reads marginalia, applies editorial judgment, edits the file (iterate), or graduates the entry to the next pipeline stage (approve). Iterate is stage-gated — only available on Ideas / Planned / Outlining / Drafting; Final locks content. The review is keyed by entry uuid, not workflow id.</p>
263
263
  <h4>Shortform review</h4>
264
264
  <p><code>/dev/editorial-review-shortform</code>. Cards grouped by platform. Each card has a version header, an editable textarea, and save · approve · iterate · reject controls.</p>
265
265
  <h4>Keyboard</h4>
@@ -20,13 +20,15 @@ import type { Entry } from '@deskwork/core/schema/entry';
20
20
  import type { StudioContext } from '../routes/api.ts';
21
21
  /**
22
22
  * Pick the entry that should be the default Longform-reviews target —
23
- * the most-recent in-pipeline entry whose review state is in-review or
24
- * iterating. Returns null when no candidate exists; the caller falls
25
- * back to the dashboard's Review section anchor.
23
+ * the most-recently-updated entry in a stage that permits edits
24
+ * (Ideas / Planned / Outlining / Drafting). Returns null when no
25
+ * candidate exists.
26
26
  *
27
- * Replaces the legacy workflow-based picker as part of the pipeline
28
- * redesign (Task 36) the studio's review surfaces are now keyed by
29
- * entry uuid, not workflow uuid.
27
+ * Per DESKWORK-STATE-MACHINE.md (v5): the previous reviewState filter
28
+ * (in-review / iterating) is retired. Stage IS the state machine; the
29
+ * editable-stage filter approximates "the entry the operator is most
30
+ * likely actively working on" without depending on the retired
31
+ * reviewState concept.
30
32
  */
31
33
  export declare function pickDefaultLongformEntry(entries: readonly Entry[]): Entry | null;
32
34
  export declare function renderStudioIndex(ctx: StudioContext): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pages/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAqDtD;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,SAAS,KAAK,EAAE,GACxB,KAAK,GAAG,IAAI,CAOd;AAkKD,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA8B3E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pages/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAqDtD;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,SAAS,KAAK,EAAE,GACxB,KAAK,GAAG,IAAI,CAMd;AAmKD,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA8B3E"}
@@ -30,18 +30,19 @@ const LONGFORM_PIPELINE_STAGES = new Set([
30
30
  ]);
31
31
  /**
32
32
  * Pick the entry that should be the default Longform-reviews target —
33
- * the most-recent in-pipeline entry whose review state is in-review or
34
- * iterating. Returns null when no candidate exists; the caller falls
35
- * back to the dashboard's Review section anchor.
33
+ * the most-recently-updated entry in a stage that permits edits
34
+ * (Ideas / Planned / Outlining / Drafting). Returns null when no
35
+ * candidate exists.
36
36
  *
37
- * Replaces the legacy workflow-based picker as part of the pipeline
38
- * redesign (Task 36) the studio's review surfaces are now keyed by
39
- * entry uuid, not workflow uuid.
37
+ * Per DESKWORK-STATE-MACHINE.md (v5): the previous reviewState filter
38
+ * (in-review / iterating) is retired. Stage IS the state machine; the
39
+ * editable-stage filter approximates "the entry the operator is most
40
+ * likely actively working on" without depending on the retired
41
+ * reviewState concept.
40
42
  */
41
43
  export function pickDefaultLongformEntry(entries) {
42
44
  const candidates = entries
43
45
  .filter((e) => LONGFORM_PIPELINE_STAGES.has(e.currentStage))
44
- .filter((e) => e.reviewState === 'in-review' || e.reviewState === 'iterating')
45
46
  .slice()
46
47
  .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
47
48
  return candidates[0] ?? null;
@@ -56,13 +57,14 @@ async function buildSections(ctx) {
56
57
  }
57
58
  })();
58
59
  const longformDefaultEntry = pickDefaultLongformEntry(entries);
59
- // Issue #107: III links to the most-recent in-review (or iterating)
60
- // longform entry when one exists, else falls back to the dashboard's
61
- // Review section anchor (`#stage-review`). The link target is the
62
- // entry-keyed review route `/dev/editorial-review/entry/<uuid>`.
60
+ // Issue #107: III links to the most-recently-updated longform entry
61
+ // in a stage that permits edits (Ideas / Planned / Outlining /
62
+ // Drafting), else falls back to the dashboard's Drafting section
63
+ // anchor. The link target is the entry-keyed review route
64
+ // `/dev/editorial-review/entry/<uuid>`.
63
65
  const longformLinkHref = longformDefaultEntry !== null
64
66
  ? `/dev/editorial-review/entry/${longformDefaultEntry.uuid}`
65
- : '/dev/editorial-studio#stage-review';
67
+ : '/dev/editorial-studio#stage-drafting';
66
68
  return [
67
69
  {
68
70
  ornament: '¶',
@@ -100,8 +102,8 @@ async function buildSections(ctx) {
100
102
  desc: 'Per-entry margin notes, decisions, iterate flow.',
101
103
  hint: 'entry-by-entry',
102
104
  postHint: longformDefaultEntry !== null
103
- ? `Defaults to the most-recent in-review longform (${longformDefaultEntry.slug}). Or reach via the Dashboard or Content view.`
104
- : 'Defaults to the dashboard\'s Review section. Open a longform workflow to populate the per-entry deep-link.',
105
+ ? `Defaults to the most-recently-updated longform (${longformDefaultEntry.slug}). Or reach via the Dashboard or Content view.`
106
+ : 'Defaults to the dashboard\'s Drafting section. Add or ingest a longform entry to populate the per-entry deep-link.',
105
107
  },
106
108
  ],
107
109
  },
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pages/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pages/index.ts"],"names":[],"mappings":"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"}
@@ -74,20 +74,21 @@ interface IndexSection {
74
74
 
75
75
  /**
76
76
  * Pick the entry that should be the default Longform-reviews target —
77
- * the most-recent in-pipeline entry whose review state is in-review or
78
- * iterating. Returns null when no candidate exists; the caller falls
79
- * back to the dashboard's Review section anchor.
77
+ * the most-recently-updated entry in a stage that permits edits
78
+ * (Ideas / Planned / Outlining / Drafting). Returns null when no
79
+ * candidate exists.
80
80
  *
81
- * Replaces the legacy workflow-based picker as part of the pipeline
82
- * redesign (Task 36) the studio's review surfaces are now keyed by
83
- * entry uuid, not workflow uuid.
81
+ * Per DESKWORK-STATE-MACHINE.md (v5): the previous reviewState filter
82
+ * (in-review / iterating) is retired. Stage IS the state machine; the
83
+ * editable-stage filter approximates "the entry the operator is most
84
+ * likely actively working on" without depending on the retired
85
+ * reviewState concept.
84
86
  */
85
87
  export function pickDefaultLongformEntry(
86
88
  entries: readonly Entry[],
87
89
  ): Entry | null {
88
90
  const candidates = entries
89
91
  .filter((e) => LONGFORM_PIPELINE_STAGES.has(e.currentStage))
90
- .filter((e) => e.reviewState === 'in-review' || e.reviewState === 'iterating')
91
92
  .slice()
92
93
  .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
93
94
  return candidates[0] ?? null;
@@ -102,14 +103,15 @@ async function buildSections(ctx: StudioContext): Promise<readonly IndexSection[
102
103
  }
103
104
  })();
104
105
  const longformDefaultEntry = pickDefaultLongformEntry(entries);
105
- // Issue #107: III links to the most-recent in-review (or iterating)
106
- // longform entry when one exists, else falls back to the dashboard's
107
- // Review section anchor (`#stage-review`). The link target is the
108
- // entry-keyed review route `/dev/editorial-review/entry/<uuid>`.
106
+ // Issue #107: III links to the most-recently-updated longform entry
107
+ // in a stage that permits edits (Ideas / Planned / Outlining /
108
+ // Drafting), else falls back to the dashboard's Drafting section
109
+ // anchor. The link target is the entry-keyed review route
110
+ // `/dev/editorial-review/entry/<uuid>`.
109
111
  const longformLinkHref =
110
112
  longformDefaultEntry !== null
111
113
  ? `/dev/editorial-review/entry/${longformDefaultEntry.uuid}`
112
- : '/dev/editorial-studio#stage-review';
114
+ : '/dev/editorial-studio#stage-drafting';
113
115
 
114
116
  return [
115
117
  {
@@ -149,8 +151,8 @@ async function buildSections(ctx: StudioContext): Promise<readonly IndexSection[
149
151
  hint: 'entry-by-entry',
150
152
  postHint:
151
153
  longformDefaultEntry !== null
152
- ? `Defaults to the most-recent in-review longform (${longformDefaultEntry.slug}). Or reach via the Dashboard or Content view.`
153
- : 'Defaults to the dashboard\'s Review section. Open a longform workflow to populate the per-entry deep-link.',
154
+ ? `Defaults to the most-recently-updated longform (${longformDefaultEntry.slug}). Or reach via the Dashboard or Content view.`
155
+ : 'Defaults to the dashboard\'s Drafting section. Add or ingest a longform entry to populate the per-entry deep-link.',
154
156
  },
155
157
  ],
156
158
  },
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAS5B,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAwBtE,UAAU,OAAO;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,qEAAqE;IACrE,WAAW,EAAE,OAAO,CAAC;CACtB;AAKD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CA8CpD;AAkFD,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAyOlD"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAS5B,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAwBtE,UAAU,OAAO;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,qEAAqE;IACrE,WAAW,EAAE,OAAO,CAAC;CACtB;AAKD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CA8CpD;AAkFD,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAwPlD"}
package/dist/server.js CHANGED
@@ -383,6 +383,17 @@ export function createApp(ctx) {
383
383
  }));
384
384
  // Convenience root redirect to the studio index.
385
385
  app.get('/', (c) => c.redirect('/dev/'));
386
+ // Document root — serves top-level project files (DESKWORK-STATE-MACHINE.md,
387
+ // THESIS.md, README.md, DESIGN-STANDARDS.md, etc.) so the studio's URL
388
+ // namespace mirrors the project filesystem layout. Registered LAST so
389
+ // every more-specific route (`/dev/*`, `/api/*`, `/static/*`, the `/`
390
+ // redirect) matches first; only unmatched paths fall through to a
391
+ // filesystem lookup against the project root. Symlinks in `public/`
392
+ // didn't survive serveStatic's resolution (operator-reported 2026-05-09);
393
+ // serving the project root directly removes the need for symlinks at all.
394
+ app.use('*', serveStatic({
395
+ root: ctx.projectRoot,
396
+ }));
386
397
  return app;
387
398
  }
388
399
  async function main() {