@skillcdn/console 0.4.1 → 0.4.2

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 (271) hide show
  1. package/README.md +19 -2
  2. package/SKILLCDN.md +7 -5
  3. package/dist/api.d.ts +4 -3
  4. package/dist/api.d.ts.map +1 -1
  5. package/dist/api.js +4 -3
  6. package/dist/api.js.map +1 -1
  7. package/dist/cli/cli.d.ts.map +1 -1
  8. package/dist/cli/cli.js +543 -34
  9. package/dist/cli/cli.js.map +1 -1
  10. package/dist/cli/format.d.ts +34 -3
  11. package/dist/cli/format.d.ts.map +1 -1
  12. package/dist/cli/format.js +277 -6
  13. package/dist/cli/format.js.map +1 -1
  14. package/dist/cli/help.d.ts.map +1 -1
  15. package/dist/cli/help.js +35 -2
  16. package/dist/cli/help.js.map +1 -1
  17. package/dist/cli/plugin-check.d.ts +21 -0
  18. package/dist/cli/plugin-check.d.ts.map +1 -0
  19. package/dist/cli/plugin-check.js +374 -0
  20. package/dist/cli/plugin-check.js.map +1 -0
  21. package/dist/cli/plugin-cli.d.ts +20 -0
  22. package/dist/cli/plugin-cli.d.ts.map +1 -0
  23. package/dist/cli/plugin-cli.js +123 -0
  24. package/dist/cli/plugin-cli.js.map +1 -0
  25. package/dist/cli/plugin-init.d.ts +20 -0
  26. package/dist/cli/plugin-init.d.ts.map +1 -0
  27. package/dist/cli/plugin-init.js +74 -0
  28. package/dist/cli/plugin-init.js.map +1 -0
  29. package/dist/cli/plugin-main.d.ts +3 -0
  30. package/dist/cli/plugin-main.d.ts.map +1 -0
  31. package/dist/cli/plugin-main.js +28 -0
  32. package/dist/cli/plugin-main.js.map +1 -0
  33. package/dist/client.d.ts +97 -1
  34. package/dist/client.d.ts.map +1 -1
  35. package/dist/client.js +63 -2
  36. package/dist/client.js.map +1 -1
  37. package/dist/compat.d.ts +1 -1
  38. package/dist/compat.js +2 -2
  39. package/dist/components/board.d.ts +8 -0
  40. package/dist/components/board.d.ts.map +1 -1
  41. package/dist/components/board.js +59 -15
  42. package/dist/components/board.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 +33 -1
  46. package/dist/components/event-feed.js.map +1 -1
  47. package/dist/components/plugin-frame.d.ts +52 -0
  48. package/dist/components/plugin-frame.d.ts.map +1 -0
  49. package/dist/components/plugin-frame.js +314 -0
  50. package/dist/components/plugin-frame.js.map +1 -0
  51. package/dist/components/plugin-settings.d.ts +38 -0
  52. package/dist/components/plugin-settings.d.ts.map +1 -0
  53. package/dist/components/plugin-settings.js +348 -0
  54. package/dist/components/plugin-settings.js.map +1 -0
  55. package/dist/components/shell.d.ts +2 -0
  56. package/dist/components/shell.d.ts.map +1 -1
  57. package/dist/components/shell.js +26 -1
  58. package/dist/components/shell.js.map +1 -1
  59. package/dist/components/workspace.d.ts +7 -1
  60. package/dist/components/workspace.d.ts.map +1 -1
  61. package/dist/components/workspace.js +1 -1
  62. package/dist/components/workspace.js.map +1 -1
  63. package/dist/console.css +327 -0
  64. package/dist/console.d.ts.map +1 -1
  65. package/dist/console.js +136 -26
  66. package/dist/console.js.map +1 -1
  67. package/dist/data.d.ts +7 -1
  68. package/dist/data.d.ts.map +1 -1
  69. package/dist/data.js +19 -2
  70. package/dist/data.js.map +1 -1
  71. package/dist/i18n/en.d.ts +149 -0
  72. package/dist/i18n/en.d.ts.map +1 -1
  73. package/dist/i18n/en.js +160 -0
  74. package/dist/i18n/en.js.map +1 -1
  75. package/dist/i18n/ko.d.ts.map +1 -1
  76. package/dist/i18n/ko.js +144 -0
  77. package/dist/i18n/ko.js.map +1 -1
  78. package/dist/index.d.ts +3 -1
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.js +3 -1
  81. package/dist/index.js.map +1 -1
  82. package/dist/plugin/args.d.ts +148 -0
  83. package/dist/plugin/args.d.ts.map +1 -0
  84. package/dist/plugin/args.js +369 -0
  85. package/dist/plugin/args.js.map +1 -0
  86. package/dist/plugin/bridge.d.ts +146 -0
  87. package/dist/plugin/bridge.d.ts.map +1 -0
  88. package/dist/plugin/bridge.js +125 -0
  89. package/dist/plugin/bridge.js.map +1 -0
  90. package/dist/plugin/capabilities.d.ts +20 -0
  91. package/dist/plugin/capabilities.d.ts.map +1 -0
  92. package/dist/plugin/capabilities.js +133 -0
  93. package/dist/plugin/capabilities.js.map +1 -0
  94. package/dist/plugin/context.d.ts +374 -0
  95. package/dist/plugin/context.d.ts.map +1 -0
  96. package/dist/plugin/context.js +2 -0
  97. package/dist/plugin/context.js.map +1 -0
  98. package/dist/plugin/define.d.ts +208 -0
  99. package/dist/plugin/define.d.ts.map +1 -0
  100. package/dist/plugin/define.js +482 -0
  101. package/dist/plugin/define.js.map +1 -0
  102. package/dist/plugin/definition-error.d.ts +11 -0
  103. package/dist/plugin/definition-error.d.ts.map +1 -0
  104. package/dist/plugin/definition-error.js +17 -0
  105. package/dist/plugin/definition-error.js.map +1 -0
  106. package/dist/plugin/limits.d.ts +67 -0
  107. package/dist/plugin/limits.d.ts.map +1 -0
  108. package/dist/plugin/limits.js +70 -0
  109. package/dist/plugin/limits.js.map +1 -0
  110. package/dist/plugin/load-worker.d.ts +7 -0
  111. package/dist/plugin/load-worker.d.ts.map +1 -0
  112. package/dist/plugin/load-worker.js +41 -0
  113. package/dist/plugin/load-worker.js.map +1 -0
  114. package/dist/plugin/load.d.ts +18 -0
  115. package/dist/plugin/load.d.ts.map +1 -0
  116. package/dist/plugin/load.js +62 -0
  117. package/dist/plugin/load.js.map +1 -0
  118. package/dist/plugin/manifest.d.ts +237 -0
  119. package/dist/plugin/manifest.d.ts.map +1 -0
  120. package/dist/plugin/manifest.js +411 -0
  121. package/dist/plugin/manifest.js.map +1 -0
  122. package/dist/plugin/refusals.d.ts +49 -0
  123. package/dist/plugin/refusals.d.ts.map +1 -0
  124. package/dist/plugin/refusals.js +79 -0
  125. package/dist/plugin/refusals.js.map +1 -0
  126. package/dist/plugin/rest-schemas.d.ts +556 -0
  127. package/dist/plugin/rest-schemas.d.ts.map +1 -0
  128. package/dist/plugin/rest-schemas.js +262 -0
  129. package/dist/plugin/rest-schemas.js.map +1 -0
  130. package/dist/plugin/sandbox.d.ts +23 -0
  131. package/dist/plugin/sandbox.d.ts.map +1 -0
  132. package/dist/plugin/sandbox.js +99 -0
  133. package/dist/plugin/sandbox.js.map +1 -0
  134. package/dist/plugin/testing.d.ts +45 -0
  135. package/dist/plugin/testing.d.ts.map +1 -0
  136. package/dist/plugin/testing.js +420 -0
  137. package/dist/plugin/testing.js.map +1 -0
  138. package/dist/plugin/web-react.d.ts +11 -0
  139. package/dist/plugin/web-react.d.ts.map +1 -0
  140. package/dist/plugin/web-react.js +34 -0
  141. package/dist/plugin/web-react.js.map +1 -0
  142. package/dist/plugin/web.d.ts +95 -0
  143. package/dist/plugin/web.d.ts.map +1 -0
  144. package/dist/plugin/web.js +245 -0
  145. package/dist/plugin/web.js.map +1 -0
  146. package/dist/plugin-nav.d.ts +29 -0
  147. package/dist/plugin-nav.d.ts.map +1 -0
  148. package/dist/plugin-nav.js +92 -0
  149. package/dist/plugin-nav.js.map +1 -0
  150. package/dist/plugin-testing.d.ts +2 -0
  151. package/dist/plugin-testing.d.ts.map +1 -0
  152. package/dist/plugin-testing.js +4 -0
  153. package/dist/plugin-testing.js.map +1 -0
  154. package/dist/plugin-web-react.d.ts +3 -0
  155. package/dist/plugin-web-react.d.ts.map +1 -0
  156. package/dist/plugin-web-react.js +3 -0
  157. package/dist/plugin-web-react.js.map +1 -0
  158. package/dist/plugin-web.d.ts +4 -0
  159. package/dist/plugin-web.d.ts.map +1 -0
  160. package/dist/plugin-web.js +5 -0
  161. package/dist/plugin-web.js.map +1 -0
  162. package/dist/plugin.d.ts +11 -0
  163. package/dist/plugin.d.ts.map +1 -0
  164. package/dist/plugin.js +15 -0
  165. package/dist/plugin.js.map +1 -0
  166. package/dist/router.d.ts +28 -0
  167. package/dist/router.d.ts.map +1 -1
  168. package/dist/router.js +47 -0
  169. package/dist/router.js.map +1 -1
  170. package/dist/routes.d.ts +4 -0
  171. package/dist/routes.d.ts.map +1 -1
  172. package/dist/routes.js +6 -0
  173. package/dist/routes.js.map +1 -1
  174. package/dist/schemas.d.ts +117 -0
  175. package/dist/schemas.d.ts.map +1 -1
  176. package/dist/schemas.js +40 -1
  177. package/dist/schemas.js.map +1 -1
  178. package/dist/tokens.d.ts +2 -0
  179. package/dist/tokens.d.ts.map +1 -0
  180. package/dist/tokens.js +101 -0
  181. package/dist/tokens.js.map +1 -0
  182. package/dist/vocabulary.d.ts +11 -1
  183. package/dist/vocabulary.d.ts.map +1 -1
  184. package/dist/vocabulary.js +24 -0
  185. package/dist/vocabulary.js.map +1 -1
  186. package/dist/web.d.ts.map +1 -1
  187. package/dist/web.js +2 -0
  188. package/dist/web.js.map +1 -1
  189. package/docs/specs/cli.md +11 -4
  190. package/docs/specs/plugins.md +487 -0
  191. package/docs/specs/rest.md +3 -2
  192. package/package.json +20 -2
  193. package/skills/building-a-console/SKILL.md +25 -26
  194. package/skills/building-a-console/references/configuring.md +40 -0
  195. package/skills/building-a-console/references/the-default-console.md +1 -1
  196. package/skills/building-a-console/references/the-look-from-a-website.md +5 -5
  197. package/skills/building-a-plugin/SKILL.md +137 -0
  198. package/skills/deploying-a-console/SKILL.md +24 -26
  199. package/skills/deploying-a-console/references/access.md +13 -9
  200. package/skills/deploying-a-console/references/resources.md +25 -10
  201. package/skills/deploying-a-console/references/running-it-again.md +15 -0
  202. package/skills/deploying-a-console/references/sizing.md +2 -0
  203. package/skills/planning-the-board/SKILL.md +96 -0
  204. package/skills/planning-the-board/references/a-task.md +36 -0
  205. package/skills/planning-the-board/references/setting-up.md +44 -0
  206. package/skills/working-the-board/SKILL.md +43 -34
  207. package/skills/working-the-board/references/the-pack.md +19 -0
  208. package/src/api.ts +8 -0
  209. package/src/cli/cli.ts +697 -33
  210. package/src/cli/format.ts +356 -9
  211. package/src/cli/help.ts +41 -2
  212. package/src/cli/plugin-check.ts +470 -0
  213. package/src/cli/plugin-cli.ts +148 -0
  214. package/src/cli/plugin-init.ts +90 -0
  215. package/src/cli/plugin-main.ts +30 -0
  216. package/src/client.ts +294 -0
  217. package/src/compat.ts +2 -2
  218. package/src/components/board.tsx +62 -14
  219. package/src/components/event-feed.tsx +42 -1
  220. package/src/components/plugin-frame.tsx +437 -0
  221. package/src/components/plugin-settings.tsx +1111 -0
  222. package/src/components/shell.tsx +82 -14
  223. package/src/components/workspace.tsx +18 -0
  224. package/src/console.tsx +286 -19
  225. package/src/data.ts +27 -2
  226. package/src/i18n/en.ts +168 -0
  227. package/src/i18n/ko.ts +148 -0
  228. package/src/index.ts +12 -0
  229. package/src/plugin/args.ts +526 -0
  230. package/src/plugin/bridge.ts +314 -0
  231. package/src/plugin/capabilities.ts +150 -0
  232. package/src/plugin/context.ts +416 -0
  233. package/src/plugin/define.ts +792 -0
  234. package/src/plugin/definition-error.ts +19 -0
  235. package/src/plugin/limits.ts +70 -0
  236. package/src/plugin/load-worker.ts +50 -0
  237. package/src/plugin/load.ts +82 -0
  238. package/src/plugin/manifest.ts +561 -0
  239. package/src/plugin/refusals.ts +94 -0
  240. package/src/plugin/rest-schemas.ts +354 -0
  241. package/src/plugin/sandbox.ts +123 -0
  242. package/src/plugin/testing.ts +612 -0
  243. package/src/plugin/web-react.ts +45 -0
  244. package/src/plugin/web.ts +403 -0
  245. package/src/plugin-nav.ts +132 -0
  246. package/src/plugin-testing.ts +10 -0
  247. package/src/plugin-web-react.ts +4 -0
  248. package/src/plugin-web.ts +35 -0
  249. package/src/plugin.ts +126 -0
  250. package/src/router.ts +73 -0
  251. package/src/routes.ts +7 -0
  252. package/src/schemas.ts +43 -0
  253. package/src/styles/console.css +327 -0
  254. package/src/tokens.ts +101 -0
  255. package/src/vocabulary.ts +30 -0
  256. package/src/web.ts +2 -0
  257. package/template/plugin/.gitignore +2 -0
  258. package/template/plugin/README.md +26 -0
  259. package/template/plugin/SKILLCDN.md +13 -0
  260. package/template/plugin/build.mjs +40 -0
  261. package/template/plugin/console-plugin.json +50 -0
  262. package/template/plugin/package.json +27 -0
  263. package/template/plugin/skills/__key__/SKILL.md +23 -0
  264. package/template/plugin/src/check.test.ts +34 -0
  265. package/template/plugin/src/server/index.test.ts +41 -0
  266. package/template/plugin/src/server/index.ts +72 -0
  267. package/template/plugin/src/web/index.css +51 -0
  268. package/template/plugin/src/web/index.ts +115 -0
  269. package/template/plugin/tsconfig.json +17 -0
  270. package/skills/working-the-board/references/setting-up.md +0 -3
  271. /package/skills/{working-the-board → planning-the-board}/references/project-rules.md +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillcdn/console",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "What a custom SkillCDN console is built from: the API client and schemas, the components, the composition of the default console, and the console command agents work the board with.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/skillcdn/console#readme",
@@ -20,7 +20,8 @@
20
20
  "type": "module",
21
21
  "sideEffects": false,
22
22
  "bin": {
23
- "console": "./dist/cli/main.js"
23
+ "console": "./dist/cli/main.js",
24
+ "console-plugin": "./dist/cli/plugin-main.js"
24
25
  },
25
26
  "engines": {
26
27
  "node": ">=24"
@@ -42,6 +43,22 @@
42
43
  "types": "./dist/web.d.ts",
43
44
  "default": "./dist/web.js"
44
45
  },
46
+ "./plugin": {
47
+ "types": "./dist/plugin.d.ts",
48
+ "default": "./dist/plugin.js"
49
+ },
50
+ "./plugin/web": {
51
+ "types": "./dist/plugin-web.d.ts",
52
+ "default": "./dist/plugin-web.js"
53
+ },
54
+ "./plugin/web/react": {
55
+ "types": "./dist/plugin-web-react.d.ts",
56
+ "default": "./dist/plugin-web-react.js"
57
+ },
58
+ "./plugin/testing": {
59
+ "types": "./dist/plugin-testing.d.ts",
60
+ "default": "./dist/plugin-testing.js"
61
+ },
45
62
  "./console.css": "./dist/console.css",
46
63
  "./package.json": "./package.json"
47
64
  },
@@ -51,6 +68,7 @@
51
68
  "src",
52
69
  "!src/**/*.test.ts",
53
70
  "!src/**/*.test.tsx",
71
+ "template",
54
72
  "skills",
55
73
  "docs",
56
74
  "SKILLCDN.md"
@@ -1,16 +1,16 @@
1
1
  ---
2
2
  name: building-a-console
3
- description: "Builds a console from the @skillcdn/console package: a console of a person's own, served from their machine with their token by console serve; an organization's console, which takes the default UI's place in the image and, given the organization's website, takes its look, the marks, the colours and the type, by default; or a script against the console's REST API. Says where the package's layers are (the API client and schemas, the components, the composition), how the default console is put together, what to configure and what to replace (a component, the language packs, the brand, the styles' tokens), how a look is read from a website and mapped onto the pages, how a build is run against the board and checked, and the rules that keep untrusted content harmless. Use when an agent is asked to make, change, re-skin or extend a SkillCDN Console UI or a client of its API. To work tasks on the board, use working-the-board; to deploy a console for an organization, use deploying-a-console."
3
+ description: "Builds a console from the @skillcdn/console package: a person's own console, served from their machine by console serve; an organization's console, which takes the default pages' place in the image and, given the organization's website, its look, the marks, the colours and the type; or a script against the console's REST API. Use when a person says 'make me a console with a column for this', 're-skin the console in our brand', 'add a page that shows that', 'build our own console UI', or 'write a script that reads the board'. A feature with data of its own (leave, customers) is a plugin, not a page: use building-a-plugin. To work tasks on the board, use working-the-board; to deploy a console, deploying-a-console. The package's README, types and sources are the reference; this skill says what to configure before anything is replaced, how the build is run against the real board and checked, and what keeps untrusted content harmless. Nothing is spent, pushed or published here."
4
4
  license: MIT
5
5
  compatibility: A shell with Node.js 24 or newer and npm or pnpm, and an agent that reads and writes files. For looking at the pages against a board, the console command signed in by a person. A browser the agent can drive is optional. No key of the agent's own is needed, and it never sees a token.
6
6
  metadata:
7
7
  author: skillcdn
8
- version: "1.7"
8
+ version: "1.9"
9
9
  skillcdn:
10
10
  translations:
11
11
  ko:
12
12
  title: 패키지로 콘솔 만들기
13
- description: "@skillcdn/console 패키지로 콘솔을 만듭니다. console serve로 내 PC에서 내 토큰으로 돌리는 개인 콘솔, 이미지에서 기본 UI 자리를 대신하며 조직의 웹사이트가 있으면 그 디자인(마크, 색, 글꼴)을 기본으로 삼는 조직 콘솔, 또는 콘솔 REST API를 쓰는 스크립트. 패키지의 세 계층(API 클라이언트와 스키마, 컴포넌트, 구성)이 어디 있는지, 기본 콘솔이 어떻게 조립되는지, 무엇을 설정하고 무엇을 바꾸는지(컴포넌트, 언어 팩, 브랜드, 스타일 토큰), 웹사이트에서 디자인을 읽어 페이지에 입히는 법, 빌드를 보드에 붙여 돌리고 확인하는 법, 신뢰할 수 없는 내용을 안전하게 다루는 규칙을 말합니다. SkillCDN 콘솔 UI나 API 클라이언트를 만들거나 바꾸거나 디자인을 바꾸라고 할 때 쓰세요. 보드의 작업을 할 때는 working-the-board를, 조직의 콘솔을 배포할 때는 deploying-a-console을 쓰세요."
13
+ description: "@skillcdn/console 패키지로 콘솔을 만듭니다. console serve로 내 PC에서 내 토큰으로 돌리는 개인 콘솔, 이미지의 기본 페이지 자리를 대신하며 조직 웹사이트가 있으면 그 디자인(마크, 색, 글꼴)을 입는 조직 콘솔, 또는 콘솔 REST API를 쓰는 스크립트. '이 열이 있는 내 콘솔 만들어줘', '콘솔을 우리 브랜드로 바꿔줘', '그걸 보여주는 페이지 추가해줘', '우리 콘솔 UI 만들자', '보드를 읽는 스크립트 써줘'라고 할 때 쓰세요. 자기 데이터를 가진 조직 업무 기능(연차, 고객, 돈)은 페이지가 아니라 플러그인입니다: building-a-plugin을 쓰세요. 보드의 작업은 working-the-board, 콘솔 배포는 deploying-a-console(디자인은 이 스킬로 만듭니다)을 쓰세요. 기준은 패키지의 README·타입·소스이고, 이 스킬은 그것이 어디 있는지, 무엇을 바꾸기 전에 설정으로 할지, 빌드를 실제 보드에 붙여 돌리고 확인하는 법, 신뢰할 수 없는 내용을 안전하게 두는 규칙을 말합니다. 비용은 들지 않고, 여기서는 푸시도 발행도 하지 않습니다."
14
14
  ---
15
15
  # Building a console from the package
16
16
 
@@ -19,7 +19,7 @@ What goes in: what the console is for, which is one person's own, the organizati
19
19
  ## How the person is involved
20
20
 
21
21
  - **Questions:** one message at the start, the ones under "Inputs" that the request leaves open, each for the half it leaves open. Everything else is derived and shown with the plan.
22
- - **Checkpoints:** the plan (the kind, where the build goes, what is configured and what is replaced, the colours and the marks as they will be used), before a file of the console is written; the look, with the pages in front of them, before more pages are built on it. One short message each, with the recommendation; "OK", in the person's language, continues.
22
+ - **Checkpoints:** the plan (the kind, where the build goes, what is configured and what is replaced, the colours and the marks as they will be used, with the contrast checked), before a file of the console is written; the look, with the pages in front of them, before more pages are built on it. One short message each, with the recommendation; "OK", in the person's language, continues.
23
23
  - **Go-ahead:** when the person says to go ahead alone, the look is reported instead of approved; the plan holds in every mode. Nothing is pushed or published here.
24
24
  - **Changes mid-run:** applied from that point; a change after the build rewrites the parts it touches, not the whole console. A phase with nothing to do for the request is skipped, and the line says so.
25
25
 
@@ -28,8 +28,8 @@ What goes in: what the console is for, which is one person's own, the organizati
28
28
  | Need | How | When missing |
29
29
  |---|---|---|
30
30
  | Node.js 24 or newer, with npm or pnpm | `node --version` | Stop and say so. |
31
- | The package | `npm install @skillcdn/console react react-dom`, for pages `npm install --save-dev vite @vitejs/plugin-react typescript`, and for Korean `npm install pretendard`, the face the default console loads | The package is on npm; nothing else is needed. |
32
- | For looking at the pages against a board, one's own or the organization's: the `console` command, signed in | `console whoami` says as whom and at which console. | `npm install -g @skillcdn/console`, then `console login --url <the console's address>`: a person approves the code it shows. Never look for a token. |
31
+ | The package | `npm install @skillcdn/console react react-dom`, at the version the deployment pins for the organization's console (phase 1); for a console with pages `npm install --save-dev vite @vitejs/plugin-react typescript`, and for Korean `npm install pretendard`, the face the default console loads | The package is on npm; nothing else is needed. |
32
+ | For looking at the pages against a board, one's own or the organization's: the `console` command, signed in | `console whoami` says as whom and at which console; `console rules` what the board asks of agents, which holds over this skill's defaults where it speaks of consoles. | `npm install -g @skillcdn/console`, then `console login --url <the console's address>`: a person approves the code it shows. Never look for a token. |
33
33
  | Optional: a browser the agent can drive, or a screenshot tool | Looking at the pages and their console at the look checkpoint and for the verdicts. | The person opens the local address themselves, and the layout, console and policy verdicts are reported as not run. |
34
34
 
35
35
  ## Where to read, in this order
@@ -37,23 +37,22 @@ What goes in: what the console is for, which is one person's own, the organizati
37
37
  Nothing here restates them: they are the contract, current at the version installed.
38
38
 
39
39
  1. **The package's README**: `node_modules/@skillcdn/console/README.md` once installed, [`packages/console/README.md`](/packages/console/README.md) in the console's repository. Every export by layer and what each takes, the styles, the languages, and "A console of your own" with two of the four files to write.
40
- 2. **The types**: `node_modules/@skillcdn/console/dist/index.d.ts`, `api.d.ts`, `cli/cli.d.ts` and `web.d.ts`: the exact props of every component and the shape of every answer, with the comment that says what each is for. `brand` takes a `symbol`, a `wordmark`, or both.
41
- 3. **The sources**, shipped with the package under `src/`: `console.tsx` (how the default console composes the pages from the components, routes, and loads its data), `components/*.tsx` (each component and what it renders), `data.ts` (how the workspace and a project are loaded and kept current by the stream), `styles/console.css` (the tokens, `--sc-*`, and every class, `sc-`-prefixed), `i18n/en.ts` (every word the pages show, keyed as a pack is). The repository's tests (`packages/console/src/components/components.test.tsx`, `src/console.test.tsx`), not shipped in the package, show what each piece renders, for tests of one's own.
42
- 4. **The REST API**: [docs/specs/rest.md](/docs/specs/rest.md), in the package at `docs/specs/rest.md`: every route, what it takes and answers, who may ask, and the codes of its refusals. **The command line**: [docs/specs/cli.md](/docs/specs/cli.md).
40
+ 2. **The types**: `node_modules/@skillcdn/console/dist/index.d.ts`, `api.d.ts`, `cli/cli.d.ts` and `web.d.ts`: the exact props of every component and the shape of every answer, with the comment that says what each is for.
41
+ 3. **The sources**, shipped with the package under `src/`: `console.tsx` (how the default console composes the pages from the components, routes, and loads its data), `components/*.tsx` (each component and what it renders), `data.ts` (how the workspace and a project are loaded and kept current by the stream), `styles/console.css` (the tokens, `--sc-*`, and every class, `sc`-prefixed), `i18n/en.ts` (every word the pages show, keyed as a pack is). The repository's tests (`packages/console/src/components/components.test.tsx`, `src/console.test.tsx`), not shipped in the package, show what each piece renders, for tests of one's own.
42
+ 4. **The REST API**: [docs/specs/rest.md](/docs/specs/rest.md), in the package at `docs/specs/rest.md`: every route, what it takes and answers, who may ask, and the codes of its refusals; for a script. **The command line**: [docs/specs/cli.md](/docs/specs/cli.md), for `console serve`.
43
43
  5. **The default console itself**, `apps/console/web/` in the console's repository: the page, the script, the build and the compiler's settings, with the brand, the fonts and the icons wired in. Its four files are quoted in [the-default-console.md](references/the-default-console.md), kept identical to them by the repository's check, for an agent that has the skill and not the repository; a console of one's own copies their shape.
44
- 6. **The architecture**: [docs/architecture.md](/docs/architecture.md) for how the parts fit, and the [decisions](/docs/adr/README.md), served through the repository's connection and not in the package; ADR-0014 says how a person's own console reaches the organization's.
44
+ 6. **The architecture**: [docs/architecture.md](/docs/architecture.md) for how the parts fit, and the [decisions](/docs/adr/README.md), both documents of the console's repository, read through the connection that served this skill and not in the package; ADR-0014 says how a person's own console reaches the organization's. Not needed for a re-skin.
45
45
 
46
46
  ## Inputs
47
47
 
48
48
  | Input | Source |
49
49
  |---|---|
50
50
  | Which kind | Asked when the request does not say: "Is this console for you alone, served from your machine with your token; for the whole organization, in place of the default pages in the image; or a script against the API?" A member usually wants their own. |
51
- | Where the organization's build goes | Asked for the organization's: "How is the console run: with the deployment repository that deploying-a-console made, with an image you build yourselves, or from a directory mounted into it?" The answer places the result: the source in `console-ui/` of that repository, which its workflow builds on every push; a repository of its own whose build goes beside the Dockerfile of [deploy/README.md](/deploy/README.md) "A custom console in the image"; or the build in the directory. |
52
- | What it must show or do | From the request: a page, a component, a language, a brand, a column, a filter, a report. Asked for its missing half: "What should it show or do that the default console does not?" Everything else is the default console's and stays. |
53
- | The marks | From the organization's website when the request, or deploying-a-console, names one: its symbol and wordmark read from the site as [the-look-from-a-website.md](references/the-look-from-a-website.md) says, the dark version or, with the person's word, the one-colour mark recoloured, shown at the plan. Else asked for a console that shows marks of its own, for the half the request leaves open: "Which picture should the pages show beside the board's name: a small square mark, the name as lettering, or both? Where is the file? The pages are light, so it should be a dark one." `brand` takes either or both. The symbol's slot is a square of one line's height (`.sc-brand-symbol`, 1rem): a wide mark, a lettermark of three or four times its height, is a wordmark and goes in as one, alone or beside a square symbol. A mark drawn in a light colour vanishes on the light pages: ask for a dark version, or, with the person's word, recolour it when it is one colour. Default without a site: the board's name alone and no marks, which is the honest console. |
54
- | The colour | From the website's own colours when one is named, as the reference says, its primary colour read from the theme colour, the stylesheet's properties or the primary button. Else asked when the request names none and marks are wanted: "Which colour, or which mood?" A colour comes as words or a value; the value is the mark's own fill when it has one, else chosen and shown. A dark or saturated colour becomes the accent (`--sc-color-accent` and its family); a pale one tints the field (`--sc-field-gradient`), with a darker shade of it as the accent, since an accent must read on the light field. The mapping is shown at the plan, with the contrast checked. |
55
- | The languages | Asked when the organization's language is not among the packs: "Which languages should the pages speak?" Default: the packs the package ships, chosen by the browser; a Korean organization gets Pretendard loaded, as the default console does. |
56
- | The name | Not asked: the server names the board (`WORKSPACE_NAME`, conventionally the organization or the person it is for, then Console: `Acme Console`), and `title` is only what the page says until the server answers. `index.html` gets the organization's `<title>` and `lang`. |
51
+ | Where the organization's build goes | Asked for the organization's: "How is the console run: with the deployment repository that deploying-a-console made, with an image you build yourselves, or from a directory mounted into it? And where is that repository: a folder on this machine, or its address to clone?" The answer places the result: the source in `console-ui/` of that repository, which its workflow builds on every push, an existing `console-ui/` there being the console to change, not to start over; a repository of its own whose build goes beside the Dockerfile of [deploy/README.md](/deploy/README.md) "A custom console in the image"; or the build in the directory. |
52
+ | What it must show or do | From the request: a page, a component, a language, a brand, a column, a filter, a report. Asked for its missing half, when the request wants more than a look: "What should it show or do that the default console does not?" Everything else is the default console's and stays. |
53
+ | The look: the marks and the colour | From the organization's website when the request, or deploying-a-console, names one: read and mapped as [the-look-from-a-website.md](references/the-look-from-a-website.md) says, and shown at the plan; the pages stay light unless the person says otherwise, a mark is recoloured only with their word, and a site that cannot be read, or shows no mark or colour of its own, is said so, the person asked for the files or the honest default kept. Else asked, for a console that is to show marks of its own, each for the half the request leaves open: "Which picture should the pages show beside the board's name: a small square mark, the name as lettering, or both? Where is the file? The pages are light, so it should be a dark one." and "Which colour, or which mood?" A colour comes as words or a value; the value is the mark's own fill when it has one, else chosen and shown. Default without a site: the board's name alone and no marks, which is the honest console. How a mark, a colour and a face go into the pages is [configuring.md](references/configuring.md). |
54
+ | The languages | Asked when the organization's language, the request's and the site's `lang`, is not among the packs: "Which languages should the pages speak?" Default: the packs the package ships, chosen by the browser; a Korean organization gets Pretendard loaded, as the default console does. |
55
+ | The name | Not asked: the server names the board (`WORKSPACE_NAME`, conventionally the organization or the person it is for, then Console: `Acme Console`), and `title` is only what the page says until the server answers. `index.html` gets the board's name, as `console whoami` prints it, for its `<title>`, and the organization's language for `lang`. |
57
56
  | The console's address | For running one's own, what `console whoami` says. A script takes `CONSOLE_URL` and `CONSOLE_TOKEN` from the environment, never from a file in the repository. |
58
57
 
59
58
  ## Workflow
@@ -62,40 +61,40 @@ Each phase produces something the person can look at and ends with one line to t
62
61
 
63
62
  ### Phase 1: Start from the default console
64
63
 
65
- Produces the **plan** and the first build. Install first, in the new folder, so that the README, the types and the sources are at hand for the plan: the install writes only `package.json`, the lockfile and `node_modules`, and the plan is shown before any file of the console is written. A console is four files and a configuration: `index.html` with a `#root`, `src/main.tsx` that calls `createConsole({ ... }).mount(root)` and imports `@skillcdn/console/console.css`, `vite.config.ts` with the React plugin and, for building against the real board, `/api` sent to `console serve` with `changeOrigin`, and `tsconfig.json` with `jsx`, `moduleResolution: "Bundler"` and the `vite/client` types that make an imported picture a module. The README's "A console of your own" shows two of them, the-default-console.md all four with the marks, the icons and a face wired in. Write the plan (the kind, where the build goes, the files, what is configured, what is replaced, the colours and the marks) and stop for the checkpoint; then write the files and build: `npx vite build` makes `dist/` with its `index.html`. A script instead imports `createClient` from `@skillcdn/console/api`, which brings no React.
64
+ Produces the **plan** and the first build. Install first, in the new folder, or in `console-ui/` of the deployment repository, so that the README, the types and the sources are at hand for the plan: the install writes only `package.json`, the lockfile and `node_modules`, and the plan is shown before any file of the console is written. For the organization's console the package is installed at the version the deployment pins: `CONSOLE_REF` in `deploy/console.env` of the deployment repository is the commit of a release tag `@skillcdn/console@<version>`, and `npm install @skillcdn/console@<version>` takes that one, so that the README, the types and the sources are the deployment's own, and the pages and the server are one release. A console is four files and a configuration: `index.html` with a `#root`, `src/main.tsx` that calls `createConsole({ ... }).mount(root)` and imports `@skillcdn/console/console.css`, `vite.config.ts` with the React plugin and, for building against the real board, `/api` sent to `console serve` with `changeOrigin`, and `tsconfig.json` with `jsx`, `moduleResolution: "Bundler"` and the `vite/client` types that make an imported picture a module. The README's "A console of your own" shows two of them, the-default-console.md all four with the marks, the icons and a face wired in. Write the plan (the kind, where the build goes, the files, what is configured, what is replaced, the colours and the marks) and stop for the checkpoint; then write the files and build: `npx vite build` makes `dist/` with its `index.html`. A script instead imports `createClient` from `@skillcdn/console/api`, which brings no React.
66
65
 
67
66
  ### Phase 2: Configure before replacing
68
67
 
69
- Produces the **configuration**. `createConsole(config)` takes `title`; `brand`, the addresses of a symbol and a wordmark; `languages`, the packs the pages speak, where a language of one's own is `src/i18n/en.ts` copied whole and translated; `components`, the pieces to replace, with the props `ConsoleComponents` names; `pages`, tabs of the console's own, each a `CustomPage` with a key, a label by language, a level (the workspace's pages or every project's) and `render`, given the data, the client, the navigation and the words; `baseUrl`, the API's origin, the page's own when left out; and `client`, for tests. The look is the stylesheet's tokens, `--sc-*` on `:root`, set in a stylesheet of the console's own loaded after `console.css`, and the blocks are styled by their `sc-` classes; the package's README lists the tokens by group. A console with marks of its own imports their files in `main.tsx`, so that the build takes them as assets, and passes their addresses through `brand`; `build: { assetsInlineLimit: 0 }` in `vite.config.ts` keeps every picture and font a file, since the policy allows a small picture inlined as a `data:` address but no `data:` font, and the default console only happens to have none small enough; sets `index.html`'s `<title>`, its `lang` and its icons, the mark as `favicon.svg` linked directly, with an `.ico` and a touch icon when the person has them (the default console links three from its brand package through a small build plugin); and loads the faces its languages need. Most wants are configuration or the styles: re-skinning starts and mostly ends with the tokens of `console.css` (the colours, the glass, the field), overridden by a stylesheet of the console's own loaded after the package's, with the mapping of the plan. Replace a component only when configuration cannot do it: start from its source under `src/components/`, keep its props, and keep or add `sc-` classes. With the look in place, show the pages and stop for the look checkpoint.
68
+ Produces the **configuration**, as [configuring.md](references/configuring.md) lays it out: `createConsole(config)` with its `title`, `brand`, `languages`, `components`, `pages`, `baseUrl` and `client`; the look as the tokens of `console.css`, `--sc-*`, set in a stylesheet of the console's own imported in `main.tsx` after the package's, with the mapping of the plan; the marks imported in `main.tsx` so that the build takes them as assets, with `build: { assetsInlineLimit: 0 }` so that every picture and font stays a file; the page's `<title>`, `lang` and icons; the faces its languages need. Most wants are configuration or the styles: re-skinning starts and mostly ends with the tokens. Replace a component only when configuration cannot do it: start from its source under `src/components/`, keep its props, and keep or add `sc-` classes. With the look in place, serve it as phase 4 says, show the pages, and stop for the look checkpoint.
70
69
 
71
70
  ### Phase 3: Compose pages of one's own
72
71
 
73
- Produces the **pages**. For a page the default console lacks: `useConsoleData(client, projectKey)` answers the workspace and the project the page is on, kept current by the project's stream, with the actions; the components take their data as props and nothing from the network; `matchRoute`, `PATHS`, `projectHref`, `taskHref`, `decisionHref` and `docHref` name the addresses; `Shell` is the header with the tabs and the person's menu. A page as a tab is `pages` in the configuration, its `render` composing the components over what it is given; a composition of one's own is `src/console.tsx` with pages added or taken away. A request without a page of its own skips this phase.
72
+ Produces the **pages**. For a page the default console lacks: `useConsoleData(client, projectKey)` answers the workspace and the project the page is on, kept current by the project's stream, with the actions; the components take their data as props and nothing from the network; `matchRoute`, `PATHS`, `projectHref`, `taskHref`, `decisionHref` and `docHref` name the addresses; `Shell` is the header with the tabs and the person's menu. A page as a tab is `pages` in the configuration, its `render` composing the components over what it is given; a composition of one's own is `src/console.tsx` with pages added or taken away (configuring.md "A page of one's own"). A page composes the board's own data and holds none of its own: a page that would keep records, run logic or reach outside is a feature of the organization's work, which is a plugin, not a page ([building-a-plugin](/skills/building-a-plugin/SKILL.md)); a plugin's pages come in its package and run in frames the console serves, drawn into the tabs by the console itself, so that a console's pages need no build and no change for one. A request without a page of its own skips this phase.
74
73
 
75
74
  ### Phase 4: Run it against the board
76
75
 
77
- Produces the **running console**. `console serve` serves the API at `http://127.0.0.1:11197/api/` while `npx vite` serves the pages, and `console serve dist` serves the build whole at `http://127.0.0.1:11197/`. The pages hold no token; the command carries it, on the loopback only. The pages know they hold a token (`GET /api/v1/me` answers `agent`) and offer nothing a token cannot do: the tokens themselves stay on the organization's console, and everything else, configuring included, the pages do on the token as the person ([ADR-0021](/docs/adr/0021-a-token-configures-as-its-person-does.md)). The organization's console is looked at the same way, on the builder's token: it shows every page a token may see, and the pages a token may not (the agents) are the package's own and unchanged, so the look checkpoint covers everything the console changed. Where the organization's build then goes is the plan's answer: `console-ui/` of the deployment repository, whose workflow builds it into the image on every push, handed over to deploying-a-console, the skill beside this one at the same address (in the package under `node_modules/@skillcdn/console/skills/deploying-a-console/`), with the source and the repository, and with the package pinned at the version of the release the deployment pins as `CONSOLE_REF` (the tag `@skillcdn/console@<version>`), so that the pages and the server are one release and move together; the build beside the Dockerfile of [deploy/README.md](/deploy/README.md) "A custom console in the image", for an image the organization builds itself; or the mounted directory. A script: `createClient({ baseUrl, token })`, every answer parsed with the package's schemas; it configures as its person does too, with `createProject`, `updatePerson`, a project's `update`, `setIcon`, `addMember`, `updateMember` and `removeMember`, `createCategory`, `updateCategory` and `removeCategory`, and the rules of the board with `writeRules` and `archiveRules` and a project's as the page `rules` ([ADR-0023](/docs/adr/0023-the-rules-of-a-board-are-pages-the-workspace-and-its-projects-keep-read-first-by-every-agent.md)), refused with `auth.forbidden` where the person may not, and never the tokens.
76
+ Produces the **running console**. `console serve` serves the API at `http://127.0.0.1:11197/api/` while `npx vite` serves the pages, and `console serve dist` serves the build whole at `http://127.0.0.1:11197/`. The pages hold no token; the command carries it, on the loopback only. The pages know they hold a token (`GET /api/v1/me` answers `agent`) and offer nothing a token cannot do: the tokens themselves stay on the organization's console, and everything else, configuring included, the pages do on the token as the person ([ADR-0021](/docs/adr/0021-a-token-configures-as-its-person-does.md)). The organization's console is looked at the same way, on the builder's token: it shows every page a token may see, and the pages a token may not (the agents) are the package's own, reached by the tokens as every page is, so the look checkpoint covers everything but them, which the delivery names. Where the organization's build then goes is the plan's answer: `console-ui/` of the deployment repository, whose workflow builds it into the image on every push, with the package pinned at the deployment's `CONSOLE_REF` version, so that the pages and the server are one release and move together; the first deploy is deploying-a-console's, the skill beside this one at the same address (in the package under `node_modules/@skillcdn/console/skills/deploying-a-console/`), handed the source and the repository, and a console that is already deployed takes the commit in `console-ui/`, whose push the person makes, since a push there deploys; the build beside the Dockerfile of [deploy/README.md](/deploy/README.md) "A custom console in the image", for an image the organization builds itself; or the mounted directory. A script: `createClient({ baseUrl, token })`, every answer parsed with the package's schemas; it configures as its person does too, with the client's methods for projects, members, categories, people and the rules (configuring.md "A script"), refused with `auth.forbidden` where the person may not, and never the tokens.
78
77
 
79
78
  ### Phase 5: Check and show
80
79
 
81
- Produces the **checked build** and the delivery. `npx tsc --noEmit` and `npx vite build` pass; the pages are looked at, with a browser the agent can drive (the board, a task, a decision, the documents, a narrow window, and the browser's console), else by the person at the local address, with the layout, console and policy verdicts reported as not run; `dist/` holds no token and loads no script, style or font from elsewhere. `git init` and a commit of what was made; the CI job is the organization's own: with the reference deployment, the deployment repository's workflow builds `console-ui/`, else a job that runs the two checks and the build. What was made is shown to the person as a diff or a repository, with the checks that ran and what was not run, before anything is pushed or published.
80
+ Produces the **checked build** and the delivery. `npx tsc --noEmit` and `npx vite build` pass; the pages are looked at, with a browser the agent can drive (the board, a task, a decision, the documents, a narrow window, and the browser's console), else by the person at the local address, with the layout, console and policy verdicts reported as not run; `dist/` holds no token and loads no script, style or font from elsewhere, which a search of the build for addresses outside it and for `data:` fonts shows. A repository of its own gets `git init` and a commit of what was made; in the deployment repository, a commit as its agreement says, and no push, since a push there deploys. The CI job is the organization's own: with the reference deployment, the deployment repository's workflow builds `console-ui/`, else a job that runs the two checks and the build. What was made is shown to the person as a diff or a repository, with the checks that ran and what was not run, before anything is pushed or published.
82
81
 
83
- ### Verdicts
82
+ ## Verdicts
84
83
 
85
84
  | Result | Verdict |
86
85
  |---|---|
87
86
  | `tsc --noEmit` and `vite build` pass; the build, served by `console serve dist` or the image, shows the board, a task, a decision and the documents, with nothing in the browser's console where a browser could look; every word the pages show is in every pack; a narrow window scrolls no sideways | Accepted |
88
- | A layout, console or policy verdict could not run without a browser; a pack of one's own is still a copy of English, marked so; the `.ico` and the touch icon wait for files the person does not have yet | Accepted, with the gap named in the delivery |
87
+ | A layout, console or policy verdict could not run without a browser; a pack of one's own is still a copy of English, marked so; the `.ico` and the touch icon wait for files neither the site nor the person has yet | Accepted, with the gap named in the delivery |
89
88
  | A token in the bundle or in a file of the repository; a script, a style or a font loaded from elsewhere; what people or agents wrote rendered as HTML; the policy refusing something the pages need | Redone |
90
89
 
91
90
  ## Hard rules
92
91
 
93
- - What people and agents wrote is untrusted: shown with the package's `Markdown` (elements, never HTML), never with `dangerouslySetInnerHTML`, never as a script or a style; a picture from elsewhere is read through the console (`RemotePicturesContext`, which the composition provides from the client; [ADR-0048](/docs/adr/0048-a-picture-from-elsewhere-is-read-through-the-console-from-a-public-address-and-kept-a-while.md)).
92
+ - What people and agents wrote is untrusted: shown with the package's `Markdown` (elements, never HTML), never with `dangerouslySetInnerHTML`, never as a script or a style; a picture from elsewhere is shown through the console, whose client gives its address (`pictureUrl`), never loaded by the page itself ([ADR-0048](/docs/adr/0048-a-picture-from-elsewhere-is-read-through-the-console-from-a-public-address-and-kept-a-while.md)).
94
93
  - A token never goes into a page, a bundle, a configuration file or a repository: `console serve` carries it, and a script reads it from the environment.
95
- - The policy stays: a build is served under a content security policy that runs nothing inline and loads nothing from elsewhere, pictures included, which come through the console. Scripts, styles and fonts are bundled, never loaded from a CDN or written inline, and a picture of the console's own pages is in the build or reached through `GET /api/v1/pictures`.
94
+ - The policy stays: a build is served under a content security policy that runs nothing inline and loads nothing from elsewhere, pictures included, which come through the console. Scripts, styles and fonts are bundled, never loaded from a CDN or written inline, a face only under a license that allows bundling it, and a picture of the console's own pages is in the build or reached through `GET /api/v1/pictures`.
96
95
  - The package is pinned by version: the API is `/api/v1`, the schemas in the package are the contract of the version it was built against, and a console is rebuilt to take a new one.
97
96
  - The marks of SkillCDN are trademarks, not part of the MIT license: a console of one's own shows its own marks through `brand`, or none.
98
- - Nothing of the server is rebuilt: a console shows the organization's board and holds nothing of its own. A second database is not a console.
97
+ - Nothing of the server is rebuilt: a console shows the organization's board and holds nothing of its own. A second database is not a console, and a feature with data of its own is a plugin, not a page.
99
98
 
100
99
  ## Terms
101
100
 
@@ -0,0 +1,40 @@
1
+ # Configuring a console
2
+
3
+ What `createConsole` takes, how the look is set, how marks, icons and faces go in, how a language is added, when a component is replaced and how a page of one's own is composed, and what a script against the API uses. The package's README lists every export and every token, and the types under `dist/` are exact; this page says what goes where.
4
+
5
+ ## The configuration
6
+
7
+ `createConsole(config)` returns `{ App, mount }`; `config` takes:
8
+
9
+ | Field | What it is |
10
+ |---|---|
11
+ | `title` | What the page says until the server answers with the board's name (`WORKSPACE_NAME`). |
12
+ | `brand` | The addresses of a `symbol`, a `wordmark`, or both, imported as files so that the build takes them as assets. |
13
+ | `languages` | The packs the pages speak; a language of one's own is `src/i18n/en.ts` copied whole and translated, every key kept. |
14
+ | `components` | The pieces to replace, with the props `ConsoleComponents` names. |
15
+ | `pages` | Tabs of the console's own: each a `CustomPage` with a key, a label by language, a level (the workspace's pages or every project's) and `render`, given the data, the client, the navigation and the words. |
16
+ | `baseUrl` | The API's origin; the page's own when left out. |
17
+ | `client` | A client of one's own, for tests. |
18
+
19
+ ## The look
20
+
21
+ The tokens, `--sc-*` on `:root` in the package's `console.css`, grouped as the README lists them (the colours, the glass, the field, the radii, the type), are set in a stylesheet of the console's own loaded after the package's; the blocks are styled by their `sc-` classes. A dark or saturated colour becomes the accent, `--sc-color-accent` and its family (`-solid`, `-contrast`, `-subtle`); a pale one tints the field, `--sc-field-gradient`, with a darker shade of it as the accent, since an accent must read on the light field. The mapping is shown at the plan, value by value, with the contrast checked at 4.5:1 for text ([the-look-from-a-website.md](the-look-from-a-website.md)). The pages are light by default ([ADR-0040](/docs/adr/0040-the-pages-are-light-by-default.md)); darkening them is the person's word, not the default.
22
+
23
+ ## Marks, icons and faces
24
+
25
+ - The marks go in through `brand`, imported in `main.tsx` as files, so that the build bundles them as assets and gives back their addresses. The symbol's slot is a square of one line's height (`.sc-brand-symbol`, 1rem); a wide mark, three or four times its height, is a wordmark and goes in as one, alone or beside a square symbol. A mark drawn in a light colour vanishes on the light pages: take a dark version, or, with the person's word, recolour a one-colour mark.
26
+ - `build: { assetsInlineLimit: 0 }` in `vite.config.ts` keeps every picture and font a file: Vite inlines an asset under 4 KB as a `data:` address, which the policy allows for a picture and refuses for a font (`font-src 'self'`); the default console gets by only because none of its assets is that small.
27
+ - The page's icons: the mark as `favicon.svg` linked directly in `index.html`, with an `.ico` and a touch icon from the site where it has them, else when the person has them; the default console links three from its brand package through a small build plugin ([the-default-console.md](the-default-console.md)).
28
+ - The faces: a face the organization owns, or one under a license that allows bundling, which the person is asked ("Does your organization own the site's typeface, or is it under a license that allows bundling it?"), in the repository and named in `--sc-font-sans`; otherwise the system faces stay. Pretendard for Korean, `npm install pretendard` and its stylesheet imported in `main.tsx`, as the default console does. No script, style or font from a CDN.
29
+
30
+ ## A component replaced
31
+
32
+ Only when configuration cannot do it. Start from the component's source under `src/components/` of the package, keep its props (the types say them), keep or add `sc-` classes so that the tokens still reach it, and pass it in `components`. A component takes its data as props and nothing from the network; what people and agents wrote goes through the package's `Markdown`, elements and never HTML.
33
+
34
+ ## A page of one's own
35
+
36
+ `useConsoleData(client, projectKey)` answers the workspace and the project the page is on, kept current by the project's stream, with the actions; `matchRoute`, `PATHS`, `projectHref`, `taskHref`, `decisionHref` and `docHref` name the addresses; `Shell` is the header with the tabs and the person's menu. A page as a tab is `pages` in the configuration, its `render` composing the components over what it is given; a composition of one's own is `src/console.tsx` of the package copied, with pages added or taken away. A picture from elsewhere in what people wrote is shown through the console: the composition asks the client for its address (`pictureUrl`), and the pages load nothing from elsewhere themselves ([ADR-0048](/docs/adr/0048-a-picture-from-elsewhere-is-read-through-the-console-from-a-public-address-and-kept-a-while.md)).
37
+
38
+ ## A script
39
+
40
+ `createClient` from `@skillcdn/console/api` brings no React: `createClient({ baseUrl, token })`, the token from the environment (`CONSOLE_URL`, `CONSOLE_TOKEN`) and never from a file in the repository; every answer is parsed with the package's schemas, and a refusal is an `ApiError` with the server's stable code. The client configures as its person does too ([ADR-0021](/docs/adr/0021-a-token-configures-as-its-person-does.md)): `createProject`, `updatePerson`, `createListing` and `removeListing`, `updateWorkspace`, `createCategory`, `updateCategory` and `removeCategory`, the rules with `writeRules` and `archiveRules`, and on a project (`client.project(key)`) `update`, `setIcon`, `addMember`, `updateMember`, `removeMember`, the SkillCDN token a private pack is read with (`pack-token`) and the rules as the page `rules` ([ADR-0023](/docs/adr/0023-the-rules-of-a-board-are-pages-the-workspace-and-its-projects-keep-read-first-by-every-agent.md)); refused with `auth.forbidden` where the person may not, and never the tokens themselves, which stay on the console's own pages.
@@ -137,4 +137,4 @@ export default defineConfig({
137
137
  }
138
138
  ```
139
139
 
140
- What a console of one's own changes. In the page: its `<title>` and `lang`, and its icons, linked directly in the page or through the plugin, for its own. In the script: the `title` it passes; the two `@skillcdn/brand` imports, for its own symbol and wordmark (a dark one, since the pages are light), or none; the face it loads, for its languages (`npm install pretendard` for Korean). In the build: the proxy's target, `http://127.0.0.1:11197` with `changeOrigin: true` for `console serve`; the default console's own proxy points at the `api` role's development port, which a console of one's own does not have, and its plugin reads the icons from the brand package, which a console of one's own replaces with files of its own. In the compiler's settings: `jsx`, `moduleResolution` and the `vite/client` types stay, which make an imported picture a module; `extends` and `references` are the repository's and go, with `"strict": true` of the console's own in their place. One thing to add in the build: `build: { assetsInlineLimit: 0 }`, so that every picture and font stays a file; Vite inlines an asset under 4 KB as a `data:` address, which the policy allows for a picture and refuses for a font (`font-src 'self'`), and the default console gets by only because none of its assets is that small.
140
+ What a console of one's own changes. In the page: its `<title>` and `lang`, and its icons, linked directly in the page or through the plugin, for its own. In the script: the `title` it passes; the two `@skillcdn/brand` imports, for its own symbol and wordmark (a dark one, since the pages are light), or none; the face it loads, for its languages (`npm install pretendard` for Korean). In the build: the proxy's target, `http://127.0.0.1:11197` with `changeOrigin: true` for `console serve`; the default console's own proxy points at the `api` role's development port, which a console of one's own does not have, and its plugin reads the icons from the brand package, which a console of one's own replaces with files of its own. In the compiler's settings: `jsx`, `moduleResolution` and the `vite/client` types stay, which make an imported picture a module; `node` leaves `types` unless `@types/node` is installed; `extends` and `references` are the repository's and go, with `"strict": true` and a `target` (`ES2022` or newer) of the console's own in their place. One thing to add in the build: `build: { assetsInlineLimit: 0 }`, so that every picture and font stays a file; Vite inlines an asset under 4 KB as a `data:` address, which the policy allows for a picture and refuses for a font (`font-src 'self'`), and the default console gets by only because none of its assets is that small.
@@ -4,24 +4,24 @@ An organization with a website has a look already: its marks, its colours, its t
4
4
 
5
5
  ## Reading the site
6
6
 
7
- Fetch the homepage as HTML, with the agent's own tools, and read, in this order:
7
+ Fetch the homepage as HTML, with the agent's own tools (a fetch tool, or `curl` from the shell), and its stylesheets where the head links them, and read, in this order:
8
8
 
9
9
  | What | Where it is | What to take |
10
10
  |---|---|---|
11
11
  | The symbol | `<link rel="icon">` and `apple-touch-icon` in the head; an inline `<svg>` in the header; an `<img>` whose name or `alt` says logo, mark or brand | The square mark, as SVG where there is one, else the largest PNG. It goes in `brand.symbol`, in a slot one line high (`.sc-brand-symbol`). |
12
12
  | The wordmark | The same header: the name as lettering, wide, often an SVG beside or instead of the symbol | `brand.wordmark`, alone or beside the symbol. A mark three or four times wider than high is a wordmark, not a symbol. |
13
- | The colours | `<meta name="theme-color">`; custom properties on `:root` in the site's stylesheet (`--color-primary`, `--brand`, `--accent` and their kin); the fill of the primary button and the colour of links | One primary colour, as a value; a second where the site plainly has two. |
13
+ | The colours | `<meta name="theme-color">`; custom properties on `:root` in the site's stylesheet (`--color-primary`, `--brand`, `--accent` and their kin); the rule that fills the primary button and the one that colours links, read from the stylesheet | One primary colour, as a value; a second where the site plainly has two. |
14
14
  | The type | `font-family` of the body and of the headings, in the stylesheet | The names, to tell the person; a face is loaded only as the rules below allow. |
15
15
  | The mood | The site itself: dark or light, flat or glassy, round or square corners | Whether the field stays light (the pages are light by default, ADR-0040; a dark site is said at the plan, and darkening the pages is the person's word, not the default), and whether the radii follow the site (`--sc-radius-*`). |
16
16
 
17
- A site that cannot be fetched (a login wall, a block, no site after all) ends the reading: say so in one line and ask the person for the files, or keep the honest default.
17
+ A site that cannot be fetched (a login wall, a block, no site after all), or one fetched that shows no mark or no colour of its own, ends the reading: say so in one line and ask the person for the files, or keep the honest default, the board's name alone.
18
18
 
19
19
  ## Mapping onto the pages
20
20
 
21
21
  The pages are light: a pale field, and panes of frosted glass over it. The mapping is shown at the plan as a table, value by value, before a file is written.
22
22
 
23
23
  - **A mark drawn in a light colour vanishes** on the light pages. Take the site's dark or black variant first (its header on a light page, a light-mode asset, a `prefers-color-scheme` rule). Found none, and the mark is one colour: recolour it to the pages' text colour, with the person's word, since the mark is theirs. A mark of several colours on a light fill: keep its fill as a rounded square behind it.
24
- - **A dark or saturated primary colour** becomes the accent: `--sc-color-accent` and its family (`-solid`, `-contrast`, `-subtle`, the point), as the package's README lists them.
24
+ - **A dark or saturated primary colour** becomes the accent: `--sc-color-accent` and its family (`-solid`, `-contrast`, `-subtle`), as the package's README lists them.
25
25
  - **A pale primary colour** tints the field: `--sc-field-gradient`, with a darker shade of it as the accent, since an accent must read on the light field.
26
26
  - **Contrast is checked**, not assumed: the accent on the field, and text on the panes, at the 4.5:1 of WCAG AA for text; a shade is moved until it passes, and the plan says which.
27
27
  - **The type follows the rules of the skill**: scripts, styles and fonts are bundled, never loaded from a CDN or written inline. A face the organization owns, or one under a license that allows bundling, is put in the repository and named in `--sc-font-sans`; otherwise the system faces stay, and the plan says that the site's face was not taken and why. Pretendard stays for Korean, as the default console has it.
@@ -36,4 +36,4 @@ The pages are light: a pale field, and panes of frosted glass over it. The mappi
36
36
 
37
37
  ## Where it goes
38
38
 
39
- For an organization's console deployed with deploying-a-console, the result is the source in `console-ui/` of the deployment repository, depending on `@skillcdn/console` at the console's pinned version, which the workflow builds into the image on every push; the first deploy already carries the look. For a console of one's own, the same configuration in its own repository. Either way the look checkpoint shows the pages, a screenshot where a browser can be driven, before more is built on it.
39
+ For an organization's console deployed with deploying-a-console, the result is the source in `console-ui/` of the deployment repository, depending on `@skillcdn/console` at the console's pinned version, which the workflow builds into the image on every push; the first deploy already carries the look. For a console of one's own, the same configuration in its own repository. Either way the pages are shown before more is built on them, at the plan of deploying-a-console or at the look checkpoint of building-a-console, a screenshot where a browser can be driven.
@@ -0,0 +1,137 @@
1
+ ---
2
+ name: building-a-plugin
3
+ description: "Writes a plugin of the SkillCDN Console: one npm package that adds a feature of an organization's work (leave, customers, money) to a console, under its rule that people decide and agents work. The feature is split into commands and queries an agent runs, decisions and tasks people answer on a board project, hooks and jobs the console runs itself, and pages people see; written from console-plugin init, kept in records or a schema of its own, run on a local console, tested and checked as a console would, published or tagged, and handed to the deployment. Use when a person says 'write a plugin for leave', 'add a feature to the console for our customers', 'the console should track X'. For a console's own pages, use building-a-console; to install a plugin, deploying-a-console; to work one, working-the-board. docs/specs/plugins.md is the reference for every field, bound and refusal; this skill says what to ask, how to split the work and how it is checked. Nothing is spent or published without the person's word."
4
+ license: MIT
5
+ compatibility: A shell with Node.js 24 or newer, npm and git, and an agent that reads and writes files. For running the plugin on a local console, Docker for the database and a checkout of the console's repository, where signing in needs a GitHub OAuth app of the person's own, as the console's README says. The console command is optional, for running the plugin's commands as an agent would. No key of the agent's own is needed, and it never sees a token.
6
+ metadata:
7
+ author: skillcdn
8
+ version: "1.0"
9
+ skillcdn:
10
+ translations:
11
+ ko:
12
+ title: 콘솔 플러그인 만들기
13
+ description: "SkillCDN 콘솔의 플러그인을 만듭니다. 조직 업무의 기능 하나(연차, 고객, 돈)를 npm 패키지 하나로 콘솔에 더하되, 사람은 정하고 에이전트는 일한다는 콘솔의 규칙 아래 둡니다. 기능을 에이전트가 돌리는 명령과 조회, 보드 프로젝트에서 사람이 답하는 결정과 작업, 콘솔이 스스로 돌리는 훅과 잡, 사람이 보는 페이지와 위젯으로 나누고, console-plugin init으로 시작해, 콘솔이 보관하는 레코드나 자기 스키마에 데이터를 두고, 패키지를 PLUGINS_DIR에 링크한 로컬 콘솔에서 돌리고, 패키지의 테스트 컨텍스트와 console-plugin check로 검사하고, 발행하거나 태그를 붙이고, 배포에 설치 작업으로 넘깁니다. '연차 플러그인 만들어줘', '고객 관리 기능을 콘솔에 넣어줘', '콘솔이 X를 추적하면 좋겠어'라고 할 때 쓰세요. 콘솔의 페이지 자체는 building-a-console, 플러그인 설치는 deploying-a-console, 보드에서 플러그인으로 일하기는 working-the-board를 쓰세요. 필드·한도·거절의 기준은 docs/specs/plugins.md이고, 이 스킬은 무엇을 묻고, 일을 어떻게 나누고, 어떻게 검사하는지를 말합니다. 비용은 들지 않고, 사람의 말 없이는 발행하지 않습니다."
14
+ ---
15
+ # Building a plugin of the console
16
+
17
+ What goes in: a feature of the organization's work that the console should carry, in the person's words, and who uses it. What comes out: a repository holding one npm package, the plugin: its manifest, its server module, its web bundle where people look at it, its skills, its tests and its build, checked as a console would check it; and the install, handed to the deployment as a task, since a plugin reaches a console by being built into its image and turned on by an administrator ([ADR-0049](/docs/adr/0049-a-plugin-is-an-npm-package-installed-into-the-image-and-enabled-by-an-administrator.md)). The console holds the people, the projects, the board, the records and the frames; the plugin holds the feature's logic and nothing of the console's. It runs in a host the console keeps apart from everything else and reaches the console only through what its manifest declared and an administrator consented to ([ADR-0050](/docs/adr/0050-plugin-code-runs-in-a-host-process-of-its-own-and-reaches-the-console-only-through-the-capabilities-it-declared.md)); so the first work is deciding what the feature asks for, and asking for the least.
18
+
19
+ The contract is the [specification of plugins](/docs/specs/plugins.md): every field of the manifest, every member of `ctx`, every capability with what it opens, every bound and every refusal. This skill repeats none of them; where it and the specification differ, the specification is right.
20
+
21
+ ## How the person is involved
22
+
23
+ - **Questions:** one message, before anything is written, with what the request leaves open under "Inputs": what the feature does and for whom, what a person must decide and what an agent may do alone, where it reaches (a board, which projects, people, an outside service), what it keeps, its name. Plain words; the person need not be a developer.
24
+ - **Checkpoints:** the design (phase 1), as the table of the split and the manifest's capabilities read aloud as the sentences an administrator will consent to; the pages, once they run on a local console (phase 4), where a browser can show them; publishing or tagging (phase 5), named with where it goes. One short message each, with the recommendation, and "OK" continues.
25
+ - **Go-ahead:** when the person says to go ahead alone, the design is still shown before code, and publishing is still confirmed; the rest needs no answer.
26
+ - **Language:** the conversation's in chat; code, identifiers, commit messages and the plugin's skills in English; what people read of the plugin (its name, description, agent note, roles, settings, pages) in every language the organization uses, through the manifest's language maps, `en` first.
27
+
28
+ ## Requirements
29
+
30
+ | Need | How | When missing |
31
+ |---|---|---|
32
+ | Node.js 24 or newer, npm, git | `node --version`, `npm --version`, `git --version` | Stop and tell the person: the console's runtime is Node.js 24, and the check runs the plugin as the console would. |
33
+ | The authoring command | `console-plugin`, a second command of `@skillcdn/console`: with the package installed globally (`npm install -g @skillcdn/console`, which also gives the console command), or `npx --package @skillcdn/console console-plugin ...` | `npm install -g @skillcdn/console`; `console-plugin help` says its two commands. |
34
+ | The specification and the types | In the plugin's own `node_modules/@skillcdn/console/` once installed (phase 2): `docs/specs/plugins.md`, the package's `README.md`, the types under `src/plugin/`, and this skill under `skills/building-a-plugin/`; or through the connection that served this skill | Read them there; this skill is a map of them. |
35
+ | A local console to run the plugin on (phase 4) | A checkout of the console's repository with Docker for its database, run as its README's "Install" says, with `PLUGINS_DIR` set; signing in there needs a GitHub OAuth app of the person's own, registered for the local address as `apps/console/README.md` of the console says | Phases 1 to 3 and 5 need none; phase 4 is then reported as not run, and the plugin is proven on the deployment's console after the install. |
36
+ | The console command, signed in on that console | `console login --url http://127.0.0.1:11199`, approved on the local console's pages; `console whoami` | Optional: the plugin's commands are tried on the pages, or through the frame alone. |
37
+
38
+ ## Where to read, in this order
39
+
40
+ 1. [docs/specs/plugins.md](/docs/specs/plugins.md): "Words", "The package", "The manifest", "The server module", "The context", "Capabilities", "Roles and grants", "Settings", "Records" or "SQL", "The board", "Events, hooks and jobs", then "Pages" when the plugin has any, and "Security model", "Limits and refusals" and "Authoring" before the check. Every name this skill uses is defined there.
41
+ 2. The plugin `console-plugin init` writes (phase 2): a manifest, a server module with one collection, one command and one query, a web bundle with one page and one widget, one skill, the tests and the build, each file saying what it is for. It is the smallest complete plugin, and `examples/plugin-hello` of the console's repository is the same plugin built.
42
+ 3. The package's README, "A plugin": the shape of `definePlugin` and its definers, `connect()` of the web bundle, `createTestContext` of the tests and the two commands, in a page.
43
+ 4. [deploy/README.md, "Plugins in the image"](/deploy/README.md#plugins-in-the-image): how a deployment installs the plugin, and what `storage:sql`, an `outbound` host or files ask of it, which the hand-over of phase 5 names.
44
+ 5. The decisions, for why: [ADR-0051](/docs/adr/0051-a-plugin-keeps-its-data-in-records-the-console-holds-or-in-a-schema-of-its-own-by-consent.md) (records or a schema), [ADR-0052](/docs/adr/0052-a-plugins-board-is-a-project-made-or-chosen-when-it-is-enabled-and-what-it-puts-there-carries-its-name.md) (the board project), [ADR-0053](/docs/adr/0053-agents-reach-a-plugin-through-one-command-whose-definitions-the-console-holds.md) (one command for agents), [ADR-0054](/docs/adr/0054-a-plugins-pages-run-in-a-sandboxed-frame-and-speak-only-to-their-plugin.md) (the frames).
45
+
46
+ ## Inputs
47
+
48
+ | Input | Source |
49
+ |---|---|
50
+ | The feature | What the person said, in chat or in a document they point to: what the organization does today by hand or in a spreadsheet, and what the console should carry of it. One feature is one plugin; two features that share nothing are two. |
51
+ | Who uses it | Asked: "Who uses this: everyone, or some people? What may each kind of person do?" Each kind is a role of the manifest; a role everyone holds is `defaultRole`; the rest are granted by the administrator. Up to the bound the specification names. |
52
+ | What people decide | Asked: "What must a person approve or choose here, and who?" Each is a decision the plugin raises on its board project, addressed to the person the setting or the record names; the plugin never decides it. A feature where nobody decides anything has `board.needs: "none"`. |
53
+ | What agents do, and read | Derived from the feature: each thing an agent does for a person is a command (it writes), each thing it looks up a query (it reads); named as verbs and nouns an agent would type after `console plugin <key>`, with arguments in the console's own forms (a text, a number, a day, a person by login, a project by key, a file, a record). |
54
+ | What happens on its own | Derived: what the console must tell the plugin (a decision answered, a task done, a member added) is a hook on the console's events; what another plugin tells it is a hook on that plugin's events; what time brings (a balance renewed, a reminder) is a job on a schedule; what an outside service sends is a webhook endpoint; what the plugin must fetch is an outbound request to a host the manifest names, with a secret the administrator sets. |
55
+ | Where it reaches | Asked when the feature does not say: "Does it belong to one project, to some, or to every project of the workspace?" Pages at the workspace level, at the project level, or both; the projects the plugin is on named by the administrator at enable. |
56
+ | What it keeps | Derived: the collections, each with its fields, what is filtered and ordered by (`indexes`), searched (`search`), who owns a record (`owner`), whether a record belongs to a project, whether history is kept, who may read; or a schema of its own with `storage:sql`, by the rule of phase 1. |
57
+ | The key and the name | The key from the feature's one word, lowercase, as the specification's rule and reserved words allow (`leave`, `crm`, `finance`); the name and the description per language; the agent note, one sentence an agent reads with the rules: what the plugin is for and when to use it. Shown at the design checkpoint and changed on request. |
58
+ | Where the code lives, and how it ships | Asked: "A repository of its own on GitHub, under which account? Published to npm, or installed from the repository's tag?" Default: a repository `console-plugin-<key>`, and publishing when the person has an npm account, a tag otherwise. |
59
+ | The deployment | Asked: "Which console is this for, and who runs its deployment?" The install is a task for them (phase 5). |
60
+ | Everything else | Derived and shown in the design: the capabilities from the split, the settings (a number the organization chooses, a person who approves, a secret for an outside service), the board project's defaults (its key, name and description), the menu group, the pages and the widgets with their roles, `dataVersion: 1`. |
61
+
62
+ ## Workflow
63
+
64
+ Each phase produces something the person can look at and ends with one line to them; phases 1, 4 and 5 stop for a checkpoint.
65
+
66
+ ### Phase 1: Split the feature so that agents work and people decide
67
+
68
+ Produces the **design**: one table, a row per thing the feature does, saying who starts it and what it becomes in the plugin. The questions to ask of each row, in this order:
69
+
70
+ | The row | What it becomes |
71
+ |---|---|
72
+ | An agent does it for a person, and something changes | A **command**: `defineCommand({ about, args, roles, run })`. Its `text` answer is for people, its `data` for agents (`--json`); it does one thing and does it again safely where it can. |
73
+ | An agent, or a page, looks something up | A **query**: `defineQuery(...)`, which writes nothing; a query may answer a file. |
74
+ | A person must approve, choose or confirm | A **decision** the command raises with `ctx.console.decisions.ask`, with options, addressed to the person a setting or the record names (`deciderId`), `about` the record it is for; the command answers `waiting`, the agent waits as the console's own `ask` is waited for, and the plugin hears the answer in a hook on `console:decision.answered` and goes on. The plugin never answers one, and never computes what a person must choose. |
75
+ | Someone must do something later | A **task** on the board project with `ctx.console.tasks.create`, marked as the plugin's, worked by whoever takes it. |
76
+ | The console must tell the plugin something happened | A **hook**, `on["console:<kind>"]` (`events:console`): the plugin's board project, the projects it is on and the items it made are what it hears of. Delivery is at least once: a handler reads the record first and does nothing twice. |
77
+ | Another plugin must tell it | A **hook** on `plugin:<key>:<kind>` (`events:plugins`), or a call on the other's `api` (`plugins:<key>`). |
78
+ | Time passes | A **job** (`jobs`), `every` or `at` in the workspace's time zone, never two at once; what it did goes into records and, where people should know, a task or a decision. |
79
+ | An outside service calls in | An **endpoint** (`endpoints`): a `person` endpoint for whoever holds a role, a `webhook` for nobody, verified with `ctx.secrets.verify` against a secret setting. |
80
+ | The plugin must call out | `ctx.fetch` to a host the manifest names (`outbound:<host>`), the secret put in by the console from a `secret` setting, never read by the plugin. |
81
+ | People look at it, or fill a form | A **page** (level `workspace` or `project`) or a **widget** on the front page: it shows records and calls commands and queries through the bridge; the logic stays in the server module, so that the command line and the pages do the same thing. |
82
+ | An agent must know how | A **skill** in the package, one per kind of work, naming the commands as `console plugin <key> <command>`, with the rules of that work; `SKILLCDN.md` at the root. The agent note of the manifest is the one line that sends an agent to them. |
83
+
84
+ Then the data. Records, unless the feature needs what records do not give: joins across many collections, more rows than a plugin's records may hold, or figures beyond counting, summing, the least and the most; then `storage:sql`, a schema and a role of the plugin's own with migrations under `migrations/`, which needs the deployment's database user to hold `CREATEROLE` and is said in the hand-over. Records are the default: the console keeps them with versions, files, links, search and aggregates, exports and purges them, and shows them to people by role; a schema is the plugin's to keep.
85
+
86
+ Then the capabilities: the list the split needs, each read as the sentence the administrator will consent to (the specification's catalogue says what each opens and what a malicious plugin could do with it). A capability no row needs is dropped; `people:read:all`, `projects:read:all`, `storage:sql` and every `outbound:<host>` are asked for only where the design shows the row that needs them. Write the design: the table, the collections with their fields, the roles, the settings, the board (`needs`, the defaults), the menu group, the pages and the widgets, and the capabilities with their sentences; stop for the checkpoint.
87
+
88
+ ### Phase 2: Start from the template, then fill it
89
+
90
+ Produces the **plugin as source**. `console-plugin init <dir> --key <key> --name "<Name>"` writes the smallest complete plugin: the manifest, a server module with one collection, one command and one query, a web bundle with one page and one widget, one skill with its `SKILLCDN.md`, the tests, the build and a README that says where things are; `--console` names the version of `@skillcdn/console` it depends on, the command's own unless said, and for a plugin written for a deployed console, the version that console runs (`console whoami` says it). Then, in `<dir>`: `npm install`, `npm run build`, `npm test`, `npm run check`, all green before a line is changed, and `git init`.
91
+
92
+ Then the design goes in, file by file: the manifest `console-plugin.json` from the design, its `key`, names and descriptions per language, `agentNote`, `capabilities`, `roles` and `defaultRole`, `board`, `settings`, `menu`, `pages`, `widgets`, `dataVersion`; the server module `src/server/index.ts`, one `defineCollection` per collection, one `defineCommand` or `defineQuery` per row, `endpoints`, `on`, `jobs`, `api`, `onEnable` and `onDisable` where the design has them, exported by name for the tests and gathered in `definePlugin(...)` as the default export; the web bundle `src/web/index.ts` and `index.css`, where `connect()` gives the page the context (who looks, at what, in which language), `command`, `query`, `records`, `files`, `navigate`, `download`, `setTitle` and the events, every class prefixed `pl-<key>-`, the console's `sc-` classes and `--sc-*` tokens for the look, and every word a person wrote put in as text; the skills under `skills/<name>/SKILL.md`, one per kind of work, in the SkillCDN Format, and the README of the package. The server module imports only what the host allows and bundles everything it imports; it keeps no state between calls but in records, since its thread is started afresh after a fault. Where the design has `storage:sql`, `migrations/0001-<words>.sql` makes the tables, and `manifest.migrations` names the directory.
93
+
94
+ ### Phase 3: Test it as the console runs it
95
+
96
+ Produces the **tests**, green. `src/server/index.test.ts` runs each command, query, hook and job against `createTestContext({ collections, plugin, caller, console, secrets, ... })` from `@skillcdn/console/plugin/testing`: the records in memory, checked against the schema and the indexes as the console checks them; the console answering what the test provided (a person, a project, a task) and refusing the rest as `plugin.forbidden`; `emitted` and `logged` to assert on; `as(caller)` to run the same store as another person. One test per row of the design: what it does, what it refuses (a schema it does not fit, a role it lacks, a record another owns), and what it tells people. The template's second test builds the package and runs `console-plugin check` on it, as a console or a store would, and fails on anything the console would refuse the plugin for: an invalid manifest, a server module that does not load under the host's hardening or names what the manifest does not declare, a built-in the host refuses, a web bundle that is not self-contained, a license that is not permissive, `files` that leave out what runs. `npm run typecheck`, `npm test` and `npm run check` are the three that pass before phase 4, and before every commit.
97
+
98
+ ### Phase 4: Run it on a local console
99
+
100
+ Produces the **plugin running**, enabled, with its commands tried and its pages shown. The console from its checkout, as the console's README's "Install" says, with one difference: before the api starts, `.env` sets `PLUGINS_DIR` to a directory made for the purpose, whose `package.json` is `{ "private": true, "dependencies": {} }` and in which `npm install --ignore-scripts <path to the plugin>` writes the plugin as a `file:` dependency and links `node_modules/<its name>` to the checkout, built; the console reads the link where it points, so the checkout is the plugin, and `npm run build` in it followed by a restart of the api is a new version. The person signs in on the local console as its administrator (`ADMINS` in `.env`, a GitHub OAuth app registered for the local address, as `apps/console/README.md` of the console says), opens the plugins' settings page, where the plugin is listed as installed with any reason it failed to load, and enables it: the consent to each capability, the board project made from the manifest's defaults or chosen, the projects it is on, the settings; or their agent does the same with `console plugin <key> enable` ([setting-up.md](/skills/planning-the-board/references/setting-up.md), "A plugin's board project"), signed in there with `console login`. The compose database's user owns the database, so `storage:sql` is available locally. Then the tabs appear where the manifest put them, and the plugin is worked as an agent works it ([working-the-board](/skills/working-the-board/SKILL.md)): `console plugin <key>` lists the commands, `console plugin <key> <command> ...` runs one, a decision raised is answered on the pages, a hook runs, a job runs at its time (the worker inside the api, locally), and the pages are looked at with a browser the agent can drive, else by the person. What is seen is shown at the checkpoint; what could not run is reported as not run.
101
+
102
+ ### Phase 5: Ship, and hand the install to the deployment
103
+
104
+ Produces the **release** and the **hand-over**. The version in `package.json` moves as semver says, `dataVersion` moves with an entry in `upgrades` whenever the shape of a record changed; `npm run build`, `npm test` and `npm run check` pass; a commit, and a push of the repository. Then one of two, confirmed with its consequence: `npm publish` (`--access public` for a scoped name), which puts the package on the registry under that name for good, and is done by the person or with their word; or a tag `v<version>` whose tree carries the built package (the template's `.gitignore` leaves `dist/` out of git, so a release commit adds it with `git add -f dist` before the tag), since the deployment installs with no scripts and runs no build. The deployment then names the plugin as `"<name>": "<version>"` or `"github:<owner>/<repo>#v<version>"`.
105
+
106
+ The hand-over is a task on the deployment's board, written as [planning-the-board](/skills/planning-the-board/SKILL.md) writes one, or the same words in chat where there is no board: the package and its version, and how it is installed ([deploy/README.md, "Plugins in the image"](/deploy/README.md#plugins-in-the-image), a row of deploying-a-console's [running-it-again.md](/skills/deploying-a-console/references/running-it-again.md)); what the deployment must provide, where the plugin asks it (`CREATEROLE` for `storage:sql`, the hosts of `outbound`, a bound on the files); what the administrator does when they enable it: the capabilities they consent to, the board project, the projects, the settings to fill and the secrets to set, the roles and who gets them; and where the plugin's skills are once it runs (`console plugin <key> skills`). The deployment's agent installs it as a release of the deployment; the administrator enables it; the plugin is then proven on that console as phase 4 proved it locally, and that is the delivery.
107
+
108
+ ## Verdicts
109
+
110
+ | Result | Verdict |
111
+ |---|---|
112
+ | `npm run typecheck`, `npm test` and `npm run check` pass; the design's every row is a command, a query, a decision, a task, a hook, a job, an endpoint, a page or a widget of the plugin, with a test; the plugin was enabled on a local console, its commands ran and its pages were shown; the package is published or tagged and the install is a task of the deployment | Accepted |
113
+ | A local console could not run (no Docker, no OAuth app), so phase 4 is reported as not run and the proof waits for the deployment's console | Accepted, with the gap named in the delivery |
114
+ | `console-plugin check` warns of a capability no code uses, a class without the prefix or a private package, and the person wants it so | Accepted, with the warning named |
115
+ | The plugin decides what a person should (an approval computed, a decision answered), reaches what it did not declare, reads a secret's value, renders what people wrote as HTML, or keeps state outside records; `check` fails; a capability is asked for without a row that needs it | Redone |
116
+
117
+ ## Hard rules
118
+
119
+ - People decide: a plugin raises decisions and waits; it never answers one, never acts as a person it is not, and never computes an approval. What it makes on a board carries its name and is reversible by people.
120
+ - The fewest capabilities: each one in the manifest has a row of the design that needs it, and the sentence an administrator reads for it is true of the code. `check` warns of one no definition uses; it is dropped.
121
+ - A secret is a `secret` setting the administrator sets, put into a request by the console or verified by it; the plugin never reads its value, logs it, keeps it in a record, or puts it in the repository, the tests or the chat.
122
+ - Everything a person wrote is shown as text, in the pages and in a command's answer; the frame renders no HTML from a record, and its classes are prefixed `pl-<key>-`.
123
+ - The server module imports nothing the host refuses, reaches no network but `ctx.fetch`, no file but its own, and keeps no state between calls but in records; a hook does nothing twice.
124
+ - Nothing is published, tagged for an install or installed without the person's word; the install is the deployment's release, planned and started by its people, never by this skill.
125
+ - The specification wins: a field, a bound or a refusal is as [docs/specs/plugins.md](/docs/specs/plugins.md) says; the plugin is rebuilt against the console it runs on, since before 1.0 the plugin API moves with the console's line.
126
+
127
+ ## Terms
128
+
129
+ The specification's "Words" table defines the plugin's own: plugin, manifest, host, capability, role, board project, record and collection, command and query, endpoint, hook and job, frame and bridge, widget. Beside them here: **the design**, the table of phase 1, which the manifest and the tests are read against; **the split**, how a feature becomes rows of that table so that agents work and people decide; **the hand-over**, the task that carries the install to the deployment; **a local console**, the console from its checkout with the plugin linked into `PLUGINS_DIR`.
130
+
131
+ ## Beside this skill
132
+
133
+ - The contract, every field, bound and refusal: [docs/specs/plugins.md](/docs/specs/plugins.md).
134
+ - How a deployment installs a plugin: [deploy/README.md, "Plugins in the image"](/deploy/README.md#plugins-in-the-image); as a change to a deployed console, [deploying-a-console](/skills/deploying-a-console/SKILL.md), "Running it again".
135
+ - Enabling a plugin and its board project, for an administrator's agent: [planning-the-board](/skills/planning-the-board/SKILL.md), setting-up.md "A plugin's board project".
136
+ - Working a plugin on the board, as the agents who use it will: [working-the-board](/skills/working-the-board/SKILL.md).
137
+ - A console's own pages, which show the board and hold nothing of their own: [building-a-console](/skills/building-a-console/SKILL.md).