@skillcdn/console 0.1.12 → 0.1.14

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 (72) hide show
  1. package/README.md +6 -4
  2. package/dist/cli/cli.d.ts.map +1 -1
  3. package/dist/cli/cli.js +260 -6
  4. package/dist/cli/cli.js.map +1 -1
  5. package/dist/cli/format.d.ts +7 -1
  6. package/dist/cli/format.d.ts.map +1 -1
  7. package/dist/cli/format.js +22 -0
  8. package/dist/cli/format.js.map +1 -1
  9. package/dist/cli/help.d.ts.map +1 -1
  10. package/dist/cli/help.js +69 -2
  11. package/dist/cli/help.js.map +1 -1
  12. package/dist/components/calendar.d.ts +15 -0
  13. package/dist/components/calendar.d.ts.map +1 -1
  14. package/dist/components/calendar.js +57 -30
  15. package/dist/components/calendar.js.map +1 -1
  16. package/dist/components/decision-list.d.ts.map +1 -1
  17. package/dist/components/decision-list.js +1 -1
  18. package/dist/components/decision-list.js.map +1 -1
  19. package/dist/components/skills.d.ts.map +1 -1
  20. package/dist/components/skills.js +1 -1
  21. package/dist/components/skills.js.map +1 -1
  22. package/dist/components/work.d.ts +4 -0
  23. package/dist/components/work.d.ts.map +1 -1
  24. package/dist/components/work.js +8 -3
  25. package/dist/components/work.js.map +1 -1
  26. package/dist/connect-page.d.ts.map +1 -1
  27. package/dist/connect-page.js +1 -1
  28. package/dist/connect-page.js.map +1 -1
  29. package/dist/console.css +35 -1
  30. package/dist/console.d.ts +3 -2
  31. package/dist/console.d.ts.map +1 -1
  32. package/dist/console.js +24 -58
  33. package/dist/console.js.map +1 -1
  34. package/dist/dates.d.ts +4 -0
  35. package/dist/dates.d.ts.map +1 -1
  36. package/dist/dates.js +26 -0
  37. package/dist/dates.js.map +1 -1
  38. package/dist/i18n/en.d.ts +7 -19
  39. package/dist/i18n/en.d.ts.map +1 -1
  40. package/dist/i18n/en.js +10 -22
  41. package/dist/i18n/en.js.map +1 -1
  42. package/dist/i18n/ko.d.ts.map +1 -1
  43. package/dist/i18n/ko.js +10 -22
  44. package/dist/i18n/ko.js.map +1 -1
  45. package/dist/index.d.ts +3 -3
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +3 -3
  48. package/dist/index.js.map +1 -1
  49. package/dist/router.d.ts +4 -0
  50. package/dist/router.d.ts.map +1 -1
  51. package/dist/router.js +10 -2
  52. package/dist/router.js.map +1 -1
  53. package/docs/specs/cli.md +15 -2
  54. package/docs/specs/rest.md +13 -13
  55. package/package.json +1 -1
  56. package/skills/building-a-console/SKILL.md +2 -2
  57. package/skills/working-the-board/SKILL.md +5 -1
  58. package/src/cli/cli.ts +333 -5
  59. package/src/cli/format.ts +27 -0
  60. package/src/cli/help.ts +86 -1
  61. package/src/components/calendar.tsx +219 -91
  62. package/src/components/decision-list.tsx +0 -1
  63. package/src/components/skills.tsx +0 -1
  64. package/src/components/work.tsx +66 -46
  65. package/src/connect-page.tsx +0 -1
  66. package/src/console.tsx +22 -74
  67. package/src/dates.ts +28 -0
  68. package/src/i18n/en.ts +10 -28
  69. package/src/i18n/ko.ts +10 -28
  70. package/src/index.ts +5 -0
  71. package/src/router.ts +15 -5
  72. package/src/styles/console.css +35 -1
package/src/console.tsx CHANGED
@@ -91,6 +91,7 @@ import {
91
91
  signInFailureOf,
92
92
  taskHref,
93
93
  withoutSignInParam,
94
+ workHref,
94
95
  } from "./router.js";
95
96
  import { projectPath } from "./routes.js";
96
97
  import { errorWords, useAction } from "./use-action.js";
@@ -332,13 +333,12 @@ function holdsToken(data: ConsoleData): boolean {
332
333
  }
333
334
 
334
335
  /**
335
- * The pages a console that holds a token does not offer: the tokens themselves and
336
- * configuring, which are a person's own doing on the console's own pages, signed in.
336
+ * The pages a console that holds a token does not offer: the tokens themselves, and the
337
+ * approval of an agent's connection, which makes one; a person's own doing on the console's
338
+ * own pages, signed in. Everything else a person may do, their agent may (ADR-0021).
337
339
  */
338
340
  export function onlyOnOwnPages(route: Route): boolean {
339
341
  return (
340
- route.name === "new-project" ||
341
- route.name === "settings" ||
342
342
  route.name === "agents" ||
343
343
  route.name === "new-token" ||
344
344
  route.name === "person-agents" ||
@@ -351,28 +351,6 @@ function NotWithToken() {
351
351
  return <EmptyState title={words.title} body={words.body} />;
352
352
  }
353
353
 
354
- /**
355
- * Where a console that holds a token keeps the person's choice of language: the browser's own
356
- * storage, which may be absent or refuse, and then the browser's languages decide.
357
- */
358
- const LANGUAGE_KEY = "sc-language";
359
-
360
- function storedLanguage(): string | undefined {
361
- try {
362
- return globalThis.localStorage?.getItem(LANGUAGE_KEY) ?? undefined;
363
- } catch {
364
- return undefined;
365
- }
366
- }
367
-
368
- function storeLanguage(tag: string): void {
369
- try {
370
- globalThis.localStorage?.setItem(LANGUAGE_KEY, tag);
371
- } catch {
372
- // A browser that keeps nothing: the choice holds for this page.
373
- }
374
- }
375
-
376
354
  /** A link that reads as a button: where a form is, for instance. */
377
355
  function LinkButton(props: {
378
356
  readonly href: string;
@@ -397,18 +375,16 @@ function ProjectsPage(props: {
397
375
  const { data, components, navigation, making } = props;
398
376
  const { busy, error, act } = useAction();
399
377
  const href = (project: RestProject) => projectHref(project.key);
400
- const configures = !holdsToken(data);
401
378
  return (
402
379
  <>
403
380
  <div className="sc-page-head">
404
381
  <h1 className="sc-page-title">{words.title}</h1>
405
- {!making && configures && (
382
+ {!making && (
406
383
  <LinkButton href={PATHS.newProject} variant="primary">
407
384
  {words.newProject}
408
385
  </LinkButton>
409
386
  )}
410
387
  </div>
411
- <p className="sc-lead">{words.lead}</p>
412
388
  {error !== undefined && <Callout tone="danger">{error}</Callout>}
413
389
  {making && (
414
390
  <section className="sc-panel sc-panel-form" aria-label={words.form.aria}>
@@ -435,11 +411,7 @@ function ProjectsPage(props: {
435
411
  <EmptyState
436
412
  title={words.empty.title}
437
413
  body={words.empty.body}
438
- action={
439
- configures ? (
440
- <LinkButton href={PATHS.newProject}>{words.newProject}</LinkButton>
441
- ) : undefined
442
- }
414
+ action={<LinkButton href={PATHS.newProject}>{words.newProject}</LinkButton>}
443
415
  />
444
416
  }
445
417
  />
@@ -668,7 +640,6 @@ function ProjectPage(props: {
668
640
  {words.board.writeTask}
669
641
  </LinkButton>
670
642
  </div>
671
- <p className="sc-lead">{calendar.lead}</p>
672
643
  {data.tasks.length > 0 && (
673
644
  <BoardFilters
674
645
  filter={route.filter}
@@ -718,7 +689,6 @@ function ProjectPage(props: {
718
689
  {open.length > 0 && (
719
690
  <section className="sc-task-section" aria-label={calendar.workload.title}>
720
691
  <h2 className="sc-section-title">{calendar.workload.title}</h2>
721
- <p className="sc-lead">{calendar.workload.lead}</p>
722
692
  <Workload
723
693
  tasks={shown}
724
694
  today={now}
@@ -747,7 +717,6 @@ function ProjectPage(props: {
747
717
  </LinkButton>
748
718
  )}
749
719
  </div>
750
- <p className="sc-lead">{roadmap.lead}</p>
751
720
  {error !== undefined && <Callout tone="danger">{error}</Callout>}
752
721
  {making && (
753
722
  <section className="sc-panel sc-panel-form" aria-label={roadmap.setGoalAria}>
@@ -966,17 +935,14 @@ function ProjectPage(props: {
966
935
  }
967
936
  if (route.name === "members") {
968
937
  const me = data.me?.person ?? undefined;
969
- const configures = owner && !holdsToken(data);
938
+ const configures = owner;
970
939
  const members = words.projects.members;
971
940
  return (
972
941
  <>
973
942
  <div className="sc-page-head">
974
943
  <h1 className="sc-page-title">{members.title}</h1>
975
944
  </div>
976
- <p className="sc-lead">
977
- {project.visibility === "workspace" ? members.leadWorkspace : members.leadPrivate}{" "}
978
- {members.leadRoles}
979
- </p>
945
+ <p className="sc-lead">{words.vocabulary.visibility[project.visibility]}</p>
980
946
  {error !== undefined && <Callout tone="danger">{error}</Callout>}
981
947
  <components.MemberList
982
948
  members={data.members}
@@ -1017,11 +983,6 @@ function ProjectPage(props: {
1017
983
  <div className="sc-page-head">
1018
984
  <h1 className="sc-page-title">{settings.title}</h1>
1019
985
  </div>
1020
- <p className="sc-lead">
1021
- {settings.leadBefore}
1022
- <code>{project.key}</code>
1023
- {settings.leadAfter}
1024
- </p>
1025
986
  {error !== undefined && <Callout tone="danger">{error}</Callout>}
1026
987
  <section className="sc-panel sc-panel-form" aria-label={settings.aria}>
1027
988
  <ProjectForm
@@ -1110,9 +1071,6 @@ function PersonAgentsPage(props: {
1110
1071
  </h1>
1111
1072
  <LinkButton href={PATHS.people}>{words.nav.people}</LinkButton>
1112
1073
  </div>
1113
- <p className="sc-lead">
1114
- {words.people.agentsLead(person?.name ?? person?.login ?? words.feed.someone)}
1115
- </p>
1116
1074
  {error !== undefined && <Callout tone="danger">{error}</Callout>}
1117
1075
  {tokens === undefined ? (
1118
1076
  <div className="sc-loading">
@@ -1136,7 +1094,12 @@ function PersonAgentsPage(props: {
1136
1094
  }
1137
1095
 
1138
1096
  /** What is on the person's plate, across their projects: read when the page is opened. */
1139
- function WorkPage(props: { readonly data: ConsoleData; readonly components: ConsoleComponents }) {
1097
+ function WorkPage(props: {
1098
+ readonly data: ConsoleData;
1099
+ readonly components: ConsoleComponents;
1100
+ /** A day of the week shown at the top, from the address; today's week when it names none. */
1101
+ readonly week: string | undefined;
1102
+ }) {
1140
1103
  const words = useWords();
1141
1104
  const { data, components } = props;
1142
1105
  const [work, setWork] = useState<RestWork | undefined>(undefined);
@@ -1163,7 +1126,6 @@ function WorkPage(props: { readonly data: ConsoleData; readonly components: Cons
1163
1126
  <div className="sc-page-head">
1164
1127
  <h1 className="sc-page-title">{words.work.title}</h1>
1165
1128
  </div>
1166
- <p className="sc-lead">{words.work.lead}</p>
1167
1129
  {problem !== undefined && <Callout tone="danger">{problem}</Callout>}
1168
1130
  {work === undefined ? (
1169
1131
  problem === undefined && (
@@ -1176,8 +1138,10 @@ function WorkPage(props: { readonly data: ConsoleData; readonly components: Cons
1176
1138
  ) : (
1177
1139
  <components.WorkList
1178
1140
  work={work}
1141
+ week={props.week}
1179
1142
  taskHref={(projectKey, task) => taskHref(projectKey, task.number)}
1180
1143
  decisionHref={(projectKey, decisionId) => decisionHref(projectKey, decisionId)}
1144
+ weekHref={workHref}
1181
1145
  />
1182
1146
  )}
1183
1147
  </>
@@ -1196,20 +1160,17 @@ function WorkspacePage(props: {
1196
1160
  const { busy, error, act } = useAction();
1197
1161
 
1198
1162
  if (route.name === "work") {
1199
- return <WorkPage data={data} components={components} />;
1163
+ return <WorkPage data={data} components={components} week={route.week} />;
1200
1164
  }
1201
1165
  if (route.name === "categories") {
1202
1166
  const me = data.me?.person ?? undefined;
1203
- const administrator = me?.role === "admin" && !holdsToken(data);
1167
+ const administrator = me?.role === "admin";
1204
1168
  const categories = words.categories;
1205
1169
  return (
1206
1170
  <>
1207
1171
  <div className="sc-page-head">
1208
1172
  <h1 className="sc-page-title">{categories.title}</h1>
1209
1173
  </div>
1210
- <p className="sc-lead">
1211
- {categories.lead} {categories.onlyAdmin}
1212
- </p>
1213
1174
  {error !== undefined && <Callout tone="danger">{error}</Callout>}
1214
1175
  <components.CategoryList
1215
1176
  categories={data.categories}
@@ -1232,20 +1193,18 @@ function WorkspacePage(props: {
1232
1193
  }
1233
1194
  empty={<EmptyState title={categories.empty.title} body={categories.empty.body} />}
1234
1195
  />
1235
- {administrator && <p className="sc-muted">{categories.inUse}</p>}
1236
1196
  </>
1237
1197
  );
1238
1198
  }
1239
1199
 
1240
1200
  if (route.name === "people") {
1241
1201
  const me = data.me?.person ?? undefined;
1242
- const administrator = me?.role === "admin" && !holdsToken(data);
1202
+ const administrator = me?.role === "admin";
1243
1203
  return (
1244
1204
  <>
1245
1205
  <div className="sc-page-head">
1246
1206
  <h1 className="sc-page-title">{words.people.title}</h1>
1247
1207
  </div>
1248
- <p className="sc-lead">{words.people.lead}</p>
1249
1208
  {error !== undefined && <Callout tone="danger">{error}</Callout>}
1250
1209
  <components.PeopleList
1251
1210
  people={data.people}
@@ -1281,7 +1240,6 @@ function WorkspacePage(props: {
1281
1240
  </LinkButton>
1282
1241
  )}
1283
1242
  </div>
1284
- <p className="sc-lead">{agents.lead}</p>
1285
1243
  {error !== undefined && <Callout tone="danger">{error}</Callout>}
1286
1244
  {fresh !== undefined && (
1287
1245
  <NewToken token={fresh.token} secret={fresh.secret} onDone={() => setFresh(undefined)} />
@@ -1334,10 +1292,7 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
1334
1292
  const title = data.me?.workspace.name ?? fallbackTitle;
1335
1293
  const viaToken = holdsToken(data);
1336
1294
  // The language: the person's choice, else the browser's, else the first the console speaks.
1337
- // A console that holds a token cannot keep the choice on the person, and keeps it in the
1338
- // browser instead.
1339
- const [ownChoice, setOwnChoice] = useState<string | undefined>(storedLanguage);
1340
- const chosen = viaToken ? (ownChoice ?? data.me?.language) : data.me?.language;
1295
+ const chosen = data.me?.language;
1341
1296
  const pack = useMemo(
1342
1297
  () =>
1343
1298
  chooseLanguage(
@@ -1485,7 +1440,7 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
1485
1440
  label: words.nav.members,
1486
1441
  current: route.name === "members",
1487
1442
  },
1488
- ...(project?.role === "owner" && !viaToken
1443
+ ...(project?.role === "owner"
1489
1444
  ? [
1490
1445
  {
1491
1446
  href: projectHref(projectKey, "settings"),
@@ -1591,14 +1546,7 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
1591
1546
  label: candidate.label,
1592
1547
  current: candidate.tag === pack.tag,
1593
1548
  }))}
1594
- onLanguage={(tag) => {
1595
- if (viaToken) {
1596
- storeLanguage(tag);
1597
- setOwnChoice(tag);
1598
- } else {
1599
- void data.actions.updateMe({ language: tag }).catch(() => undefined);
1600
- }
1601
- }}
1549
+ onLanguage={(tag) => void data.actions.updateMe({ language: tag }).catch(() => undefined)}
1602
1550
  person={data.me.person}
1603
1551
  live={projectKey === undefined ? undefined : data.live}
1604
1552
  wide={
package/src/dates.ts CHANGED
@@ -113,6 +113,17 @@ export function weekdays(firstDay = 1): number[] {
113
113
  return Array.from({ length: 7 }, (_, index) => ((firstDay - 1 + index) % 7) + 1);
114
114
  }
115
115
 
116
+ /** The seven days of the week `day` is in, from the day the week begins on (1 for Monday, 7 for Sunday). */
117
+ export function weekOf(day: string, firstDay = 1): string[] {
118
+ const date = dateOf(day);
119
+ if (Number.isNaN(date.getTime())) {
120
+ return [];
121
+ }
122
+ const weekday = date.getDay() === 0 ? 7 : date.getDay();
123
+ const first = addDays(day, -((weekday - firstDay + 7) % 7));
124
+ return Array.from({ length: 7 }, (_, index) => addDays(first, index));
125
+ }
126
+
116
127
  /** A day as people read one in a language: the month and the day, with the year when it is not this year's. */
117
128
  export function formatDay(day: string, language?: string, now: Date = new Date()): string {
118
129
  const date = dateOf(day);
@@ -126,6 +137,23 @@ export function formatDay(day: string, language?: string, now: Date = new Date()
126
137
  });
127
138
  }
128
139
 
140
+ /** A stretch of days as people read one: from a day to a day, with the year. */
141
+ export function formatDays(from: string, to: string, language?: string): string {
142
+ const start = dateOf(from);
143
+ const end = dateOf(to);
144
+ if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) {
145
+ return `${from} - ${to}`;
146
+ }
147
+ const format = new Intl.DateTimeFormat(language, {
148
+ month: "short",
149
+ day: "numeric",
150
+ year: "numeric",
151
+ });
152
+ return typeof format.formatRange === "function"
153
+ ? format.formatRange(start, end)
154
+ : `${format.format(start)} - ${format.format(end)}`;
155
+ }
156
+
129
157
  /** A month as people read one: the month and the year. */
130
158
  export function formatMonth(month: string, language?: string): string {
131
159
  const date = dateOf(`${month}-01`);
package/src/i18n/en.ts CHANGED
@@ -89,7 +89,7 @@ export const en = {
89
89
  },
90
90
  notWithToken: {
91
91
  title: "Done on the console's own pages",
92
- body: "This console holds a token, which acts as you on the board. Connecting agents, configuring projects and people, and keeping a language are done on the organization's console, signed in.",
92
+ body: "This console holds a token, which acts as you on the board, configuring included. Agents are connected, and tokens made and removed, on the organization's console, signed in.",
93
93
  },
94
94
  you: "(you)",
95
95
  nobody: "Nobody",
@@ -143,7 +143,6 @@ export const en = {
143
143
  projects: {
144
144
  title: "Projects",
145
145
  newProject: "New project",
146
- lead: "A project holds its board, its documents, its skills and its people. What you may see and change is decided per project: an owner configures it, a member works on it.",
147
146
  empty: {
148
147
  title: "No projects yet",
149
148
  body: "Make the first one: what it is for, and who is in it. Or ask an owner to add you to theirs.",
@@ -172,11 +171,6 @@ export const en = {
172
171
  members: {
173
172
  title: "Members",
174
173
  list: "Members",
175
- leadWorkspace:
176
- "Everyone of the workspace is a member of this project; those listed here are its owners and the people named besides.",
177
- leadPrivate: "Only those listed here are in this project.",
178
- leadRoles:
179
- "An owner configures the project; a member works on it. A workspace administrator is an owner of every project.",
180
174
  since: "since",
181
175
  roleOf: (name: string) => `Role of ${name}`,
182
176
  addAria: "Add a member",
@@ -193,9 +187,6 @@ export const en = {
193
187
  settings: {
194
188
  title: "Settings",
195
189
  aria: "Project settings",
196
- leadBefore: "The key, ",
197
- leadAfter:
198
- ", is what addresses and the command say, and does not change. The skills address names a repository served by SkillCDN; empty, the organization's skills are shown.",
199
190
  onlyOwner: {
200
191
  title: "Only an owner may change the project",
201
192
  body: "Ask one of its owners, or a workspace administrator.",
@@ -305,8 +296,6 @@ export const en = {
305
296
  waiting: "Waiting",
306
297
  answered: "Answered",
307
298
  record: "The record",
308
- recordLead:
309
- "Every decision answered, newest first: what was asked, what was chosen, by whom. Open one for its context, its rationale and what followed.",
310
299
  openRecord: "Open",
311
300
  waitingForPerson: "Waiting for a person.",
312
301
  options: "Options",
@@ -337,7 +326,6 @@ export const en = {
337
326
 
338
327
  calendar: {
339
328
  title: "Calendar",
340
- lead: "The tasks on their days: planned from a start to a due day, a task lies across them; due on a day alone, it sits on it. One with no day waits at the bottom to be given one.",
341
329
  grid: "The month",
342
330
  legend: { title: "Category colours" },
343
331
  startsOnly: "Starts that day, with no due day yet",
@@ -349,9 +337,15 @@ export const en = {
349
337
  nothingOverdue: "Nothing is overdue.",
350
338
  unscheduled: "No day set",
351
339
  allScheduled: "Every open task has a day.",
340
+ week: {
341
+ title: "The week",
342
+ previous: "The week before",
343
+ next: "The week after",
344
+ thisWeek: "This week",
345
+ nothing: "Nothing is planned this week.",
346
+ },
352
347
  workload: {
353
348
  title: "Who has what",
354
- lead: "The open tasks of each person, and what of them is late or due within the week.",
355
349
  person: "Person",
356
350
  open: "Open",
357
351
  inProgress: "In progress",
@@ -363,7 +357,6 @@ export const en = {
363
357
 
364
358
  roadmap: {
365
359
  title: "Roadmap",
366
- lead: "What the project works towards: each goal with the day it is meant to be reached by, and how far its tasks are. Progress is read from the board as it stands.",
367
360
  setGoal: "Set a goal",
368
361
  setGoalAria: "Set a goal",
369
362
  editAria: "Change the goal",
@@ -402,7 +395,6 @@ export const en = {
402
395
 
403
396
  work: {
404
397
  title: "My work",
405
- lead: "What is on your plate across your projects: the open tasks assigned to you, by the day they are due, and the decisions that wait for a person.",
406
398
  loading: "Loading your work",
407
399
  couldNotLoad: "Your work could not be loaded.",
408
400
  empty: {
@@ -420,8 +412,6 @@ export const en = {
420
412
 
421
413
  categories: {
422
414
  title: "Categories",
423
- lead: "The kinds of work tasks are sorted into, the same in every project. A task carries one, the board is narrowed by one, and an administrator keeps the list.",
424
- onlyAdmin: "An administrator adds, changes and removes them; everyone else reads them here.",
425
415
  list: "Categories",
426
416
  add: "Add a category",
427
417
  addAria: "Add a category",
@@ -429,7 +419,6 @@ export const en = {
429
419
  title: "No categories",
430
420
  body: "An administrator adds the first one here.",
431
421
  },
432
- inUse: "A category tasks are sorted into cannot be removed until they are moved out of it.",
433
422
  form: {
434
423
  name: "Name",
435
424
  key: "Key",
@@ -543,10 +532,8 @@ export const en = {
543
532
  title: "No skills address yet",
544
533
  body: "This console has no address for the organization's skills. Whoever runs it names a repository served by SkillCDN in its configuration.",
545
534
  },
546
- servedBy: "The organization's skills, served by",
535
+ servedBy: "Served by",
547
536
  at: "at",
548
- howLoaded:
549
- ". An agent loads one through its SkillCDN connection; a person reads it at its page.",
550
537
  status: {
551
538
  indexing: "SkillCDN is still indexing the repository. Look again in a moment.",
552
539
  failed: "SkillCDN could not index the repository. What it found is on the address's page.",
@@ -624,12 +611,9 @@ export const en = {
624
611
  people: {
625
612
  title: "People",
626
613
  list: "People",
627
- lead: "Everyone who has signed in. An administrator configures the workspace and says what each person is; a member works in the projects they are in. What a person may do, their agents may do.",
628
614
  roleOf: (name: string) => `Role of ${name}`,
629
615
  agents: "Agents",
630
616
  agentsOf: (name: string) => `Agents of ${name}`,
631
- agentsLead: (name: string) =>
632
- `What works here as ${name}, each with a token of its own. Disconnecting one takes its token away at once.`,
633
617
  loadingAgents: "Loading the agents",
634
618
  noAgent: "No agent is connected",
635
619
  onlyAdmin: {
@@ -642,7 +626,6 @@ export const en = {
642
626
  title: "Agents",
643
627
  makeByHand: "Make a token by hand",
644
628
  makeAria: "Make a token",
645
- lead: "What works here as you: each agent you connected, with a token of its own that nobody sees. What you may do, it may do; disconnect it here when that is over. A script or a console of your own holds a token the same way, made by hand.",
646
629
  empty: {
647
630
  title: "No agent is connected yet",
648
631
  body: "Tell your agent to connect to this console, as below, and it shows up here.",
@@ -677,14 +660,13 @@ export const en = {
677
660
  connect: {
678
661
  title: "Connect an agent",
679
662
  aria: "Connect",
680
- lead: "Your agent showed you a code when it was told to connect to this console. Type it here, and say whether the agent may work as you.",
681
663
  codeAria: "The code",
682
664
  codeLabel: "The code your agent showed",
683
665
  continue: "Continue",
684
666
  lookingUp: "Looking the code up",
685
667
  notACode: "That is not a code: eight letters and digits, in two groups.",
686
668
  noSuchCode:
687
- "No agent asks to connect with this code. A code is good for ten minutes and for one approval; ask your agent for a new one.",
669
+ "No agent asks to connect with this code. A code is good for thirty minutes and for one approval; ask your agent for a new one.",
688
670
  couldNotAsk: "The console could not be asked.",
689
671
  asks: {
690
672
  title: "An agent asks to connect as you",
package/src/i18n/ko.ts CHANGED
@@ -62,7 +62,7 @@ export const ko: Messages = {
62
62
  },
63
63
  notWithToken: {
64
64
  title: "콘솔 자체 페이지에서 하는 일입니다",
65
- body: "이 콘솔은 토큰으로 당신을 대신해 보드를 씁니다. 에이전트 연결, 프로젝트와 사람 설정, 언어 저장은 조직 콘솔에 로그인해서 합니다.",
65
+ body: "이 콘솔은 토큰으로 당신을 대신해 보드를 쓰며, 설정도 그렇게 합니다. 에이전트 연결과 토큰 관리는 조직 콘솔에 로그인해서 합니다.",
66
66
  },
67
67
  you: "(나)",
68
68
  nobody: "없음",
@@ -116,7 +116,6 @@ export const ko: Messages = {
116
116
  projects: {
117
117
  title: "프로젝트",
118
118
  newProject: "새 프로젝트",
119
- lead: "프로젝트는 보드, 문서, 스킬, 사람들을 가집니다. 무엇을 보고 바꿀 수 있는지는 프로젝트마다 정해집니다. 소유자는 설정하고, 멤버는 일합니다.",
120
119
  empty: {
121
120
  title: "아직 프로젝트가 없습니다",
122
121
  body: "첫 프로젝트를 만드세요. 무엇을 위한 것인지, 누가 함께하는지. 또는 소유자에게 추가를 요청하세요.",
@@ -144,11 +143,6 @@ export const ko: Messages = {
144
143
  members: {
145
144
  title: "멤버",
146
145
  list: "멤버",
147
- leadWorkspace:
148
- "워크스페이스의 모두가 이 프로젝트의 멤버입니다. 여기 목록은 소유자와 따로 지정된 사람들입니다.",
149
- leadPrivate: "여기 목록에 있는 사람만 이 프로젝트에 속합니다.",
150
- leadRoles:
151
- "소유자는 프로젝트를 설정하고, 멤버는 프로젝트에서 일합니다. 워크스페이스 관리자는 모든 프로젝트의 소유자입니다.",
152
146
  since: "부터",
153
147
  roleOf: (name) => `${name}의 역할`,
154
148
  addAria: "멤버 추가",
@@ -165,9 +159,6 @@ export const ko: Messages = {
165
159
  settings: {
166
160
  title: "설정",
167
161
  aria: "프로젝트 설정",
168
- leadBefore: "키 ",
169
- leadAfter:
170
- "는 주소와 명령이 부르는 이름이며 바뀌지 않습니다. 스킬 주소는 SkillCDN이 제공하는 저장소를 가리킵니다. 비우면 조직의 스킬이 보입니다.",
171
162
  onlyOwner: {
172
163
  title: "소유자만 프로젝트를 바꿀 수 있습니다",
173
164
  body: "소유자나 워크스페이스 관리자에게 요청하세요.",
@@ -277,8 +268,6 @@ export const ko: Messages = {
277
268
  waiting: "대기 중",
278
269
  answered: "답변됨",
279
270
  record: "기록",
280
- recordLead:
281
- "답변된 모든 결정, 최신순. 무엇을 물었고, 무엇을 골랐고, 누가 골랐는지. 맥락과 근거, 그 뒤에 일어난 일은 각 결정을 열어 봅니다.",
282
271
  openRecord: "열기",
283
272
  waitingForPerson: "사람을 기다리는 중입니다.",
284
273
  options: "선택지",
@@ -309,7 +298,6 @@ export const ko: Messages = {
309
298
 
310
299
  calendar: {
311
300
  title: "캘린더",
312
- lead: "작업을 날짜 위에 놓고 봅니다. 시작일과 기한이 있는 작업은 그 기간에 걸쳐 놓이고, 기한만 있는 작업은 그날에 놓입니다. 날짜가 없는 작업은 아래에서 날짜를 기다립니다.",
313
301
  grid: "이 달",
314
302
  legend: { title: "카테고리 색" },
315
303
  startsOnly: "그날 시작, 기한은 아직 없음",
@@ -321,9 +309,15 @@ export const ko: Messages = {
321
309
  nothingOverdue: "기한이 지난 작업이 없습니다.",
322
310
  unscheduled: "날짜 없음",
323
311
  allScheduled: "열린 작업마다 날짜가 있습니다.",
312
+ week: {
313
+ title: "이 주",
314
+ previous: "이전 주",
315
+ next: "다음 주",
316
+ thisWeek: "이번 주",
317
+ nothing: "이 주에 잡힌 작업이 없습니다.",
318
+ },
324
319
  workload: {
325
320
  title: "누가 무엇을",
326
- lead: "사람마다 열린 작업과, 그중 늦은 것과 일주일 안에 마감인 것.",
327
321
  person: "사람",
328
322
  open: "열림",
329
323
  inProgress: "진행 중",
@@ -335,7 +329,6 @@ export const ko: Messages = {
335
329
 
336
330
  roadmap: {
337
331
  title: "로드맵",
338
- lead: "프로젝트가 향하는 것. 목표마다 달성 목표일과, 그 아래 작업들이 어디까지 왔는지. 진행은 보드의 현재 상태에서 그대로 읽습니다.",
339
332
  setGoal: "목표 세우기",
340
333
  setGoalAria: "목표 세우기",
341
334
  editAria: "목표 바꾸기",
@@ -374,7 +367,6 @@ export const ko: Messages = {
374
367
 
375
368
  work: {
376
369
  title: "내 작업",
377
- lead: "내 프로젝트들에 걸쳐 내게 놓인 일. 내게 배정된 열린 작업을 기한순으로, 그리고 사람을 기다리는 결정.",
378
370
  loading: "내 작업을 불러오는 중",
379
371
  couldNotLoad: "내 작업을 불러올 수 없습니다.",
380
372
  empty: {
@@ -392,8 +384,6 @@ export const ko: Messages = {
392
384
 
393
385
  categories: {
394
386
  title: "카테고리",
395
- lead: "작업을 나누는 일의 종류이며, 모든 프로젝트에서 같습니다. 작업은 하나를 가지고, 보드는 하나로 좁혀 보며, 관리자가 목록을 관리합니다.",
396
- onlyAdmin: "관리자가 추가하고 바꾸고 제거합니다. 다른 사람은 여기서 읽습니다.",
397
387
  list: "카테고리",
398
388
  add: "카테고리 추가",
399
389
  addAria: "카테고리 추가",
@@ -401,7 +391,6 @@ export const ko: Messages = {
401
391
  title: "카테고리가 없습니다",
402
392
  body: "관리자가 여기서 첫 카테고리를 추가합니다.",
403
393
  },
404
- inUse: "작업이 속해 있는 카테고리는 그 작업들을 옮기기 전에는 제거할 수 없습니다.",
405
394
  form: {
406
395
  name: "이름",
407
396
  key: "키",
@@ -511,10 +500,8 @@ export const ko: Messages = {
511
500
  title: "아직 스킬 주소가 없습니다",
512
501
  body: "이 콘솔에는 조직의 스킬 주소가 없습니다. 운영자가 설정에서 SkillCDN이 제공하는 저장소를 지정합니다.",
513
502
  },
514
- servedBy: "조직의 스킬. 제공:",
503
+ servedBy: "제공:",
515
504
  at: "주소:",
516
- howLoaded:
517
- ". 에이전트는 SkillCDN 연결을 통해 스킬을 불러오고, 사람은 해당 페이지에서 읽습니다.",
518
505
  status: {
519
506
  indexing: "SkillCDN이 아직 저장소를 색인하고 있습니다. 잠시 후 다시 보세요.",
520
507
  failed: "SkillCDN이 저장소를 색인하지 못했습니다. 찾은 내용은 주소의 페이지에 있습니다.",
@@ -592,12 +579,9 @@ export const ko: Messages = {
592
579
  people: {
593
580
  title: "사람들",
594
581
  list: "사람들",
595
- lead: "로그인한 모든 사람. 관리자는 워크스페이스를 설정하고 각 사람의 역할을 정합니다. 멤버는 속한 프로젝트에서 일합니다. 사람이 할 수 있는 일은 그 사람의 에이전트도 할 수 있습니다.",
596
582
  roleOf: (name) => `${name}의 역할`,
597
583
  agents: "에이전트",
598
584
  agentsOf: (name) => `${name}의 에이전트`,
599
- agentsLead: (name) =>
600
- `${name}(으)로 여기서 일하는 것들입니다. 각각 고유한 토큰을 가집니다. 연결을 끊으면 토큰이 즉시 사라집니다.`,
601
585
  loadingAgents: "에이전트를 불러오는 중",
602
586
  noAgent: "연결된 에이전트가 없습니다",
603
587
  onlyAdmin: {
@@ -610,7 +594,6 @@ export const ko: Messages = {
610
594
  title: "에이전트",
611
595
  makeByHand: "토큰 직접 만들기",
612
596
  makeAria: "토큰 만들기",
613
- lead: "나로서 여기서 일하는 것들입니다. 연결한 각 에이전트는 아무도 볼 수 없는 고유한 토큰을 가집니다. 내가 할 수 있는 일은 에이전트도 할 수 있습니다. 더 쓰지 않으면 여기서 연결을 끊으세요. 내 스크립트나 콘솔도 직접 만든 토큰으로 같은 방식으로 일합니다.",
614
597
  empty: {
615
598
  title: "아직 연결된 에이전트가 없습니다",
616
599
  body: "아래처럼 에이전트에게 이 콘솔에 연결하라고 말하면 여기에 나타납니다.",
@@ -645,14 +628,13 @@ export const ko: Messages = {
645
628
  connect: {
646
629
  title: "에이전트 연결",
647
630
  aria: "연결",
648
- lead: "에이전트에게 이 콘솔에 연결하라고 말하면 코드를 보여 줍니다. 그 코드를 여기에 입력하고, 에이전트가 나로서 일해도 되는지 답하세요.",
649
631
  codeAria: "코드",
650
632
  codeLabel: "에이전트가 보여 준 코드",
651
633
  continue: "계속",
652
634
  lookingUp: "코드를 찾는 중",
653
635
  notACode: "코드가 아닙니다. 영문자와 숫자 여덟 자, 두 묶음입니다.",
654
636
  noSuchCode:
655
- "이 코드로 연결을 요청한 에이전트가 없습니다. 코드는 10분 동안, 한 번의 승인에만 유효합니다. 에이전트에게 새 코드를 요청하세요.",
637
+ "이 코드로 연결을 요청한 에이전트가 없습니다. 코드는 30분 동안, 한 번의 승인에만 유효합니다. 에이전트에게 새 코드를 요청하세요.",
656
638
  couldNotAsk: "콘솔에 물어볼 수 없습니다.",
657
639
  asks: {
658
640
  title: "에이전트가 나로서 연결하기를 요청합니다",
package/src/index.ts CHANGED
@@ -16,6 +16,8 @@ export {
16
16
  export {
17
17
  Calendar,
18
18
  type CalendarProps,
19
+ Week,
20
+ type WeekProps,
19
21
  type WeekSegment,
20
22
  Workload,
21
23
  type WorkloadProps,
@@ -156,6 +158,7 @@ export {
156
158
  daysBetween,
157
159
  firstDayOfWeek,
158
160
  formatDay,
161
+ formatDays,
159
162
  formatMonth,
160
163
  formatWeekday,
161
164
  type GridDay,
@@ -165,6 +168,7 @@ export {
165
168
  monthOf,
166
169
  today,
167
170
  weekdays,
171
+ weekOf,
168
172
  } from "./dates.js";
169
173
  export { DocsPage, type DocsPageProps } from "./docs-page.js";
170
174
  export {
@@ -204,5 +208,6 @@ export {
204
208
  type TaskFormKind,
205
209
  taskHref,
206
210
  withoutSignInParam,
211
+ workHref,
207
212
  } from "./router.js";
208
213
  export { errorWords, useAction } from "./use-action.js";