@skillcdn/console 0.1.13 → 0.1.15

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 (170) hide show
  1. package/README.md +5 -4
  2. package/SKILLCDN.md +2 -0
  3. package/dist/agent-name.d.ts +3 -0
  4. package/dist/agent-name.d.ts.map +1 -0
  5. package/dist/agent-name.js +9 -0
  6. package/dist/agent-name.js.map +1 -0
  7. package/dist/api.d.ts +6 -4
  8. package/dist/api.d.ts.map +1 -1
  9. package/dist/api.js +6 -4
  10. package/dist/api.js.map +1 -1
  11. package/dist/cli/cli.d.ts +2 -0
  12. package/dist/cli/cli.d.ts.map +1 -1
  13. package/dist/cli/cli.js +215 -22
  14. package/dist/cli/cli.js.map +1 -1
  15. package/dist/cli/format.d.ts +14 -4
  16. package/dist/cli/format.d.ts.map +1 -1
  17. package/dist/cli/format.js +59 -10
  18. package/dist/cli/format.js.map +1 -1
  19. package/dist/cli/help.d.ts.map +1 -1
  20. package/dist/cli/help.js +27 -11
  21. package/dist/cli/help.js.map +1 -1
  22. package/dist/cli/main.js +5 -0
  23. package/dist/cli/main.js.map +1 -1
  24. package/dist/client.d.ts +20 -2
  25. package/dist/client.d.ts.map +1 -1
  26. package/dist/client.js +11 -2
  27. package/dist/client.js.map +1 -1
  28. package/dist/components/calendar.d.ts +15 -0
  29. package/dist/components/calendar.d.ts.map +1 -1
  30. package/dist/components/calendar.js +78 -41
  31. package/dist/components/calendar.js.map +1 -1
  32. package/dist/components/connect.d.ts +4 -1
  33. package/dist/components/connect.d.ts.map +1 -1
  34. package/dist/components/connect.js +7 -3
  35. package/dist/components/connect.js.map +1 -1
  36. package/dist/components/decision-list.d.ts.map +1 -1
  37. package/dist/components/decision-list.js +3 -3
  38. package/dist/components/decision-list.js.map +1 -1
  39. package/dist/components/documents.d.ts +5 -0
  40. package/dist/components/documents.d.ts.map +1 -1
  41. package/dist/components/documents.js +3 -2
  42. package/dist/components/documents.js.map +1 -1
  43. package/dist/components/event-feed.d.ts +1 -1
  44. package/dist/components/event-feed.d.ts.map +1 -1
  45. package/dist/components/event-feed.js +10 -1
  46. package/dist/components/event-feed.js.map +1 -1
  47. package/dist/components/people.d.ts +24 -1
  48. package/dist/components/people.d.ts.map +1 -1
  49. package/dist/components/people.js +35 -3
  50. package/dist/components/people.js.map +1 -1
  51. package/dist/components/projects.d.ts +6 -0
  52. package/dist/components/projects.d.ts.map +1 -1
  53. package/dist/components/projects.js +3 -3
  54. package/dist/components/projects.js.map +1 -1
  55. package/dist/components/rules.d.ts +40 -0
  56. package/dist/components/rules.d.ts.map +1 -0
  57. package/dist/components/rules.js +46 -0
  58. package/dist/components/rules.js.map +1 -0
  59. package/dist/components/runs.d.ts +1 -1
  60. package/dist/components/runs.d.ts.map +1 -1
  61. package/dist/components/runs.js +2 -1
  62. package/dist/components/runs.js.map +1 -1
  63. package/dist/components/skills.d.ts.map +1 -1
  64. package/dist/components/skills.js +5 -1
  65. package/dist/components/skills.js.map +1 -1
  66. package/dist/components/tokens.d.ts.map +1 -1
  67. package/dist/components/tokens.js +2 -9
  68. package/dist/components/tokens.js.map +1 -1
  69. package/dist/components/ui.d.ts +7 -2
  70. package/dist/components/ui.d.ts.map +1 -1
  71. package/dist/components/ui.js +13 -0
  72. package/dist/components/ui.js.map +1 -1
  73. package/dist/components/work.d.ts +9 -1
  74. package/dist/components/work.d.ts.map +1 -1
  75. package/dist/components/work.js +8 -3
  76. package/dist/components/work.js.map +1 -1
  77. package/dist/connect-page.d.ts.map +1 -1
  78. package/dist/connect-page.js +1 -1
  79. package/dist/connect-page.js.map +1 -1
  80. package/dist/console.css +253 -13
  81. package/dist/console.d.ts.map +1 -1
  82. package/dist/console.js +203 -49
  83. package/dist/console.js.map +1 -1
  84. package/dist/data.d.ts +19 -2
  85. package/dist/data.d.ts.map +1 -1
  86. package/dist/data.js +27 -1
  87. package/dist/data.js.map +1 -1
  88. package/dist/dates.d.ts +4 -0
  89. package/dist/dates.d.ts.map +1 -1
  90. package/dist/dates.js +26 -0
  91. package/dist/dates.js.map +1 -1
  92. package/dist/i18n/en.d.ts +90 -28
  93. package/dist/i18n/en.d.ts.map +1 -1
  94. package/dist/i18n/en.js +89 -31
  95. package/dist/i18n/en.js.map +1 -1
  96. package/dist/i18n/ko.d.ts.map +1 -1
  97. package/dist/i18n/ko.js +89 -31
  98. package/dist/i18n/ko.js.map +1 -1
  99. package/dist/index.d.ts +6 -5
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.js +6 -5
  102. package/dist/index.js.map +1 -1
  103. package/dist/limits.d.ts +4 -0
  104. package/dist/limits.d.ts.map +1 -1
  105. package/dist/limits.js +4 -0
  106. package/dist/limits.js.map +1 -1
  107. package/dist/router.d.ts +34 -2
  108. package/dist/router.d.ts.map +1 -1
  109. package/dist/router.js +55 -7
  110. package/dist/router.js.map +1 -1
  111. package/dist/routes.d.ts +14 -4
  112. package/dist/routes.d.ts.map +1 -1
  113. package/dist/routes.js +17 -2
  114. package/dist/routes.js.map +1 -1
  115. package/dist/rules.d.ts +28 -0
  116. package/dist/rules.d.ts.map +1 -0
  117. package/dist/rules.js +102 -0
  118. package/dist/rules.js.map +1 -0
  119. package/dist/schemas.d.ts +652 -4
  120. package/dist/schemas.d.ts.map +1 -1
  121. package/dist/schemas.js +96 -6
  122. package/dist/schemas.js.map +1 -1
  123. package/dist/vocabulary.d.ts +21 -1
  124. package/dist/vocabulary.d.ts.map +1 -1
  125. package/dist/vocabulary.js +21 -0
  126. package/dist/vocabulary.js.map +1 -1
  127. package/docs/specs/cli.md +13 -9
  128. package/docs/specs/rest.md +32 -8
  129. package/package.json +1 -1
  130. package/skills/building-a-console/SKILL.md +1 -1
  131. package/skills/deploying-a-console/SKILL.md +5 -5
  132. package/skills/deploying-a-console/assets/secrets.example.json +2 -1
  133. package/skills/deploying-a-console/references/access.md +10 -6
  134. package/skills/deploying-a-console/references/resources.md +10 -7
  135. package/skills/working-the-board/SKILL.md +10 -9
  136. package/skills/working-the-board/references/project-rules.md +36 -0
  137. package/src/agent-name.ts +9 -0
  138. package/src/api.ts +37 -0
  139. package/src/cli/cli.ts +253 -24
  140. package/src/cli/format.ts +74 -10
  141. package/src/cli/help.ts +30 -10
  142. package/src/cli/main.ts +5 -0
  143. package/src/client.ts +47 -1
  144. package/src/components/calendar.tsx +242 -101
  145. package/src/components/connect.tsx +12 -6
  146. package/src/components/decision-list.tsx +2 -2
  147. package/src/components/documents.tsx +7 -3
  148. package/src/components/event-feed.tsx +16 -3
  149. package/src/components/people.tsx +244 -35
  150. package/src/components/projects.tsx +31 -8
  151. package/src/components/rules.tsx +167 -0
  152. package/src/components/runs.tsx +4 -2
  153. package/src/components/skills.tsx +22 -11
  154. package/src/components/tokens.tsx +2 -14
  155. package/src/components/ui.tsx +25 -2
  156. package/src/components/work.tsx +69 -43
  157. package/src/connect-page.tsx +0 -1
  158. package/src/console.tsx +531 -67
  159. package/src/data.ts +52 -2
  160. package/src/dates.ts +28 -0
  161. package/src/i18n/en.ts +99 -38
  162. package/src/i18n/ko.ts +95 -38
  163. package/src/index.ts +21 -1
  164. package/src/limits.ts +4 -0
  165. package/src/router.ts +77 -12
  166. package/src/routes.ts +23 -3
  167. package/src/rules.ts +109 -0
  168. package/src/schemas.ts +121 -4
  169. package/src/styles/console.css +253 -13
  170. package/src/vocabulary.ts +30 -0
package/src/i18n/ko.ts CHANGED
@@ -18,6 +18,7 @@ export const ko: Messages = {
18
18
  },
19
19
  priority: { low: "낮음", normal: "보통", high: "높음", urgent: "긴급" },
20
20
  role: { admin: "관리자", member: "멤버" },
21
+ status: { active: "활성", deactivated: "비활성화" },
21
22
  projectRole: { owner: "소유자", member: "멤버" },
22
23
  visibility: { workspace: "워크스페이스의 모두", private: "목록에 있는 사람만" },
23
24
  runStatus: {
@@ -68,6 +69,8 @@ export const ko: Messages = {
68
69
  nobody: "없음",
69
70
  nothing: "없음",
70
71
  language: "언어",
72
+ copy: "복사",
73
+ copied: "복사됨",
71
74
  showMore: (n, of) => `${of}개 중 ${n}개 더 보기`,
72
75
  },
73
76
 
@@ -76,7 +79,6 @@ export const ko: Messages = {
76
79
  work: "내 작업",
77
80
  people: "사람들",
78
81
  agents: "에이전트",
79
- categories: "카테고리",
80
82
  board: "보드",
81
83
  roadmap: "로드맵",
82
84
  calendar: "캘린더",
@@ -116,13 +118,13 @@ export const ko: Messages = {
116
118
  projects: {
117
119
  title: "프로젝트",
118
120
  newProject: "새 프로젝트",
119
- lead: "프로젝트는 보드, 문서, 스킬, 사람들을 가집니다. 무엇을 보고 바꿀 수 있는지는 프로젝트마다 정해집니다. 소유자는 설정하고, 멤버는 일합니다.",
120
121
  empty: {
121
122
  title: "아직 프로젝트가 없습니다",
122
123
  body: "첫 프로젝트를 만드세요. 무엇을 위한 것인지, 누가 함께하는지. 또는 소유자에게 추가를 요청하세요.",
123
124
  },
124
125
  list: "프로젝트",
125
126
  private: "비공개",
127
+ public: "공개",
126
128
  decisionsWaiting: (n) => `결정 ${n}건 대기 중`,
127
129
  form: {
128
130
  aria: "새 프로젝트",
@@ -133,7 +135,11 @@ export const ko: Messages = {
133
135
  descriptionPlaceholder: "이 프로젝트가 무엇을 위한 것인지, 한두 문장으로.",
134
136
  whoIsMember: "멤버 범위",
135
137
  skillsAddress: "스킬 주소",
136
- skillsAddressPlaceholder: "/gh/<owner>/<repo>, 비우면 조직의 스킬",
138
+ skillsAddressPlaceholder: "/gh/<owner>/<repo>",
139
+ skillsAddressHint: (address) =>
140
+ address === null
141
+ ? "비우면 이 프로젝트에 스킬이 없습니다. 콘솔에 조직의 주소가 없습니다."
142
+ : `비우면 조직의 스킬: ${address}`,
137
143
  symbol: "마크",
138
144
  image: "이미지",
139
145
  imageRemove: "이미지 지우기",
@@ -144,11 +150,6 @@ export const ko: Messages = {
144
150
  members: {
145
151
  title: "멤버",
146
152
  list: "멤버",
147
- leadWorkspace:
148
- "워크스페이스의 모두가 이 프로젝트의 멤버입니다. 여기 목록은 소유자와 따로 지정된 사람들입니다.",
149
- leadPrivate: "여기 목록에 있는 사람만 이 프로젝트에 속합니다.",
150
- leadRoles:
151
- "소유자는 프로젝트를 설정하고, 멤버는 프로젝트에서 일합니다. 워크스페이스 관리자는 모든 프로젝트의 소유자입니다.",
152
153
  since: "부터",
153
154
  roleOf: (name) => `${name}의 역할`,
154
155
  addAria: "멤버 추가",
@@ -165,13 +166,9 @@ export const ko: Messages = {
165
166
  settings: {
166
167
  title: "설정",
167
168
  aria: "프로젝트 설정",
168
- leadBefore: "키 ",
169
- leadAfter:
170
- "는 주소와 명령이 부르는 이름이며 바뀌지 않습니다. 스킬 주소는 SkillCDN이 제공하는 저장소를 가리킵니다. 비우면 조직의 스킬이 보입니다.",
171
- onlyOwner: {
172
- title: "소유자만 프로젝트를 바꿀 수 있습니다",
173
- body: "소유자나 워크스페이스 관리자에게 요청하세요.",
174
- },
169
+ edit: "프로젝트 편집",
170
+ organizationsSkills: (address) => `조직의 스킬: ${address}`,
171
+ noSkills: "없음: 콘솔에 조직의 주소가 없습니다.",
175
172
  },
176
173
  },
177
174
 
@@ -277,8 +274,6 @@ export const ko: Messages = {
277
274
  waiting: "대기 중",
278
275
  answered: "답변됨",
279
276
  record: "기록",
280
- recordLead:
281
- "답변된 모든 결정, 최신순. 무엇을 물었고, 무엇을 골랐고, 누가 골랐는지. 맥락과 근거, 그 뒤에 일어난 일은 각 결정을 열어 봅니다.",
282
277
  openRecord: "열기",
283
278
  waitingForPerson: "사람을 기다리는 중입니다.",
284
279
  options: "선택지",
@@ -309,10 +304,8 @@ export const ko: Messages = {
309
304
 
310
305
  calendar: {
311
306
  title: "캘린더",
312
- lead: "작업을 날짜 위에 놓고 봅니다. 시작일과 기한이 있는 작업은 그 기간에 걸쳐 놓이고, 기한만 있는 작업은 그날에 놓입니다. 날짜가 없는 작업은 아래에서 날짜를 기다립니다.",
313
307
  grid: "이 달",
314
308
  legend: { title: "카테고리 색" },
315
- startsOnly: "그날 시작, 기한은 아직 없음",
316
309
  previous: "이전 달",
317
310
  next: "다음 달",
318
311
  thisMonth: "이번 달",
@@ -321,9 +314,15 @@ export const ko: Messages = {
321
314
  nothingOverdue: "기한이 지난 작업이 없습니다.",
322
315
  unscheduled: "날짜 없음",
323
316
  allScheduled: "열린 작업마다 날짜가 있습니다.",
317
+ week: {
318
+ title: "이 주",
319
+ previous: "이전 주",
320
+ next: "다음 주",
321
+ thisWeek: "이번 주",
322
+ nothing: "이 주에 잡힌 작업이 없습니다.",
323
+ },
324
324
  workload: {
325
325
  title: "누가 무엇을",
326
- lead: "사람마다 열린 작업과, 그중 늦은 것과 일주일 안에 마감인 것.",
327
326
  person: "사람",
328
327
  open: "열림",
329
328
  inProgress: "진행 중",
@@ -335,7 +334,6 @@ export const ko: Messages = {
335
334
 
336
335
  roadmap: {
337
336
  title: "로드맵",
338
- lead: "프로젝트가 향하는 것. 목표마다 달성 목표일과, 그 아래 작업들이 어디까지 왔는지. 진행은 보드의 현재 상태에서 그대로 읽습니다.",
339
337
  setGoal: "목표 세우기",
340
338
  setGoalAria: "목표 세우기",
341
339
  editAria: "목표 바꾸기",
@@ -374,7 +372,6 @@ export const ko: Messages = {
374
372
 
375
373
  work: {
376
374
  title: "내 작업",
377
- lead: "내 프로젝트들에 걸쳐 내게 놓인 일. 내게 배정된 열린 작업을 기한순으로, 그리고 사람을 기다리는 결정.",
378
375
  loading: "내 작업을 불러오는 중",
379
376
  couldNotLoad: "내 작업을 불러올 수 없습니다.",
380
377
  empty: {
@@ -392,8 +389,6 @@ export const ko: Messages = {
392
389
 
393
390
  categories: {
394
391
  title: "카테고리",
395
- lead: "작업을 나누는 일의 종류이며, 모든 프로젝트에서 같습니다. 작업은 하나를 가지고, 보드는 하나로 좁혀 보며, 관리자가 목록을 관리합니다.",
396
- onlyAdmin: "관리자가 추가하고 바꾸고 제거합니다. 다른 사람은 여기서 읽습니다.",
397
392
  list: "카테고리",
398
393
  add: "카테고리 추가",
399
394
  addAria: "카테고리 추가",
@@ -401,7 +396,6 @@ export const ko: Messages = {
401
396
  title: "카테고리가 없습니다",
402
397
  body: "관리자가 여기서 첫 카테고리를 추가합니다.",
403
398
  },
404
- inUse: "작업이 속해 있는 카테고리는 그 작업들을 옮기기 전에는 제거할 수 없습니다.",
405
399
  form: {
406
400
  name: "이름",
407
401
  key: "키",
@@ -413,6 +407,39 @@ export const ko: Messages = {
413
407
  colorOf: (key) => `${key}의 색`,
414
408
  },
415
409
 
410
+ settings: {
411
+ title: "설정",
412
+ categories: "카테고리",
413
+ manageCategories: "카테고리 관리",
414
+ skills: "스킬",
415
+ skillsSource: "SkillCDN 제공 주소",
416
+ skillsAddress: "조직의 스킬",
417
+ noSkillsAddress: "주소 없음: 프로젝트마다 자기 주소를 두거나, 두지 않습니다.",
418
+ skillsFromConfiguration:
419
+ "콘솔을 운영하는 쪽이 설정으로 정합니다. 스킬을 읽어 오는 배포와 조직의 주소.",
420
+ },
421
+
422
+ rules: {
423
+ title: "규칙",
424
+ loading: "규칙을 불러오는 중",
425
+ reference:
426
+ "관리자가 조직의 규칙을 쓰기 전까지 콘솔의 기본 규칙이 적용됩니다. 콘솔 버전과 함께 바뀝니다.",
427
+ writeOrganizations: "조직의 규칙 쓰기",
428
+ useReference: "콘솔의 기본 규칙으로 초기화",
429
+ read: "규칙 읽기",
430
+ none: "이 프로젝트에 더하는 규칙이 없습니다. 워크스페이스의 규칙이 적용됩니다.",
431
+ write: "이 프로젝트의 규칙 쓰기",
432
+ projectRules: "이 프로젝트의 규칙",
433
+ workspaceRules: "워크스페이스의 규칙",
434
+ onWorkspaceSettings: "워크스페이스 설정에서 바꿉니다.",
435
+ form: {
436
+ body: "규칙",
437
+ hint: (max) =>
438
+ `Markdown, 최대 ${max}자. 여기서 일하는 모든 에이전트가 먼저 읽습니다. 먼저 불러올 스킬, 일이 있는 곳, 페이지, 혼자 정할 것, 보고 방식. {language}는 에이전트가 대신 일하는 사람의 언어로 바뀝니다. 토큰이나 비밀번호 같은 민감한 정보는 넣지 않습니다.`,
439
+ save: "규칙 저장",
440
+ },
441
+ },
442
+
416
443
  feed: {
417
444
  title: "일어난 일",
418
445
  list: "일어난 일",
@@ -457,6 +484,10 @@ export const ko: Messages = {
457
484
  event: {
458
485
  personJoined: () => "보드에 들어왔습니다",
459
486
  roleChanged: (login, role) => `${login}을(를) ${role}(으)로 지정했습니다`,
487
+ personListed: (login) => `${login}을(를) 추가했습니다`,
488
+ personUnlisted: (login) => `${login}을(를) 목록에서 뺐습니다`,
489
+ personDeactivated: (login) => `${login}을(를) 비활성화했습니다`,
490
+ personReactivated: (login) => `${login}을(를) 다시 활성화했습니다`,
460
491
  projectCreated: (project) => `프로젝트 ${project}을(를) 만들었습니다`,
461
492
  projectUpdated: (fields, project) => `프로젝트 ${project}의 ${fields}을(를) 바꿨습니다`,
462
493
  memberAdded: (login, project, role) =>
@@ -511,10 +542,10 @@ export const ko: Messages = {
511
542
  title: "아직 스킬 주소가 없습니다",
512
543
  body: "이 콘솔에는 조직의 스킬 주소가 없습니다. 운영자가 설정에서 SkillCDN이 제공하는 저장소를 지정합니다.",
513
544
  },
514
- servedBy: "조직의 스킬. 제공:",
545
+ servedBy: "제공:",
515
546
  at: "주소:",
516
- howLoaded:
517
- ". 에이전트는 SkillCDN 연결을 통해 스킬을 불러오고, 사람은 해당 페이지에서 읽습니다.",
547
+ connect: "에이전트는 이 주소에 자기 MCP 연결로 스킬을 받습니다. 사람이 한 번 연결해 줍니다:",
548
+ connectLink: "SkillCDN 페이지의 연결 안내",
518
549
  status: {
519
550
  indexing: "SkillCDN이 아직 저장소를 색인하고 있습니다. 잠시 후 다시 보세요.",
520
551
  failed: "SkillCDN이 저장소를 색인하지 못했습니다. 찾은 내용은 주소의 페이지에 있습니다.",
@@ -592,12 +623,44 @@ export const ko: Messages = {
592
623
  people: {
593
624
  title: "사람들",
594
625
  list: "사람들",
595
- lead: "로그인한 모든 사람. 관리자는 워크스페이스를 설정하고 각 사람의 역할을 정합니다. 멤버는 속한 프로젝트에서 일합니다. 사람이 할 수 있는 일은 그 사람의 에이전트도 할 수 있습니다.",
596
626
  roleOf: (name) => `${name}의 역할`,
627
+ letIn: "사람 추가",
628
+ letInAria: "사람 추가",
629
+ notSignedIn: "추가됨, 아직 로그인하지 않음",
630
+ deactivated: "비활성화됨",
631
+ deactivate: "비활성화",
632
+ reactivate: "다시 활성화",
633
+ leftOrganization: "조직에서 나감",
634
+ source: {
635
+ organization: "조직의 구성원",
636
+ domain: "도메인의 계정",
637
+ listed: "관리자가 추가함",
638
+ },
639
+ at: { gh: "GitHub", google: "Google" },
640
+ organization: (name) => `GitHub 조직 ${name}이(가) 구성원을 정합니다.`,
641
+ organizationRead: "마지막으로 읽음",
642
+ organizationNotRead: "아직 읽지 않았습니다.",
643
+ form: {
644
+ login: "로그인 아이디 또는 주소",
645
+ provider: "로그인 방식",
646
+ byShape: "아이디 모양대로",
647
+ hint: "GitHub 아이디나 Google 주소. 그 계정으로 로그인하는 사람이 들어옵니다.",
648
+ submit: "추가",
649
+ },
650
+ work: "작업",
651
+ workOf: (name) => `${name}의 작업`,
652
+ loadingWork: "작업을 불러오는 중",
653
+ couldNotLoadWork: "작업을 불러올 수 없습니다.",
654
+ noWork: {
655
+ title: (name) => `${name}에게 배정된 작업이 없습니다`,
656
+ body: "내가 볼 수 있는 프로젝트에서 그 사람에게 배정된 열린 작업이 여기에 나타납니다.",
657
+ },
658
+ notOverseen: {
659
+ title: "볼 수 없는 작업입니다",
660
+ body: "관리자는 모든 사람의 작업을, 소유자는 자기 프로젝트에 속한 사람의 작업을 봅니다.",
661
+ },
597
662
  agents: "에이전트",
598
663
  agentsOf: (name) => `${name}의 에이전트`,
599
- agentsLead: (name) =>
600
- `${name}(으)로 여기서 일하는 것들입니다. 각각 고유한 토큰을 가집니다. 연결을 끊으면 토큰이 즉시 사라집니다.`,
601
664
  loadingAgents: "에이전트를 불러오는 중",
602
665
  noAgent: "연결된 에이전트가 없습니다",
603
666
  onlyAdmin: {
@@ -610,7 +673,6 @@ export const ko: Messages = {
610
673
  title: "에이전트",
611
674
  makeByHand: "토큰 직접 만들기",
612
675
  makeAria: "토큰 만들기",
613
- lead: "나로서 여기서 일하는 것들입니다. 연결한 각 에이전트는 아무도 볼 수 없는 고유한 토큰을 가집니다. 내가 할 수 있는 일은 에이전트도 할 수 있습니다. 더 쓰지 않으면 여기서 연결을 끊으세요. 내 스크립트나 콘솔도 직접 만든 토큰으로 같은 방식으로 일합니다.",
614
676
  empty: {
615
677
  title: "아직 연결된 에이전트가 없습니다",
616
678
  body: "아래처럼 에이전트에게 이 콘솔에 연결하라고 말하면 여기에 나타납니다.",
@@ -632,8 +694,6 @@ export const ko: Messages = {
632
694
  fresh: {
633
695
  ready: (name) => `토큰 "${name}"이(가) 준비됐습니다`,
634
696
  copyNow: "지금 복사하세요. 이번 한 번만 보이며, 콘솔은 해시만 보관합니다.",
635
- copy: "복사",
636
- copied: "복사됨",
637
697
  useIt:
638
698
  "이 토큰으로 console 명령을 로그인시키거나, REST API에 bearer 토큰으로 제시하거나, 내 콘솔이나 스크립트에 주세요.",
639
699
  removeWhenDone: "만료되지 않으니, 더 쓰지 않게 되면 여기서 제거하세요.",
@@ -645,7 +705,6 @@ export const ko: Messages = {
645
705
  connect: {
646
706
  title: "에이전트 연결",
647
707
  aria: "연결",
648
- lead: "에이전트에게 이 콘솔에 연결하라고 말하면 코드를 보여 줍니다. 그 코드를 여기에 입력하고, 에이전트가 나로서 일해도 되는지 답하세요.",
649
708
  codeAria: "코드",
650
709
  codeLabel: "에이전트가 보여 준 코드",
651
710
  continue: "계속",
@@ -679,11 +738,9 @@ export const ko: Messages = {
679
738
  title: "에이전트 연결하기",
680
739
  tellYourAgent: "에이전트의 대화창에서 이렇게 말하세요:",
681
740
  quote: (origin) =>
682
- `npm으로 @skillcdn/console을 설치하고, console login --url ${origin} 을 실행한 뒤 나오는 주소와 코드를 알려줘.`,
741
+ `이 두 명령을 실행하고, 두 번째 명령이 보여 주는 주소와 코드를 알려 줘:\nnpm install -g @skillcdn/console\nconsole login --url ${origin}`,
683
742
  doesTheRest:
684
743
  "명령을 실행할 수 있는 에이전트는 나머지를 알아서 합니다. 명령을 설치하고, 연결하고, 코드가 있는 주소를 보여 줍니다.",
685
- thenApprove:
686
- "여기에 로그인한 채 그 주소를 열고, 페이지에 같은 코드가 보이는지 확인하고, 에이전트에게 이름을 붙이고, 승인하세요. 그때부터 에이전트는 내가 할 수 있는 범위 안에서 나로서 여기서 일합니다. 더 쓰지 않으면 이 페이지에서 연결을 끊으세요. 에이전트가 가진 토큰은 나를 포함해 아무에게도 보이지 않습니다.",
687
744
  byHand: "에이전트가 명령을 대신 실행하지 않는다면, 직접:",
688
745
  },
689
746
  },
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,
@@ -67,7 +69,12 @@ export {
67
69
  } from "./components/goals.js";
68
70
  export { Markdown, type MarkdownProps } from "./components/markdown.js";
69
71
  export { PAGE_SIZE, ShowMore, usePaged } from "./components/paged.js";
70
- export { PeopleList, type PeopleListProps } from "./components/people.js";
72
+ export {
73
+ ListingForm,
74
+ type ListingFormProps,
75
+ PeopleList,
76
+ type PeopleListProps,
77
+ } from "./components/people.js";
71
78
  export {
72
79
  keyOf,
73
80
  MemberList,
@@ -81,6 +88,12 @@ export {
81
88
  ProjectRoleBadge,
82
89
  VISIBILITY_LABELS,
83
90
  } from "./components/projects.js";
91
+ export {
92
+ RulesForm,
93
+ type RulesFormProps,
94
+ RulesView,
95
+ type RulesViewProps,
96
+ } from "./components/rules.js";
84
97
  export {
85
98
  RUN_STATUS_LABELS,
86
99
  RunCard,
@@ -116,6 +129,7 @@ export {
116
129
  Button,
117
130
  Callout,
118
131
  CategoryBadge,
132
+ CopyButton,
119
133
  cx,
120
134
  Day,
121
135
  DueBadge,
@@ -156,6 +170,7 @@ export {
156
170
  daysBetween,
157
171
  firstDayOfWeek,
158
172
  formatDay,
173
+ formatDays,
159
174
  formatMonth,
160
175
  formatWeekday,
161
176
  type GridDay,
@@ -165,6 +180,7 @@ export {
165
180
  monthOf,
166
181
  today,
167
182
  weekdays,
183
+ weekOf,
168
184
  } from "./dates.js";
169
185
  export { DocsPage, type DocsPageProps } from "./docs-page.js";
170
186
  export {
@@ -198,11 +214,15 @@ export {
198
214
  PATHS,
199
215
  type ProjectPage,
200
216
  personAgentsHref,
217
+ personWorkHref,
201
218
  projectHref,
219
+ projectSettingsHref,
202
220
  type Route,
221
+ settingsHref,
203
222
  signInFailureOf,
204
223
  type TaskFormKind,
205
224
  taskHref,
206
225
  withoutSignInParam,
226
+ workHref,
207
227
  } from "./router.js";
208
228
  export { errorWords, useAction } from "./use-action.js";
package/src/limits.ts CHANGED
@@ -33,6 +33,8 @@ export const MAX_FILE_BYTES = 10 * 1024 * 1024;
33
33
  export const MAX_FILE_NAME_LENGTH = 200;
34
34
  /** What a person calls a token: the agent it is for, where it runs. One line. */
35
35
  export const MAX_TOKEN_NAME_LENGTH = 80;
36
+ /** A login at a git host, or an address at a Workspace, as an administrator lists one. */
37
+ export const MAX_LOGIN_LENGTH = 254;
36
38
  /** How long a token may be good for, in days, and how long one is when nothing is said. */
37
39
  export const MAX_TOKEN_DAYS = 365;
38
40
  export const DEFAULT_TOKEN_DAYS = 90;
@@ -54,6 +56,8 @@ export const MAX_DOCUMENT_PATH_LENGTH = 200;
54
56
  export const MAX_DOCUMENT_SEGMENT_LENGTH = 64;
55
57
  /** A document's body: a page of Markdown. */
56
58
  export const MAX_DOCUMENT_LENGTH = 64_000;
59
+ /** The rules of a board, the workspace's or a project's (ADR-0023): kept short, since every agent reads them. */
60
+ export const MAX_RULES_LENGTH = 12_000;
57
61
  /** How many versions one document keeps, and how many files attach to one. */
58
62
  export const MAX_VERSIONS_PER_DOCUMENT = 500;
59
63
  export const MAX_FILES_PER_DOCUMENT = 50;
package/src/router.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { isFolderPath, isSignInFailure, SIGN_IN_PARAM, type SignInFailure } from "./api.js";
2
- import { isMonth } from "./dates.js";
2
+ import { isDay, isMonth } from "./dates.js";
3
3
 
4
4
  // The addresses of the default console (ADR-0010): the router is a function from a URL to a
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=`, and the board's
9
- // filters). The old addresses are taken to the new.
8
+ // how a page is shown (`?edit`, `?ask`, `?new`, `?version=`, `?q=`, `?month=`, `?week=`, and the
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. */
12
12
  export type TaskFormKind = "edit" | "ask";
@@ -70,14 +70,26 @@ export type Route =
70
70
  | { readonly name: "feed"; readonly project: string }
71
71
  | { readonly name: "skills"; readonly project: string }
72
72
  | { readonly name: "members"; readonly project: string }
73
- | { readonly name: "settings"; readonly project: string }
73
+ /** A project's settings, read; or one of its forms open: the project's own, or its rules (ADR-0023). */
74
+ | {
75
+ readonly name: "settings";
76
+ readonly project: string;
77
+ readonly form: "edit" | "rules" | undefined;
78
+ }
79
+ /** The workspace's settings: its rules, its categories, its skills; or the form the rules are written on. */
80
+ | { readonly name: "workspace-settings"; readonly form: "rules" | undefined }
74
81
  | { readonly name: "people" }
82
+ /** The form where an administrator lets someone in by login (ADR-0022). */
83
+ | { readonly name: "new-listing" }
75
84
  /** The agents of one person, for an administrator. */
76
85
  | { readonly name: "person-agents"; readonly id: string }
86
+ /** Another person's plate, for whoever oversees them: a day of the week shown at the top, or today's. */
87
+ | { readonly name: "person-work"; readonly id: string; readonly week: string | undefined }
77
88
  | { readonly name: "agents" }
78
89
  | { readonly name: "new-token" }
79
90
  /** What is on the person's plate across their projects. */
80
- | { readonly name: "work" }
91
+ /** What is on the person's plate: a day of the week shown at the top, or today's when the address names none. */
92
+ | { readonly name: "work"; readonly week: string | undefined }
81
93
  /** The categories tasks are sorted into; an administrator keeps them here. */
82
94
  | { readonly name: "categories" }
83
95
  /** Where a person approves an agent's connection, by the code it showed, or types one. */
@@ -114,12 +126,16 @@ export const PATHS = {
114
126
  /** What is on the person's plate, across the projects they may see. */
115
127
  work: "/work",
116
128
  people: "/people",
129
+ /** The form where an administrator lets someone in by login. */
130
+ newListing: "/people/new",
117
131
  /** The agents of whoever is signed in, which hold their tokens: their own page. */
118
132
  agents: "/agents",
119
133
  /** The form for a token made by hand, for a script or a console of one's own. */
120
134
  newToken: "/agents/new",
121
- /** The categories tasks are sorted into, kept by an administrator. */
135
+ /** The categories tasks are sorted into, kept by an administrator; reached from the settings. */
122
136
  categories: "/categories",
137
+ /** The workspace's settings: the rules, the categories, the skills (ADR-0023). */
138
+ settings: "/settings",
123
139
  /** Where the pages a console adds of its own are: `/pages/<key>`, and `/projects/<key>/pages/<page>` on a project. */
124
140
  pages: "/pages",
125
141
  /** Where an agent's connection is approved (ADR-0011): `/connect/<code>`, or the code typed. */
@@ -132,12 +148,11 @@ const NUMBER = /^[1-9][0-9]{0,8}$/;
132
148
  /** A code as it may be typed into an address: checked for what it is by the page. */
133
149
  const CODE_TEXT = /^[A-Za-z0-9-]{1,16}$/;
134
150
  /** The pages of a project that take nothing after their name. */
135
- const PLAIN_PAGES: readonly Exclude<ProjectPage, "docs" | "calendar" | "roadmap">[] = [
151
+ const PLAIN_PAGES: readonly Exclude<ProjectPage, "docs" | "calendar" | "roadmap" | "settings">[] = [
136
152
  "decisions",
137
153
  "feed",
138
154
  "skills",
139
155
  "members",
140
- "settings",
141
156
  ];
142
157
  const NOT_FOUND: Route = { name: "not-found" };
143
158
 
@@ -192,6 +207,12 @@ const docsViewOf = (params: URLSearchParams, path: string): DocsView | undefined
192
207
  return { kind: "read" };
193
208
  };
194
209
 
210
+ /** The week a plate's address names, or none for this week's; a value that is not a day is nobody's address. */
211
+ function weekShown(params: URLSearchParams): { readonly week: string | undefined } | undefined {
212
+ const week = params.get("week");
213
+ return week !== null && !isDay(week) ? undefined : { week: week ?? undefined };
214
+ }
215
+
195
216
  export function matchRoute(pathname: string, search = ""): Route {
196
217
  const path = pathname.length > 1 ? pathname.replace(/\/+$/, "") : pathname;
197
218
  const moved = movedFrom(path);
@@ -206,11 +227,15 @@ export function matchRoute(pathname: string, search = ""): Route {
206
227
  return { name: "new-project" };
207
228
  }
208
229
  if (path === PATHS.work) {
209
- return { name: "work" };
230
+ const shown = weekShown(params);
231
+ return shown === undefined ? NOT_FOUND : { name: "work", ...shown };
210
232
  }
211
233
  if (path === PATHS.people) {
212
234
  return { name: "people" };
213
235
  }
236
+ if (path === PATHS.newListing) {
237
+ return { name: "new-listing" };
238
+ }
214
239
  if (path === PATHS.agents) {
215
240
  return { name: "agents" };
216
241
  }
@@ -220,6 +245,9 @@ export function matchRoute(pathname: string, search = ""): Route {
220
245
  if (path === PATHS.categories) {
221
246
  return { name: "categories" };
222
247
  }
248
+ if (path === PATHS.settings) {
249
+ return { name: "workspace-settings", form: params.has("rules") ? "rules" : undefined };
250
+ }
223
251
  if (path === PATHS.connect) {
224
252
  return { name: "connect", code: undefined };
225
253
  }
@@ -229,9 +257,17 @@ export function matchRoute(pathname: string, search = ""): Route {
229
257
  }
230
258
  if (path.startsWith(`${PATHS.people}/`)) {
231
259
  const [id, page, ...more] = path.slice(PATHS.people.length + 1).split("/");
232
- return id !== undefined && UUID.test(id) && page === "agents" && more.length === 0
233
- ? { name: "person-agents", id }
234
- : NOT_FOUND;
260
+ if (id === undefined || !UUID.test(id) || more.length > 0) {
261
+ return NOT_FOUND;
262
+ }
263
+ if (page === "agents") {
264
+ return { name: "person-agents", id };
265
+ }
266
+ if (page === "work") {
267
+ const shown = weekShown(params);
268
+ return shown === undefined ? NOT_FOUND : { name: "person-work", id, ...shown };
269
+ }
270
+ return NOT_FOUND;
235
271
  }
236
272
  if (path.startsWith(`${PATHS.pages}/`)) {
237
273
  const [page, ...more] = path.slice(PATHS.pages.length + 1).split("/");
@@ -311,6 +347,13 @@ export function matchRoute(pathname: string, search = ""): Route {
311
347
  if (page === "roadmap") {
312
348
  return { name: "roadmap", project };
313
349
  }
350
+ if (page === "settings") {
351
+ return {
352
+ name: "settings",
353
+ project,
354
+ form: params.has("edit") ? "edit" : params.has("rules") ? "rules" : undefined,
355
+ };
356
+ }
314
357
  const found = PLAIN_PAGES.find((candidate) => candidate === page);
315
358
  return found === undefined ? NOT_FOUND : { name: found, project };
316
359
  }
@@ -325,12 +368,29 @@ export function personAgentsHref(personId: string): string {
325
368
  return `${PATHS.people}/${personId}/agents`;
326
369
  }
327
370
 
371
+ /** Where another person's work is seen, with the week of a day at the top, or this week's when none is named. */
372
+ export function personWorkHref(personId: string, week?: string): string {
373
+ const base = `${PATHS.people}/${personId}/work`;
374
+ return week === undefined ? base : `${base}?week=${week}`;
375
+ }
376
+
328
377
  /** Where a project's board is, or one of its pages. */
329
378
  export function projectHref(key: string, page?: ProjectPage): string {
330
379
  const base = `${PATHS.project}/${key}`;
331
380
  return page === undefined ? base : `${base}/${page}`;
332
381
  }
333
382
 
383
+ /** Where a project's settings are read, or one of their forms is open: the project's own, or its rules. */
384
+ export function projectSettingsHref(key: string, form?: "edit" | "rules"): string {
385
+ const base = projectHref(key, "settings");
386
+ return form === undefined ? base : `${base}?${form}`;
387
+ }
388
+
389
+ /** Where the workspace's settings are, or the form its rules are written on. */
390
+ export function settingsHref(form?: "rules"): string {
391
+ return form === undefined ? PATHS.settings : `${PATHS.settings}?${form}`;
392
+ }
393
+
334
394
  /** Where a project's board is, narrowed as the filter says; the plain board for an empty one. */
335
395
  export function boardHref(key: string, filter: BoardFilter = {}): string {
336
396
  const parts = filterParts(filter);
@@ -377,6 +437,11 @@ export function decisionHref(key: string, id: string): string {
377
437
  return `${PATHS.project}/${key}/decisions/${id}`;
378
438
  }
379
439
 
440
+ /** Where the person's own work is, with the week of a day at the top, or this week's when none is named. */
441
+ export function workHref(week?: string): string {
442
+ return week === undefined ? PATHS.work : `${PATHS.work}?week=${week}`;
443
+ }
444
+
380
445
  /** Where a project's calendar is, on a month, or on this one when none is named, narrowed as the filter says. */
381
446
  export function calendarHref(key: string, month?: string, filter: BoardFilter = {}): string {
382
447
  const base = projectHref(key, "calendar");
package/src/routes.ts CHANGED
@@ -7,8 +7,12 @@ import type { ProviderKey } from "./vocabulary.js";
7
7
  export const REST_ROUTES = {
8
8
  /** Who is signed in, what the workspace is called, and whether anyone can sign in. */
9
9
  me: "/api/v1/me",
10
- /** The people of the workspace: everyone who has signed in. */
10
+ /** The token a request is made with, for it to give itself up. */
11
+ meToken: "/api/v1/me/token",
12
+ /** The people of the workspace: everyone who has signed in, and the logins let in that have not. */
11
13
  people: "/api/v1/people",
14
+ /** The logins an administrator let in (ADR-0022), made and removed by one. */
15
+ listings: "/api/v1/listings",
12
16
  /** The projects the asker may see; the board of each is under its key. */
13
17
  projects: "/api/v1/projects",
14
18
  /** The workspace's own events, the ones about no project: who joined, who was made what. */
@@ -21,8 +25,15 @@ export const REST_ROUTES = {
21
25
  categories: "/api/v1/categories",
22
26
  /** What is on the asker's plate across the projects they may see: their open tasks, and the decisions waiting. */
23
27
  work: "/api/v1/work",
28
+ /** The rules of the board (ADR-0023): the console's own until an administrator writes the organization's. */
29
+ rules: "/api/v1/rules",
24
30
  } as const;
25
31
 
32
+ /** The REST path of the workspace's rules put away, or of their versions. */
33
+ export function rulesPath(part?: "archive" | "versions"): string {
34
+ return part === undefined ? REST_ROUTES.rules : `${REST_ROUTES.rules}/${part}`;
35
+ }
36
+
26
37
  /** The REST path of one category, by its key. */
27
38
  export function categoryPath(key: string): string {
28
39
  return `${REST_ROUTES.categories}/${encodeURIComponent(key)}`;
@@ -37,6 +48,11 @@ export function connectPath(code: string, action?: "approve" | "deny"): string {
37
48
  return action === undefined ? base : `${base}/${action}`;
38
49
  }
39
50
 
51
+ /** The REST path of another person's plate: for an administrator, or an owner of a project they are in. */
52
+ export function personWorkPath(personId: string): string {
53
+ return `${restPath("people", personId)}/work`;
54
+ }
55
+
40
56
  /** The REST path of a person's tokens, or of one of them: for an administrator. */
41
57
  export function personTokensPath(personId: string, tokenId?: string): string {
42
58
  const base = `${restPath("people", personId)}/tokens`;
@@ -54,6 +70,7 @@ export const PROJECT_COLLECTIONS = [
54
70
  "members",
55
71
  "docs",
56
72
  "goals",
73
+ "rules",
57
74
  ] as const;
58
75
 
59
76
  export type ProjectCollection = (typeof PROJECT_COLLECTIONS)[number];
@@ -94,8 +111,11 @@ export function signInPath(page: string, failure: SignInFailure): string {
94
111
  return `${page}${page.includes("?") ? "&" : "?"}${SIGN_IN_PARAM}=${failure}`;
95
112
  }
96
113
 
97
- /** The REST path of one person, token or project: the collection, then the id or the key. */
98
- export function restPath(collection: "people" | "tokens" | "projects", id: string): string {
114
+ /** The REST path of one person, listing, token or project: the collection, then the id or the key. */
115
+ export function restPath(
116
+ collection: "people" | "listings" | "tokens" | "projects",
117
+ id: string,
118
+ ): string {
99
119
  return `${REST_ROUTES[collection]}/${encodeURIComponent(id)}`;
100
120
  }
101
121