@skillcdn/console 0.1.16 → 0.1.18

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 (143) hide show
  1. package/README.md +4 -3
  2. package/dist/api.d.ts +4 -3
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +3 -2
  5. package/dist/api.js.map +1 -1
  6. package/dist/cli/cli.d.ts +12 -0
  7. package/dist/cli/cli.d.ts.map +1 -1
  8. package/dist/cli/cli.js +226 -21
  9. package/dist/cli/cli.js.map +1 -1
  10. package/dist/cli/format.d.ts +8 -3
  11. package/dist/cli/format.d.ts.map +1 -1
  12. package/dist/cli/format.js +31 -5
  13. package/dist/cli/format.js.map +1 -1
  14. package/dist/cli/help.d.ts.map +1 -1
  15. package/dist/cli/help.js +34 -8
  16. package/dist/cli/help.js.map +1 -1
  17. package/dist/cli/install.d.ts +21 -0
  18. package/dist/cli/install.d.ts.map +1 -0
  19. package/dist/cli/install.js +87 -0
  20. package/dist/cli/install.js.map +1 -0
  21. package/dist/cli/main.js +24 -4
  22. package/dist/cli/main.js.map +1 -1
  23. package/dist/cli/notices.d.ts +13 -0
  24. package/dist/cli/notices.d.ts.map +1 -0
  25. package/dist/cli/notices.js +31 -0
  26. package/dist/cli/notices.js.map +1 -0
  27. package/dist/cli/terminal.d.ts +5 -0
  28. package/dist/cli/terminal.d.ts.map +1 -1
  29. package/dist/cli/terminal.js +11 -1
  30. package/dist/cli/terminal.js.map +1 -1
  31. package/dist/client.d.ts +43 -5
  32. package/dist/client.d.ts.map +1 -1
  33. package/dist/client.js +69 -4
  34. package/dist/client.js.map +1 -1
  35. package/dist/compat.d.ts +66 -0
  36. package/dist/compat.d.ts.map +1 -0
  37. package/dist/compat.js +115 -0
  38. package/dist/compat.js.map +1 -0
  39. package/dist/components/calendar.d.ts +3 -1
  40. package/dist/components/calendar.d.ts.map +1 -1
  41. package/dist/components/calendar.js +21 -2
  42. package/dist/components/calendar.js.map +1 -1
  43. package/dist/components/comments.d.ts +59 -0
  44. package/dist/components/comments.d.ts.map +1 -0
  45. package/dist/components/comments.js +138 -0
  46. package/dist/components/comments.js.map +1 -0
  47. package/dist/components/event-feed.d.ts.map +1 -1
  48. package/dist/components/event-feed.js +2 -0
  49. package/dist/components/event-feed.js.map +1 -1
  50. package/dist/components/goals.d.ts +3 -1
  51. package/dist/components/goals.d.ts.map +1 -1
  52. package/dist/components/goals.js +23 -11
  53. package/dist/components/goals.js.map +1 -1
  54. package/dist/components/markdown.d.ts +6 -0
  55. package/dist/components/markdown.d.ts.map +1 -1
  56. package/dist/components/markdown.js +2 -1
  57. package/dist/components/markdown.js.map +1 -1
  58. package/dist/components/projects.d.ts.map +1 -1
  59. package/dist/components/projects.js +6 -1
  60. package/dist/components/projects.js.map +1 -1
  61. package/dist/components/roadmap.d.ts +37 -0
  62. package/dist/components/roadmap.d.ts.map +1 -0
  63. package/dist/components/roadmap.js +76 -0
  64. package/dist/components/roadmap.js.map +1 -0
  65. package/dist/components/task-view.d.ts +8 -3
  66. package/dist/components/task-view.d.ts.map +1 -1
  67. package/dist/components/task-view.js +6 -4
  68. package/dist/components/task-view.js.map +1 -1
  69. package/dist/components/tokens.d.ts +2 -0
  70. package/dist/components/tokens.d.ts.map +1 -1
  71. package/dist/components/tokens.js +13 -3
  72. package/dist/components/tokens.js.map +1 -1
  73. package/dist/console.css +314 -2
  74. package/dist/console.d.ts.map +1 -1
  75. package/dist/console.js +30 -11
  76. package/dist/console.js.map +1 -1
  77. package/dist/data.d.ts +5 -1
  78. package/dist/data.d.ts.map +1 -1
  79. package/dist/data.js +3 -1
  80. package/dist/data.js.map +1 -1
  81. package/dist/i18n/en.d.ts +38 -2
  82. package/dist/i18n/en.d.ts.map +1 -1
  83. package/dist/i18n/en.js +38 -2
  84. package/dist/i18n/en.js.map +1 -1
  85. package/dist/i18n/ko.d.ts.map +1 -1
  86. package/dist/i18n/ko.js +38 -2
  87. package/dist/i18n/ko.js.map +1 -1
  88. package/dist/index.d.ts +3 -1
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +3 -1
  91. package/dist/index.js.map +1 -1
  92. package/dist/limits.d.ts +3 -0
  93. package/dist/limits.d.ts.map +1 -1
  94. package/dist/limits.js +3 -0
  95. package/dist/limits.js.map +1 -1
  96. package/dist/router.d.ts +6 -1
  97. package/dist/router.d.ts.map +1 -1
  98. package/dist/router.js +10 -1
  99. package/dist/router.js.map +1 -1
  100. package/dist/rules.js +2 -2
  101. package/dist/rules.js.map +1 -1
  102. package/dist/schemas.d.ts +147 -0
  103. package/dist/schemas.d.ts.map +1 -1
  104. package/dist/schemas.js +50 -1
  105. package/dist/schemas.js.map +1 -1
  106. package/dist/vocabulary.d.ts +1 -1
  107. package/dist/vocabulary.d.ts.map +1 -1
  108. package/dist/vocabulary.js +1 -0
  109. package/dist/vocabulary.js.map +1 -1
  110. package/docs/specs/cli.md +17 -10
  111. package/docs/specs/rest.md +17 -6
  112. package/package.json +3 -2
  113. package/skills/working-the-board/SKILL.md +8 -5
  114. package/src/api.ts +35 -0
  115. package/src/cli/cli.ts +273 -22
  116. package/src/cli/format.ts +36 -4
  117. package/src/cli/help.ts +38 -7
  118. package/src/cli/install.ts +111 -0
  119. package/src/cli/main.ts +25 -4
  120. package/src/cli/notices.ts +48 -0
  121. package/src/cli/terminal.ts +12 -1
  122. package/src/client.ts +142 -8
  123. package/src/compat.ts +173 -0
  124. package/src/components/calendar.tsx +41 -1
  125. package/src/components/comments.tsx +342 -0
  126. package/src/components/event-feed.tsx +2 -0
  127. package/src/components/goals.tsx +86 -7
  128. package/src/components/markdown.tsx +9 -1
  129. package/src/components/projects.tsx +16 -3
  130. package/src/components/roadmap.tsx +242 -0
  131. package/src/components/task-view.tsx +32 -33
  132. package/src/components/tokens.tsx +38 -1
  133. package/src/console.tsx +45 -3
  134. package/src/data.ts +9 -1
  135. package/src/i18n/en.ts +40 -2
  136. package/src/i18n/ko.ts +40 -2
  137. package/src/index.ts +20 -0
  138. package/src/limits.ts +3 -0
  139. package/src/router.ts +13 -2
  140. package/src/rules.ts +2 -2
  141. package/src/schemas.ts +60 -1
  142. package/src/styles/console.css +314 -2
  143. package/src/vocabulary.ts +1 -0
package/src/i18n/en.ts CHANGED
@@ -249,8 +249,6 @@ export const en = {
249
249
  raiseDecision: "Raise a decision",
250
250
  nothingMore: "Nothing more was written about it.",
251
251
  links: "Links",
252
- runs: "Runs",
253
- decisions: "Decisions",
254
252
  history: "What happened",
255
253
  subtasks: "Subtasks",
256
254
  partOfIt: "Part of it",
@@ -387,16 +385,33 @@ export const en = {
387
385
  inProgress: (n: number) => `${n} in progress`,
388
386
  noTasks: "No task works towards it yet.",
389
387
  tasks: "Tasks",
388
+ category: "Category",
389
+ noCategory: "No category",
390
+ starts: "Starts",
391
+ noStart: "No start day",
390
392
  target: "Target",
391
393
  noTarget: "No target day",
392
394
  setBy: "Set by",
393
395
  state: "State",
394
396
  nothingMore: "Nothing more was written about it.",
397
+ timeline: {
398
+ title: "The months",
399
+ legend: "Category colours",
400
+ earlier: "A month earlier",
401
+ later: "A month later",
402
+ thisMonth: "This month",
403
+ today: "Today",
404
+ nothing: "No goal is planned in these months.",
405
+ noDays: "No day set",
406
+ },
395
407
  form: {
396
408
  title: "Title",
397
409
  body: "What reaching it means",
398
410
  bodyPlaceholder: "What is true once the goal is reached, in Markdown.",
399
411
  state: "State",
412
+ category: "Category",
413
+ noCategory: "No category",
414
+ startsOn: "Start day",
400
415
  dueOn: "Target day",
401
416
  set: "Set the goal",
402
417
  },
@@ -538,6 +553,8 @@ export const en = {
538
553
  taskCreated: (task: string) => `wrote ${task}`,
539
554
  taskMoved: (task: string, from: string, to: string) => `moved ${task} from ${from} to ${to}`,
540
555
  taskUpdated: (fields: string, task: string) => `changed ${fields} of ${task}`,
556
+ taskCommented: (task: string, excerpt: string | undefined) =>
557
+ `commented on ${task}${excerpt === undefined || excerpt === "" ? "" : `: ${excerpt}`}`,
541
558
  decisionRaised: (question: string) => `asked: ${question}`,
542
559
  decisionAnswered: (question: string, option: string) => `answered "${question}": ${option}`,
543
560
  decisionUpdated: (fields: string, question: string) =>
@@ -571,6 +588,20 @@ export const en = {
571
588
  label: (agent: string, name: string) => `${agent} for ${name}`,
572
589
  },
573
590
 
591
+ comments: {
592
+ title: "Discussion",
593
+ empty: "Nothing was said yet.",
594
+ one: "Comment",
595
+ write: "Write a comment",
596
+ placeholder: "A word in the discussion, in Markdown.",
597
+ files: "Files",
598
+ chooseFiles: "Add files",
599
+ hint: "A picture pasted or chosen here goes with the comment; ![words](its name) places it in the text.",
600
+ removeFile: (name: string) => `Take ${name} out`,
601
+ picture: (name: string) => `The picture ${name}`,
602
+ label: (name: string) => `A comment by ${name}`,
603
+ },
604
+
574
605
  skills: {
575
606
  loading: "Loading the skills",
576
607
  list: "Skills",
@@ -720,6 +751,13 @@ export const en = {
720
751
  goodUntil: "Good until",
721
752
  notActive: "Not active yet",
722
753
  lastActive: "Last active",
754
+ command: (version: string) => `console ${version}`,
755
+ commandVerdict: {
756
+ behind: "an update is available",
757
+ ahead: "newer than this console",
758
+ outdated: "must be updated",
759
+ too_new: "too new for this console",
760
+ },
723
761
  disconnect: "Disconnect",
724
762
  form: {
725
763
  name: "Name",
package/src/i18n/ko.ts CHANGED
@@ -218,8 +218,6 @@ export const ko: Messages = {
218
218
  raiseDecision: "결정 요청",
219
219
  nothingMore: "더 적힌 내용이 없습니다.",
220
220
  links: "링크",
221
- runs: "실행",
222
- decisions: "결정",
223
221
  history: "일어난 일",
224
222
  subtasks: "하위 작업",
225
223
  partOfIt: "하위 작업",
@@ -356,16 +354,33 @@ export const ko: Messages = {
356
354
  inProgress: (n) => `${n}개 진행 중`,
357
355
  noTasks: "아직 이 목표를 향한 작업이 없습니다.",
358
356
  tasks: "작업",
357
+ category: "카테고리",
358
+ noCategory: "카테고리 없음",
359
+ starts: "시작일",
360
+ noStart: "시작일 없음",
359
361
  target: "목표일",
360
362
  noTarget: "목표일 없음",
361
363
  setBy: "세운 사람",
362
364
  state: "상태",
363
365
  nothingMore: "더 적힌 내용이 없습니다.",
366
+ timeline: {
367
+ title: "달별 로드맵",
368
+ legend: "카테고리 색",
369
+ earlier: "한 달 앞으로",
370
+ later: "한 달 뒤로",
371
+ thisMonth: "이번 달",
372
+ today: "오늘",
373
+ nothing: "이 기간에 잡힌 목표가 없습니다.",
374
+ noDays: "날짜 없음",
375
+ },
364
376
  form: {
365
377
  title: "제목",
366
378
  body: "달성의 의미",
367
379
  bodyPlaceholder: "목표를 이루면 무엇이 참이 되는지, Markdown으로.",
368
380
  state: "상태",
381
+ category: "카테고리",
382
+ noCategory: "카테고리 없음",
383
+ startsOn: "시작일",
369
384
  dueOn: "목표일",
370
385
  set: "목표 세우기",
371
386
  },
@@ -504,6 +519,8 @@ export const ko: Messages = {
504
519
  taskCreated: (task) => `${task}을(를) 썼습니다`,
505
520
  taskMoved: (task, from, to) => `${task}을(를) ${from}에서 ${to}(으)로 옮겼습니다`,
506
521
  taskUpdated: (fields, task) => `${task}의 ${fields}을(를) 바꿨습니다`,
522
+ taskCommented: (task, excerpt) =>
523
+ `${task}에 댓글을 남겼습니다${excerpt === undefined || excerpt === "" ? "" : `: ${excerpt}`}`,
507
524
  decisionRaised: (question) => `질문했습니다: ${question}`,
508
525
  decisionAnswered: (question, option) => `"${question}"에 답했습니다: ${option}`,
509
526
  decisionUpdated: (fields, question) => `결정 "${question}"의 ${fields}을(를) 썼습니다`,
@@ -536,6 +553,20 @@ export const ko: Messages = {
536
553
  label: (agent, name) => `${name}을(를) 위한 ${agent}`,
537
554
  },
538
555
 
556
+ comments: {
557
+ title: "논의",
558
+ empty: "아직 아무 말도 없습니다.",
559
+ one: "댓글 남기기",
560
+ write: "댓글 쓰기",
561
+ placeholder: "논의에 보탤 말을 마크다운으로.",
562
+ files: "파일",
563
+ chooseFiles: "파일 추가",
564
+ hint: "여기에 붙여 넣거나 고른 그림은 댓글과 함께 올라갑니다. ![설명](파일 이름)으로 본문에 넣을 수 있습니다.",
565
+ removeFile: (name) => `${name} 빼기`,
566
+ picture: (name) => `그림 ${name}`,
567
+ label: (name) => `${name}의 댓글`,
568
+ },
569
+
539
570
  skills: {
540
571
  loading: "스킬을 불러오는 중",
541
572
  list: "스킬",
@@ -684,6 +715,13 @@ export const ko: Messages = {
684
715
  goodUntil: "만료",
685
716
  notActive: "아직 활동 없음",
686
717
  lastActive: "마지막 활동",
718
+ command: (version) => `console ${version}`,
719
+ commandVerdict: {
720
+ behind: "업데이트할 수 있음",
721
+ ahead: "이 콘솔보다 새 버전",
722
+ outdated: "업데이트 필요",
723
+ too_new: "이 콘솔에는 너무 새 버전",
724
+ },
687
725
  disconnect: "연결 끊기",
688
726
  form: {
689
727
  name: "이름",
package/src/index.ts CHANGED
@@ -26,6 +26,18 @@ export {
26
26
  workloadOf,
27
27
  } from "./components/calendar.js";
28
28
  export { CategoryList, type CategoryListProps } from "./components/categories.js";
29
+ export {
30
+ CommentCard,
31
+ type CommentCardProps,
32
+ type CommentDraft,
33
+ CommentForm,
34
+ type CommentFormProps,
35
+ isPicture,
36
+ TaskThread,
37
+ type TaskThreadProps,
38
+ type ThreadItem,
39
+ threadOf,
40
+ } from "./components/comments.js";
29
41
  export {
30
42
  ConnectApproval,
31
43
  type ConnectApprovalProps,
@@ -88,6 +100,13 @@ export {
88
100
  ProjectRoleBadge,
89
101
  VISIBILITY_LABELS,
90
102
  } from "./components/projects.js";
103
+ export {
104
+ DEFAULT_TIMELINE_MONTHS,
105
+ GoalTimeline,
106
+ type GoalTimelineProps,
107
+ type TimelineBar,
108
+ timelineBars,
109
+ } from "./components/roadmap.js";
91
110
  export {
92
111
  RulesForm,
93
112
  type RulesFormProps,
@@ -218,6 +237,7 @@ export {
218
237
  projectHref,
219
238
  projectSettingsHref,
220
239
  type Route,
240
+ roadmapHref,
221
241
  settingsHref,
222
242
  signInFailureOf,
223
243
  type TaskFormKind,
package/src/limits.ts CHANGED
@@ -28,6 +28,9 @@ export const MAX_SUMMARY_LENGTH = 2000;
28
28
  /** How many reports, and how many artifacts, one run may carry. */
29
29
  export const MAX_REPORTS_PER_RUN = 500;
30
30
  export const MAX_ARTIFACTS_PER_RUN = 50;
31
+ /** How many comments one task carries, and how many files one comment carries, together within `MAX_FILE_BYTES`. */
32
+ export const MAX_COMMENTS_PER_TASK = 500;
33
+ export const MAX_FILES_PER_COMMENT = 10;
31
34
  /** A file a run hands in: how many bytes, and its name, one line without a path. */
32
35
  export const MAX_FILE_BYTES = 10 * 1024 * 1024;
33
36
  export const MAX_FILE_NAME_LENGTH = 200;
package/src/router.ts CHANGED
@@ -59,7 +59,8 @@ export type Route =
59
59
  readonly month: string | undefined;
60
60
  readonly filter: BoardFilter;
61
61
  }
62
- | { readonly name: "roadmap"; readonly project: string }
62
+ /** The roadmap of a project: the months shown from the one named, or from this one. */
63
+ | { readonly name: "roadmap"; readonly project: string; readonly from: string | undefined }
63
64
  | { readonly name: "new-goal"; readonly project: string }
64
65
  | {
65
66
  readonly name: "goal";
@@ -345,7 +346,11 @@ export function matchRoute(pathname: string, search = ""): Route {
345
346
  return { name: "calendar", project, month: month ?? undefined, filter: boardFilterOf(params) };
346
347
  }
347
348
  if (page === "roadmap") {
348
- return { name: "roadmap", project };
349
+ const from = params.get("from");
350
+ if (from !== null && !isMonth(from)) {
351
+ return NOT_FOUND;
352
+ }
353
+ return { name: "roadmap", project, from: from ?? undefined };
349
354
  }
350
355
  if (page === "settings") {
351
356
  return {
@@ -455,6 +460,12 @@ export function customPageHref(page: string, project?: string): string {
455
460
  }
456
461
 
457
462
  /** Where a goal is set: the form. */
463
+ /** Where a project's roadmap is, from a month on, or from this one when none is named. */
464
+ export function roadmapHref(key: string, from?: string): string {
465
+ const base = projectHref(key, "roadmap");
466
+ return from === undefined ? base : `${base}?from=${from}`;
467
+ }
468
+
458
469
  export function newGoalHref(key: string): string {
459
470
  return `${PATHS.project}/${key}/roadmap/new`;
460
471
  }
package/src/rules.ts CHANGED
@@ -23,7 +23,7 @@ export const REFERENCE_RULES = [
23
23
  "",
24
24
  "## Start here, every time",
25
25
  "",
26
- "1. These rules come with the task: `console take` prints them under it, and `console rules` reads them any time. Read them before anything is made. The task says where the work is and what it links to; `console task <number>` shows a task in full, with its plan, its decisions and the runs on it, without taking it. How the board is worked is the skill working-the-board, shipped with the command (`console skills` says where it is); these rules say what this organization asks, not how the command works.",
26
+ "1. These rules come with the task: `console take` prints them under it, and `console rules` reads them any time. Read them before anything is made. The task says where the work is and what it links to; `console task <number>` shows a task in full, with its plan, its decisions, the runs on it and the discussion on it, without taking it. How the board is worked is the skill working-the-board, shipped with the command (`console skills` says where it is); these rules say what this organization asks, not how the command works.",
27
27
  "2. Act as the person whose token the command holds, and no further. What they may not do, the console refuses; that step goes back to them in a report, never around them.",
28
28
  "",
29
29
  "## The organization's skills",
@@ -44,7 +44,7 @@ export const REFERENCE_RULES = [
44
44
  "",
45
45
  "## Reports",
46
46
  "",
47
- "Report at the milestones, not every step: what was found, what was done, what is next, in words for people; a problem as a problem, with what it blocks. What people read on the board, the reports, the questions and their options, the tasks and the pages, is written in {language}. A task's title says what is to be done, in plain words that stand on their own; what it refers to, a milestone, a commit, a page, goes in the body, linked where it can be. The result goes in a last report or is handed in as a link or a file, with the check that ran and its result; a check that did not run is said to be not run.",
47
+ "Report at the milestones, not every step: what was found, what was done, what is next, in words for people; a problem as a problem, with what it blocks. What people read on the board, the reports, the questions and their options, the tasks and the pages, is written in {language}. A task's title says what is to be done, in plain words that stand on their own; what it refers to, a milestone, a commit, a page, goes in the body, linked where it can be. The result goes in a last report or is handed in as a link or a file, with the check that ran and its result; a check that did not run is said to be not run. A report is the run's record; a word to the task's people, an answer to what they asked in its comments, a question that is not a decision, a remark, is a comment on the task (`console comment`), and what they put in a comment is read with `console file`.",
48
48
  "",
49
49
  "## What never happens",
50
50
  "",
package/src/schemas.ts CHANGED
@@ -196,6 +196,13 @@ export const restMeSchema = z.object({
196
196
  /** The language the person chose for the pages (ADR-0012), or `null` for the browser's. */
197
197
  language: z.nullable(languageTag),
198
198
  signIn: z.array(restProviderSchema),
199
+ /**
200
+ * The console's version and the range of command versions it takes, as npm spells one
201
+ * (ADR-0025): what a console of a person's own compares the package it was built on with.
202
+ * Every console answers it from 0.1.18; read as optional, so that a command or a console
203
+ * built on this package still reads an older console's answer, and says it is older.
204
+ */
205
+ console: z.optional(z.object({ version: z.string(), clientRange: z.string() })),
199
206
  });
200
207
  export type RestMe = z.infer<typeof restMeSchema>;
201
208
 
@@ -485,6 +492,12 @@ export const restGoalSchema = z.object({
485
492
  /** Markdown: what reaching the goal means. Shown as text or rendered to elements, never as HTML. */
486
493
  body: z.string(),
487
494
  state: z.enum(GOAL_STATES),
495
+ /** The category the goal is sorted into, as the workspace keeps it, or `null` (ADR-0026). */
496
+ category: z.nullable(
497
+ z.object({ key: z.string(), name: z.string(), color: z.enum(CATEGORY_COLORS) }),
498
+ ),
499
+ /** The plan (ADR-0026): the day the work towards the goal is meant to begin, or `null`. */
500
+ startsOn: z.nullable(day),
488
501
  /** The day the goal is meant to be reached by, or `null`. */
489
502
  dueOn: z.nullable(day),
490
503
  createdBy: restPersonSchema,
@@ -505,6 +518,9 @@ export const restGoalInputSchema = z.object({
505
518
  body: z.optional(body),
506
519
  /** Left out: `planned`. */
507
520
  state: z.optional(z.enum(GOAL_STATES)),
521
+ /** The key of a category of the workspace, or `null` for none. */
522
+ category: z.optional(z.nullable(categoryKey)),
523
+ startsOn: z.optional(z.nullable(day)),
508
524
  dueOn: z.optional(z.nullable(day)),
509
525
  });
510
526
  export type RestGoalInput = z.infer<typeof restGoalInputSchema>;
@@ -514,6 +530,8 @@ export const restGoalPatchSchema = z.object({
514
530
  title: z.optional(line(MAX_TITLE_LENGTH)),
515
531
  body: z.optional(body),
516
532
  state: z.optional(z.enum(GOAL_STATES)),
533
+ category: z.optional(z.nullable(categoryKey)),
534
+ startsOn: z.optional(z.nullable(day)),
517
535
  dueOn: z.optional(z.nullable(day)),
518
536
  });
519
537
  export type RestGoalPatch = z.infer<typeof restGoalPatchSchema>;
@@ -647,8 +665,10 @@ export const restEventDataSchema = z.object({
647
665
  status: z.optional(z.enum(RUN_STATUSES)),
648
666
  /** For `run.handed_in`: what the artifact is called. */
649
667
  label: z.optional(z.string()),
650
- /** For `run.reported`: the first words of the report. */
668
+ /** For `run.reported` and `task.commented`: the first words of what was written. */
651
669
  excerpt: z.optional(z.string()),
670
+ /** For `task.commented`: how many files came with it. */
671
+ files: z.optional(z.int()),
652
672
  });
653
673
  export type RestEventData = z.infer<typeof restEventDataSchema>;
654
674
 
@@ -740,6 +760,34 @@ export type RestRun = z.infer<typeof restRunSchema>;
740
760
  export const restRunsSchema = z.object({ items: z.array(restRunSchema), more: z.boolean() });
741
761
  export type RestRuns = z.infer<typeof restRunsSchema>;
742
762
 
763
+ /** A file put in a comment, kept as a run's file is; its bytes are at `projectPath(key, "files", <id>)`. */
764
+ export const restCommentFileSchema = z.object({
765
+ id: uuid,
766
+ file: restFileSchema,
767
+ });
768
+ export type RestCommentFile = z.infer<typeof restCommentFileSchema>;
769
+
770
+ /**
771
+ * A word in the discussion on a task (ADR-0024): by a person, or by their agent, with the
772
+ * files put in it. Never rewritten: a mistake is corrected in the next one.
773
+ */
774
+ export const restCommentSchema = z.object({
775
+ id: uuid,
776
+ taskId: uuid,
777
+ author: restPersonSchema,
778
+ /** The agent the author wrote through, or `null` when a person wrote it themselves. */
779
+ agent: z.nullable(z.string()),
780
+ /** Markdown. A picture among the files is placed in it as `![words](its name)`. */
781
+ body: z.string(),
782
+ files: z.array(restCommentFileSchema),
783
+ createdAt: instant,
784
+ });
785
+ export type RestComment = z.infer<typeof restCommentSchema>;
786
+
787
+ /** `GET .../tasks/<id>/comments`: the discussion on a task, oldest first, whole. */
788
+ export const restCommentsSchema = z.object({ items: z.array(restCommentSchema) });
789
+ export type RestComments = z.infer<typeof restCommentsSchema>;
790
+
743
791
  /** `GET .../events?after=`: what happened after that number, oldest first. */
744
792
  export const restEventsSchema = z.object({
745
793
  items: z.array(restEventSchema),
@@ -761,6 +809,8 @@ export const restTokenSchema = z.object({
761
809
  expiresAt: z.nullable(instant),
762
810
  /** When it was last presented, or `null` if never. */
763
811
  lastUsedAt: z.nullable(instant),
812
+ /** The version of the command that last presented it (`0.1.18`), or `null` when the last to present it named none. */
813
+ client: z.nullable(z.string()),
764
814
  });
765
815
  export type RestToken = z.infer<typeof restTokenSchema>;
766
816
 
@@ -1032,6 +1082,15 @@ export const restReportInputSchema = z.object({
1032
1082
  });
1033
1083
  export type RestReportInput = z.infer<typeof restReportInputSchema>;
1034
1084
 
1085
+ /**
1086
+ * What `POST .../tasks/<id>/comments` is sent as JSON: the word, in Markdown. As a form, the
1087
+ * part `body` says the same and the parts `file` carry the files; then the body may be blank.
1088
+ */
1089
+ export const restCommentInputSchema = z.object({
1090
+ body,
1091
+ });
1092
+ export type RestCommentInput = z.infer<typeof restCommentInputSchema>;
1093
+
1035
1094
  /** What `POST .../runs/<id>/artifacts` is sent: a link to what was made. */
1036
1095
  export const restArtifactInputSchema = z.object({
1037
1096
  url,