@skillcdn/console 0.1.24 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +8 -7
  2. package/dist/api.d.ts +2 -2
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +2 -2
  5. package/dist/api.js.map +1 -1
  6. package/dist/cli/cli.d.ts +1 -1
  7. package/dist/cli/cli.d.ts.map +1 -1
  8. package/dist/cli/cli.js +248 -92
  9. package/dist/cli/cli.js.map +1 -1
  10. package/dist/cli/credentials.d.ts +5 -0
  11. package/dist/cli/credentials.d.ts.map +1 -1
  12. package/dist/cli/credentials.js +2 -0
  13. package/dist/cli/credentials.js.map +1 -1
  14. package/dist/cli/directory.d.ts +7 -0
  15. package/dist/cli/directory.d.ts.map +1 -1
  16. package/dist/cli/directory.js +7 -0
  17. package/dist/cli/directory.js.map +1 -1
  18. package/dist/cli/format.d.ts +13 -28
  19. package/dist/cli/format.d.ts.map +1 -1
  20. package/dist/cli/format.js +74 -274
  21. package/dist/cli/format.js.map +1 -1
  22. package/dist/cli/help.d.ts.map +1 -1
  23. package/dist/cli/help.js +36 -19
  24. package/dist/cli/help.js.map +1 -1
  25. package/dist/cli/pack.d.ts +46 -0
  26. package/dist/cli/pack.d.ts.map +1 -0
  27. package/dist/cli/pack.js +250 -0
  28. package/dist/cli/pack.js.map +1 -0
  29. package/dist/client.d.ts +26 -1
  30. package/dist/client.d.ts.map +1 -1
  31. package/dist/client.js +14 -1
  32. package/dist/client.js.map +1 -1
  33. package/dist/compat.d.ts +1 -1
  34. package/dist/compat.js +1 -1
  35. package/dist/components/calendar.d.ts +5 -1
  36. package/dist/components/calendar.d.ts.map +1 -1
  37. package/dist/components/calendar.js +3 -3
  38. package/dist/components/calendar.js.map +1 -1
  39. package/dist/components/decision-list.d.ts +13 -1
  40. package/dist/components/decision-list.d.ts.map +1 -1
  41. package/dist/components/decision-list.js +74 -29
  42. package/dist/components/decision-list.js.map +1 -1
  43. package/dist/components/event-feed.d.ts.map +1 -1
  44. package/dist/components/event-feed.js +2 -0
  45. package/dist/components/event-feed.js.map +1 -1
  46. package/dist/components/pack-connect.d.ts +23 -0
  47. package/dist/components/pack-connect.d.ts.map +1 -0
  48. package/dist/components/pack-connect.js +86 -0
  49. package/dist/components/pack-connect.js.map +1 -0
  50. package/dist/components/pack-token.d.ts +27 -0
  51. package/dist/components/pack-token.d.ts.map +1 -0
  52. package/dist/components/pack-token.js +11 -0
  53. package/dist/components/pack-token.js.map +1 -0
  54. package/dist/components/paged.d.ts +24 -0
  55. package/dist/components/paged.d.ts.map +1 -1
  56. package/dist/components/paged.js +40 -4
  57. package/dist/components/paged.js.map +1 -1
  58. package/dist/components/projects.d.ts +13 -0
  59. package/dist/components/projects.d.ts.map +1 -1
  60. package/dist/components/projects.js +37 -5
  61. package/dist/components/projects.js.map +1 -1
  62. package/dist/components/skills.d.ts.map +1 -1
  63. package/dist/components/skills.js +8 -4
  64. package/dist/components/skills.js.map +1 -1
  65. package/dist/components/ui.d.ts +2 -0
  66. package/dist/components/ui.d.ts.map +1 -1
  67. package/dist/components/ui.js +7 -2
  68. package/dist/components/ui.js.map +1 -1
  69. package/dist/components/work.d.ts +3 -1
  70. package/dist/components/work.d.ts.map +1 -1
  71. package/dist/components/work.js +1 -1
  72. package/dist/components/work.js.map +1 -1
  73. package/dist/components/workspace.d.ts +46 -0
  74. package/dist/components/workspace.d.ts.map +1 -0
  75. package/dist/components/workspace.js +124 -0
  76. package/dist/components/workspace.js.map +1 -0
  77. package/dist/console.css +268 -5
  78. package/dist/console.d.ts.map +1 -1
  79. package/dist/console.js +62 -23
  80. package/dist/console.js.map +1 -1
  81. package/dist/data.d.ts +16 -1
  82. package/dist/data.d.ts.map +1 -1
  83. package/dist/data.js +64 -2
  84. package/dist/data.js.map +1 -1
  85. package/dist/dates.d.ts +12 -2
  86. package/dist/dates.d.ts.map +1 -1
  87. package/dist/dates.js +20 -2
  88. package/dist/dates.js.map +1 -1
  89. package/dist/i18n/en.d.ts +66 -0
  90. package/dist/i18n/en.d.ts.map +1 -1
  91. package/dist/i18n/en.js +80 -8
  92. package/dist/i18n/en.js.map +1 -1
  93. package/dist/i18n/ko.d.ts.map +1 -1
  94. package/dist/i18n/ko.js +75 -7
  95. package/dist/i18n/ko.js.map +1 -1
  96. package/dist/index.d.ts +5 -2
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +5 -2
  99. package/dist/index.js.map +1 -1
  100. package/dist/router.d.ts +10 -5
  101. package/dist/router.d.ts.map +1 -1
  102. package/dist/router.js +24 -9
  103. package/dist/router.js.map +1 -1
  104. package/dist/routes.d.ts +4 -0
  105. package/dist/routes.d.ts.map +1 -1
  106. package/dist/routes.js +4 -0
  107. package/dist/routes.js.map +1 -1
  108. package/dist/schemas.d.ts +500 -158
  109. package/dist/schemas.d.ts.map +1 -1
  110. package/dist/schemas.js +169 -165
  111. package/dist/schemas.js.map +1 -1
  112. package/dist/vocabulary.d.ts +19 -1
  113. package/dist/vocabulary.d.ts.map +1 -1
  114. package/dist/vocabulary.js +16 -0
  115. package/dist/vocabulary.js.map +1 -1
  116. package/docs/specs/cli.md +19 -14
  117. package/docs/specs/rest.md +34 -19
  118. package/package.json +2 -1
  119. package/skills/building-a-console/SKILL.md +5 -5
  120. package/skills/building-a-console/references/the-look-from-a-website.md +39 -0
  121. package/skills/deploying-a-console/SKILL.md +9 -8
  122. package/skills/working-the-board/SKILL.md +5 -5
  123. package/skills/working-the-board/references/setting-up.md +1 -1
  124. package/skills/working-the-board/references/terms.md +2 -0
  125. package/skills/working-the-board/references/the-sentence.md +1 -1
  126. package/src/api.ts +18 -7
  127. package/src/cli/cli.ts +345 -109
  128. package/src/cli/credentials.ts +7 -0
  129. package/src/cli/directory.ts +9 -0
  130. package/src/cli/format.ts +82 -341
  131. package/src/cli/help.ts +43 -19
  132. package/src/cli/pack.ts +356 -0
  133. package/src/client.ts +84 -0
  134. package/src/compat.ts +1 -1
  135. package/src/components/calendar.tsx +8 -2
  136. package/src/components/decision-list.tsx +227 -94
  137. package/src/components/event-feed.tsx +2 -0
  138. package/src/components/pack-connect.tsx +179 -0
  139. package/src/components/pack-token.tsx +74 -0
  140. package/src/components/paged.tsx +72 -3
  141. package/src/components/projects.tsx +108 -9
  142. package/src/components/skills.tsx +51 -33
  143. package/src/components/ui.tsx +16 -3
  144. package/src/components/work.tsx +4 -1
  145. package/src/components/workspace.tsx +298 -0
  146. package/src/console.tsx +176 -29
  147. package/src/data.ts +89 -2
  148. package/src/dates.ts +23 -2
  149. package/src/i18n/en.ts +94 -8
  150. package/src/i18n/ko.ts +84 -7
  151. package/src/index.ts +25 -1
  152. package/src/router.ts +37 -14
  153. package/src/routes.ts +4 -0
  154. package/src/schemas.ts +202 -189
  155. package/src/styles/console.css +268 -5
  156. package/src/vocabulary.ts +25 -0
package/src/i18n/en.ts CHANGED
@@ -3,14 +3,18 @@ import type {
3
3
  CategoryColor,
4
4
  GoalState,
5
5
  MembershipSource,
6
+ PackConnectEnding,
7
+ PeopleVisibility,
6
8
  PersonRole,
7
9
  PersonStatus,
8
10
  ProjectRole,
9
11
  ProjectVisibility,
10
12
  ProviderKey,
11
13
  RunStatus,
14
+ SkillsStatus,
12
15
  TaskPriority,
13
16
  TaskState,
17
+ WeekStart,
14
18
  } from "../vocabulary.js";
15
19
 
16
20
  // Every word the default console shows, in English: the source of the keys every other pack
@@ -43,9 +47,18 @@ export const en = {
43
47
  status: { active: "Active", deactivated: "Deactivated" } satisfies Record<PersonStatus, string>,
44
48
  projectRole: { owner: "Owner", member: "Member" } satisfies Record<ProjectRole, string>,
45
49
  visibility: {
46
- workspace: "Everyone of the workspace",
47
- private: "Only those listed",
50
+ workspace: "Open: everyone of the workspace",
51
+ private: "Private: only those listed",
48
52
  } satisfies Record<ProjectVisibility, string>,
53
+ peopleVisibility: {
54
+ everyone: "Everyone of the workspace",
55
+ shared_projects: "Only the people one shares a project with",
56
+ } satisfies Record<PeopleVisibility, string>,
57
+ weekStart: {
58
+ auto: "System default",
59
+ monday: "Monday",
60
+ sunday: "Sunday",
61
+ } satisfies Record<WeekStart, string>,
49
62
  runStatus: {
50
63
  running: "Open",
51
64
  waiting: "Waiting for a decision",
@@ -102,6 +115,12 @@ export const en = {
102
115
  copy: "Copy",
103
116
  copied: "Copied",
104
117
  showMore: (n: number, of: number) => `Show ${n} more of ${of}`,
118
+ pager: {
119
+ label: "Pages",
120
+ previous: "Previous page",
121
+ next: "Next page",
122
+ range: (from: number, to: number, of: number) => `${from}-${to} of ${of}`,
123
+ },
105
124
  },
106
125
 
107
126
  nav: {
@@ -188,6 +207,13 @@ export const en = {
188
207
  chooseSomeone: "Choose someone",
189
208
  as: "As",
190
209
  add: "Add",
210
+ open: "An open project: everyone of the workspace is a member. The owners configure it, and an owner is made from this list.",
211
+ addByLoginAria: "Add a member by login",
212
+ login: "Login",
213
+ addByLogin: "Add by login",
214
+ lookupHint:
215
+ "Someone the list does not show: their login at the git host, or their address, exactly.",
216
+ nobodyCalled: (login: string) => `Nobody of the workspace is called ${login}.`,
191
217
  empty: {
192
218
  title: "Nobody is listed",
193
219
  workspace: "Everyone of the workspace is in; the administrators own it.",
@@ -195,11 +221,33 @@ export const en = {
195
221
  },
196
222
  },
197
223
  packToken: {
198
- aria: "The pack token",
224
+ aria: "The SkillCDN token",
225
+ intro:
226
+ "A private pack is read with a SkillCDN token for its repository; a public one needs none. Connect it with a code approved at SkillCDN, or paste a token made there by hand. The console keeps the token sealed and shows it to nobody. A project that reads the organization's pack may leave this to the workspace's token, on the Settings page.",
227
+ connectTitle: "With a code approved at SkillCDN",
228
+ pasteTitle: "With a token made by hand",
229
+ pasteAria: "Paste a token",
199
230
  label: "Token",
200
- hint: "A token a person made at SkillCDN for the pack's repository, on their account page there. The console keeps it sealed, reads the pack with it for whoever may see the project, and shows it to nobody.",
231
+ hint: "Made on the account page at SkillCDN, for the pack's repository.",
232
+ setSince: "A token has been set since",
201
233
  placeholder: "scdn_repo_…",
234
+ connect: "Connect at SkillCDN",
235
+ connectHint:
236
+ "The console asks SkillCDN for a code. Open the page it gives, signed in there as someone who may open the repository, check the code and approve.",
237
+ connectCode: "Code",
238
+ connectOpen: "Open the page at SkillCDN",
239
+ connectWaiting: "Waiting for the approval at SkillCDN.",
240
+ connectExpires: "The code expires",
241
+ connectCancel: "Stop waiting",
242
+ connectDone: "Connected: the console reads the pack with the token from now on.",
243
+ connectEnded: {
244
+ expired: "The code expired before anyone approved it. Connect again for a new one.",
245
+ declined: "The request was declined at SkillCDN, or the code was spent.",
246
+ refused:
247
+ "SkillCDN refused the request: the repository is not one the person may open, the pack is public and needs no token, or they hold as many tokens as one may.",
248
+ } satisfies Record<PackConnectEnding, string>,
202
249
  set: "Set the token",
250
+ replace: "Replace the token",
203
251
  remove: "Remove the token",
204
252
  },
205
253
  settings: {
@@ -208,10 +256,11 @@ export const en = {
208
256
  edit: "Edit the project",
209
257
  organizationsSkills: (address: string) => `The organization's: ${address}`,
210
258
  noSkills: "None: the console names no address for the organization's.",
211
- packToken: "Pack token",
212
- packTokenNone: "None: a public pack needs none, and a private one is not read.",
259
+ packToken: "SkillCDN token",
260
+ packTokenNone: "None",
213
261
  packTokenSet: "Set",
214
262
  packTokenEdit: "Change it",
263
+ packTokenAdd: "Set one",
215
264
  },
216
265
  },
217
266
 
@@ -325,6 +374,9 @@ export const en = {
325
374
  waitingForPerson: "Waiting for a person.",
326
375
  options: "Options",
327
376
  notePlaceholder: "A word about it, if any",
377
+ own: "Something else",
378
+ ownPlaceholder: "Your answer, in a line",
379
+ ownAnswer: "in their own words",
328
380
  answer: "Answer",
329
381
  asked: "asked",
330
382
  askedThrough: (agent: string) => `asked through ${agent}`,
@@ -488,6 +540,26 @@ export const en = {
488
540
  noSkillsAddress: "No address: each project names its own, or has none.",
489
541
  skillsFromConfiguration:
490
542
  "Set by whoever runs the console, in its configuration: the deployment the skills are read through, and the organization's address.",
543
+ skillsToken: "SkillCDN token",
544
+ skillsTokenIntro:
545
+ "Every project that names no address of its own, and holds no token of its own, reads the organization's pack with this token; a public pack needs none. Connect it with a code approved at SkillCDN, or paste a token made there by hand. The console keeps the token sealed and shows it to nobody.",
546
+ workspace: {
547
+ title: "Workspace",
548
+ aria: "Workspace settings",
549
+ peopleVisibility: "Member visibility",
550
+ peopleVisibilityHint:
551
+ "Whom a member sees on the People page and in the pickers: everyone of the workspace, or only the people they share a project with. An administrator always sees everyone, and a project open to the workspace has everyone in it.",
552
+ weekStart: "The week begins on",
553
+ weekStartHint:
554
+ "On the calendars and on My work. System default follows the language and region set on each person's device; Monday or Sunday holds for everyone.",
555
+ timeZone: "Time zone",
556
+ timeZoneHint:
557
+ "The console command and the agents print moments in this zone. The pages show them in each device's own. None: the command prints them in UTC.",
558
+ timeZoneNone: "None",
559
+ timeZoneDevice: (zone: string) => `This device: ${zone}`,
560
+ timeZoneUseDevice: (zone: string) => `Use this device's: ${zone}`,
561
+ save: "Save the settings",
562
+ },
491
563
  },
492
564
 
493
565
  rules: {
@@ -551,9 +623,14 @@ export const en = {
551
623
  dueOn: "the due date",
552
624
  state: "the state",
553
625
  color: "the colour",
626
+ peopleVisibility: "the member visibility",
627
+ weekStart: "the first day of the week",
628
+ timeZone: "the time zone",
629
+ packToken: "the SkillCDN token",
554
630
  } as Readonly<Record<string, string>>,
555
631
  event: {
556
632
  personJoined: () => "joined the board",
633
+ workspaceUpdated: (fields: string) => `changed ${fields} of the workspace`,
557
634
  roleChanged: (login: string, role: string) => `made ${login} ${role}`,
558
635
  personListed: (login: string) => `added ${login}`,
559
636
  personUnlisted: (login: string) => `took ${login} off the list`,
@@ -662,13 +739,21 @@ export const en = {
662
739
  connect:
663
740
  "An agent reads these with the console command (console skill <path>), or through its own MCP connection to this address, which a person makes once:",
664
741
  connectLink: "how, on the address's page at SkillCDN",
742
+ fromMachine: "Read from a directory on the console's machine, at",
743
+ connectLocal:
744
+ "An agent reads these with the console command (console skill <path>); the pack is on the console's machine and nowhere else.",
745
+ localStatus: {
746
+ not_found:
747
+ "No pack is served from the console's machine at this address: whoever runs the console puts it in the packs directory, as <owner>/<name>.",
748
+ unavailable: "The pack could not be read from the console's machine. Look again later.",
749
+ } as Partial<Record<SkillsStatus, string>>,
665
750
  status: {
666
751
  indexing: "SkillCDN is still indexing the repository. Look again in a moment.",
667
752
  failed: "SkillCDN could not index the repository. What it found is on the address's page.",
668
753
  not_found:
669
- "SkillCDN does not serve this address to the console: there is nothing there, or the pack is private and the project holds no pack token for it (Settings).",
754
+ "SkillCDN does not serve this address to the console: there is nothing there, or the pack is private and no SkillCDN token reads it, the project's own or the workspace's. An owner connects one on the Settings page, with a code approved at SkillCDN.",
670
755
  token_invalid:
671
- "The pack token the project holds no longer works at SkillCDN: it expired, was removed, or its maker lost the repository. An owner sets a new one on the Settings page.",
756
+ "The SkillCDN token the pack is read with no longer works at SkillCDN: it expired, was removed, or its maker lost the repository. An owner sets a new one on the Settings page.",
672
757
  unavailable: "SkillCDN could not be reached. The skills are as they were; look again later.",
673
758
  },
674
759
  none: {
@@ -746,6 +831,7 @@ export const en = {
746
831
  people: {
747
832
  title: "People",
748
833
  list: "People",
834
+ narrowed: "The people you share a project with, and the administrators.",
749
835
  roleOf: (name: string) => `Role of ${name}`,
750
836
  letIn: "Add a person",
751
837
  letInAria: "Add a person",
package/src/i18n/ko.ts CHANGED
@@ -20,7 +20,12 @@ export const ko: Messages = {
20
20
  role: { admin: "관리자", member: "멤버" },
21
21
  status: { active: "활성", deactivated: "비활성화" },
22
22
  projectRole: { owner: "소유자", member: "멤버" },
23
- visibility: { workspace: "워크스페이스의 모두", private: "목록에 있는 사람만" },
23
+ visibility: { workspace: "공개: 워크스페이스의 모두", private: "비공개: 목록에 있는 사람만" },
24
+ peopleVisibility: {
25
+ everyone: "워크스페이스의 모두",
26
+ shared_projects: "같은 프로젝트에 속한 사람만",
27
+ },
28
+ weekStart: { auto: "시스템 기본", monday: "월요일", sunday: "일요일" },
24
29
  runStatus: {
25
30
  running: "열림",
26
31
  waiting: "결정 대기 중",
@@ -72,6 +77,12 @@ export const ko: Messages = {
72
77
  copy: "복사",
73
78
  copied: "복사됨",
74
79
  showMore: (n, of) => `${of}개 중 ${n}개 더 보기`,
80
+ pager: {
81
+ label: "페이지",
82
+ previous: "이전",
83
+ next: "다음",
84
+ range: (from, to, of) => `${of}건 중 ${from}-${to}`,
85
+ },
75
86
  },
76
87
 
77
88
  nav: {
@@ -157,6 +168,12 @@ export const ko: Messages = {
157
168
  chooseSomeone: "선택하세요",
158
169
  as: "역할",
159
170
  add: "추가",
171
+ open: "공개 프로젝트입니다. 워크스페이스의 모든 구성원이 멤버이고, 소유자는 이 목록에서 지정합니다.",
172
+ addByLoginAria: "로그인으로 멤버 추가",
173
+ login: "로그인",
174
+ addByLogin: "로그인으로 추가",
175
+ lookupHint: "목록에 보이지 않는 사람: 깃 호스트의 로그인이나 주소를 정확히 적습니다.",
176
+ nobodyCalled: (login) => `워크스페이스에 ${login}이라는 사람이 없습니다.`,
160
177
  empty: {
161
178
  title: "목록에 아무도 없습니다",
162
179
  workspace: "워크스페이스의 모두가 속해 있고, 관리자가 소유합니다.",
@@ -164,11 +181,33 @@ export const ko: Messages = {
164
181
  },
165
182
  },
166
183
  packToken: {
167
- aria: "팩 토큰",
184
+ aria: "SkillCDN 토큰",
185
+ intro:
186
+ "비공개 팩은 저장소에 대한 SkillCDN 토큰으로 읽습니다. 공개 팩에는 필요 없습니다. SkillCDN에서 승인한 코드로 연결하거나, 거기서 직접 만든 토큰을 붙여 넣으세요. 콘솔은 토큰을 봉인해 보관하고 누구에게도 보여 주지 않습니다. 조직의 팩을 읽는 프로젝트는 워크스페이스 설정의 토큰을 그대로 쓸 수 있습니다.",
187
+ connectTitle: "SkillCDN에서 승인한 코드로",
188
+ pasteTitle: "직접 만든 토큰으로",
189
+ pasteAria: "토큰 붙여넣기",
168
190
  label: "토큰",
169
- hint: "사람이 SkillCDN 계정 페이지에서 팩의 저장소에 대해 만든 토큰입니다. 콘솔이 봉인해 보관하고, 프로젝트를 볼 수 있는 사람을 위해 팩을 읽는 데 쓰며, 누구에게도 보여 주지 않습니다.",
191
+ hint: "SkillCDN 계정 페이지에서 팩의 저장소에 대해 만든 토큰입니다.",
192
+ setSince: "토큰이 설정되어 있습니다:",
170
193
  placeholder: "scdn_repo_…",
194
+ connect: "SkillCDN에서 연결",
195
+ connectHint:
196
+ "콘솔이 SkillCDN에 코드를 요청합니다. 안내된 페이지를 저장소를 볼 수 있는 계정으로 열어, 코드를 확인하고 승인하세요.",
197
+ connectCode: "코드",
198
+ connectOpen: "SkillCDN 페이지 열기",
199
+ connectWaiting: "SkillCDN에서 승인을 기다리는 중입니다.",
200
+ connectExpires: "코드 만료:",
201
+ connectCancel: "기다리기 중단",
202
+ connectDone: "연결되었습니다. 콘솔이 이제 이 토큰으로 팩을 읽습니다.",
203
+ connectEnded: {
204
+ expired: "승인되기 전에 코드가 만료되었습니다. 다시 연결해 새 코드를 받으세요.",
205
+ declined: "SkillCDN에서 요청이 거절되었거나 코드가 이미 쓰였습니다.",
206
+ refused:
207
+ "SkillCDN이 요청을 거부했습니다. 그 사람이 볼 수 없는 저장소이거나, 공개 팩이라 토큰이 필요 없거나, 토큰을 더 만들 수 없습니다.",
208
+ },
171
209
  set: "토큰 넣기",
210
+ replace: "토큰 바꾸기",
172
211
  remove: "토큰 빼기",
173
212
  },
174
213
  settings: {
@@ -177,10 +216,11 @@ export const ko: Messages = {
177
216
  edit: "프로젝트 편집",
178
217
  organizationsSkills: (address) => `조직의 스킬: ${address}`,
179
218
  noSkills: "없음: 콘솔에 조직의 주소가 없습니다.",
180
- packToken: "팩 토큰",
181
- packTokenNone: "없음: 공개 팩은 필요 없고, 비공개 팩은 읽히지 않습니다.",
219
+ packToken: "SkillCDN 토큰",
220
+ packTokenNone: "없음",
182
221
  packTokenSet: "설정됨",
183
222
  packTokenEdit: "바꾸기",
223
+ packTokenAdd: "등록",
184
224
  },
185
225
  },
186
226
 
@@ -294,6 +334,9 @@ export const ko: Messages = {
294
334
  waitingForPerson: "사람을 기다리는 중입니다.",
295
335
  options: "선택지",
296
336
  notePlaceholder: "덧붙일 말이 있다면",
337
+ own: "직접 입력",
338
+ ownPlaceholder: "원하는 답을 한 줄로",
339
+ ownAnswer: "직접 입력",
297
340
  answer: "답변",
298
341
  asked: "질문",
299
342
  askedThrough: (agent) => `${agent}을(를) 통해 질문`,
@@ -455,6 +498,26 @@ export const ko: Messages = {
455
498
  noSkillsAddress: "주소 없음: 프로젝트마다 자기 주소를 두거나, 두지 않습니다.",
456
499
  skillsFromConfiguration:
457
500
  "콘솔을 운영하는 쪽이 설정으로 정합니다. 스킬을 읽어 오는 배포와 조직의 주소.",
501
+ skillsToken: "SkillCDN 토큰",
502
+ skillsTokenIntro:
503
+ "자기 주소도 자기 토큰도 없는 모든 프로젝트가 이 토큰으로 조직의 팩을 읽습니다. 공개 팩에는 필요 없습니다. SkillCDN에서 승인한 코드로 연결하거나, 거기서 직접 만든 토큰을 붙여 넣으세요. 콘솔은 토큰을 봉인해 보관하고 누구에게도 보여 주지 않습니다.",
504
+ workspace: {
505
+ title: "워크스페이스",
506
+ aria: "워크스페이스 설정",
507
+ peopleVisibility: "멤버 공개 범위",
508
+ peopleVisibilityHint:
509
+ "멤버가 사람들 페이지와 선택 목록에서 보는 범위: 워크스페이스의 모두, 또는 같은 프로젝트에 속한 사람만. 관리자는 언제나 모두를 보고, 워크스페이스에 공개된 프로젝트에는 모두가 속합니다.",
510
+ weekStart: "주의 시작 요일",
511
+ weekStartHint:
512
+ "캘린더와 내 작업에서. 시스템 기본은 각 사람의 기기에 설정된 언어와 지역을 따르고, 월요일이나 일요일은 모두에게 같게 적용됩니다.",
513
+ timeZone: "타임존",
514
+ timeZoneHint:
515
+ "콘솔 명령과 에이전트가 시각을 이 타임존으로 찍습니다. 페이지는 각 기기의 타임존으로 보여 줍니다. 없음이면 명령은 UTC로 찍습니다.",
516
+ timeZoneNone: "없음",
517
+ timeZoneDevice: (zone) => `이 기기: ${zone}`,
518
+ timeZoneUseDevice: (zone) => `이 기기의 타임존 쓰기: ${zone}`,
519
+ save: "설정 저장",
520
+ },
458
521
  },
459
522
 
460
523
  rules: {
@@ -518,9 +581,14 @@ export const ko: Messages = {
518
581
  dueOn: "기한",
519
582
  state: "상태",
520
583
  color: "색",
584
+ peopleVisibility: "멤버 공개 범위",
585
+ weekStart: "주의 시작 요일",
586
+ timeZone: "타임존",
587
+ packToken: "SkillCDN 토큰",
521
588
  },
522
589
  event: {
523
590
  personJoined: () => "보드에 들어왔습니다",
591
+ workspaceUpdated: (fields) => `워크스페이스의 ${fields}을(를) 바꿨습니다`,
524
592
  roleChanged: (login, role) => `${login}을(를) ${role}(으)로 지정했습니다`,
525
593
  personListed: (login) => `${login}을(를) 추가했습니다`,
526
594
  personUnlisted: (login) => `${login}을(를) 목록에서 뺐습니다`,
@@ -626,13 +694,21 @@ export const ko: Messages = {
626
694
  connect:
627
695
  "에이전트는 콘솔 명령(console skill <경로>)으로, 또는 이 주소에 자기 MCP 연결로 스킬을 받습니다. MCP 연결은 사람이 한 번 해 줍니다:",
628
696
  connectLink: "SkillCDN 페이지의 연결 안내",
697
+ fromMachine: "콘솔 기계의 디렉터리에서 읽음, 주소:",
698
+ connectLocal:
699
+ "에이전트는 콘솔 명령(console skill <경로>)으로 읽습니다. 이 팩은 콘솔 기계에만 있습니다.",
700
+ localStatus: {
701
+ not_found:
702
+ "이 주소로 콘솔 기계에서 제공되는 팩이 없습니다. 콘솔 운영자가 팩 디렉터리에 <owner>/<name>으로 넣습니다.",
703
+ unavailable: "콘솔 기계에서 팩을 읽지 못했습니다. 나중에 다시 보세요.",
704
+ },
629
705
  status: {
630
706
  indexing: "SkillCDN이 아직 저장소를 색인하고 있습니다. 잠시 후 다시 보세요.",
631
707
  failed: "SkillCDN이 저장소를 색인하지 못했습니다. 찾은 내용은 주소의 페이지에 있습니다.",
632
708
  not_found:
633
- "SkillCDN이 이 주소를 콘솔에 제공하지 않습니다. 그곳에 아무것도 없거나, 비공개 팩인데 프로젝트에 팩 토큰이 없습니다(설정).",
709
+ "SkillCDN이 이 주소를 콘솔에 제공하지 않습니다. 그곳에 아무것도 없거나, 비공개 팩인데 읽을 SkillCDN 토큰이 프로젝트에도 워크스페이스에도 없습니다. 소유자가 설정 페이지에서 SkillCDN의 승인 코드로 연결합니다.",
634
710
  token_invalid:
635
- "프로젝트가 가진 팩 토큰이 SkillCDN에서 더 이상 통하지 않습니다. 만료되었거나 지워졌거나, 만든 사람이 저장소 권한을 잃었습니다. 소유자가 설정 페이지에서 새로 넣습니다.",
711
+ "이 팩을 읽는 SkillCDN 토큰이 SkillCDN에서 더 이상 통하지 않습니다. 만료되었거나 지워졌거나, 만든 사람이 저장소 권한을 잃었습니다. 소유자가 설정 페이지에서 새로 넣습니다.",
636
712
  unavailable:
637
713
  "SkillCDN에 연결할 수 없습니다. 스킬은 이전 상태 그대로입니다. 나중에 다시 보세요.",
638
714
  },
@@ -710,6 +786,7 @@ export const ko: Messages = {
710
786
  people: {
711
787
  title: "사람들",
712
788
  list: "사람들",
789
+ narrowed: "같은 프로젝트에 속한 사람들과 관리자입니다.",
713
790
  roleOf: (name) => `${name}의 역할`,
714
791
  letIn: "사람 추가",
715
792
  letInAria: "사람 추가",
package/src/index.ts CHANGED
@@ -82,7 +82,20 @@ export {
82
82
  goalMonth,
83
83
  } from "./components/goals.js";
84
84
  export { Markdown, type MarkdownProps } from "./components/markdown.js";
85
- export { PAGE_SIZE, ShowMore, usePaged } from "./components/paged.js";
85
+ export {
86
+ PackConnect,
87
+ type PackConnectProps,
88
+ type PackConnectState,
89
+ } from "./components/pack-connect.js";
90
+ export { PackTokenWays, type PackTokenWaysProps } from "./components/pack-token.js";
91
+ export {
92
+ PAGE_SIZE,
93
+ Pager,
94
+ pageOf,
95
+ RECORD_PAGE_SIZE,
96
+ ShowMore,
97
+ usePaged,
98
+ } from "./components/paged.js";
86
99
  export {
87
100
  ListingForm,
88
101
  type ListingFormProps,
@@ -193,6 +206,16 @@ export {
193
206
  Time,
194
207
  } from "./components/ui.js";
195
208
  export { WorkList, type WorkListProps } from "./components/work.js";
209
+ export {
210
+ DEFAULT_PEOPLE_VISIBILITY,
211
+ peopleVisibilityOf,
212
+ timeZoneOf,
213
+ WorkspaceSettingsForm,
214
+ type WorkspaceSettingsFormProps,
215
+ WorkspaceSettingsView,
216
+ type WorkspaceSettingsViewProps,
217
+ weekStartOf,
218
+ } from "./components/workspace.js";
196
219
  export { ConnectPage, type ConnectPageProps } from "./connect-page.js";
197
220
  export {
198
221
  type ConsoleApp,
@@ -246,6 +269,7 @@ export {
246
269
  customPageHref,
247
270
  type DocsView,
248
271
  decisionHref,
272
+ decisionsHref,
249
273
  docHref,
250
274
  GOAL_TASK_VIEWS,
251
275
  type GoalPageOptions,
package/src/router.ts CHANGED
@@ -5,7 +5,7 @@ import { isDay, isMonth } from "./dates.js";
5
5
  // route, and the hrefs below are its inverse. A project's pages live under `/projects/<key>`,
6
6
  // the word the REST API uses; an address names what it shows (a task by its number, a decision
7
7
  // by its id, a document by its path, a goal by its id), every form has one, and the query says
8
- // how a page is shown (`?edit`, `?ask`, `?new`, `?version=`, `?q=`, `?month=`, `?week=`, and the
8
+ // how a page is shown (`?edit`, `?ask`, `?new`, `?version=`, `?q=`, `?month=`, `?week=`, `?page=`, and the
9
9
  // board's filters). The old addresses are taken to the new.
10
10
 
11
11
  /** How a task's page is shown: as it is, or with one of its forms open. */
@@ -49,7 +49,8 @@ export type Route =
49
49
  readonly path: string;
50
50
  readonly view: DocsView;
51
51
  }
52
- | { readonly name: "decisions"; readonly project: string }
52
+ /** The decisions of a project: the waiting ones, and the record on one of its pages, the first when the address names none. */
53
+ | { readonly name: "decisions"; readonly project: string; readonly page: number | undefined }
53
54
  | { readonly name: "new-decision"; readonly project: string }
54
55
  | { readonly name: "decision"; readonly project: string; readonly id: string }
55
56
  /** The calendar of a project: the month shown, or this one when the address names none, narrowed as the board is. */
@@ -82,8 +83,11 @@ export type Route =
82
83
  readonly project: string;
83
84
  readonly form: "edit" | "rules" | "pack-token" | undefined;
84
85
  }
85
- /** The workspace's settings: its rules, its categories, its skills; or the form the rules are written on. */
86
- | { readonly name: "workspace-settings"; readonly form: "rules" | undefined }
86
+ /** The workspace's settings: its own, its rules, its categories, its skills; or the form the rules, or the settings (ADR-0035), are written on. */
87
+ | {
88
+ readonly name: "workspace-settings";
89
+ readonly form: "rules" | "workspace" | "pack-token" | undefined;
90
+ }
87
91
  | { readonly name: "people" }
88
92
  /** The form where an administrator lets someone in by login (ADR-0022). */
89
93
  | { readonly name: "new-listing" }
@@ -155,13 +159,10 @@ const NUMBER = /^[1-9][0-9]{0,8}$/;
155
159
  /** A code as it may be typed into an address: checked for what it is by the page. */
156
160
  const CODE_TEXT = /^[A-Za-z0-9-]{1,16}$/;
157
161
  /** The pages of a project that take nothing after their name. */
158
- const PLAIN_PAGES: readonly Exclude<ProjectPage, "docs" | "calendar" | "roadmap" | "settings">[] = [
159
- "decisions",
160
- "archive",
161
- "feed",
162
- "skills",
163
- "members",
164
- ];
162
+ const PLAIN_PAGES: readonly Exclude<
163
+ ProjectPage,
164
+ "docs" | "decisions" | "calendar" | "roadmap" | "settings"
165
+ >[] = ["archive", "feed", "skills", "members"];
165
166
  const NOT_FOUND: Route = { name: "not-found" };
166
167
 
167
168
  /** Where an address of the 0.1 line before this one leads now, or nothing for a current one. */
@@ -254,7 +255,16 @@ export function matchRoute(pathname: string, search = ""): Route {
254
255
  return { name: "categories" };
255
256
  }
256
257
  if (path === PATHS.settings) {
257
- return { name: "workspace-settings", form: params.has("rules") ? "rules" : undefined };
258
+ return {
259
+ name: "workspace-settings",
260
+ form: params.has("workspace")
261
+ ? "workspace"
262
+ : params.has("rules")
263
+ ? "rules"
264
+ : params.has("pack-token")
265
+ ? "pack-token"
266
+ : undefined,
267
+ };
258
268
  }
259
269
  if (path === PATHS.connect) {
260
270
  return { name: "connect", code: undefined };
@@ -386,6 +396,13 @@ export function matchRoute(pathname: string, search = ""): Route {
386
396
  : undefined,
387
397
  };
388
398
  }
399
+ if (page === "decisions") {
400
+ const turned = params.get("page");
401
+ if (turned !== null && !NUMBER.test(turned)) {
402
+ return NOT_FOUND;
403
+ }
404
+ return { name: "decisions", project, page: turned === null ? undefined : Number(turned) };
405
+ }
389
406
  const found = PLAIN_PAGES.find((candidate) => candidate === page);
390
407
  return found === undefined ? NOT_FOUND : { name: found, project };
391
408
  }
@@ -418,8 +435,8 @@ export function projectSettingsHref(key: string, form?: "edit" | "rules" | "pack
418
435
  return form === undefined ? base : `${base}?${form}`;
419
436
  }
420
437
 
421
- /** Where the workspace's settings are, or the form its rules are written on. */
422
- export function settingsHref(form?: "rules"): string {
438
+ /** Where the workspace's settings are, or the form its rules, or its own settings, are written on. */
439
+ export function settingsHref(form?: "rules" | "workspace" | "pack-token"): string {
423
440
  return form === undefined ? PATHS.settings : `${PATHS.settings}?${form}`;
424
441
  }
425
442
 
@@ -469,6 +486,12 @@ export function decisionHref(key: string, id: string): string {
469
486
  return `${PATHS.project}/${key}/decisions/${id}`;
470
487
  }
471
488
 
489
+ /** Where a project's decisions are: the waiting ones and the record, on one of its pages, or on the first when none is named. */
490
+ export function decisionsHref(key: string, page?: number): string {
491
+ const base = projectHref(key, "decisions");
492
+ return page === undefined || page <= 1 ? base : `${base}?page=${page}`;
493
+ }
494
+
472
495
  /** Where the person's own work is, with the week of a day at the top, or this week's when none is named. */
473
496
  export function workHref(week?: string): string {
474
497
  return week === undefined ? PATHS.work : `${PATHS.work}?week=${week}`;
package/src/routes.ts CHANGED
@@ -9,6 +9,10 @@ export const REST_ROUTES = {
9
9
  me: "/api/v1/me",
10
10
  /** The token a request is made with, for it to give itself up. */
11
11
  meToken: "/api/v1/me/token",
12
+ /** The workspace's settings (ADR-0035), changed by an administrator; read through `me`. */
13
+ workspace: "/api/v1/workspace",
14
+ /** The SkillCDN token the organization's pack is read with (ADR-0036), an administrator's; `/connect` under it connects one with a code. */
15
+ workspacePackToken: "/api/v1/workspace/pack-token",
12
16
  /** The people of the workspace: everyone who has signed in, and the logins let in that have not. */
13
17
  people: "/api/v1/people",
14
18
  /** The logins an administrator let in (ADR-0022), made and removed by one. */