@agimon-ai/po-author 0.0.0-alpha.2 → 0.0.0-alpha.21

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.
Files changed (39) hide show
  1. package/LICENSE +149 -21
  2. package/README.md +5 -3
  3. package/dist/apiContracts.cjs +3 -3
  4. package/dist/apiContracts.cjs.map +1 -1
  5. package/dist/apiContracts.mjs +3 -3
  6. package/dist/apiContracts.mjs.map +1 -1
  7. package/dist/{authorFacade-BYvlm8Ff.cjs → authorFacade-BkIMF1lR.cjs} +2 -2
  8. package/dist/authorFacade-BkIMF1lR.cjs.map +1 -0
  9. package/dist/{authorFacade--Lc599Ft.mjs → authorFacade-CpLG3duk.mjs} +3 -3
  10. package/dist/authorFacade-CpLG3duk.mjs.map +1 -0
  11. package/dist/{authorFacade-89Eb2-sW.d.mts → authorFacade-DCTTx7EE.d.mts} +3 -3
  12. package/dist/{authorFacade-89Eb2-sW.d.mts.map → authorFacade-DCTTx7EE.d.mts.map} +1 -1
  13. package/dist/authorFacade.cjs +1 -1
  14. package/dist/authorFacade.d.mts +1 -1
  15. package/dist/authorFacade.mjs +1 -1
  16. package/dist/extensions/server.cjs +104 -40
  17. package/dist/extensions/server.cjs.map +1 -1
  18. package/dist/extensions/server.d.mts +2 -2
  19. package/dist/extensions/server.d.mts.map +1 -1
  20. package/dist/extensions/server.mjs +101 -37
  21. package/dist/extensions/server.mjs.map +1 -1
  22. package/dist/extensions/web.mjs +797 -385
  23. package/dist/extensions/web.mjs.map +1 -1
  24. package/dist/index.cjs +1 -1
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.mts +6 -6
  27. package/dist/index.d.mts.map +1 -1
  28. package/dist/index.mjs +1 -1
  29. package/dist/index.mjs.map +1 -1
  30. package/dist/{structuredDocuments-B914GLxx.mjs → structuredDocuments-BAvFI8VH.mjs} +9 -7
  31. package/dist/structuredDocuments-BAvFI8VH.mjs.map +1 -0
  32. package/dist/{structuredDocuments-CNac1JmJ.cjs → structuredDocuments-OYXnnCrZ.cjs} +18 -10
  33. package/dist/structuredDocuments-OYXnnCrZ.cjs.map +1 -0
  34. package/package.json +18 -17
  35. package/src/prompts/po-use-author/SKILL.md +1 -1
  36. package/dist/authorFacade--Lc599Ft.mjs.map +0 -1
  37. package/dist/authorFacade-BYvlm8Ff.cjs.map +0 -1
  38. package/dist/structuredDocuments-B914GLxx.mjs.map +0 -1
  39. package/dist/structuredDocuments-CNac1JmJ.cjs.map +0 -1
@@ -1,13 +1,16 @@
1
1
  import { apiResponse, createApiClient, defineApiRoutes, defineChannelFile, defineDockFace, defineFileLinks, defineFill, defineGlobalStore, defineLeaderBinding, defineMinorModeFile, defineSessionStore, defineSlotFile, defineToolRenderer, defineWebLifecycle, defineWebPlugin, sessionApiAddress, toolResultTextLines } from "@agimon-ai/po-core/web";
2
2
  import { Store } from "@tanstack/store";
3
3
  import { useStore } from "@tanstack/react-store";
4
- import { useEffect, useRef, useState } from "react";
4
+ import { useEffect, useLayoutEffect, useRef, useState } from "react";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
- import { Button, CodeEditor, Markdown, MediaPreview, MessageItem, MessageItemBody, MessageItemHeader, MessageItemStatus, MessageLines, collapseLines, toolTone } from "@agimon-ai/po-web-components";
6
+ import { Button, CodeEditor, Dot, FileIcon, Markdown, MediaPreview, MessageItem, MessageItemBody, MessageItemHeader, MessageItemStatus, MessageLines, SparklesIcon, StatusBadge, TrashIcon, collapseLines, toolTone } from "@agimon-ai/po-web-components";
7
7
  import { sealedTransport } from "@agimon-ai/po-web-security/browser";
8
8
  //#region src/types/webAuthor.ts
9
9
  const authorChannelType = "author_webmcp";
10
10
  //#endregion
11
+ //#region src/types/author.ts
12
+ const AUTHOR_MODE_ID = "author";
13
+ //#endregion
11
14
  //#region src/extensions/workspaces/sessions/(frontend)/_lib/authorRuntime.ts
12
15
  const AUTHOR_RUNTIME_BINDING_IDS = {
13
16
  text: "author.viewport.text",
@@ -157,7 +160,9 @@ const documentProfiles = (profiles) => profiles.map((profile) => ({
157
160
  var AuthorBrowserBridge = class {
158
161
  #host;
159
162
  #canvases = /* @__PURE__ */ new Map();
163
+ #parked = /* @__PURE__ */ new Map();
160
164
  #opening = /* @__PURE__ */ new Map();
165
+ #modeWatches = /* @__PURE__ */ new Map();
161
166
  #generation = 0;
162
167
  #disposed = false;
163
168
  #releaseConnected;
@@ -173,27 +178,61 @@ var AuthorBrowserBridge = class {
173
178
  }
174
179
  async open(sessionId, alias, profiles) {
175
180
  if (this.#disposed) throw new Error("Author browser bridge is disposed");
181
+ this.#watch(sessionId);
176
182
  const key = canvasKey(sessionId, alias);
177
183
  if (this.#canvases.has(key)) return;
184
+ const parkedCanvas = this.#parked.get(key);
185
+ if (parkedCanvas !== void 0) {
186
+ if (this.#agentEnabled(sessionId)) await this.#openLive(parkedCanvas);
187
+ return;
188
+ }
189
+ const pending = this.#opening.get(key);
190
+ if (pending !== void 0) return await pending.promise;
191
+ const parked = {
192
+ sessionId,
193
+ alias,
194
+ profiles: documentProfiles(profiles)
195
+ };
196
+ if (!this.#agentEnabled(sessionId)) {
197
+ this.#parked.set(key, parked);
198
+ return;
199
+ }
200
+ await this.#openLive(parked);
201
+ }
202
+ async #openLive(parked) {
203
+ const { sessionId, alias, profiles } = parked;
204
+ const key = canvasKey(sessionId, alias);
205
+ if (this.#disposed || this.#canvases.has(key)) return;
178
206
  const pending = this.#opening.get(key);
179
207
  if (pending !== void 0) return await pending.promise;
208
+ if (!this.#agentEnabled(sessionId)) {
209
+ this.#parked.set(key, parked);
210
+ return;
211
+ }
212
+ this.#parked.delete(key);
180
213
  const runtime = new AuthorRuntime(this.#host);
181
214
  const generation = ++this.#generation;
182
- const base = documentProfiles(profiles);
183
215
  let opening;
184
216
  opening = (async () => {
185
- const release = await runtime.replaceProfiles(base);
186
- if (this.#disposed || this.#canvases.has(key) || this.#opening.get(key)?.promise !== opening) {
217
+ let release;
218
+ try {
219
+ release = await runtime.replaceProfiles(profiles);
220
+ } catch (error) {
221
+ if (this.#disposed || !this.#agentEnabled(sessionId) || this.#opening.get(key)?.promise !== opening) return;
222
+ throw error;
223
+ }
224
+ if (this.#disposed || !this.#agentEnabled(sessionId) || this.#canvases.has(key) || this.#opening.get(key)?.promise !== opening) {
187
225
  release();
188
226
  runtime.dispose();
227
+ if (!this.#disposed && !this.#agentEnabled(sessionId)) this.#parked.set(key, parked);
189
228
  return;
190
229
  }
191
230
  const canvas = {
192
231
  sessionId,
193
232
  alias,
194
233
  generation,
195
- profiles: base,
196
- documentProfiles: base,
234
+ profiles,
235
+ documentProfiles: profiles,
197
236
  runtime,
198
237
  release,
199
238
  pending: /* @__PURE__ */ new Map(),
@@ -206,7 +245,8 @@ var AuthorBrowserBridge = class {
206
245
  })();
207
246
  this.#opening.set(key, {
208
247
  promise: opening,
209
- runtime
248
+ runtime,
249
+ parked
210
250
  });
211
251
  try {
212
252
  await opening;
@@ -216,6 +256,7 @@ var AuthorBrowserBridge = class {
216
256
  }
217
257
  async focus(sessionId, alias, profiles) {
218
258
  await this.open(sessionId, alias, profiles);
259
+ if (!this.#agentEnabled(sessionId)) return () => void 0;
219
260
  const canvas = this.#canvases.get(canvasKey(sessionId, alias));
220
261
  if (canvas === void 0) return () => void 0;
221
262
  canvas.visible = true;
@@ -229,21 +270,28 @@ var AuthorBrowserBridge = class {
229
270
  };
230
271
  }
231
272
  drop(sessionId, alias) {
232
- for (const [key, entry] of this.#opening) if (key.startsWith(`${sessionId}\n`) && (alias === void 0 || key === canvasKey(sessionId, alias))) {
273
+ for (const [key, entry] of this.#opening) {
274
+ if (entry.parked.sessionId !== sessionId || alias !== void 0 && entry.parked.alias !== alias) continue;
233
275
  this.#opening.delete(key);
234
276
  entry.runtime.dispose();
235
277
  }
278
+ for (const [key, parked] of this.#parked) {
279
+ if (parked.sessionId !== sessionId || alias !== void 0 && parked.alias !== alias) continue;
280
+ this.#parked.delete(key);
281
+ }
236
282
  for (const canvas of this.#canvases.values()) {
237
283
  if (canvas.sessionId !== sessionId || alias !== void 0 && canvas.alias !== alias) continue;
238
- this.#canvases.delete(canvasKey(sessionId, canvas.alias));
239
- this.#release(canvas);
240
- canvas.runtime.dispose();
284
+ this.#dropLive(canvas);
241
285
  }
242
286
  }
243
287
  apply(sessionId, message) {
244
- if (message.alias === void 0) return;
288
+ if (!this.#agentEnabled(sessionId) || message.alias === void 0) return;
245
289
  const canvas = this.#canvases.get(canvasKey(sessionId, message.alias));
246
- if (canvas === void 0 || message.kind === "rejected") return;
290
+ if (canvas === void 0) return;
291
+ if (message.kind === "rejected") {
292
+ console.warn(`Author canvas '${canvas.alias}' was rejected: ${message.reason}`);
293
+ return;
294
+ }
247
295
  if (message.generation !== canvas.generation || message.ownerToken !== canvas.ownerToken && canvas.ownerToken !== void 0) return;
248
296
  if (message.kind === "accepted") {
249
297
  canvas.ownerToken = message.ownerToken;
@@ -310,17 +358,54 @@ var AuthorBrowserBridge = class {
310
358
  if (this.#disposed) return;
311
359
  this.#disposed = true;
312
360
  this.#releaseConnected();
313
- for (const canvas of this.#canvases.values()) {
314
- this.#release(canvas);
315
- canvas.runtime.dispose();
316
- }
317
- this.#canvases.clear();
361
+ for (const release of this.#modeWatches.values()) release();
362
+ this.#modeWatches.clear();
363
+ for (const canvas of this.#canvases.values()) this.#dropLive(canvas);
364
+ this.#parked.clear();
318
365
  for (const entry of this.#opening.values()) entry.runtime.dispose();
319
366
  this.#opening.clear();
320
367
  }
368
+ #agentEnabled(sessionId) {
369
+ return this.#host.minorModes?.active(sessionId).includes(AUTHOR_MODE_ID) === true;
370
+ }
371
+ #watch(sessionId) {
372
+ if (this.#modeWatches.has(sessionId) || this.#host.minorModes === void 0) return;
373
+ const release = this.#host.minorModes.subscribe(sessionId, () => this.#modeChanged(sessionId));
374
+ this.#modeWatches.set(sessionId, release);
375
+ }
376
+ #modeChanged(sessionId) {
377
+ if (this.#disposed) return;
378
+ if (this.#agentEnabled(sessionId)) {
379
+ for (const parked of this.#parked.values()) {
380
+ if (parked.sessionId !== sessionId) continue;
381
+ this.#openLive(parked).catch((error) => console.warn(`Author canvas '${parked.alias}' could not enable browser tools: ${error instanceof Error ? error.message : String(error)}`));
382
+ }
383
+ return;
384
+ }
385
+ for (const [key, entry] of this.#opening) {
386
+ if (entry.parked.sessionId !== sessionId) continue;
387
+ this.#opening.delete(key);
388
+ this.#parked.set(key, entry.parked);
389
+ entry.runtime.dispose();
390
+ }
391
+ for (const canvas of this.#canvases.values()) {
392
+ if (canvas.sessionId !== sessionId) continue;
393
+ this.#parked.set(canvasKey(canvas.sessionId, canvas.alias), {
394
+ sessionId: canvas.sessionId,
395
+ alias: canvas.alias,
396
+ profiles: canvas.documentProfiles
397
+ });
398
+ this.#dropLive(canvas);
399
+ }
400
+ }
401
+ #dropLive(canvas) {
402
+ this.#canvases.delete(canvasKey(canvas.sessionId, canvas.alias));
403
+ this.#release(canvas);
404
+ canvas.runtime.dispose();
405
+ }
321
406
  async #replace(canvas, profiles) {
322
407
  const key = canvasKey(canvas.sessionId, canvas.alias);
323
- if (this.#disposed || this.#canvases.get(key) !== canvas) return;
408
+ if (this.#disposed || !this.#agentEnabled(canvas.sessionId) || this.#canvases.get(key) !== canvas) return;
324
409
  this.#release(canvas);
325
410
  const generation = canvas.generation;
326
411
  const replacementId = ++canvas.replacementId;
@@ -340,7 +425,7 @@ var AuthorBrowserBridge = class {
340
425
  this.#register(canvas);
341
426
  }
342
427
  #register(canvas) {
343
- if (this.#canvases.get(canvasKey(canvas.sessionId, canvas.alias)) === canvas) this.#send(canvas, {
428
+ if (this.#agentEnabled(canvas.sessionId) && this.#canvases.get(canvasKey(canvas.sessionId, canvas.alias)) === canvas) this.#send(canvas, {
344
429
  kind: "register",
345
430
  alias: canvas.alias,
346
431
  generation: canvas.generation
@@ -384,7 +469,7 @@ var AuthorBrowserBridge = class {
384
469
  sessionId: canvas.sessionId,
385
470
  message: payload
386
471
  }
387
- }).catch(() => void 0);
472
+ }).catch((error) => console.warn(`Author canvas '${canvas.alias}' could not send '${payload.kind}': ${error instanceof Error ? error.message : String(error)}`));
388
473
  }
389
474
  #current(canvas, requestId, controller) {
390
475
  return this.#canvases.get(canvasKey(canvas.sessionId, canvas.alias)) === canvas && canvas.pending.get(requestId) === controller;
@@ -526,7 +611,8 @@ function resolveAuthorGridCell(sessionId, cell, expectedGeometryToken) {
526
611
  const TERMINAL_REQUEST_STATUSES = /* @__PURE__ */ new Set([
527
612
  "COMPLETE",
528
613
  "FAILED",
529
- "CANCELLED"
614
+ "CANCELLED",
615
+ "UNTRACKED"
530
616
  ]);
531
617
  const EMPTY_SESSION = {
532
618
  generation: 0,
@@ -1133,9 +1219,12 @@ var author_webmcp_web_default = defineChannelFile({
1133
1219
  }
1134
1220
  });
1135
1221
  //#endregion
1222
+ //#region src/constants/author.ts
1223
+ const AUTHOR_FILE_TAB_PREFIX = "author-file-";
1224
+ //#endregion
1136
1225
  //#region src/extensions/workspaces/sessions/(frontend)/_components/AuthorGridOverlay.tsx
1137
1226
  function autonomousVoiceGridVisible(statuses) {
1138
- return statuses["doom-voice"]?.trimStart().startsWith("voice auto:") === true;
1227
+ return statuses["po-voice"]?.trimStart().startsWith("voice auto:") === true;
1139
1228
  }
1140
1229
  function AuthorGridOverlay({ sessionId, document, visible }) {
1141
1230
  const host = useRef(null);
@@ -1193,9 +1282,9 @@ function AuthorGridOverlay({ sessionId, document, visible }) {
1193
1282
  const column = index % 8;
1194
1283
  const row = Math.floor(index / 8);
1195
1284
  return /* @__PURE__ */ jsx("div", {
1196
- className: "relative border border-doom-red/25",
1285
+ className: "relative border border-po-red/25",
1197
1286
  children: /* @__PURE__ */ jsxs("span", {
1198
- className: "absolute left-1 top-0.5 rounded bg-doom-deep/80 px-1 text-2xs font-semibold text-doom-red",
1287
+ className: "absolute left-1 top-0.5 rounded bg-po-deep/80 px-1 text-2xs font-semibold text-po-red",
1199
1288
  children: [AUTHOR_GRID_COLUMNS[column], row + 1]
1200
1289
  })
1201
1290
  }, index);
@@ -1308,7 +1397,8 @@ function createAuthorCapturePacket(captureId, capturedAt, document, regions, ali
1308
1397
  kind: document.kind,
1309
1398
  revision: document.version,
1310
1399
  ...document.sourceSha256 === void 0 ? {} : { sourceSha256: document.sourceSha256 },
1311
- ...document.storyPreview === void 0 ? {} : { storyPreview: structuredClone(document.storyPreview) }
1400
+ ...document.storyPreview === void 0 ? {} : { storyPreview: structuredClone(document.storyPreview) },
1401
+ ...document.imageArtifact === void 0 ? {} : { imageArtifact: { ...document.imageArtifact } }
1312
1402
  },
1313
1403
  regions: regions.map((region, index) => {
1314
1404
  if (region.documentPath !== document.path || region.revision !== document.version || region.sourceSha256 !== document.sourceSha256) throw new Error(`Region ${String(index + 1)} is stale for the focused document.`);
@@ -1378,7 +1468,14 @@ function authorCaptureContext(packet) {
1378
1468
  const metadata = JSON.stringify(packet);
1379
1469
  if (bytes(metadata) > 65536) throw new Error("Author capture packet exceeds 64 KiB.");
1380
1470
  const annotations = packet.regions.map((region) => `(${String(region.ordinal)}) ${region.comment} [${anchorLocation(region.anchor)}]${region.quote ? `\nQuoted text: ${region.quote}` : ""}`).join("\n\n");
1381
- const provenance = storyPreviewProvenance(packet);
1471
+ const artifact = packet.document.imageArtifact;
1472
+ const provenance = artifact === void 0 ? storyPreviewProvenance(packet) : [
1473
+ "Generated image feedback: preserve the original image; generate a new refinement only when requested.",
1474
+ `Original artifact: ${artifact.id} (session ${artifact.sessionId})`,
1475
+ `Original canonical path: ${artifact.originalPath}`,
1476
+ `Original SHA-256: ${artifact.sourceSha256}`,
1477
+ `For imagegen refinement use referenced_image_paths: ${JSON.stringify([artifact.originalPath])}`
1478
+ ].join("\n");
1382
1479
  const content = provenance === void 0 ? annotations : `${provenance}\n\nAnnotations:\n${annotations}`;
1383
1480
  return {
1384
1481
  kind: "author-capture",
@@ -1562,11 +1659,11 @@ function AuthorRegionDrafts({ sessionId, path, drafts }) {
1562
1659
  children: [
1563
1660
  drafts.candidate ? /* @__PURE__ */ jsxs(Fragment, { children: [
1564
1661
  /* @__PURE__ */ jsxs("h3", {
1565
- className: "text-base font-semibold text-doom-text",
1662
+ className: "text-base font-semibold text-po-hi",
1566
1663
  children: ["Current ", candidateKind]
1567
1664
  }),
1568
1665
  /* @__PURE__ */ jsxs("p", {
1569
- className: "text-base text-doom-dim sm:text-sm",
1666
+ className: "text-base text-po-dim sm:text-sm",
1570
1667
  children: [
1571
1668
  "Add feedback to keep this ",
1572
1669
  candidateKind,
@@ -1574,7 +1671,7 @@ function AuthorRegionDrafts({ sessionId, path, drafts }) {
1574
1671
  ]
1575
1672
  }),
1576
1673
  drafts.candidate.anchor.kind === "video-time-rect" || drafts.candidate.anchor.kind === "video-time-point" ? /* @__PURE__ */ jsxs("p", {
1577
- className: "text-base text-doom-dim sm:text-sm",
1674
+ className: "text-base text-po-dim sm:text-sm",
1578
1675
  children: [
1579
1676
  "Frame at ",
1580
1677
  drafts.candidate.anchor.timeSeconds.toFixed(3),
@@ -1587,32 +1684,34 @@ function AuthorRegionDrafts({ sessionId, path, drafts }) {
1587
1684
  onChange: (event) => setAuthorCandidateText(sessionId, path, event.target.value),
1588
1685
  placeholder: "What should change here?",
1589
1686
  rows: 3,
1590
- className: "min-h-11 w-full resize-y rounded border border-doom-border bg-doom-deep p-2 text-lg leading-normal text-doom-text focus:border-doom-red focus:outline-none sm:text-sm"
1591
- }),
1592
- /* @__PURE__ */ jsx(Button, {
1593
- className: "min-h-11 min-w-11 text-base [@media(pointer:fine)]:min-h-8 sm:text-sm",
1594
- variant: "outline",
1595
- onClick: add,
1596
- disabled: !drafts.candidate || !drafts.candidateText.trim() || drafts.annotations.length >= 16,
1597
- children: "add annotation"
1687
+ className: "min-h-24 w-full resize-y rounded-md border border-po-border-soft bg-po-panel p-3 text-lg leading-normal text-po-text placeholder:text-po-dim focus:border-po-green focus:outline-none sm:text-base"
1598
1688
  }),
1599
- /* @__PURE__ */ jsx(Button, {
1600
- variant: "ghost",
1601
- className: "min-h-11 min-w-11 text-base [@media(pointer:fine)]:min-h-8 sm:text-sm",
1602
- onClick: () => {
1603
- setAuthorRegionCandidate(sessionId, path, void 0);
1604
- setAuthorCandidateText(sessionId, path, "");
1605
- setError(void 0);
1606
- },
1607
- children: "Discard annotation"
1689
+ /* @__PURE__ */ jsxs("div", {
1690
+ className: "flex flex-wrap gap-2",
1691
+ children: [/* @__PURE__ */ jsx(Button, {
1692
+ className: "min-h-11 min-w-11 text-base [@media(pointer:fine)]:min-h-8 sm:text-sm",
1693
+ variant: "outline",
1694
+ onClick: add,
1695
+ disabled: !drafts.candidate || !drafts.candidateText.trim() || drafts.annotations.length >= 16,
1696
+ children: "add annotation"
1697
+ }), /* @__PURE__ */ jsx(Button, {
1698
+ variant: "ghost",
1699
+ className: "min-h-11 min-w-11 text-base [@media(pointer:fine)]:min-h-8 sm:text-sm",
1700
+ onClick: () => {
1701
+ setAuthorRegionCandidate(sessionId, path, void 0);
1702
+ setAuthorCandidateText(sessionId, path, "");
1703
+ setError(void 0);
1704
+ },
1705
+ children: "Discard annotation"
1706
+ })]
1608
1707
  })
1609
1708
  ] }) : null,
1610
1709
  error ? /* @__PURE__ */ jsx("output", {
1611
- className: "block text-base text-doom-red",
1710
+ className: "block text-base text-po-red",
1612
1711
  children: error
1613
1712
  }) : null,
1614
1713
  drafts.annotations.length > 0 ? /* @__PURE__ */ jsxs("h3", {
1615
- className: "text-base font-semibold text-doom-text",
1714
+ className: "text-sm text-po-dim",
1616
1715
  children: [
1617
1716
  "Unsent annotations (",
1618
1717
  drafts.annotations.length,
@@ -1622,16 +1721,31 @@ function AuthorRegionDrafts({ sessionId, path, drafts }) {
1622
1721
  /* @__PURE__ */ jsx("ol", {
1623
1722
  className: "space-y-2",
1624
1723
  children: drafts.annotations.map((region, index) => /* @__PURE__ */ jsxs("li", {
1625
- className: "rounded border border-doom-border bg-doom-panel p-2 text-base leading-normal text-doom-text sm:text-sm",
1724
+ className: "flex flex-wrap items-center gap-x-3 gap-y-1 rounded-md border border-po-border-soft bg-po-panel py-1 pl-3 pr-1 text-base leading-normal text-po-text",
1626
1725
  children: [
1627
- /* @__PURE__ */ jsxs("span", { children: [
1628
- "(",
1629
- index + 1,
1630
- ") ",
1631
- region.mode === "point" ? "Point" : "Region",
1632
- ": ",
1633
- region.comment
1634
- ] }),
1726
+ /* @__PURE__ */ jsx("span", {
1727
+ "aria-hidden": "true",
1728
+ className: "flex h-6 min-w-6 shrink-0 items-center justify-center rounded-full bg-po-magenta px-1 text-sm font-semibold text-po-rail",
1729
+ children: index + 1
1730
+ }),
1731
+ /* @__PURE__ */ jsxs("span", {
1732
+ className: "min-w-0 flex-1 break-words py-1",
1733
+ children: [
1734
+ /* @__PURE__ */ jsxs("span", {
1735
+ className: "sr-only",
1736
+ children: [
1737
+ "(",
1738
+ index + 1,
1739
+ ") "
1740
+ ]
1741
+ }),
1742
+ region.comment,
1743
+ /* @__PURE__ */ jsx("span", {
1744
+ className: "block text-sm text-po-dim",
1745
+ children: region.mode === "point" ? "Point" : "Region"
1746
+ })
1747
+ ]
1748
+ }),
1635
1749
  region.anchor.kind === "video-time-rect" || region.anchor.kind === "video-time-point" ? /* @__PURE__ */ jsxs(Button, {
1636
1750
  variant: "outline",
1637
1751
  className: "min-h-11 min-w-11 text-base [@media(pointer:fine)]:min-h-8 sm:text-sm",
@@ -1650,7 +1764,10 @@ function AuthorRegionDrafts({ sessionId, path, drafts }) {
1650
1764
  variant: "ghost",
1651
1765
  "aria-label": `Remove annotation ${index + 1}`,
1652
1766
  onClick: () => removeAuthorRegion(sessionId, path, region.id),
1653
- children: "remove"
1767
+ children: /* @__PURE__ */ jsx(TrashIcon, {
1768
+ "aria-hidden": "true",
1769
+ className: "size-4"
1770
+ })
1654
1771
  })
1655
1772
  ]
1656
1773
  }, region.id))
@@ -1664,7 +1781,7 @@ function AuthorFeedbackControls({ sessionId, document, drafts, submitCapture })
1664
1781
  const [status, setStatus] = useState();
1665
1782
  const [capturing, setCapturing] = useState(false);
1666
1783
  return /* @__PURE__ */ jsxs("div", {
1667
- className: "space-y-2",
1784
+ className: "space-y-3",
1668
1785
  children: [
1669
1786
  /* @__PURE__ */ jsx(AuthorRegionDrafts, {
1670
1787
  sessionId,
@@ -1672,8 +1789,9 @@ function AuthorFeedbackControls({ sessionId, document, drafts, submitCapture })
1672
1789
  drafts
1673
1790
  }),
1674
1791
  drafts.annotations.length > 0 ? /* @__PURE__ */ jsx(Button, {
1675
- className: "min-h-11 min-w-11 w-full text-base [@media(pointer:fine)]:min-h-8 sm:text-sm",
1676
- variant: "outline",
1792
+ className: "min-h-11 min-w-11 w-full text-base",
1793
+ size: "lg",
1794
+ variant: "primary",
1677
1795
  "data-testid": "author-attach-capture",
1678
1796
  disabled: capturing || drafts.candidate !== void 0 || submitCapture === void 0,
1679
1797
  onClick: async () => {
@@ -1696,11 +1814,11 @@ function AuthorFeedbackControls({ sessionId, document, drafts, submitCapture })
1696
1814
  children: capturing ? "Submitting…" : `Submit ${drafts.annotations.length} annotation${drafts.annotations.length === 1 ? "" : "s"}`
1697
1815
  }) : null,
1698
1816
  submitCapture === void 0 ? /* @__PURE__ */ jsx("output", {
1699
- className: "text-sm text-doom-red",
1817
+ className: "text-sm text-po-red",
1700
1818
  children: "Submission unavailable. Reload to update the app."
1701
1819
  }) : null,
1702
1820
  status ? /* @__PURE__ */ jsx("output", {
1703
- className: "block text-sm text-doom-dim",
1821
+ className: "block text-sm text-po-dim",
1704
1822
  children: status
1705
1823
  }) : null
1706
1824
  ]
@@ -1714,15 +1832,26 @@ const STATUS_LABELS = {
1714
1832
  CHANGED: "Change ready",
1715
1833
  COMPLETE: "Request completed",
1716
1834
  FAILED: "Request failed",
1717
- CANCELLED: "Request cancelled"
1835
+ CANCELLED: "Request cancelled",
1836
+ UNTRACKED: "Sent, not tracked"
1718
1837
  };
1719
1838
  const STATUS_STYLES = {
1720
- REQUESTED: "border-doom-yellow/35 bg-doom-yellow/5 text-doom-yellow",
1721
- CHANGING: "border-doom-magenta/45 bg-doom-magenta/10 text-doom-yellow",
1722
- CHANGED: "border-doom-cyan/40 bg-doom-cyan/5 text-doom-cyan",
1723
- COMPLETE: "border-doom-green/40 bg-doom-green/5 text-doom-green",
1724
- FAILED: "border-doom-red/45 bg-doom-red/10 text-doom-red",
1725
- CANCELLED: "border-doom-border bg-doom-panel text-doom-dim"
1839
+ REQUESTED: "border-po-border-soft bg-po-bg text-po-dim",
1840
+ CHANGING: "border-po-edge-green bg-po-tint-green text-po-green",
1841
+ CHANGED: "border-po-edge-green bg-po-tint-green text-po-green",
1842
+ COMPLETE: "border-po-edge-green bg-po-tint-green text-po-green",
1843
+ FAILED: "border-po-edge-red bg-po-tint-red text-po-red",
1844
+ CANCELLED: "border-po-border-soft bg-po-bg text-po-dim",
1845
+ UNTRACKED: "border-po-border-soft bg-po-bg text-po-dim"
1846
+ };
1847
+ const STATUS_TONES = {
1848
+ REQUESTED: "neutral",
1849
+ CHANGING: "ok",
1850
+ CHANGED: "ok",
1851
+ COMPLETE: "ok",
1852
+ FAILED: "error",
1853
+ CANCELLED: "neutral",
1854
+ UNTRACKED: "neutral"
1726
1855
  };
1727
1856
  function requestInstruction(requestText) {
1728
1857
  const referencedContext = requestText.search(/(?:^|\s+)Referenced context "/u);
@@ -1755,38 +1884,49 @@ function progressLabel(request) {
1755
1884
  if (request.status === "COMPLETE") return "Agent finished processing this request";
1756
1885
  if (request.status === "FAILED") return "Stopped with an error";
1757
1886
  if (request.status === "CANCELLED") return "Stopped before completion";
1887
+ if (request.status === "UNTRACKED") return "Sent to the agent · see its session for the outcome";
1758
1888
  return `${total} annotation${total === 1 ? "" : "s"} queued`;
1759
1889
  }
1760
1890
  function RequestRecord({ request, prominent = false }) {
1761
1891
  const instruction = requestInstruction(request.requestText);
1762
1892
  return /* @__PURE__ */ jsxs("article", {
1763
1893
  "data-testid": prominent ? "author-active-request" : void 0,
1764
- className: "space-y-3",
1894
+ className: "space-y-3 rounded-md border border-po-border-soft bg-po-panel p-3",
1765
1895
  children: [
1766
1896
  /* @__PURE__ */ jsxs("header", {
1767
- className: "border-b border-doom-border-soft pb-3",
1768
- children: [/* @__PURE__ */ jsx("p", {
1769
- className: "text-lg font-semibold text-doom-hi",
1770
- children: "Document context"
1771
- }), /* @__PURE__ */ jsxs("p", {
1772
- className: "mt-2 flex items-center gap-2 truncate text-base font-semibold text-doom-hi",
1773
- children: [/* @__PURE__ */ jsx("span", {
1774
- "aria-hidden": true,
1775
- className: "text-doom-magenta",
1776
- children: "↗"
1777
- }), documentName(request.documentPath)]
1897
+ className: "flex gap-3 border-b border-po-border-soft pb-3",
1898
+ children: [/* @__PURE__ */ jsx(SparklesIcon, {
1899
+ "aria-hidden": "true",
1900
+ className: "mt-1 size-4 shrink-0 text-po-green"
1901
+ }), /* @__PURE__ */ jsxs("div", {
1902
+ className: "min-w-0 flex-1",
1903
+ children: [
1904
+ /* @__PURE__ */ jsx("p", {
1905
+ className: "text-lg font-semibold text-po-hi",
1906
+ children: "Document context"
1907
+ }),
1908
+ /* @__PURE__ */ jsx("p", {
1909
+ className: "mt-1 truncate text-base font-semibold text-po-hi",
1910
+ children: documentName(request.documentPath)
1911
+ }),
1912
+ /* @__PURE__ */ jsx(StatusBadge, {
1913
+ tone: STATUS_TONES[request.status],
1914
+ className: "mt-2 whitespace-normal",
1915
+ children: progressLabel(request)
1916
+ })
1917
+ ]
1778
1918
  })]
1779
1919
  }),
1780
1920
  /* @__PURE__ */ jsx("section", {
1781
1921
  "aria-label": "Request locations",
1782
- className: "rounded border border-doom-border bg-doom-panel p-3",
1922
+ className: "rounded-md border border-po-border-soft bg-po-bg p-3",
1783
1923
  children: /* @__PURE__ */ jsx("ol", {
1784
1924
  className: "space-y-3",
1785
1925
  children: request.regions.map((region, index) => /* @__PURE__ */ jsxs("li", {
1786
1926
  className: "space-y-2",
1787
1927
  children: [
1788
1928
  /* @__PURE__ */ jsxs("p", {
1789
- className: "text-sm font-medium text-doom-yellow",
1929
+ className: "text-sm font-medium text-po-magenta",
1790
1930
  children: [
1791
1931
  "Where · ",
1792
1932
  request.regions.length > 1 ? `${index + 1} · ` : "",
@@ -1798,7 +1938,7 @@ function RequestRecord({ request, prominent = false }) {
1798
1938
  ]
1799
1939
  }),
1800
1940
  region.quote ? /* @__PURE__ */ jsxs("blockquote", {
1801
- className: "line-clamp-3 text-base italic leading-relaxed text-doom-text",
1941
+ className: "line-clamp-3 text-base italic leading-relaxed text-po-text",
1802
1942
  children: [
1803
1943
  "“",
1804
1944
  region.quote,
@@ -1806,7 +1946,7 @@ function RequestRecord({ request, prominent = false }) {
1806
1946
  ]
1807
1947
  }) : null,
1808
1948
  /* @__PURE__ */ jsx("p", {
1809
- className: "text-base leading-relaxed text-doom-dim",
1949
+ className: "text-base leading-relaxed text-po-dim",
1810
1950
  children: region.comment
1811
1951
  })
1812
1952
  ]
@@ -1815,7 +1955,7 @@ function RequestRecord({ request, prominent = false }) {
1815
1955
  }),
1816
1956
  /* @__PURE__ */ jsxs("section", {
1817
1957
  "data-testid": prominent ? "author-operation-card" : void 0,
1818
- className: `rounded border p-3 ${STATUS_STYLES[request.status]}`,
1958
+ className: `rounded-md border p-3 ${STATUS_STYLES[request.status]}`,
1819
1959
  children: [
1820
1960
  /* @__PURE__ */ jsxs("p", {
1821
1961
  className: "text-sm font-semibold",
@@ -1826,15 +1966,15 @@ function RequestRecord({ request, prominent = false }) {
1826
1966
  ]
1827
1967
  }),
1828
1968
  /* @__PURE__ */ jsx("p", {
1829
- className: "mt-2 text-base leading-relaxed text-doom-hi",
1969
+ className: "mt-2 text-base leading-relaxed text-po-hi",
1830
1970
  children: request.currentOperation || STATUS_LABELS[request.status]
1831
1971
  }),
1832
1972
  request.error ? /* @__PURE__ */ jsx("p", {
1833
- className: "mt-2 text-sm leading-relaxed text-doom-red",
1973
+ className: "mt-2 text-sm leading-relaxed text-po-red",
1834
1974
  children: request.error
1835
1975
  }) : null,
1836
1976
  request.before !== void 0 || request.after !== void 0 ? /* @__PURE__ */ jsxs("details", {
1837
- className: "mt-2 border-t border-current/20 pt-2 text-base text-doom-dim",
1977
+ className: "mt-2 border-t border-current/20 pt-2 text-base text-po-dim",
1838
1978
  children: [
1839
1979
  /* @__PURE__ */ jsx("summary", {
1840
1980
  className: "cursor-pointer select-none",
@@ -1855,19 +1995,15 @@ function RequestRecord({ request, prominent = false }) {
1855
1995
  /* @__PURE__ */ jsxs("section", {
1856
1996
  className: "space-y-2",
1857
1997
  children: [/* @__PURE__ */ jsx("p", {
1858
- className: "text-lg font-semibold text-doom-hi",
1998
+ className: "text-base font-semibold text-po-hi",
1859
1999
  children: "Request · how to change"
1860
2000
  }), /* @__PURE__ */ jsx("div", {
1861
- className: "rounded border border-doom-border bg-doom-deep p-3",
2001
+ className: "rounded-md border border-po-border-soft bg-po-bg p-3",
1862
2002
  children: /* @__PURE__ */ jsx("p", {
1863
- className: "whitespace-pre-wrap text-base leading-relaxed text-doom-text",
2003
+ className: "whitespace-pre-wrap text-base leading-relaxed text-po-text",
1864
2004
  children: instruction || "No additional instruction."
1865
2005
  })
1866
2006
  })]
1867
- }),
1868
- /* @__PURE__ */ jsx("footer", {
1869
- className: "text-sm text-doom-dim",
1870
- children: progressLabel(request)
1871
2007
  })
1872
2008
  ]
1873
2009
  });
@@ -1880,21 +2016,21 @@ function AuthorRequestLog({ requests }) {
1880
2016
  className: "space-y-3",
1881
2017
  children: [
1882
2018
  /* @__PURE__ */ jsx("h3", {
1883
- className: "text-lg font-semibold text-doom-hi",
1884
- children: "Authoring"
2019
+ className: "text-lg font-semibold text-po-hi",
2020
+ children: "Author"
1885
2021
  }),
1886
2022
  latest === void 0 ? /* @__PURE__ */ jsx("p", {
1887
- className: "text-sm leading-relaxed text-doom-dim",
2023
+ className: "text-sm leading-relaxed text-po-dim",
1888
2024
  children: "No requests or changes yet."
1889
2025
  }) : /* @__PURE__ */ jsx(RequestRecord, {
1890
2026
  request: latest,
1891
2027
  prominent: true
1892
2028
  }),
1893
2029
  earlier.length > 0 ? /* @__PURE__ */ jsxs("details", {
1894
- className: "border-t border-doom-border-soft pt-3",
2030
+ className: "border-t border-po-border-soft pt-3",
1895
2031
  "data-testid": "author-earlier-requests",
1896
2032
  children: [/* @__PURE__ */ jsxs("summary", {
1897
- className: "cursor-pointer select-none text-base font-medium text-doom-dim",
2033
+ className: "cursor-pointer select-none text-base font-medium text-po-dim",
1898
2034
  children: [
1899
2035
  "Earlier requests (",
1900
2036
  earlier.length,
@@ -1910,6 +2046,10 @@ function AuthorRequestLog({ requests }) {
1910
2046
  }
1911
2047
  //#endregion
1912
2048
  //#region src/extensions/workspaces/sessions/(frontend)/dock/_components/AuthorToolPalette.tsx
2049
+ /** One tool tile. An active annotation tool is the person's mark (rose); an active view tool is Po's jade. */
2050
+ function authorToolClassName(active, annotates) {
2051
+ return `h-auto min-h-11 min-w-11 flex-col gap-1 rounded-md px-1 py-2 text-base [@media(pointer:fine)]:min-h-8 ${!active ? "border-po-border-soft bg-po-panel text-po-dim" : annotates ? "border-po-edge-magenta bg-po-tint-magenta font-semibold text-po-magenta hover:text-po-magenta" : "border-po-edge-green bg-po-tint-green font-semibold text-po-green hover:text-po-green"}`;
2052
+ }
1913
2053
  function AuthorToolPalette({ sessionId, path, kind, activeTool }) {
1914
2054
  const [error, setError] = useState();
1915
2055
  const format = (style) => {
@@ -1937,18 +2077,21 @@ function AuthorToolPalette({ sessionId, path, kind, activeTool }) {
1937
2077
  label: "Pan",
1938
2078
  glyph: "✋",
1939
2079
  action: () => setAuthorToolMode(sessionId, path, activeTool === "pan" ? "select" : "pan"),
1940
- active: activeTool === "pan"
2080
+ active: activeTool === "pan",
2081
+ annotates: false
1941
2082
  }, {
1942
2083
  label: "Draw",
1943
2084
  glyph: "✎",
1944
2085
  action: () => setAuthorToolMode(sessionId, path, activeTool === "draw" ? "select" : "draw"),
1945
- active: activeTool === "draw"
2086
+ active: activeTool === "draw",
2087
+ annotates: true
1946
2088
  }] : [],
1947
2089
  {
1948
2090
  label: "Region",
1949
2091
  glyph: "⌗",
1950
2092
  action: () => setAuthorToolMode(sessionId, path, activeTool === "mark" ? "select" : "mark"),
1951
- active: activeTool === "mark"
2093
+ active: activeTool === "mark",
2094
+ annotates: true
1952
2095
  },
1953
2096
  ...kind === "markdown" ? [
1954
2097
  {
@@ -1976,41 +2119,43 @@ function AuthorToolPalette({ sessionId, path, kind, activeTool }) {
1976
2119
  label: "Comment",
1977
2120
  glyph: "●",
1978
2121
  action: () => setAuthorToolMode(sessionId, path, activeTool === "comment" ? "select" : "comment"),
1979
- active: activeTool === "comment"
2122
+ active: activeTool === "comment",
2123
+ annotates: true
1980
2124
  }
1981
2125
  ];
1982
2126
  return /* @__PURE__ */ jsxs("section", {
1983
2127
  "data-testid": "author-tool-palette",
1984
- className: "space-y-2 border-b border-doom-border-soft pb-3",
2128
+ className: "space-y-2",
1985
2129
  children: [
1986
- /* @__PURE__ */ jsxs("div", {
1987
- className: "flex justify-between text-sm text-doom-dim",
1988
- children: [/* @__PURE__ */ jsx("h3", {
1989
- className: "text-lg font-semibold text-doom-hi",
1990
- children: "Tools"
1991
- }), /* @__PURE__ */ jsx("span", { children: "focused tab" })]
2130
+ /* @__PURE__ */ jsx("h3", {
2131
+ className: "sr-only",
2132
+ children: "Tools"
1992
2133
  }),
1993
2134
  /* @__PURE__ */ jsx("div", {
1994
- className: "grid grid-cols-3 gap-1.5",
2135
+ className: "grid grid-cols-4 gap-1.5",
1995
2136
  children: tools.map((tool) => /* @__PURE__ */ jsxs(Button, {
1996
2137
  size: "md",
1997
2138
  variant: "outline",
1998
2139
  "aria-label": tool.label === "Region" ? "mark region" : tool.label,
1999
2140
  "aria-pressed": tool.active,
2000
2141
  onClick: tool.action,
2001
- className: `min-h-11 min-w-11 gap-1.5 rounded border text-base [@media(pointer:fine)]:min-h-8 ${tool.active ? "border-doom-red bg-doom-red/10 text-doom-hi hover:bg-doom-red/15" : "border-doom-border bg-doom-panel text-doom-dim"}`,
2142
+ className: authorToolClassName(tool.active === true, tool.annotates === true),
2002
2143
  children: [/* @__PURE__ */ jsx("span", {
2003
2144
  "aria-hidden": "true",
2145
+ className: "text-lg leading-none",
2004
2146
  children: tool.glyph
2005
- }), tool.label]
2147
+ }), /* @__PURE__ */ jsx("span", {
2148
+ className: "text-sm",
2149
+ children: tool.label
2150
+ })]
2006
2151
  }, tool.label))
2007
2152
  }),
2008
2153
  /* @__PURE__ */ jsx("p", {
2009
- className: "text-base leading-normal text-doom-dim",
2154
+ className: "text-base leading-normal text-po-dim sm:text-sm",
2010
2155
  children: activeTool === "draw" ? "Draw a location mark, then enter feedback text. Marks never edit the source." : activeTool === "pan" ? "Drag to pan; pinch to zoom. Use Fit to reset the view." : activeTool === "mark" ? "Drag over the document to mark a region." : activeTool === "comment" ? "Click the document to place a comment pin." : "Choose Region to drag an area, or Comment to place a point."
2011
2156
  }),
2012
2157
  error ? /* @__PURE__ */ jsx("output", {
2013
- className: "block text-base text-doom-red",
2158
+ className: "block text-base text-po-red",
2014
2159
  children: error
2015
2160
  }) : null
2016
2161
  ]
@@ -2018,7 +2163,7 @@ function AuthorToolPalette({ sessionId, path, kind, activeTool }) {
2018
2163
  }
2019
2164
  //#endregion
2020
2165
  //#region src/extensions/workspaces/sessions/(frontend)/dock/_components/AuthorPanel.tsx
2021
- function AuthorPanel({ sessionId, activeMinorModes, submitCapture, statuses, renderSlot, renderSessionActivity }) {
2166
+ function AuthorPanel({ sessionId, submitCapture, statuses, renderSlot, renderSessionActivity }) {
2022
2167
  const documents = useStore(authorWorkspace.store, (state) => {
2023
2168
  if (sessionId === null) return [];
2024
2169
  const prefix = `${sessionId}\n`;
@@ -2031,43 +2176,43 @@ function AuthorPanel({ sessionId, activeMinorModes, submitCapture, statuses, ren
2031
2176
  const requests = (workspace?.requests ?? []).filter((request) => focusedPath === void 0 || request.documentPath === focusedPath);
2032
2177
  const drafts = useStore(authorWorkspace.store, (state) => authorDocumentAnnotations(sessionId, focusedPath ?? "", state));
2033
2178
  const activity = sessionId !== null && focusedPath !== void 0 && requests.some((request) => request.status === "REQUESTED" || request.status === "CHANGING") ? renderSessionActivity?.() ?? null : null;
2034
- if (!activeMinorModes?.includes("author")) return null;
2035
2179
  return /* @__PURE__ */ jsxs("section", {
2036
2180
  "data-testid": "author-panel",
2037
2181
  className: "flex min-h-0 flex-1 flex-col overflow-hidden",
2038
2182
  children: [/* @__PURE__ */ jsx("div", {
2039
2183
  className: "min-h-0 flex-1 overflow-y-auto p-3",
2040
2184
  children: /* @__PURE__ */ jsxs("div", {
2041
- className: "flex flex-col gap-2",
2185
+ className: "flex flex-col gap-3",
2042
2186
  children: [
2043
2187
  /* @__PURE__ */ jsx("div", {
2044
2188
  "data-testid": "author-preview-providers",
2189
+ className: "empty:hidden",
2045
2190
  children: renderSlot("author.preview-provider")
2046
2191
  }),
2047
2192
  sessionId !== null && workspace !== void 0 && focused !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2193
+ /* @__PURE__ */ jsx(AuthorToolPalette, {
2194
+ sessionId,
2195
+ path: focused.path,
2196
+ kind: focused.kind,
2197
+ activeTool: workspace.toolsByDocument[normalizeAuthorPath(focused.path)] ?? "select"
2198
+ }),
2048
2199
  /* @__PURE__ */ jsx("h2", {
2049
- className: "text-base font-semibold text-doom-text",
2200
+ className: "border-t border-po-border-soft pt-3 text-lg font-semibold text-po-hi",
2050
2201
  children: "Annotations"
2051
2202
  }),
2052
2203
  /* @__PURE__ */ jsx("p", {
2053
- className: "text-base leading-normal text-doom-dim sm:text-sm",
2204
+ className: "text-base leading-normal text-po-dim sm:text-sm",
2054
2205
  children: "Drag a region or place a point, add feedback, then submit here. Requests queue while the agent is working."
2055
2206
  }),
2056
2207
  focused.kind === "video" ? /* @__PURE__ */ jsx("p", {
2057
- className: "text-base text-doom-dim sm:text-sm",
2208
+ className: "text-base text-po-dim sm:text-sm",
2058
2209
  children: "Annotations reference video frames. They do not save changes to the source video."
2059
2210
  }) : null,
2060
- /* @__PURE__ */ jsx(AuthorToolPalette, {
2061
- sessionId,
2062
- path: focused.path,
2063
- kind: focused.kind,
2064
- activeTool: workspace.toolsByDocument[normalizeAuthorPath(focused.path)] ?? "select"
2065
- }),
2066
2211
  autonomousVoiceGridVisible(statuses) && grid !== void 0 ? /* @__PURE__ */ jsxs("div", {
2067
2212
  "data-testid": "author-grid-snapshot",
2068
- className: "rounded border border-doom-red/40 bg-doom-red/5 p-2 text-base text-doom-dim",
2213
+ className: "rounded border border-po-red/40 bg-po-red/5 p-2 text-base text-po-dim",
2069
2214
  children: [/* @__PURE__ */ jsx("strong", {
2070
- className: "text-doom-red",
2215
+ className: "text-po-red",
2071
2216
  children: "VOICE GRID A1–H8"
2072
2217
  }), /* @__PURE__ */ jsxs("p", {
2073
2218
  className: "mt-1 truncate",
@@ -2075,7 +2220,7 @@ function AuthorPanel({ sessionId, activeMinorModes, submitCapture, statuses, ren
2075
2220
  })]
2076
2221
  }) : null,
2077
2222
  /* @__PURE__ */ jsx("div", {
2078
- className: "hidden sm:block",
2223
+ className: "max-sm:hidden",
2079
2224
  children: /* @__PURE__ */ jsx(AuthorFeedbackControls, {
2080
2225
  sessionId,
2081
2226
  document: focused,
@@ -2084,12 +2229,15 @@ function AuthorPanel({ sessionId, activeMinorModes, submitCapture, statuses, ren
2084
2229
  }, focused.path)
2085
2230
  })
2086
2231
  ] }) : null,
2087
- /* @__PURE__ */ jsx(AuthorRequestLog, { requests })
2232
+ /* @__PURE__ */ jsx("div", {
2233
+ className: focused === void 0 ? void 0 : "border-t border-po-border-soft pt-3",
2234
+ children: /* @__PURE__ */ jsx(AuthorRequestLog, { requests })
2235
+ })
2088
2236
  ]
2089
2237
  })
2090
2238
  }), activity === null ? null : /* @__PURE__ */ jsx("footer", {
2091
2239
  "data-testid": "author-session-activity",
2092
- className: "shrink-0 border-t border-doom-border bg-doom-rail p-3",
2240
+ className: "shrink-0 border-t border-po-border bg-po-rail p-3",
2093
2241
  children: activity
2094
2242
  })]
2095
2243
  });
@@ -2098,17 +2246,17 @@ function AuthorPanel({ sessionId, activeMinorModes, submitCapture, statuses, ren
2098
2246
  //#region src/extensions/workspaces/sessions/(frontend)/dock/authoring.web.tsx
2099
2247
  var authoring_web_default = defineDockFace({
2100
2248
  id: "authoring",
2101
- label: "authoring",
2249
+ label: "Author",
2102
2250
  order: 30,
2103
- autoSelect: true,
2251
+ autoSelect: ({ tabId }) => tabId?.startsWith(AUTHOR_FILE_TAB_PREFIX) === true,
2104
2252
  panel: AuthorPanel,
2105
- requiredMinorMode: "author",
2106
2253
  visibility: {
2107
- subscribe() {
2108
- return () => void 0;
2254
+ subscribe(listener) {
2255
+ const subscription = authorWorkspace.store.subscribe(listener);
2256
+ return () => subscription.unsubscribe();
2109
2257
  },
2110
2258
  isVisible(sessionId) {
2111
- return sessionId !== null;
2259
+ return sessionId !== null && authorWorkspace.store.state.sessions[sessionId]?.focusedDocument !== void 0;
2112
2260
  }
2113
2261
  }
2114
2262
  });
@@ -2307,8 +2455,29 @@ function authorKindForPath(path) {
2307
2455
  * itself, and the digest travels in a header on both legs.
2308
2456
  */
2309
2457
  function authorSessionFileUrl(sessionId, path) {
2458
+ if (path.startsWith("artifact:")) return artifactApi.session(sessionId).content.url({ query: { path: path.slice(9) } });
2310
2459
  return api.session(sessionId).file.url({ query: { path } });
2311
2460
  }
2461
+ /** The file name a person sees: the last path segment, without the `artifact:` scheme. */
2462
+ function authorFileName(path) {
2463
+ const local = path.startsWith("artifact:") ? path.slice(9) : path;
2464
+ return local.split("/").at(-1) ?? local;
2465
+ }
2466
+ /**
2467
+ * po-artifact's read route, which owns the session artifact folder's guards.
2468
+ * Browser code cannot import that package, so its one raw route is restated.
2469
+ */
2470
+ const artifactApi = createApiClient({ content: {
2471
+ method: "GET",
2472
+ path: "/content",
2473
+ query: ["path"],
2474
+ raw: true
2475
+ } }, {
2476
+ scopes: ["session"],
2477
+ basePath: "artifacts",
2478
+ transport: (input, init) => sealedTransport.fetch(input, init),
2479
+ sessionAddress: sessionApiAddress
2480
+ });
2312
2481
  /** One document route, with the refusal the reader is shown: the route's own words, or its status. */
2313
2482
  async function documentRequest(method, sessionId, body, signal) {
2314
2483
  const result = await method({
@@ -2338,7 +2507,7 @@ async function loadAuthorDocument(sessionId, path, signal) {
2338
2507
  return {
2339
2508
  path,
2340
2509
  kind,
2341
- title: path.split("/").at(-1) ?? path,
2510
+ title: authorFileName(path),
2342
2511
  structuredFormat: format,
2343
2512
  fragments: parsed.fragments,
2344
2513
  ...csvDialect === void 0 ? {} : { csvDialect },
@@ -2351,7 +2520,7 @@ async function loadAuthorDocument(sessionId, path, signal) {
2351
2520
  return {
2352
2521
  path,
2353
2522
  kind,
2354
- title: path.split("/").at(-1) ?? path,
2523
+ title: authorFileName(path),
2355
2524
  ...content === void 0 ? {} : { content },
2356
2525
  ...mediaUrl === void 0 ? {} : { mediaUrl },
2357
2526
  ...sourceSha256 === void 0 ? {} : { sourceSha256 }
@@ -2427,6 +2596,7 @@ async function bytesToSave(sessionId, document, signal) {
2427
2596
  return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
2428
2597
  }
2429
2598
  async function saveAuthorDocument(sessionId, document, signal) {
2599
+ if (document.path.startsWith("artifact:")) throw new Error("Artifacts are read-only.");
2430
2600
  if (document.sourceSha256 === void 0) throw new Error("This Author view has no source digest.");
2431
2601
  const response = await sealedTransport.fetch(authorSessionFileUrl(sessionId, document.path), {
2432
2602
  method: "PUT",
@@ -2865,13 +3035,17 @@ function authorProfilesForDocument(sessionId, path, kind) {
2865
3035
  * own. The transport stays raw because what comes back is a blob, and a call
2866
3036
  * through the generated client reads the body as JSON to report a refusal.
2867
3037
  */
2868
- async function loadAuthorMedia(source, signal) {
2869
- const response = await sealedTransport.fetch(source, {
2870
- signal,
2871
- cache: "no-store"
2872
- });
2873
- if (!response.ok) throw new Error(`Author media could not be loaded (${response.status}).`);
2874
- const blob = await response.blob();
3038
+ async function loadAuthorMedia(source, signal, imageData) {
3039
+ let blob;
3040
+ if (imageData !== void 0) blob = new Blob([Uint8Array.from(atob(imageData), (character) => character.charCodeAt(0))], { type: "image/png" });
3041
+ else {
3042
+ const response = await sealedTransport.fetch(source, {
3043
+ signal,
3044
+ cache: "no-store"
3045
+ });
3046
+ if (!response.ok) throw new Error(`Author media could not be loaded (${response.status}).`);
3047
+ blob = await response.blob();
3048
+ }
2875
3049
  signal.throwIfAborted();
2876
3050
  const url = URL.createObjectURL(blob);
2877
3051
  let disposed = false;
@@ -2897,7 +3071,7 @@ function AuthorVideoControls({ playback, ready, locked, marking, onSeek, onToggl
2897
3071
  const buttonClass = "min-h-11 px-3 text-base [@media(pointer:fine)]:min-h-8 sm:text-sm";
2898
3072
  return /* @__PURE__ */ jsxs("section", {
2899
3073
  "aria-label": "Video annotation controls",
2900
- className: "mt-2 space-y-2 rounded border border-doom-border bg-doom-panel p-2.5 text-base text-doom-text sm:text-sm",
3074
+ className: "mt-2 space-y-2 rounded border border-po-border bg-po-panel p-2.5 text-base text-po-text sm:text-sm",
2901
3075
  children: [
2902
3076
  /* @__PURE__ */ jsxs("div", {
2903
3077
  className: "flex flex-wrap items-center justify-between gap-3",
@@ -2910,7 +3084,7 @@ function AuthorVideoControls({ playback, ready, locked, marking, onSeek, onToggl
2910
3084
  videoTimeLabel(duration)
2911
3085
  ]
2912
3086
  }), /* @__PURE__ */ jsx("span", {
2913
- className: "text-doom-dim",
3087
+ className: "text-po-dim",
2914
3088
  children: locked ? "Annotation draft: add or discard it before seeking." : marking ? "Frame paused. Drag a region on the video." : "Seek to a moment, then choose Annotate this frame."
2915
3089
  })]
2916
3090
  }),
@@ -2923,7 +3097,7 @@ function AuthorVideoControls({ playback, ready, locked, marking, onSeek, onToggl
2923
3097
  value: Math.min(playback.currentTime, duration),
2924
3098
  disabled: locked || duration <= 0,
2925
3099
  onChange: (event) => onSeek(Number(event.target.value)),
2926
- className: "h-11 w-full cursor-pointer accent-doom-blue [@media(pointer:fine)]:h-6"
3100
+ className: "h-11 w-full cursor-pointer accent-po-blue [@media(pointer:fine)]:h-6"
2927
3101
  }),
2928
3102
  /* @__PURE__ */ jsxs("div", {
2929
3103
  className: "flex flex-wrap items-center gap-2",
@@ -2964,7 +3138,7 @@ function AuthorVideoControls({ playback, ready, locked, marking, onSeek, onToggl
2964
3138
  children: [
2965
3139
  /* @__PURE__ */ jsx("label", {
2966
3140
  htmlFor: "author-video-seconds",
2967
- className: "text-doom-dim",
3141
+ className: "text-po-dim",
2968
3142
  children: "Go to seconds"
2969
3143
  }),
2970
3144
  /* @__PURE__ */ jsx("input", {
@@ -2977,7 +3151,7 @@ function AuthorVideoControls({ playback, ready, locked, marking, onSeek, onToggl
2977
3151
  onChange: (event) => setSeconds(event.target.value),
2978
3152
  disabled: locked || duration <= 0,
2979
3153
  placeholder: "1.250",
2980
- className: "h-11 w-24 rounded border border-doom-border bg-doom-deep px-2 text-lg [@media(pointer:fine)]:h-8 sm:text-sm"
3154
+ className: "h-11 w-24 rounded border border-po-border bg-po-deep px-2 text-lg [@media(pointer:fine)]:h-8 sm:text-sm"
2981
3155
  }),
2982
3156
  /* @__PURE__ */ jsx(Button, {
2983
3157
  type: "submit",
@@ -2994,6 +3168,8 @@ function AuthorVideoControls({ playback, ready, locked, marking, onSeek, onToggl
2994
3168
  }
2995
3169
  //#endregion
2996
3170
  //#region src/extensions/workspaces/sessions/(frontend)/_components/AuthorMediaView.tsx
3171
+ const REGION_FRAME = "pointer-events-none absolute border-2 border-po-magenta bg-po-magenta/10";
3172
+ const ORDINAL_BADGE = "absolute -left-3 -top-3 flex h-6 min-w-6 items-center justify-center rounded-full border-2 border-po-panel bg-po-magenta px-1 text-sm font-semibold text-po-rail";
2997
3173
  /** Marks source media. Native playback and page controls remain usable in select mode. */
2998
3174
  function AuthorMediaView({ sessionId, document: source, activeTool, displayedRegions, pendingCandidate = false, seekRequest }) {
2999
3175
  const host = useRef(null);
@@ -3004,7 +3180,35 @@ function AuthorMediaView({ sessionId, document: source, activeTool, displayedReg
3004
3180
  const pointers = useRef(/* @__PURE__ */ new Map());
3005
3181
  const pan = useRef(void 0);
3006
3182
  const pinch = useRef(void 0);
3183
+ const frame = useRef(null);
3184
+ const zoomAnchor = useRef(void 0);
3007
3185
  const [zoom, setZoom] = useState(1);
3186
+ const zoomTo = (requested, at) => {
3187
+ const next = Math.min(8, Math.max(.25, requested));
3188
+ if (next === zoom) return;
3189
+ const view = host.current?.getBoundingClientRect();
3190
+ const bounds = frame.current?.getBoundingClientRect();
3191
+ if (view && bounds && bounds.width > 0 && bounds.height > 0) {
3192
+ const x = at?.x ?? view.left + view.width / 2;
3193
+ const y = at?.y ?? view.top + view.height / 2;
3194
+ zoomAnchor.current = {
3195
+ x,
3196
+ y,
3197
+ fx: (x - bounds.left) / bounds.width,
3198
+ fy: (y - bounds.top) / bounds.height
3199
+ };
3200
+ }
3201
+ setZoom(next);
3202
+ };
3203
+ useLayoutEffect(() => {
3204
+ const anchor = zoomAnchor.current;
3205
+ zoomAnchor.current = void 0;
3206
+ const container = host.current;
3207
+ const bounds = frame.current?.getBoundingClientRect();
3208
+ if (!anchor || !container || !bounds) return;
3209
+ container.scrollLeft += bounds.left + anchor.fx * bounds.width - anchor.x;
3210
+ container.scrollTop += bounds.top + anchor.fy * bounds.height - anchor.y;
3211
+ }, [zoom]);
3008
3212
  const [stroke, setStroke] = useState();
3009
3213
  const [pdfPlane, setPdfPlane] = useState();
3010
3214
  const [playback, setPlayback] = useState({
@@ -3023,6 +3227,7 @@ function AuthorMediaView({ sessionId, document: source, activeTool, displayedReg
3023
3227
  pan.current = void 0;
3024
3228
  setStroke(void 0);
3025
3229
  setSelection(void 0);
3230
+ zoomAnchor.current = void 0;
3026
3231
  setZoom(1);
3027
3232
  }, [
3028
3233
  source.path,
@@ -3084,7 +3289,7 @@ function AuthorMediaView({ sessionId, document: source, activeTool, displayedReg
3084
3289
  const controller = new AbortController();
3085
3290
  let dispose;
3086
3291
  setError(void 0);
3087
- loadAuthorMedia(input, controller.signal).then((asset) => {
3292
+ loadAuthorMedia(input, controller.signal, source.imageData).then((asset) => {
3088
3293
  if (controller.signal.aborted) {
3089
3294
  asset.dispose();
3090
3295
  return;
@@ -3101,7 +3306,7 @@ function AuthorMediaView({ sessionId, document: source, activeTool, displayedReg
3101
3306
  controller.abort();
3102
3307
  dispose?.();
3103
3308
  };
3104
- }, [source.mediaUrl]);
3309
+ }, [source.mediaUrl, source.imageData]);
3105
3310
  const seek = (seconds) => {
3106
3311
  if (authorDocumentAnnotations(sessionId, source.path).candidate || !Number.isFinite(seconds)) return;
3107
3312
  const player = video.current;
@@ -3277,14 +3482,14 @@ function AuthorMediaView({ sessionId, document: source, activeTool, displayedReg
3277
3482
  strokeWidth: "5",
3278
3483
  strokeLinecap: "round",
3279
3484
  strokeLinejoin: "round",
3280
- className: ordinal === void 0 ? "text-doom-red" : "text-doom-yellow"
3485
+ className: "text-po-magenta"
3281
3486
  })
3282
3487
  });
3283
3488
  const selected = selection?.path === source.path ? selection.rect : void 0;
3284
3489
  const selectedPoint = selection?.path === source.path ? selection.point : void 0;
3285
3490
  const selectionOverlay = selected === void 0 ? null : /* @__PURE__ */ jsx("div", {
3286
3491
  "data-testid": "author-media-selection",
3287
- className: "pointer-events-none absolute border-2 border-doom-red bg-doom-red/10",
3492
+ className: "pointer-events-none absolute border-2 border-dashed border-po-magenta bg-po-magenta/10",
3288
3493
  style: {
3289
3494
  left: `${selected.x * 100}%`,
3290
3495
  top: `${selected.y * 100}%`,
@@ -3295,7 +3500,7 @@ function AuthorMediaView({ sessionId, document: source, activeTool, displayedReg
3295
3500
  const pointPin = (ordinal, point, key) => /* @__PURE__ */ jsx("span", {
3296
3501
  "data-author-point": ordinal,
3297
3502
  "data-testid": ordinal === void 0 ? "author-media-point-selection" : void 0,
3298
- className: `pointer-events-none absolute z-10 flex h-5 min-w-5 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full border-2 px-1 text-2xs font-semibold ${ordinal === void 0 ? "border-white bg-doom-red text-white" : "border-doom-deep bg-doom-yellow text-doom-deep"}`,
3503
+ className: `pointer-events-none absolute z-10 flex h-6 min-w-6 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full border-2 px-1 text-sm font-semibold ${ordinal === void 0 ? "border-po-magenta bg-po-panel text-po-magenta" : "border-po-panel bg-po-magenta text-po-rail"}`,
3299
3504
  style: {
3300
3505
  left: `${String(point.x * 100)}%`,
3301
3506
  top: `${String(point.y * 100)}%`
@@ -3304,8 +3509,7 @@ function AuthorMediaView({ sessionId, document: source, activeTool, displayedReg
3304
3509
  }, key);
3305
3510
  const pointSelectionOverlay = selectedPoint === void 0 ? null : pointPin(void 0, selectedPoint, "selection");
3306
3511
  return /* @__PURE__ */ jsxs("div", {
3307
- ref: host,
3308
- className: "min-h-0 flex-1 overflow-auto p-4",
3512
+ className: "flex min-h-0 flex-1 flex-col",
3309
3513
  style: { cursor: activeTool === "draw" || activeTool === "mark" ? "crosshair" : void 0 },
3310
3514
  onPointerMove: (event) => {
3311
3515
  if (pointers.current.has(event.pointerId)) pointers.current.set(event.pointerId, {
@@ -3315,7 +3519,10 @@ function AuthorMediaView({ sessionId, document: source, activeTool, displayedReg
3315
3519
  if (pinch.current !== void 0 && pointers.current.size >= 2) {
3316
3520
  const [a, b] = [...pointers.current.values()];
3317
3521
  const distance = Math.hypot(a.x - b.x, a.y - b.y);
3318
- if (pinch.current.distance > 0) setZoom(Math.min(8, Math.max(1, pinch.current.zoom * distance / pinch.current.distance)));
3522
+ if (pinch.current.distance > 0) zoomTo(pinch.current.zoom * distance / pinch.current.distance, {
3523
+ x: (a.x + b.x) / 2,
3524
+ y: (a.y + b.y) / 2
3525
+ });
3319
3526
  return;
3320
3527
  }
3321
3528
  if (pan.current !== void 0 && activeTool === "pan") {
@@ -3425,141 +3632,44 @@ function AuthorMediaView({ sessionId, document: source, activeTool, displayedReg
3425
3632
  pan.current = void 0;
3426
3633
  setStroke(void 0);
3427
3634
  },
3428
- children: [
3429
- /* @__PURE__ */ jsxs("div", {
3430
- className: "sticky top-0 z-20 mb-2 flex items-center gap-2 bg-doom-bg py-1",
3431
- role: "group",
3432
- "aria-label": "Canvas zoom",
3635
+ children: [/* @__PURE__ */ jsx("div", {
3636
+ ref: host,
3637
+ className: "@container flex min-h-0 flex-1 flex-col overflow-auto bg-po-deep/50 p-6",
3638
+ children: /* @__PURE__ */ jsxs("div", {
3639
+ className: "m-auto flex max-w-full flex-col items-center-safe gap-3",
3433
3640
  children: [
3434
- /* @__PURE__ */ jsx(Button, {
3435
- size: "md",
3436
- variant: "outline",
3437
- "aria-label": "Zoom out",
3438
- className: "min-h-11 min-w-11",
3439
- onClick: () => setZoom((current) => Math.max(1, current / 1.5)),
3440
- children: "−"
3441
- }),
3442
- /* @__PURE__ */ jsxs("output", {
3443
- className: "text-sm text-doom-dim",
3444
- children: [Math.round(zoom * 100), "%"]
3445
- }),
3446
- /* @__PURE__ */ jsx(Button, {
3447
- size: "md",
3448
- variant: "outline",
3449
- "aria-label": "Zoom in",
3450
- className: "min-h-11 min-w-11",
3451
- onClick: () => setZoom((current) => Math.min(8, current * 1.5)),
3452
- children: "+"
3453
- }),
3454
- /* @__PURE__ */ jsx(Button, {
3455
- size: "md",
3456
- variant: "outline",
3457
- "aria-label": "Fit canvas",
3458
- className: "min-h-11",
3459
- onClick: () => {
3460
- setZoom(1);
3461
- if (host.current) {
3462
- host.current.scrollLeft = 0;
3463
- host.current.scrollTop = 0;
3464
- }
3641
+ mediaUrl === void 0 ? /* @__PURE__ */ jsx("p", {
3642
+ className: "text-po-dim",
3643
+ children: error === void 0 ? "Loading media..." : "Media unavailable."
3644
+ }) : source.kind === "image" ? /* @__PURE__ */ jsxs("div", {
3645
+ ref: frame,
3646
+ className: "relative w-max max-w-[100cqw] shadow-sm ring-1 ring-po-border-soft",
3647
+ style: {
3648
+ zoom,
3649
+ touchAction: activeTool === "select" ? "auto" : "none"
3465
3650
  },
3466
- children: "Fit"
3467
- })
3468
- ]
3469
- }),
3470
- mediaUrl === void 0 ? /* @__PURE__ */ jsx("p", {
3471
- className: "text-doom-dim",
3472
- children: error === void 0 ? "Loading media..." : "Media unavailable."
3473
- }) : source.kind === "image" ? /* @__PURE__ */ jsxs("div", {
3474
- className: "relative inline-block max-w-full",
3475
- style: {
3476
- zoom,
3477
- touchAction: activeTool === "select" ? "auto" : "none"
3478
- },
3479
- children: [
3480
- /* @__PURE__ */ jsx("img", {
3481
- ref: image,
3482
- src: mediaUrl,
3483
- alt: source.path,
3484
- draggable: false,
3485
- className: "block max-w-full"
3486
- }),
3487
- selectionOverlay,
3488
- pointSelectionOverlay,
3489
- strokeOverlay(stroke),
3490
- displayedRegions.flatMap(({ ordinal, region }) => {
3491
- if (region.stroke !== void 0) return [/* @__PURE__ */ jsxs("div", {
3492
- className: "pointer-events-none absolute inset-0",
3493
- children: [strokeOverlay(region.stroke, ordinal), pointPin(ordinal, region.stroke[0], `label:${region.id}`)]
3494
- }, region.id)];
3495
- if (region.anchor.kind === "image-point") return [pointPin(ordinal, region.anchor.point, region.id)];
3496
- if (region.anchor.kind !== "image-rect") return [];
3497
- const { rect } = region.anchor;
3498
- return [/* @__PURE__ */ jsx("div", {
3499
- "data-author-region": ordinal,
3500
- className: "pointer-events-none absolute border border-doom-yellow bg-doom-yellow/10",
3501
- style: {
3502
- left: `${String(rect.x * 100)}%`,
3503
- top: `${String(rect.y * 100)}%`,
3504
- width: `${String(rect.width * 100)}%`,
3505
- height: `${String(rect.height * 100)}%`
3506
- },
3507
- children: /* @__PURE__ */ jsx("span", {
3508
- className: "absolute -left-2 -top-2 flex h-4 min-w-4 items-center justify-center rounded-full bg-doom-yellow px-1 text-2xs font-semibold text-doom-deep",
3509
- children: ordinal
3510
- })
3511
- }, region.id)];
3512
- })
3513
- ]
3514
- }) : /* @__PURE__ */ jsxs("div", {
3515
- className: "relative w-fit max-w-full",
3516
- style: {
3517
- zoom,
3518
- touchAction: activeTool === "select" ? "auto" : "none"
3519
- },
3520
- children: [/* @__PURE__ */ jsx(MediaPreview, {
3521
- src: mediaUrl,
3522
- path: source.path,
3523
- kind: source.kind === "pdf" ? "pdf" : source.kind === "video" ? "video" : "download",
3524
- controllerRef: video,
3525
- pdfControllerRef: pdf,
3526
- "data-testid": "author-media",
3527
- videoControls: false,
3528
- onPlaybackStateChange: (state) => {
3529
- setPlayback(state);
3530
- setFrameReady(video.current?.isFrameReady() ?? false);
3531
- if (state.playing) setSelection(void 0);
3532
- }
3533
- }), /* @__PURE__ */ jsxs("div", {
3534
- className: "pointer-events-none absolute",
3535
- style: source.kind === "pdf" ? pdfPlane === void 0 ? { display: "none" } : {
3536
- left: pdfPlane.left,
3537
- top: pdfPlane.top,
3538
- width: pdfPlane.width,
3539
- height: pdfPlane.height
3540
- } : { inset: 0 },
3541
- children: [
3542
- selectionOverlay,
3543
- pointSelectionOverlay,
3544
- strokeOverlay(stroke),
3545
- displayedRegions.map(({ ordinal, region }) => {
3546
- if (region.stroke !== void 0) {
3547
- const anchor = region.anchor;
3548
- if (source.kind === "pdf" && (anchor.kind !== "pdf-page-rect" || anchor.page !== pdf.current?.getState().page)) return null;
3549
- if (source.kind === "video" && (anchor.kind !== "video-time-rect" || playback.playing || Math.abs(anchor.timeSeconds - playback.currentTime) > .1)) return null;
3550
- return /* @__PURE__ */ jsxs("div", {
3651
+ children: [
3652
+ /* @__PURE__ */ jsx("img", {
3653
+ ref: image,
3654
+ src: mediaUrl,
3655
+ alt: source.path,
3656
+ draggable: false,
3657
+ className: "block max-w-full"
3658
+ }),
3659
+ selectionOverlay,
3660
+ pointSelectionOverlay,
3661
+ strokeOverlay(stroke),
3662
+ displayedRegions.flatMap(({ ordinal, region }) => {
3663
+ if (region.stroke !== void 0) return [/* @__PURE__ */ jsxs("div", {
3551
3664
  className: "pointer-events-none absolute inset-0",
3552
3665
  children: [strokeOverlay(region.stroke, ordinal), pointPin(ordinal, region.stroke[0], `label:${region.id}`)]
3553
- }, region.id);
3554
- }
3555
- if (source.kind === "pdf") {
3556
- if (region.anchor.kind !== "pdf-page-point" && region.anchor.kind !== "pdf-page-rect") return null;
3557
- if (region.anchor.page !== pdf.current?.getState().page) return null;
3558
- if (region.anchor.kind === "pdf-page-point") return pointPin(ordinal, region.anchor.point, region.id);
3666
+ }, region.id)];
3667
+ if (region.anchor.kind === "image-point") return [pointPin(ordinal, region.anchor.point, region.id)];
3668
+ if (region.anchor.kind !== "image-rect") return [];
3559
3669
  const { rect } = region.anchor;
3560
- return /* @__PURE__ */ jsx("div", {
3670
+ return [/* @__PURE__ */ jsx("div", {
3561
3671
  "data-author-region": ordinal,
3562
- className: "pointer-events-none absolute border border-doom-yellow bg-doom-yellow/10",
3672
+ className: REGION_FRAME,
3563
3673
  style: {
3564
3674
  left: `${String(rect.x * 100)}%`,
3565
3675
  top: `${String(rect.y * 100)}%`,
@@ -3567,55 +3677,169 @@ function AuthorMediaView({ sessionId, document: source, activeTool, displayedReg
3567
3677
  height: `${String(rect.height * 100)}%`
3568
3678
  },
3569
3679
  children: /* @__PURE__ */ jsx("span", {
3570
- className: "bg-doom-yellow text-doom-deep",
3680
+ className: ORDINAL_BADGE,
3571
3681
  children: ordinal
3572
3682
  })
3573
- }, region.id);
3683
+ }, region.id)];
3684
+ })
3685
+ ]
3686
+ }) : /* @__PURE__ */ jsxs("div", {
3687
+ ref: frame,
3688
+ className: "relative w-max max-w-[100cqw] shadow-sm ring-1 ring-po-border-soft",
3689
+ style: {
3690
+ zoom,
3691
+ touchAction: activeTool === "select" ? "auto" : "none"
3692
+ },
3693
+ children: [/* @__PURE__ */ jsx(MediaPreview, {
3694
+ src: mediaUrl,
3695
+ path: source.path,
3696
+ kind: source.kind === "pdf" ? "pdf" : source.kind === "video" ? "video" : "download",
3697
+ controllerRef: video,
3698
+ pdfControllerRef: pdf,
3699
+ "data-testid": "author-media",
3700
+ videoControls: false,
3701
+ onPlaybackStateChange: (state) => {
3702
+ setPlayback(state);
3703
+ setFrameReady(video.current?.isFrameReady() ?? false);
3704
+ if (state.playing) setSelection(void 0);
3574
3705
  }
3575
- if (source.kind !== "video" || playback.playing) return null;
3576
- if (region.anchor.kind === "video-time-point" && Math.abs(region.anchor.timeSeconds - playback.currentTime) <= .1) return pointPin(ordinal, region.anchor.point, region.id);
3577
- if (region.anchor.kind !== "video-time-rect" || Math.abs(region.anchor.timeSeconds - playback.currentTime) > .1) return null;
3578
- const { rect } = region.anchor;
3579
- return /* @__PURE__ */ jsx("div", {
3580
- "data-author-region": ordinal,
3581
- className: "pointer-events-none absolute border border-doom-yellow bg-doom-yellow/10",
3582
- style: {
3583
- left: `${rect.x * 100}%`,
3584
- top: `${rect.y * 100}%`,
3585
- width: `${rect.width * 100}%`,
3586
- height: `${rect.height * 100}%`
3587
- },
3588
- children: /* @__PURE__ */ jsx("span", {
3589
- className: "bg-doom-yellow text-doom-deep",
3590
- children: ordinal
3706
+ }), /* @__PURE__ */ jsxs("div", {
3707
+ className: "pointer-events-none absolute",
3708
+ style: source.kind === "pdf" ? pdfPlane === void 0 ? { display: "none" } : {
3709
+ left: pdfPlane.left,
3710
+ top: pdfPlane.top,
3711
+ width: pdfPlane.width,
3712
+ height: pdfPlane.height
3713
+ } : { inset: 0 },
3714
+ children: [
3715
+ selectionOverlay,
3716
+ pointSelectionOverlay,
3717
+ strokeOverlay(stroke),
3718
+ displayedRegions.map(({ ordinal, region }) => {
3719
+ if (region.stroke !== void 0) {
3720
+ const anchor = region.anchor;
3721
+ if (source.kind === "pdf" && (anchor.kind !== "pdf-page-rect" || anchor.page !== pdf.current?.getState().page)) return null;
3722
+ if (source.kind === "video" && (anchor.kind !== "video-time-rect" || playback.playing || Math.abs(anchor.timeSeconds - playback.currentTime) > .1)) return null;
3723
+ return /* @__PURE__ */ jsxs("div", {
3724
+ className: "pointer-events-none absolute inset-0",
3725
+ children: [strokeOverlay(region.stroke, ordinal), pointPin(ordinal, region.stroke[0], `label:${region.id}`)]
3726
+ }, region.id);
3727
+ }
3728
+ if (source.kind === "pdf") {
3729
+ if (region.anchor.kind !== "pdf-page-point" && region.anchor.kind !== "pdf-page-rect") return null;
3730
+ if (region.anchor.page !== pdf.current?.getState().page) return null;
3731
+ if (region.anchor.kind === "pdf-page-point") return pointPin(ordinal, region.anchor.point, region.id);
3732
+ const { rect } = region.anchor;
3733
+ return /* @__PURE__ */ jsx("div", {
3734
+ "data-author-region": ordinal,
3735
+ className: REGION_FRAME,
3736
+ style: {
3737
+ left: `${String(rect.x * 100)}%`,
3738
+ top: `${String(rect.y * 100)}%`,
3739
+ width: `${String(rect.width * 100)}%`,
3740
+ height: `${String(rect.height * 100)}%`
3741
+ },
3742
+ children: /* @__PURE__ */ jsx("span", {
3743
+ className: ORDINAL_BADGE,
3744
+ children: ordinal
3745
+ })
3746
+ }, region.id);
3747
+ }
3748
+ if (source.kind !== "video" || playback.playing) return null;
3749
+ if (region.anchor.kind === "video-time-point" && Math.abs(region.anchor.timeSeconds - playback.currentTime) <= .1) return pointPin(ordinal, region.anchor.point, region.id);
3750
+ if (region.anchor.kind !== "video-time-rect" || Math.abs(region.anchor.timeSeconds - playback.currentTime) > .1) return null;
3751
+ const { rect } = region.anchor;
3752
+ return /* @__PURE__ */ jsx("div", {
3753
+ "data-author-region": ordinal,
3754
+ className: REGION_FRAME,
3755
+ style: {
3756
+ left: `${rect.x * 100}%`,
3757
+ top: `${rect.y * 100}%`,
3758
+ width: `${rect.width * 100}%`,
3759
+ height: `${rect.height * 100}%`
3760
+ },
3761
+ children: /* @__PURE__ */ jsx("span", {
3762
+ className: ORDINAL_BADGE,
3763
+ children: ordinal
3764
+ })
3765
+ }, region.id);
3591
3766
  })
3592
- }, region.id);
3767
+ ]
3768
+ })]
3769
+ }),
3770
+ source.kind === "video" ? /* @__PURE__ */ jsx(AuthorVideoControls, {
3771
+ playback,
3772
+ ready: frameReady,
3773
+ locked: pendingCandidate,
3774
+ marking: activeTool === "mark",
3775
+ onSeek: seek,
3776
+ onToggle: () => {
3777
+ setAuthorToolMode(sessionId, source.path, "select");
3778
+ setSelection(void 0);
3779
+ if (playback.playing) video.current?.pause();
3780
+ else video.current?.play().catch((reason) => setError(String(reason)));
3781
+ },
3782
+ onAnnotate: () => {
3783
+ video.current?.pause();
3784
+ setAuthorToolMode(sessionId, source.path, "mark");
3785
+ }
3786
+ }) : null,
3787
+ error ? /* @__PURE__ */ jsx("output", {
3788
+ className: "text-base text-po-red",
3789
+ children: error
3790
+ }) : null
3791
+ ]
3792
+ })
3793
+ }), /* @__PURE__ */ jsxs("footer", {
3794
+ className: "flex shrink-0 items-center gap-2 border-t border-po-border bg-po-bg px-3 py-1.5",
3795
+ children: [/* @__PURE__ */ jsxs("div", {
3796
+ role: "group",
3797
+ "aria-label": "Canvas zoom",
3798
+ className: "flex items-center gap-2",
3799
+ children: [/* @__PURE__ */ jsxs("div", {
3800
+ className: "flex items-center rounded-md border border-po-border",
3801
+ children: [
3802
+ /* @__PURE__ */ jsx(Button, {
3803
+ size: "md",
3804
+ variant: "ghost",
3805
+ "aria-label": "Zoom out",
3806
+ className: "min-h-11 min-w-11 rounded-r-none [@media(pointer:fine)]:min-h-8",
3807
+ onClick: () => zoomTo(zoom / 1.5),
3808
+ children: "−"
3809
+ }),
3810
+ /* @__PURE__ */ jsxs("output", {
3811
+ className: "flex min-w-14 items-center justify-center self-stretch border-x border-po-border-soft text-sm tabular-nums text-po-text",
3812
+ children: [Math.round(zoom * 100), "%"]
3813
+ }),
3814
+ /* @__PURE__ */ jsx(Button, {
3815
+ size: "md",
3816
+ variant: "ghost",
3817
+ "aria-label": "Zoom in",
3818
+ className: "min-h-11 min-w-11 rounded-l-none [@media(pointer:fine)]:min-h-8",
3819
+ onClick: () => zoomTo(zoom * 1.5),
3820
+ children: "+"
3593
3821
  })
3594
3822
  ]
3823
+ }), /* @__PURE__ */ jsx(Button, {
3824
+ size: "md",
3825
+ variant: "outline",
3826
+ "aria-label": "Fit canvas",
3827
+ className: "min-h-11 [@media(pointer:fine)]:min-h-8",
3828
+ onClick: () => {
3829
+ zoomAnchor.current = void 0;
3830
+ setZoom(1);
3831
+ if (host.current) {
3832
+ host.current.scrollLeft = 0;
3833
+ host.current.scrollTop = 0;
3834
+ }
3835
+ },
3836
+ children: "Fit"
3595
3837
  })]
3596
- }),
3597
- source.kind === "video" ? /* @__PURE__ */ jsx(AuthorVideoControls, {
3598
- playback,
3599
- ready: frameReady,
3600
- locked: pendingCandidate,
3601
- marking: activeTool === "mark",
3602
- onSeek: seek,
3603
- onToggle: () => {
3604
- setAuthorToolMode(sessionId, source.path, "select");
3605
- setSelection(void 0);
3606
- if (playback.playing) video.current?.pause();
3607
- else video.current?.play().catch((reason) => setError(String(reason)));
3608
- },
3609
- onAnnotate: () => {
3610
- video.current?.pause();
3611
- setAuthorToolMode(sessionId, source.path, "mark");
3612
- }
3613
- }) : null,
3614
- error ? /* @__PURE__ */ jsx("output", {
3615
- className: "text-base text-doom-red",
3616
- children: error
3617
- }) : null
3618
- ]
3838
+ }), /* @__PURE__ */ jsx("span", {
3839
+ className: "ml-auto text-sm text-po-dim first-letter:uppercase",
3840
+ children: source.kind
3841
+ })]
3842
+ })]
3619
3843
  });
3620
3844
  }
3621
3845
  //#endregion
@@ -3664,22 +3888,22 @@ function AuthorStructuredView({ sessionId, document, displayedRegions }) {
3664
3888
  "data-testid": "author-structured",
3665
3889
  className: "min-h-0 flex-1 space-y-3 overflow-auto p-4",
3666
3890
  children: [!cells ? /* @__PURE__ */ jsx("p", {
3667
- className: "text-sm text-doom-dim",
3891
+ className: "text-sm text-po-dim",
3668
3892
  children: "Slide text view, not a layout-faithful rendering."
3669
3893
  }) : null, [...groups].map(([location, fragments]) => /* @__PURE__ */ jsxs("section", {
3670
3894
  className: "space-y-1",
3671
3895
  children: [/* @__PURE__ */ jsx("h3", {
3672
- className: "text-sm text-doom-dim",
3896
+ className: "text-sm text-po-dim",
3673
3897
  children: location
3674
3898
  }), /* @__PURE__ */ jsx("div", {
3675
3899
  className: cells ? "flex gap-1" : "space-y-2",
3676
3900
  children: fragments.map((fragment) => /* @__PURE__ */ jsxs("div", {
3677
3901
  "data-author-fragment": fragment.id,
3678
3902
  "data-author-region": displayedByFragment.get(fragment.id),
3679
- className: `${cells ? "w-40 shrink-0" : ""} relative rounded ${displayedByFragment.has(fragment.id) ? "ring-1 ring-doom-yellow" : ""}`,
3903
+ className: `${cells ? "w-40 shrink-0" : ""} relative rounded ${displayedByFragment.has(fragment.id) ? "ring-1 ring-po-yellow" : ""}`,
3680
3904
  children: [
3681
3905
  displayedByFragment.has(fragment.id) ? /* @__PURE__ */ jsx("span", {
3682
- className: "absolute -left-1 -top-1 z-10 flex h-4 min-w-4 items-center justify-center rounded-full bg-doom-yellow px-1 text-2xs font-semibold text-doom-deep",
3906
+ className: "absolute -left-1 -top-1 z-10 flex h-4 min-w-4 items-center justify-center rounded-full bg-po-yellow px-1 text-2xs font-semibold text-po-deep",
3683
3907
  children: displayedByFragment.get(fragment.id)
3684
3908
  }) : null,
3685
3909
  /* @__PURE__ */ jsxs(Button, {
@@ -3717,7 +3941,7 @@ function AuthorStructuredView({ sessionId, document, displayedRegions }) {
3717
3941
  "aria-label": fragment.location,
3718
3942
  value: fragment.text,
3719
3943
  readOnly: fragment.readOnly === true,
3720
- className: "w-full rounded border border-doom-border bg-doom-deep p-2 text-base text-doom-text",
3944
+ className: "w-full rounded border border-po-border bg-po-deep p-2 text-base text-po-text",
3721
3945
  onChange: (event) => reviseAuthorFragment(sessionId, document.path, fragment.id, event.target.value)
3722
3946
  })
3723
3947
  ]
@@ -3759,13 +3983,17 @@ function AuthorTextView({ sessionId, document, preview, displayedRegions }) {
3759
3983
  label: String(ordinal)
3760
3984
  }] : []));
3761
3985
  }, [displayedRegions]);
3762
- return /* @__PURE__ */ jsx("div", {
3986
+ const lines = (document.content ?? "").split("\n").length;
3987
+ return /* @__PURE__ */ jsxs("div", {
3763
3988
  ref: host,
3764
3989
  className: "flex min-h-0 flex-1 flex-col",
3765
- children: preview ? /* @__PURE__ */ jsx("div", {
3990
+ children: [preview ? /* @__PURE__ */ jsx("div", {
3766
3991
  "data-testid": "author-markdown",
3767
- className: "min-h-0 flex-1 overflow-auto p-4 text-base text-doom-text",
3768
- children: /* @__PURE__ */ jsx(Markdown, { text: document.content ?? "" })
3992
+ className: "min-h-0 flex-1 overflow-auto bg-po-deep/50 p-6",
3993
+ children: /* @__PURE__ */ jsx("article", {
3994
+ className: "mx-auto min-h-full max-w-3xl rounded-md bg-po-panel px-6 py-8 sm:px-10 text-lg leading-relaxed text-po-text shadow-sm ring-1 ring-po-border-soft",
3995
+ children: /* @__PURE__ */ jsx(Markdown, { text: document.content ?? "" })
3996
+ })
3769
3997
  }) : /* @__PURE__ */ jsx(CodeEditor, {
3770
3998
  value: document.content ?? "",
3771
3999
  path: document.path,
@@ -3796,17 +4024,41 @@ function AuthorTextView({ sessionId, document, preview, displayedRegions }) {
3796
4024
  createdAt: Date.now()
3797
4025
  });
3798
4026
  }
3799
- })
4027
+ }), /* @__PURE__ */ jsxs("footer", {
4028
+ className: "flex shrink-0 items-center gap-2 border-t border-po-border bg-po-bg px-4 py-1.5 text-sm text-po-dim",
4029
+ children: [
4030
+ /* @__PURE__ */ jsx("span", {
4031
+ className: "first-letter:uppercase",
4032
+ children: document.kind
4033
+ }),
4034
+ /* @__PURE__ */ jsx("span", {
4035
+ "aria-hidden": "true",
4036
+ children: "·"
4037
+ }),
4038
+ /* @__PURE__ */ jsxs("span", { children: [
4039
+ lines,
4040
+ " line",
4041
+ lines === 1 ? "" : "s"
4042
+ ] })
4043
+ ]
4044
+ })]
3800
4045
  });
3801
4046
  }
3802
4047
  //#endregion
3803
4048
  //#region src/extensions/workspaces/sessions/(frontend)/_components/AuthorDocumentPanel.tsx
4049
+ const MOBILE_TOOL_GLYPHS = {
4050
+ select: "↖",
4051
+ pan: "✋",
4052
+ mark: "⌗",
4053
+ comment: "●",
4054
+ draw: "✎"
4055
+ };
3804
4056
  const pendingCanvases = /* @__PURE__ */ new Map();
3805
4057
  const canvasOwners = /* @__PURE__ */ new Map();
3806
4058
  function tabId(path) {
3807
4059
  let hash = 2166136261;
3808
4060
  for (const char of normalizeAuthorPath(path)) hash = Math.imul(hash ^ char.charCodeAt(0), 16777619);
3809
- return `author-file-${(hash >>> 0).toString(36)}`;
4061
+ return `${AUTHOR_FILE_TAB_PREFIX}${(hash >>> 0).toString(36)}`;
3810
4062
  }
3811
4063
  /** Unsent annotations only. Sent ones live in the request log, not on the canvas. */
3812
4064
  function displayedAuthorRegions(workspace) {
@@ -3816,19 +4068,8 @@ function displayedAuthorRegions(workspace) {
3816
4068
  }));
3817
4069
  }
3818
4070
  function AuthorDocumentPanel(props) {
3819
- if (!props.activeMinorModes?.includes("author")) {
3820
- const fallback = props.fileTabFor(props.path);
3821
- if (fallback !== void 0 && fallback.id !== tabId(props.path)) return /* @__PURE__ */ jsx(fallback.panel, { ...props });
3822
- return /* @__PURE__ */ jsx("p", {
3823
- "data-testid": "author-mode-inactive",
3824
- className: "p-3 text-sm text-doom-dim",
3825
- children: "No file viewer is available for this path."
3826
- });
3827
- }
3828
- return /* @__PURE__ */ jsx(ActiveAuthorDocumentPanel, { ...props });
3829
- }
3830
- function ActiveAuthorDocumentPanel(props) {
3831
4071
  const { sessionId, statuses } = props;
4072
+ const agentEnabled = props.activeMinorModes?.includes(AUTHOR_MODE_ID) === true;
3832
4073
  const path = useStore(canvasPaths, (state) => sessionId === null ? props.path : state[authorDocumentKey(sessionId, props.path)] ?? props.path);
3833
4074
  const alias = useStore(canvasAliases, (state) => props.alias ?? (sessionId === null ? void 0 : state[authorDocumentKey(sessionId, props.path)]));
3834
4075
  const loadFailure = useStore(canvasFailures, (state) => sessionId === null ? void 0 : state[authorDocumentKey(sessionId, props.path)]);
@@ -3859,7 +4100,7 @@ function ActiveAuthorDocumentPanel(props) {
3859
4100
  return () => releaseAuthorDocumentFocus(sessionId, generation);
3860
4101
  }, [path, sessionId]);
3861
4102
  useEffect(() => {
3862
- if (kind === void 0 || sessionId === null || alias === void 0) return;
4103
+ if (!agentEnabled || kind === void 0 || sessionId === null || alias === void 0) return;
3863
4104
  const profiles = authorProfilesForDocument(sessionId, path, kind);
3864
4105
  let release;
3865
4106
  let cancelled = false;
@@ -3872,13 +4113,14 @@ function ActiveAuthorDocumentPanel(props) {
3872
4113
  release?.();
3873
4114
  };
3874
4115
  }, [
4116
+ agentEnabled,
3875
4117
  alias,
3876
4118
  kind,
3877
4119
  path,
3878
4120
  sessionId
3879
4121
  ]);
3880
4122
  if (document === void 0 || sessionId === null) return /* @__PURE__ */ jsx("p", {
3881
- className: "p-4 text-sm text-doom-dim",
4123
+ className: "p-4 text-sm text-po-dim",
3882
4124
  children: loadFailure ?? status ?? "Loading document..."
3883
4125
  });
3884
4126
  const save = async () => {
@@ -3935,11 +4177,28 @@ function ActiveAuthorDocumentPanel(props) {
3935
4177
  className: "flex min-h-0 flex-1 flex-col",
3936
4178
  children: [
3937
4179
  /* @__PURE__ */ jsxs("header", {
3938
- className: "flex items-center gap-2 border-b border-doom-border px-4 py-2",
4180
+ className: "flex items-center gap-2 border-b border-po-border bg-po-bg px-4 py-2",
3939
4181
  children: [
4182
+ /* @__PURE__ */ jsx(FileIcon, {
4183
+ "aria-hidden": "true",
4184
+ className: "size-4 shrink-0 text-po-dim"
4185
+ }),
3940
4186
  /* @__PURE__ */ jsxs("strong", {
3941
- className: "min-w-0 flex-1 truncate text-base text-doom-hi",
3942
- children: [alias === void 0 ? "" : `${alias} · `, document.title ?? document.path]
4187
+ className: "min-w-0 truncate text-base font-medium text-po-hi",
4188
+ children: [alias === void 0 ? "" : `${alias} · `, document.title ?? /* @__PURE__ */ jsx("span", {
4189
+ className: "font-mono",
4190
+ children: document.path
4191
+ })]
4192
+ }),
4193
+ /* @__PURE__ */ jsx("span", {
4194
+ className: "min-w-0 flex-1",
4195
+ children: document.version === document.savedVersion ? null : /* @__PURE__ */ jsxs("span", {
4196
+ className: "inline-flex items-center gap-1.5 text-sm text-po-dim",
4197
+ children: [/* @__PURE__ */ jsx(Dot, {
4198
+ tone: "green",
4199
+ size: "md"
4200
+ }), "unsaved"]
4201
+ })
3943
4202
  }),
3944
4203
  PreviewPanel !== void 0 && previewSource !== void 0 ? /* @__PURE__ */ jsx(Button, {
3945
4204
  size: "xs",
@@ -3951,17 +4210,21 @@ function ActiveAuthorDocumentPanel(props) {
3951
4210
  children: previewOpen ? "Source" : "Preview"
3952
4211
  }) : null,
3953
4212
  document.kind === "markdown" ? /* @__PURE__ */ jsx(Button, {
3954
- size: "xs",
3955
- variant: "ghost",
4213
+ size: "sm",
4214
+ variant: "outline",
4215
+ className: "min-h-11 [@media(pointer:fine)]:min-h-8",
3956
4216
  "data-testid": "author-markdown-toggle",
3957
4217
  onClick: () => setMarkdownPreview(!markdownPreview),
3958
- children: markdownPreview ? "edit" : "preview"
4218
+ children: /* @__PURE__ */ jsx("span", {
4219
+ className: "first-letter:uppercase",
4220
+ children: markdownPreview ? "edit" : "preview"
4221
+ })
3959
4222
  }) : null,
3960
4223
  document.kind === "video" ? /* @__PURE__ */ jsx("span", {
3961
- className: "text-base text-doom-dim",
4224
+ className: "text-base text-po-dim",
3962
4225
  children: "Video feedback"
3963
4226
  }) : /* @__PURE__ */ jsx(Button, {
3964
- className: "min-h-11 px-4 text-base",
4227
+ className: "min-h-11 px-4 text-base [@media(pointer:fine)]:min-h-8",
3965
4228
  variant: "outline",
3966
4229
  "data-testid": "author-save",
3967
4230
  disabled: document.revisions.length === 0 || document.savingVersion !== void 0,
@@ -3971,7 +4234,7 @@ function ActiveAuthorDocumentPanel(props) {
3971
4234
  ]
3972
4235
  }),
3973
4236
  status === void 0 ? null : /* @__PURE__ */ jsx("output", {
3974
- className: "px-4 py-1 text-sm text-doom-dim",
4237
+ className: "px-4 py-1 text-sm text-po-dim",
3975
4238
  children: status
3976
4239
  }),
3977
4240
  [
@@ -3981,21 +4244,28 @@ function ActiveAuthorDocumentPanel(props) {
3981
4244
  "story-preview"
3982
4245
  ].includes(document.kind) ? /* @__PURE__ */ jsx("nav", {
3983
4246
  "aria-label": "Author canvas tools",
3984
- className: "flex shrink-0 gap-1 overflow-x-auto border-b border-doom-border px-2 py-1 sm:hidden",
4247
+ className: "flex shrink-0 gap-1.5 overflow-x-auto border-b border-po-border bg-po-bg px-3 py-2 sm:hidden",
3985
4248
  children: [
3986
4249
  "select",
3987
4250
  "pan",
3988
4251
  "mark",
3989
4252
  "comment",
3990
4253
  "draw"
3991
- ].map((mode) => /* @__PURE__ */ jsx(Button, {
3992
- size: "xs",
3993
- variant: activeTool === mode ? "primary" : "outline",
3994
- className: "min-h-11 min-w-11 shrink-0",
4254
+ ].map((mode) => /* @__PURE__ */ jsxs(Button, {
4255
+ size: "md",
4256
+ variant: "outline",
4257
+ className: `min-w-16 shrink-0 ${authorToolClassName(activeTool === mode, mode !== "select" && mode !== "pan")}`,
3995
4258
  "aria-label": `${mode} tool`,
3996
4259
  "aria-pressed": activeTool === mode,
3997
4260
  onClick: () => setAuthorToolMode(sessionId, document.path, mode),
3998
- children: mode
4261
+ children: [/* @__PURE__ */ jsx("span", {
4262
+ "aria-hidden": "true",
4263
+ className: "text-lg leading-none",
4264
+ children: MOBILE_TOOL_GLYPHS[mode]
4265
+ }), /* @__PURE__ */ jsx("span", {
4266
+ className: "text-sm first-letter:uppercase",
4267
+ children: mode
4268
+ })]
3999
4269
  }, mode))
4000
4270
  }) : null,
4001
4271
  /* @__PURE__ */ jsxs("div", {
@@ -4041,7 +4311,7 @@ function ActiveAuthorDocumentPanel(props) {
4041
4311
  "video",
4042
4312
  "story-preview"
4043
4313
  ].includes(document.kind) ? /* @__PURE__ */ jsx("div", {
4044
- className: "max-h-56 shrink-0 overflow-y-auto border-t border-doom-border p-2 sm:hidden",
4314
+ className: "max-h-56 shrink-0 overflow-y-auto border-t border-po-border bg-po-bg p-3 sm:hidden",
4045
4315
  children: /* @__PURE__ */ jsx(AuthorFeedbackControls, {
4046
4316
  sessionId,
4047
4317
  document,
@@ -4070,13 +4340,13 @@ function authorFileTab(path, preferredAlias) {
4070
4340
  const normalized = normalizeAuthorPath(path);
4071
4341
  return {
4072
4342
  id: tabId(normalized),
4073
- label: preferredAlias === void 0 ? normalized.split("/").at(-1) ?? normalized : `${preferredAlias} · ${normalized.split("/").at(-1) ?? normalized}`,
4343
+ label: preferredAlias === void 0 ? authorFileName(normalized) : `${preferredAlias} · ${authorFileName(normalized)}`,
4074
4344
  retainComposer: true,
4075
4345
  composerContext(sessionId) {
4076
4346
  const key = authorDocumentKey(sessionId, normalized);
4077
4347
  const documentPath = canvasPaths.state[key] ?? normalized;
4078
4348
  const alias = canvasAliases.state[key];
4079
- const name = documentPath.split("/").at(-1) ?? documentPath;
4349
+ const name = authorFileName(documentPath);
4080
4350
  return {
4081
4351
  kind: "author-document",
4082
4352
  source: "author",
@@ -4221,6 +4491,130 @@ var Author_author_open_source_web_default = defineFill({
4221
4491
  data: authorOpenSourceAction
4222
4492
  });
4223
4493
  //#endregion
4494
+ //#region src/extensions/workspaces/sessions/(frontend)/_lib/authorImageFeedback.ts
4495
+ const MAX_IMAGE_BYTES = 20971520;
4496
+ const PNG_SIGNATURE = [
4497
+ 137,
4498
+ 80,
4499
+ 78,
4500
+ 71,
4501
+ 13,
4502
+ 10,
4503
+ 26,
4504
+ 10
4505
+ ];
4506
+ /** Recheck caller identity and bytes before adapting an immutable image to author tools. */
4507
+ async function authorImageFeedbackDocument(target, sessionId, signal) {
4508
+ if (target.sessionId !== sessionId || target.mimeType !== "image/png" || !/^[a-zA-Z0-9_-]+$/u.test(sessionId) || target.id.length === 0 || target.originalPath.length === 0 || !/^[a-f0-9]{64}$/u.test(target.sourceSha256)) throw new Error("Image feedback requires a verified artifact from the active session.");
4509
+ if (target.data.length > Math.ceil(MAX_IMAGE_BYTES / 3) * 4 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u.test(target.data)) throw new Error("Image feedback PNG exceeds the size limit or is invalid.");
4510
+ const binary = atob(target.data);
4511
+ const data = Uint8Array.from(binary, (character) => character.charCodeAt(0));
4512
+ if (data.length > MAX_IMAGE_BYTES || PNG_SIGNATURE.some((byte, index) => data[index] !== byte)) throw new Error("Image feedback requires PNG bytes.");
4513
+ signal.throwIfAborted();
4514
+ const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", data));
4515
+ const sha256 = Array.from(digest, (byte) => byte.toString(16).padStart(2, "0")).join("");
4516
+ signal.throwIfAborted();
4517
+ if (sha256 !== target.sourceSha256) throw new Error("Image feedback source digest does not match.");
4518
+ return {
4519
+ path: `image-artifact/${encodeURIComponent(target.id)}/${sha256}.png`,
4520
+ kind: "image",
4521
+ title: "Generated image feedback",
4522
+ sourceSha256: sha256,
4523
+ imageData: target.data,
4524
+ mediaUrl: `image-artifact:${sha256}`,
4525
+ imageArtifact: {
4526
+ id: target.id,
4527
+ sessionId,
4528
+ originalPath: target.originalPath,
4529
+ sourceSha256: sha256
4530
+ }
4531
+ };
4532
+ }
4533
+ //#endregion
4534
+ //#region src/extensions/workspaces/sessions/(frontend)/_components/AuthorImageFeedbackPanel.tsx
4535
+ /** Optional author controls for immutable session image artifacts. */
4536
+ function AuthorImageFeedbackPanel({ target, sessionId, submitCapture }) {
4537
+ const enabled = sessionId === target.sessionId;
4538
+ const [document, setDocument] = useState();
4539
+ const [error, setError] = useState();
4540
+ useEffect(() => {
4541
+ setDocument(void 0);
4542
+ setError(void 0);
4543
+ if (!enabled || sessionId === null) return;
4544
+ const controller = new AbortController();
4545
+ let generation;
4546
+ authorImageFeedbackDocument(target, sessionId, controller.signal).then((input) => {
4547
+ if (controller.signal.aborted) return;
4548
+ setDocument(putAuthorDocument(sessionId, input));
4549
+ generation = focusAuthorDocument(sessionId, input.path);
4550
+ }).catch((reason) => {
4551
+ if (!controller.signal.aborted) setError(reason instanceof Error ? reason.message : String(reason));
4552
+ });
4553
+ return () => {
4554
+ controller.abort();
4555
+ if (generation !== void 0) releaseAuthorDocumentFocus(sessionId, generation);
4556
+ };
4557
+ }, [
4558
+ enabled,
4559
+ sessionId,
4560
+ target
4561
+ ]);
4562
+ const drafts = useStore(authorWorkspace.store, (state) => authorDocumentAnnotations(sessionId, document?.path ?? "", state));
4563
+ const tool = useStore(authorWorkspace.store, (state) => sessionId === null ? "select" : state.sessions[sessionId]?.toolsByDocument[document?.path ?? ""] ?? "select");
4564
+ if (!enabled || sessionId === null) return null;
4565
+ if (error) return /* @__PURE__ */ jsx("output", { children: error });
4566
+ if (!document || document.imageArtifact?.id !== target.id || document.sourceSha256 !== target.sourceSha256) return /* @__PURE__ */ jsx("output", { children: "Loading image feedback…" });
4567
+ const displayedRegions = drafts.annotations.map((region, index) => ({
4568
+ ordinal: index + 1,
4569
+ region
4570
+ }));
4571
+ return /* @__PURE__ */ jsxs("section", {
4572
+ className: "flex min-h-0 flex-col gap-3",
4573
+ "data-testid": "author-image-feedback",
4574
+ children: [
4575
+ /* @__PURE__ */ jsx("p", {
4576
+ className: "text-sm text-po-dim",
4577
+ children: "Original preserved. Submit annotations to request a new refinement."
4578
+ }),
4579
+ /* @__PURE__ */ jsx("div", {
4580
+ className: "sm:hidden",
4581
+ children: /* @__PURE__ */ jsx(AuthorToolPalette, {
4582
+ sessionId,
4583
+ path: document.path,
4584
+ kind: "image",
4585
+ activeTool: tool
4586
+ })
4587
+ }),
4588
+ /* @__PURE__ */ jsx(AuthorMediaView, {
4589
+ sessionId,
4590
+ document,
4591
+ activeTool: tool,
4592
+ displayedRegions,
4593
+ pendingCandidate: drafts.candidate !== void 0
4594
+ }),
4595
+ /* @__PURE__ */ jsx("div", {
4596
+ className: "sm:hidden",
4597
+ children: /* @__PURE__ */ jsx(AuthorFeedbackControls, {
4598
+ sessionId,
4599
+ document,
4600
+ drafts,
4601
+ submitCapture
4602
+ })
4603
+ })
4604
+ ]
4605
+ });
4606
+ }
4607
+ //#endregion
4608
+ //#region src/extensions/workspaces/sessions/(frontend)/fill/ImageFeedback.author.image-feedback.web.ts
4609
+ var ImageFeedback_author_image_feedback_web_default = defineFill({
4610
+ slot: "author.image-feedback",
4611
+ id: "image-feedback",
4612
+ data: {
4613
+ version: 1,
4614
+ panel: AuthorImageFeedbackPanel
4615
+ }
4616
+ });
4617
+ //#endregion
4224
4618
  //#region src/extensions/workspaces/sessions/(frontend)/leader/author-toggle.web.ts
4225
4619
  var author_toggle_web_default = defineLeaderBinding({
4226
4620
  id: "author.toggle",
@@ -4443,12 +4837,13 @@ function recordAuthorCaptureStatus(event) {
4443
4837
  if (request === void 0 || [
4444
4838
  "COMPLETE",
4445
4839
  "FAILED",
4446
- "CANCELLED"
4840
+ "CANCELLED",
4841
+ "UNTRACKED"
4447
4842
  ].includes(request.status)) return;
4448
4843
  if (event.status === "queued") return;
4449
4844
  updateAuthorRequest(event.sessionId, request.id, (record) => ({
4450
4845
  ...record,
4451
- status: event.status === "working" ? "CHANGING" : event.status === "completed" ? "COMPLETE" : "FAILED",
4846
+ status: event.status === "working" ? "CHANGING" : event.status === "completed" ? "COMPLETE" : event.status === "untracked" ? "UNTRACKED" : "FAILED",
4452
4847
  currentOperation: event.status === "working" ? "Agent is working on this request" : void 0,
4453
4848
  pendingRegions: event.status === "completed" ? [] : record.pendingRegions,
4454
4849
  error: event.status === "error" ? event.error || "Request execution failed." : void 0,
@@ -4480,6 +4875,19 @@ var mode_web_default = defineMinorModeFile({
4480
4875
  order: 45
4481
4876
  });
4482
4877
  //#endregion
4878
+ //#region src/types/imageFeedback.ts
4879
+ function parseAuthorImageFeedbackContribution(input) {
4880
+ if (input === null || typeof input !== "object") return null;
4881
+ const value = input;
4882
+ return value.version === 1 && typeof value.panel === "function" ? value : null;
4883
+ }
4884
+ //#endregion
4885
+ //#region src/extensions/workspaces/sessions/(frontend)/slot/image-feedback.web.ts
4886
+ var image_feedback_web_default = defineSlotFile({
4887
+ slot: "author.image-feedback",
4888
+ parse: parseAuthorImageFeedbackContribution
4889
+ });
4890
+ //#endregion
4483
4891
  //#region src/extensions/workspaces/sessions/(frontend)/slot/open-source.web.ts
4484
4892
  var open_source_web_default = defineSlotFile({
4485
4893
  slot: "author.open-source",
@@ -4539,7 +4947,7 @@ function DescribeAuthorToolsToolCard({ toolName, args, result, running, isError
4539
4947
  title: toolName,
4540
4948
  children: /* @__PURE__ */ jsx("span", {
4541
4949
  "data-testid": `tool-call-${toolName}`,
4542
- className: "min-w-0 flex-1 truncate text-doom-text",
4950
+ className: "min-w-0 flex-1 truncate text-po-text",
4543
4951
  children: describeAuthorToolsCallSummary(args)
4544
4952
  })
4545
4953
  }), view.shown.length > 0 || running || isError ? /* @__PURE__ */ jsxs(MessageItemBody, {
@@ -4599,7 +5007,7 @@ function OpenAuthoringFileToolCard({ args, result, running, isError, output, ope
4599
5007
  title: "open_authoring_file",
4600
5008
  children: /* @__PURE__ */ jsx("span", {
4601
5009
  "data-testid": "tool-call-open_authoring_file",
4602
- className: "min-w-0 flex-1 truncate text-doom-text",
5010
+ className: "min-w-0 flex-1 truncate text-po-text",
4603
5011
  children: alias === void 0 ? requestedPath : `${alias} · ${requestedPath}`
4604
5012
  })
4605
5013
  }), /* @__PURE__ */ jsxs(MessageItemBody, {
@@ -4672,7 +5080,7 @@ function UseAuthorToolsToolCard({ toolName, args, result, running, isError }) {
4672
5080
  title: toolName,
4673
5081
  children: /* @__PURE__ */ jsx("span", {
4674
5082
  "data-testid": `tool-call-${toolName}`,
4675
- className: "min-w-0 flex-1 truncate text-doom-text",
5083
+ className: "min-w-0 flex-1 truncate text-po-text",
4676
5084
  children: useAuthorToolsCallSummary(args)
4677
5085
  })
4678
5086
  }), view.shown.length > 0 || running || isError ? /* @__PURE__ */ jsxs(MessageItemBody, {
@@ -4725,7 +5133,10 @@ const webPlugin = defineWebPlugin({
4725
5133
  return [via({
4726
5134
  slot: "author.open-source",
4727
5135
  id: "author"
4728
- }, Author_author_open_source_web_default)];
5136
+ }, Author_author_open_source_web_default), via({
5137
+ slot: "author.image-feedback",
5138
+ id: "image-feedback"
5139
+ }, ImageFeedback_author_image_feedback_web_default)];
4729
5140
  },
4730
5141
  get leaderBindings() {
4731
5142
  return [via({ id: "author.author-toggle" }, author_toggle_web_default)];
@@ -4735,6 +5146,7 @@ const webPlugin = defineWebPlugin({
4735
5146
  },
4736
5147
  get slots() {
4737
5148
  return [
5149
+ via({ slot: "author.image-feedback" }, image_feedback_web_default),
4738
5150
  via({ slot: "author.open-source" }, open_source_web_default),
4739
5151
  via({ slot: "author.preview-action" }, preview_action_web_default),
4740
5152
  via({ slot: "author.preview-provider" }, preview_provider_web_default)