@skillcdn/console 0.4.1 → 0.4.3
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.
- package/README.md +19 -2
- package/SKILLCDN.md +7 -5
- package/dist/api.d.ts +5 -4
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +5 -4
- package/dist/api.js.map +1 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +569 -48
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/format.d.ts +34 -3
- package/dist/cli/format.d.ts.map +1 -1
- package/dist/cli/format.js +283 -7
- package/dist/cli/format.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +44 -7
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/plugin-check.d.ts +26 -0
- package/dist/cli/plugin-check.d.ts.map +1 -0
- package/dist/cli/plugin-check.js +396 -0
- package/dist/cli/plugin-check.js.map +1 -0
- package/dist/cli/plugin-cli.d.ts +20 -0
- package/dist/cli/plugin-cli.d.ts.map +1 -0
- package/dist/cli/plugin-cli.js +189 -0
- package/dist/cli/plugin-cli.js.map +1 -0
- package/dist/cli/plugin-init.d.ts +37 -0
- package/dist/cli/plugin-init.d.ts.map +1 -0
- package/dist/cli/plugin-init.js +206 -0
- package/dist/cli/plugin-init.js.map +1 -0
- package/dist/cli/plugin-main.d.ts +3 -0
- package/dist/cli/plugin-main.d.ts.map +1 -0
- package/dist/cli/plugin-main.js +28 -0
- package/dist/cli/plugin-main.js.map +1 -0
- package/dist/client.d.ts +100 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +79 -7
- package/dist/client.js.map +1 -1
- package/dist/compat.d.ts +1 -1
- package/dist/compat.js +2 -2
- package/dist/components/board.d.ts +8 -0
- package/dist/components/board.d.ts.map +1 -1
- package/dist/components/board.js +59 -15
- package/dist/components/board.js.map +1 -1
- package/dist/components/comments.d.ts.map +1 -1
- package/dist/components/comments.js +1 -1
- package/dist/components/comments.js.map +1 -1
- package/dist/components/decision-form.d.ts +2 -1
- package/dist/components/decision-form.d.ts.map +1 -1
- package/dist/components/decision-form.js +36 -4
- package/dist/components/decision-form.js.map +1 -1
- package/dist/components/decision-list.d.ts +4 -0
- package/dist/components/decision-list.d.ts.map +1 -1
- package/dist/components/decision-list.js +29 -3
- package/dist/components/decision-list.js.map +1 -1
- package/dist/components/event-feed.d.ts +1 -1
- package/dist/components/event-feed.d.ts.map +1 -1
- package/dist/components/event-feed.js +33 -1
- package/dist/components/event-feed.js.map +1 -1
- package/dist/components/my-decisions.d.ts +2 -0
- package/dist/components/my-decisions.d.ts.map +1 -1
- package/dist/components/my-decisions.js +2 -2
- package/dist/components/my-decisions.js.map +1 -1
- package/dist/components/plugin-frame.d.ts +52 -0
- package/dist/components/plugin-frame.d.ts.map +1 -0
- package/dist/components/plugin-frame.js +314 -0
- package/dist/components/plugin-frame.js.map +1 -0
- package/dist/components/plugin-settings.d.ts +38 -0
- package/dist/components/plugin-settings.d.ts.map +1 -0
- package/dist/components/plugin-settings.js +348 -0
- package/dist/components/plugin-settings.js.map +1 -0
- package/dist/components/shell.d.ts +2 -0
- package/dist/components/shell.d.ts.map +1 -1
- package/dist/components/shell.js +26 -1
- package/dist/components/shell.js.map +1 -1
- package/dist/components/task-view.d.ts +2 -1
- package/dist/components/task-view.d.ts.map +1 -1
- package/dist/components/task-view.js.map +1 -1
- package/dist/components/workspace.d.ts +7 -1
- package/dist/components/workspace.d.ts.map +1 -1
- package/dist/components/workspace.js +1 -1
- package/dist/components/workspace.js.map +1 -1
- package/dist/console.css +330 -1
- package/dist/console.d.ts.map +1 -1
- package/dist/console.js +152 -41
- package/dist/console.js.map +1 -1
- package/dist/data.d.ts +9 -2
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +45 -9
- package/dist/data.js.map +1 -1
- package/dist/i18n/en.d.ts +155 -0
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +166 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/ko.d.ts.map +1 -1
- package/dist/i18n/ko.js +150 -0
- package/dist/i18n/ko.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/limits.d.ts +2 -0
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +2 -0
- package/dist/limits.js.map +1 -1
- package/dist/plugin/args.d.ts +148 -0
- package/dist/plugin/args.d.ts.map +1 -0
- package/dist/plugin/args.js +369 -0
- package/dist/plugin/args.js.map +1 -0
- package/dist/plugin/bridge.d.ts +146 -0
- package/dist/plugin/bridge.d.ts.map +1 -0
- package/dist/plugin/bridge.js +125 -0
- package/dist/plugin/bridge.js.map +1 -0
- package/dist/plugin/capabilities.d.ts +20 -0
- package/dist/plugin/capabilities.d.ts.map +1 -0
- package/dist/plugin/capabilities.js +133 -0
- package/dist/plugin/capabilities.js.map +1 -0
- package/dist/plugin/context.d.ts +380 -0
- package/dist/plugin/context.d.ts.map +1 -0
- package/dist/plugin/context.js +2 -0
- package/dist/plugin/context.js.map +1 -0
- package/dist/plugin/define.d.ts +208 -0
- package/dist/plugin/define.d.ts.map +1 -0
- package/dist/plugin/define.js +482 -0
- package/dist/plugin/define.js.map +1 -0
- package/dist/plugin/definition-error.d.ts +11 -0
- package/dist/plugin/definition-error.d.ts.map +1 -0
- package/dist/plugin/definition-error.js +17 -0
- package/dist/plugin/definition-error.js.map +1 -0
- package/dist/plugin/limits.d.ts +67 -0
- package/dist/plugin/limits.d.ts.map +1 -0
- package/dist/plugin/limits.js +70 -0
- package/dist/plugin/limits.js.map +1 -0
- package/dist/plugin/load-worker.d.ts +7 -0
- package/dist/plugin/load-worker.d.ts.map +1 -0
- package/dist/plugin/load-worker.js +41 -0
- package/dist/plugin/load-worker.js.map +1 -0
- package/dist/plugin/load.d.ts +18 -0
- package/dist/plugin/load.d.ts.map +1 -0
- package/dist/plugin/load.js +62 -0
- package/dist/plugin/load.js.map +1 -0
- package/dist/plugin/manifest.d.ts +237 -0
- package/dist/plugin/manifest.d.ts.map +1 -0
- package/dist/plugin/manifest.js +411 -0
- package/dist/plugin/manifest.js.map +1 -0
- package/dist/plugin/refusals.d.ts +49 -0
- package/dist/plugin/refusals.d.ts.map +1 -0
- package/dist/plugin/refusals.js +79 -0
- package/dist/plugin/refusals.js.map +1 -0
- package/dist/plugin/rest-schemas.d.ts +556 -0
- package/dist/plugin/rest-schemas.d.ts.map +1 -0
- package/dist/plugin/rest-schemas.js +262 -0
- package/dist/plugin/rest-schemas.js.map +1 -0
- package/dist/plugin/sandbox.d.ts +23 -0
- package/dist/plugin/sandbox.d.ts.map +1 -0
- package/dist/plugin/sandbox.js +99 -0
- package/dist/plugin/sandbox.js.map +1 -0
- package/dist/plugin/testing.d.ts +45 -0
- package/dist/plugin/testing.d.ts.map +1 -0
- package/dist/plugin/testing.js +420 -0
- package/dist/plugin/testing.js.map +1 -0
- package/dist/plugin/web-react.d.ts +11 -0
- package/dist/plugin/web-react.d.ts.map +1 -0
- package/dist/plugin/web-react.js +34 -0
- package/dist/plugin/web-react.js.map +1 -0
- package/dist/plugin/web.d.ts +95 -0
- package/dist/plugin/web.d.ts.map +1 -0
- package/dist/plugin/web.js +245 -0
- package/dist/plugin/web.js.map +1 -0
- package/dist/plugin-nav.d.ts +29 -0
- package/dist/plugin-nav.d.ts.map +1 -0
- package/dist/plugin-nav.js +92 -0
- package/dist/plugin-nav.js.map +1 -0
- package/dist/plugin-testing.d.ts +2 -0
- package/dist/plugin-testing.d.ts.map +1 -0
- package/dist/plugin-testing.js +4 -0
- package/dist/plugin-testing.js.map +1 -0
- package/dist/plugin-web-react.d.ts +3 -0
- package/dist/plugin-web-react.d.ts.map +1 -0
- package/dist/plugin-web-react.js +3 -0
- package/dist/plugin-web-react.js.map +1 -0
- package/dist/plugin-web.d.ts +4 -0
- package/dist/plugin-web.d.ts.map +1 -0
- package/dist/plugin-web.js +5 -0
- package/dist/plugin-web.js.map +1 -0
- package/dist/plugin.d.ts +11 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +15 -0
- package/dist/plugin.js.map +1 -0
- package/dist/router.d.ts +28 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +47 -0
- package/dist/router.js.map +1 -1
- package/dist/routes.d.ts +4 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +6 -0
- package/dist/routes.js.map +1 -1
- package/dist/schemas.d.ts +194 -9
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +98 -17
- package/dist/schemas.js.map +1 -1
- package/dist/tokens.d.ts +2 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +101 -0
- package/dist/tokens.js.map +1 -0
- package/dist/vocabulary.d.ts +11 -1
- package/dist/vocabulary.d.ts.map +1 -1
- package/dist/vocabulary.js +24 -0
- package/dist/vocabulary.js.map +1 -1
- package/dist/web.d.ts.map +1 -1
- package/dist/web.js +2 -0
- package/dist/web.js.map +1 -1
- package/docs/specs/cli.md +12 -5
- package/docs/specs/plugins.md +488 -0
- package/docs/specs/rest.md +11 -9
- package/package.json +26 -8
- package/skills/building-a-console/SKILL.md +25 -26
- package/skills/building-a-console/references/configuring.md +40 -0
- package/skills/building-a-console/references/the-default-console.md +1 -1
- package/skills/building-a-console/references/the-look-from-a-website.md +5 -5
- package/skills/building-a-plugin/SKILL.md +137 -0
- package/skills/deploying-a-console/SKILL.md +24 -26
- package/skills/deploying-a-console/references/access.md +13 -9
- package/skills/deploying-a-console/references/resources.md +25 -10
- package/skills/deploying-a-console/references/running-it-again.md +15 -0
- package/skills/deploying-a-console/references/sizing.md +2 -0
- package/skills/planning-the-board/SKILL.md +96 -0
- package/skills/planning-the-board/references/a-task.md +36 -0
- package/skills/planning-the-board/references/setting-up.md +44 -0
- package/skills/working-the-board/SKILL.md +43 -34
- package/skills/working-the-board/references/the-pack.md +19 -0
- package/src/api.ts +12 -0
- package/src/cli/cli.ts +737 -55
- package/src/cli/format.ts +368 -10
- package/src/cli/help.ts +50 -6
- package/src/cli/plugin-check.ts +497 -0
- package/src/cli/plugin-cli.ts +237 -0
- package/src/cli/plugin-init.ts +257 -0
- package/src/cli/plugin-main.ts +30 -0
- package/src/client.ts +322 -9
- package/src/compat.ts +2 -2
- package/src/components/board.tsx +62 -14
- package/src/components/comments.tsx +1 -0
- package/src/components/decision-form.tsx +92 -11
- package/src/components/decision-list.tsx +71 -2
- package/src/components/event-feed.tsx +42 -1
- package/src/components/my-decisions.tsx +4 -1
- package/src/components/plugin-frame.tsx +437 -0
- package/src/components/plugin-settings.tsx +1111 -0
- package/src/components/shell.tsx +82 -14
- package/src/components/task-view.tsx +2 -1
- package/src/components/workspace.tsx +18 -0
- package/src/console.tsx +304 -31
- package/src/data.ts +59 -11
- package/src/i18n/en.ts +175 -0
- package/src/i18n/ko.ts +155 -0
- package/src/index.ts +12 -0
- package/src/limits.ts +2 -0
- package/src/plugin/args.ts +526 -0
- package/src/plugin/bridge.ts +314 -0
- package/src/plugin/capabilities.ts +150 -0
- package/src/plugin/context.ts +421 -0
- package/src/plugin/define.ts +792 -0
- package/src/plugin/definition-error.ts +19 -0
- package/src/plugin/limits.ts +70 -0
- package/src/plugin/load-worker.ts +50 -0
- package/src/plugin/load.ts +82 -0
- package/src/plugin/manifest.ts +561 -0
- package/src/plugin/refusals.ts +94 -0
- package/src/plugin/rest-schemas.ts +354 -0
- package/src/plugin/sandbox.ts +123 -0
- package/src/plugin/testing.ts +612 -0
- package/src/plugin/web-react.ts +45 -0
- package/src/plugin/web.ts +403 -0
- package/src/plugin-nav.ts +132 -0
- package/src/plugin-testing.ts +10 -0
- package/src/plugin-web-react.ts +4 -0
- package/src/plugin-web.ts +35 -0
- package/src/plugin.ts +126 -0
- package/src/router.ts +73 -0
- package/src/routes.ts +7 -0
- package/src/schemas.ts +115 -18
- package/src/styles/console.css +330 -1
- package/src/tokens.ts +101 -0
- package/src/vocabulary.ts +30 -0
- package/src/web.ts +2 -0
- package/template/plugin/.gitignore +2 -0
- package/template/plugin/README.md +26 -0
- package/template/plugin/SKILLCDN.md +13 -0
- package/template/plugin/build.mjs +40 -0
- package/template/plugin/console-plugin.json +50 -0
- package/template/plugin/package.json +27 -0
- package/template/plugin/skills/__key__/SKILL.md +23 -0
- package/template/plugin/src/check.test.ts +34 -0
- package/template/plugin/src/server/index.test.ts +41 -0
- package/template/plugin/src/server/index.ts +72 -0
- package/template/plugin/src/web/index.css +51 -0
- package/template/plugin/src/web/index.ts +115 -0
- package/template/plugin/tsconfig.json +17 -0
- package/skills/working-the-board/references/setting-up.md +0 -3
- /package/skills/{working-the-board → planning-the-board}/references/project-rules.md +0 -0
package/docs/specs/rest.md
CHANGED
|
@@ -16,6 +16,7 @@ The API is the board as its members see it: the people, the projects, and in eac
|
|
|
16
16
|
- The command names its version on every request, as the product token of its `user-agent` (`skillcdn-console/0.1.18 (cli; node 24.11.0; linux)`), and every answer under `/api` says the console's version (`console-version`) and the range of command versions it takes (`console-client-range`, as npm spells one: `>=0.1.18 <0.2.0`) ([ADR-0025](../adr/0025-the-command-names-its-version-on-every-request-and-the-console-holds-it-to-the-range-it-takes.md)). Before 1.0 the range is the console's line, every patch of its major.minor, from the floor the console names where a release raised one: the oldest command whose requests and answers still fit it, raised only by a release that changed what passes between them ([ADR-0038](../adr/0038-the-command-and-the-console-go-together-within-a-line-and-a-release-that-changes-what-passes-between-them-raises-the-floors.md)); from 1.0, the console's major and a minor within one, either way. A command outside the range is refused with `426` before anything else is asked of its request, `client.outdated` or `client.too_new`, the message naming both versions and the range. The command holds the console to a floor of its own the same way, and refuses a console below it itself, as `console.outdated`, in this same form. A request that names no command, a browser's, a script's, is held to nothing.
|
|
17
17
|
- Request bodies are JSON, at most 256 KiB, and parsed once with the package's input schema. Text is trimmed where it is a line, bounded everywhere (`MAX_TITLE_LENGTH` and the rest of `@skillcdn/console/api`), and refused when it carries control or invisible characters. Links are `https` URLs only.
|
|
18
18
|
- Errors have `{ "error": { "code": "...", "message": "..." } }`. The code is stable; the message is for a person, in English.
|
|
19
|
+
- The plugins' routes, under `/api/v1/plugins`, are in [plugins.md](plugins.md) with their refusals; every event carries `plugin`, the key of the plugin that caused it, or `null` for the console's own doing.
|
|
19
20
|
|
|
20
21
|
| Status | `code` | When |
|
|
21
22
|
|---|---|---|
|
|
@@ -38,6 +39,7 @@ The API is the board as its members see it: the people, the projects, and in eac
|
|
|
38
39
|
| 400 | `decision.invalid_task` | The decision is about a task that is not one of the project's. |
|
|
39
40
|
| 400 | `decision.no_such_option` | The answer names an option the decision does not have. |
|
|
40
41
|
| 400 | `decision.invalid_run` | A decision raised from a run that is not the asker's, or is over. |
|
|
42
|
+
| 400 | `decision.too_many_files` | The decision carries more files than one may (`MAX_FILES_PER_DECISION`, [ADR-0055](../adr/0055-a-decision-carries-the-files-put-on-it-when-it-is-raised.md)). |
|
|
41
43
|
| 400 | `decision.invalid_decider` | The person named to decide may not work in the project ([ADR-0042](../adr/0042-a-decision-is-addressed-to-a-person-its-raiser-unless-another-is-named.md)). |
|
|
42
44
|
| 400 | `token.expiry_at_most` | A token that would not expire, or would outlast `TOKEN_DAYS_AT_MOST`, where the organization requires an expiry. |
|
|
43
45
|
| 400 | `document.invalid_path` | The path a page is written at is not one: segments of lowercase letters, digits and hyphens, separated by slashes. |
|
|
@@ -63,7 +65,7 @@ The API is the board as its members see it: the people, the projects, and in eac
|
|
|
63
65
|
| 409 | `member.open_project` | The project is open to the workspace, so everyone of it is a member already; only an owner is listed there ([ADR-0035](../adr/0035-who-may-see-whom-is-decided-by-one-policy-and-the-workspace-keeps-its-settings.md)). |
|
|
64
66
|
| 409 | `category.key_taken`, `category.in_use`, `category.too_many` | A category of the workspace has that key already; tasks or goals are sorted into the category, so it stays until they are moved; the workspace has as many categories as one may (`MAX_CATEGORIES`). |
|
|
65
67
|
| 409 | `project.too_many`, `task.too_many`, `goal.too_many`, `decision.too_many`, `document.too_many`, `run.too_many` | The workspace holds as many projects as one may (`MAX_PROJECTS_PER_WORKSPACE`); the project as many tasks, goals, decisions or pages (`MAX_TASKS_PER_PROJECT`, `MAX_GOALS_PER_PROJECT`, `MAX_DECISIONS_PER_PROJECT`, `MAX_DOCUMENTS_PER_PROJECT`), those put away counted; the task has been taken as many times as one may (`MAX_RUNS_PER_TASK`). Bounds a runaway script meets and real work does not. |
|
|
66
|
-
| 409 | `project.too_many_bytes` | The files of the project, handed in by runs, put in comments and attached to pages, hold as many bytes together as the deployment allows one project (`PROJECT_FILE_BYTES_AT_MOST`, [deploy/README.md](../../deploy/README.md#a-shared-console)); no bound unless set. Asked before any byte is kept. |
|
|
68
|
+
| 409 | `project.too_many_bytes` | The files of the project, handed in by runs, put in comments and on decisions and attached to pages, hold as many bytes together as the deployment allows one project (`PROJECT_FILE_BYTES_AT_MOST`, [deploy/README.md](../../deploy/README.md#a-shared-console)); no bound unless set. Asked before any byte is kept. |
|
|
67
69
|
| 429 | `feed.too_many` | The person holds as many streams of the feed as one may at once (`MAX_STREAMS_PER_PERSON`), or the process does for everyone (`MAX_STREAMS`); `retry-after` says when to try again. |
|
|
68
70
|
| 403 | `picture.refused` | The console fetches no picture from that address: one of its own network, the loopback, a private or a link-local range, or a redirect to one ([ADR-0048](../adr/0048-a-picture-from-elsewhere-is-read-through-the-console-from-a-public-address-and-kept-a-while.md)). |
|
|
69
71
|
| 502 | `picture.unavailable` | The picture could not be fetched from where it is named: the origin answered an error or something that is not a picture, sent more than `MAX_FILE_BYTES`, or could not be reached in time. |
|
|
@@ -92,7 +94,7 @@ The API is the board as its members see it: the people, the projects, and in eac
|
|
|
92
94
|
|
|
93
95
|
### `GET /api/v1/me`
|
|
94
96
|
|
|
95
|
-
`{ "workspace": { "name", "tokenDaysAtMost", "skills": { "source", "address", "packToken" }, "peopleVisibility" }, "person": ... | null, "agent": "..." | null, "language": "..." | null, "signIn": [{ "key", "label", "admits": { "organization", "domains" } }, ...], "console": { "version", "clientRange" } }`: what the board is called, the most days a token may be good for here (or `null` where a person chooses), where the organization's skills come from (`source`, the origin of the SkillCDN deployment they are read through, and `address`, the organization's, canonical, which a project without one of its own reads, or `null`; and `packToken`, when the SkillCDN token the organization's pack is read with was set, `{ setAt }`, or `null`), who sees whom on the People page (`peopleVisibility`: `everyone`, or `shared_projects`, where a member sees only the people they share a project with and an administrator everyone; [ADR-0035](../adr/0035-who-may-see-whom-is-decided-by-one-policy-and-the-workspace-keeps-its-settings.md); read as optional, for a console from before the setting), the day the calendars begin a week on and this week is counted by (`weekStart`: `auto`, as the language of the pages has it, or `monday`, `sunday`; [ADR-0039](../adr/0039-this-week-is-the-plans-unit-and-the-week-begins-as-the-workspace-says.md)) and the workspace's time zone (`timeZone`: an IANA name, in which the command prints moments, or `null` for none; both optional the same way), who the session cookie or the token says is asking (`id`, `login`, `name` or `null`, `avatar` or `null`, `role`), with what (`agent`: the name of the token when a token asks, as its person called it, so that a console of a person's own knows it holds one and offers nothing a token cannot do; `null` on a session), the language the person chose for the pages (`language`, a tag, or `null` for the browser's), and the identity providers people sign in through (`gh`, `google`, each with the label of its button and, in `admits`, who gets in through it: the organization at the git host whose members are in, or `null`, and the Workspace domains whose accounts are, which a sign-in page says under the button; answered from 0.4.1 and read as optional), none where nobody can; and the console's own version with the range of command versions it takes (`console`, [ADR-0025](../adr/0025-the-command-names-its-version-on-every-request-and-the-console-holds-it-to-the-range-it-takes.md)), for a console built on the package to compare itself with. Nobody is an answer, not an error; the pages ask this once to decide what to show, and the command once, at `login`, to see that the console knows the token. A token the console knows whose person is out is refused here as on every route, `auth.deactivated` or `auth.not_admitted`, so that the agent learns why ([ADR-0044](../adr/0044-a-token-of-a-person-who-is-out-is-kept-and-refused-with-the-reason-until-they-are-back-in.md)).
|
|
97
|
+
`{ "workspace": { "name", "tokenDaysAtMost", "skills": { "source", "address", "packToken" }, "peopleVisibility" }, "person": ... | null, "agent": "..." | null, "language": "..." | null, "signIn": [{ "key", "label", "admits": { "organization", "domains" } }, ...], "console": { "version", "clientRange" }, "decisions": { "waiting" } | null }`: what the board is called, the most days a token may be good for here (or `null` where a person chooses), where the organization's skills come from (`source`, the origin of the SkillCDN deployment they are read through, and `address`, the organization's, canonical, which a project without one of its own reads, or `null`; and `packToken`, when the SkillCDN token the organization's pack is read with was set, `{ setAt }`, or `null`), who sees whom on the People page (`peopleVisibility`: `everyone`, or `shared_projects`, where a member sees only the people they share a project with and an administrator everyone; [ADR-0035](../adr/0035-who-may-see-whom-is-decided-by-one-policy-and-the-workspace-keeps-its-settings.md); read as optional, for a console from before the setting), the day the calendars begin a week on and this week is counted by (`weekStart`: `auto`, as the language of the pages has it, or `monday`, `sunday`; [ADR-0039](../adr/0039-this-week-is-the-plans-unit-and-the-week-begins-as-the-workspace-says.md)) and the workspace's time zone (`timeZone`: an IANA name, in which the command prints moments, or `null` for none; both optional the same way), who the session cookie or the token says is asking (`id`, `login`, `name` or `null`, `avatar` or `null`, `role`), with what (`agent`: the name of the token when a token asks, as its person called it, so that a console of a person's own knows it holds one and offers nothing a token cannot do; `null` on a session), the language the person chose for the pages (`language`, a tag, or `null` for the browser's), and the identity providers people sign in through (`gh`, `google`, each with the label of its button and, in `admits`, who gets in through it: the organization at the git host whose members are in, or `null`, and the Workspace domains whose accounts are, which a sign-in page says under the button; answered from 0.4.1 and read as optional), none where nobody can; and the console's own version with the range of command versions it takes (`console`, [ADR-0025](../adr/0025-the-command-names-its-version-on-every-request-and-the-console-holds-it-to-the-range-it-takes.md)), for a console built on the package to compare itself with; and how many decisions wait for the person's answer across the projects they may see (`decisions.waiting`, [ADR-0042](../adr/0042-a-decision-is-addressed-to-a-person-its-raiser-unless-another-is-named.md); `null` for nobody; answered from 0.4.3 and read as optional), which the pages say beside My decisions and read again when a decision is raised or answered. Nobody is an answer, not an error; the pages ask this once to decide what to show, and the command once, at `login`, to see that the console knows the token. A token the console knows whose person is out is refused here as on every route, `auth.deactivated` or `auth.not_admitted`, so that the agent learns why ([ADR-0044](../adr/0044-a-token-of-a-person-who-is-out-is-kept-and-refused-with-the-reason-until-they-are-back-in.md)).
|
|
96
98
|
|
|
97
99
|
### `GET /api/v1/people?login=`
|
|
98
100
|
|
|
@@ -144,7 +146,7 @@ Kept by an administrator, signed in or through their agent's token. `POST` takes
|
|
|
144
146
|
|
|
145
147
|
### `GET /api/v1/rules`, `PUT /api/v1/rules`, `POST /api/v1/rules/archive` and `GET /api/v1/rules/versions`
|
|
146
148
|
|
|
147
|
-
The rules of the board ([ADR-0023](../adr/0023-the-rules-of-a-board-are-pages-the-workspace-and-its-projects-keep-read-first-by-every-agent.md)): what the organization asks of agents, read by whoever is signed in or presents a token, kept by an administrator, signed in or through their agent's token. `GET` answers `{ "source", "body", "page" }`: `source` is `reference` while the organization has written none, and `body` is then the console's own rules as this version of the console carries them, with `page: null`; once written, `source` is `written`, `body` the page's and `page` the page without its body (as a folder lists one: `path` `rules`, `title` `Rules`, `version`, `updatedBy`, `agent`, `createdAt`, `updatedAt`). `PUT` takes `body` (Markdown, `MAX_RULES_LENGTH`) and optionally `baseVersion`, writes the next version of the page, bringing it back when it was put away, and answers what `GET` answers; the console's own rules sent as they are are never written, so that what holds keeps following the console's version: with none written they change nothing, and with the organization's written they put its page away, as `POST .../archive` does; a write from a version the rules have moved on from is `document.conflict`. The write is a `document.written` event in the workspace's own feed, with `path`, `title` and `version`. `POST .../archive` puts the written rules away, so that the console's own hold again (`document.archived`); what is put away already changes nothing. `.../versions` answers `{ "items": [version, ...] }` as a page's versions are answered, newest first, and `{ "items": [] }` while none is written. A body may say `{language}` for the language of the person an agent works for: the API answers the text as written, and the pages and the command fill it (`fillRules`), with the name of the language the person chose (`GET /api/v1/me`, `language`) or with the task's when they chose none.
|
|
149
|
+
The rules of the board ([ADR-0023](../adr/0023-the-rules-of-a-board-are-pages-the-workspace-and-its-projects-keep-read-first-by-every-agent.md)): what the organization asks of agents, read by whoever is signed in or presents a token, kept by an administrator, signed in or through their agent's token. `GET` answers `{ "source", "body", "page" }`: `source` is `reference` while the organization has written none, and `body` is then the console's own rules as this version of the console carries them, with `page: null`; once written, `source` is `written`, `body` the page's and `page` the page without its body (as a folder lists one: `path` `rules`, `title` `Rules`, `version`, `updatedBy`, `agent`, `createdAt`, `updatedAt`). `PUT` takes `body` (Markdown, `MAX_RULES_LENGTH`) and optionally `baseVersion`, writes the next version of the page, bringing it back when it was put away, and answers what `GET` answers; the console's own rules sent as they are are never written, so that what holds keeps following the console's version: with none written they change nothing, and with the organization's written they put its page away, as `POST .../archive` does; a write from a version the rules have moved on from is `document.conflict`. The write is a `document.written` event in the workspace's own feed, with `path`, `title` and `version`. `POST .../archive` puts the written rules away, so that the console's own hold again (`document.archived`); what is put away already changes nothing. `.../versions` answers `{ "items": [version, ...] }` as a page's versions are answered, newest first, and `{ "items": [] }` while none is written. A body may say `{language}` for the language of the person an agent works for: the API answers the text as written, and the pages and the command fill it (`fillRules`), with the name of the language the person chose (`GET /api/v1/me`, `language`) or with the task's when they chose none. The answer also carries `plugins` ([plugins.md](plugins.md), "The command"): every enabled plugin the asker may use, by key, each with its `name`, `agentNote` and `description` by language and the asker's `roles` in it; empty where the console has none.
|
|
148
150
|
|
|
149
151
|
### `GET /api/v1/work`
|
|
150
152
|
|
|
@@ -232,17 +234,17 @@ Writing one, for whoever may work in the project, with a session or a token, is
|
|
|
232
234
|
|
|
233
235
|
### `GET /api/v1/projects/<key>/decisions?open=&task=&limit=&offset=`
|
|
234
236
|
|
|
235
|
-
`{ "items": [decision, ...], "more": boolean }`: the project's, the ones that wait first, newest first within each, a page at a time as the tasks are (`limit`, `offset`, `more`); `open=true` keeps only those that wait, `task=<id>` only those about one task. A decision carries its `question`, `body` (Markdown: the context it rests on), `options` (each an `id` and a `label
|
|
237
|
+
`{ "items": [decision, ...], "more": boolean }`: the project's, the ones that wait first, newest first within each, a page at a time as the tasks are (`limit`, `offset`, `more`); `open=true` keeps only those that wait, `task=<id>` only those about one task. A decision carries its `question`, `body` (Markdown: the context it rests on), `options` (each an `id` and a `label`, and the `key` the raiser gave it, if any, for a program to read the answer by; the last carries `own: true` when it is the person's own answer, written instead of choosing, and the options given carry no `own`), `taskId` and `taskNumber` (or `null`), `raisedBy`, `decider` (whom it is for, [ADR-0042](../adr/0042-a-decision-is-addressed-to-a-person-its-raiser-unless-another-is-named.md): the raiser, unless another person of the project was named), `run` (the `id` and `agent` of the run that raised it, when an agent asked, or `null`), `files` (the files put on it when it was raised, [ADR-0055](../adr/0055-a-decision-carries-the-files-put-on-it-when-it-is-raised.md): each an `id` and the `file` as a comment's is, `name`, `size`, `contentType`, `sha256`; answered from 0.4.3 and read as optional), `answer`: `null` while it waits, else the chosen `option`, a `note` or `null` (the rationale given with it), `by` and `at`; and `outcome`, what followed, in Markdown, or `null` until someone writes it. Context, rationale and outcome make the decision a record ([ADR-0009](../adr/0009-documents-are-pages-of-markdown-in-a-project-addressed-by-path-versioned-and-linked-both-ways.md)); a link in any of them to a document's path is kept both ways, so that the document says the decision refers to it.
|
|
236
238
|
|
|
237
239
|
### `POST /api/v1/projects/<key>/decisions`
|
|
238
240
|
|
|
239
|
-
Takes `question`, `options` (two to `MAX_OPTIONS` labels), and optionally `body`, and either `taskId` or `runId
|
|
241
|
+
Takes `question`, `options` (two to `MAX_OPTIONS`, each a `label` and optionally a `key`, a lowercase word spelled as a plugin's key is and given once, which the `decision.answered` event carries back as `optionKey`, so that a program reads the answer without comparing labels), and optionally `body`, and either `taskId` or `runId`; as JSON, or, with files put on the decision ([ADR-0055](../adr/0055-a-decision-carries-the-files-put-on-it-when-it-is-raised.md)), as a form (`multipart/form-data`) whose part `decision` says what the JSON would, with a part `file` for each file, each checked as a file handed in is, at most `MAX_FILES_PER_DECISION` of them and together at most `MAX_FILE_BYTES` (`request.too_large`); the whole form is read and found good before any byte is kept, and a picture among the files is shown where the body names it as ``, the rest after the body. `deciderId` names whom the decision is for ([ADR-0042](../adr/0042-a-decision-is-addressed-to-a-person-its-raiser-unless-another-is-named.md)): a person who may work in the project, as a worker of a task must (`decision.invalid_decider` otherwise); left out, the asker, which from a run is the person the agent works for. Anyone of the project may still answer. Options are numbered from `1`. From a run, which must be the asker's and open (`decision.invalid_run`), the decision is about the run's task, `taskId` is not looked at, and the run waits (`status: waiting`) until the answer. Answers `201` with the decision and writes a `decision.raised` event, with the `agent` when a run asked and, when files came, how many as `files`.
|
|
240
242
|
|
|
241
243
|
### `GET .../decisions/<id>?wait=` and `POST .../decisions/<id>/answer`
|
|
242
244
|
|
|
243
245
|
One decision. With `wait=<seconds>` (`0` to `600`) the request is held while the decision waits, up to the server's own bound (50 seconds), and answers the decision as it stands then: how an agent learns the answer at once, woken through the database's own channel, without asking again and again. A decision answered already, or a wait of `0`, answers at once.
|
|
244
246
|
|
|
245
|
-
The answer takes `option` (the id of one of its options) or `own` (the person's own answer, where none of the options is it: one line, up to `MAX_OPTION_LABEL_LENGTH`, as an option is worded; `request.invalid` with both or with neither), and optionally a `note`. An answer of the person's own becomes one more option of the decision, numbered after the ones given and marked `own: true`, and the one chosen, so that the answer names an option either way and every reader finds its label. A decision is answered once; the answer records who gave it and when, writes a `decision.answered` event with the label of the option, and lets a run that waited go on (`status: running`), unless another decision of its still waits.
|
|
247
|
+
The answer takes `option` (the id of one of its options) or `own` (the person's own answer, where none of the options is it: one line, up to `MAX_OPTION_LABEL_LENGTH`, as an option is worded; `request.invalid` with both or with neither), and optionally a `note`. An answer of the person's own becomes one more option of the decision, numbered after the ones given and marked `own: true`, and the one chosen, so that the answer names an option either way and every reader finds its label. A decision is answered once; the answer records who gave it and when, writes a `decision.answered` event with the label of the option (`option`) and, where the raiser gave one, its key (`optionKey`), and lets a run that waited go on (`status: running`), unless another decision of its still waits.
|
|
246
248
|
|
|
247
249
|
### `PATCH /api/v1/projects/<key>/decisions/<id>`
|
|
248
250
|
|
|
@@ -270,9 +272,9 @@ How the work goes, and what was made. A report takes `body` (Markdown, `MAX_BODY
|
|
|
270
272
|
|
|
271
273
|
### `POST .../runs/<id>/files` and `GET /api/v1/projects/<key>/files/<id>`
|
|
272
274
|
|
|
273
|
-
A file handed in, as the parts of a form (`multipart/form-data`): the part `file` carries the bytes, with the file's name and its media type; the part `label` is optional. The name is one line without a path (`MAX_FILE_NAME_LENGTH`), the file is not empty and at most `MAX_FILE_BYTES` (`request.too_large`), and a media type that is not one, or none, is `application/octet-stream`. Where the deployment bounds what one project's files hold together (`PROJECT_FILE_BYTES_AT_MOST`), a file that would take the project over it, counted with every file handed in, put in a comment or attached to a page, is `project.too_many_bytes` (`409`) and nothing of it is kept; a comment's files and a page's file are held to the same bound. The bytes are kept under their SHA-256, so the same file handed in twice is kept once; the artifact on the run is `kind: "file"` with `file` filled in and `url` null. Answers `201` with the run and tells the board (`run.handed_in`, with the label or the file's name). The same rules as for a link: the run's person only, while the run is open, and only so many. A picture among the files is shown on the task's page small, and large when pressed, and a report that names it as `` shows it where the words are.
|
|
275
|
+
A file handed in, as the parts of a form (`multipart/form-data`): the part `file` carries the bytes, with the file's name and its media type; the part `label` is optional. The name is one line without a path (`MAX_FILE_NAME_LENGTH`), the file is not empty and at most `MAX_FILE_BYTES` (`request.too_large`), and a media type that is not one, or none, is `application/octet-stream`. Where the deployment bounds what one project's files hold together (`PROJECT_FILE_BYTES_AT_MOST`), a file that would take the project over it, counted with every file handed in, put in a comment or on a decision, or attached to a page, is `project.too_many_bytes` (`409`) and nothing of it is kept; a comment's files, a decision's files and a page's file are held to the same bound. The bytes are kept under their SHA-256, so the same file handed in twice is kept once; the artifact on the run is `kind: "file"` with `file` filled in and `url` null. Answers `201` with the run and tells the board (`run.handed_in`, with the label or the file's name). The same rules as for a link: the run's person only, while the run is open, and only so many. A picture among the files is shown on the task's page small, and large when pressed, and a report that names it as `` shows it where the words are.
|
|
274
276
|
|
|
275
|
-
The bytes of any file of the project, handed in by a run, put in a comment or attached to a page, are read back at `/api/v1/projects/<key>/files/<file id>`, the project's one address for files, by whoever may see the project, with a session or a token: `content-length` and `content-disposition` name the file, the few kinds a browser may show in place (pictures, plain text, Markdown, CSV, JSON) are answered with their type and `inline`, and every other kind as `application/octet-stream` and `attachment`, never sniffed (`x-content-type-options`) and under a policy that runs nothing (`sandbox`). An id that is a link's, or nothing, or another project's, is `file.not_found`.
|
|
277
|
+
The bytes of any file of the project, handed in by a run, put in a comment or on a decision, or attached to a page, are read back at `/api/v1/projects/<key>/files/<file id>`, the project's one address for files, by whoever may see the project, with a session or a token: `content-length` and `content-disposition` name the file, the few kinds a browser may show in place (pictures, plain text, Markdown, CSV, JSON) are answered with their type and `inline`, and every other kind as `application/octet-stream` and `attachment`, never sniffed (`x-content-type-options`) and under a policy that runs nothing (`sandbox`). An id that is a link's, or nothing, or another project's, is `file.not_found`.
|
|
276
278
|
|
|
277
279
|
### `POST .../runs/<id>/end`
|
|
278
280
|
|
|
@@ -296,7 +298,7 @@ A private pack connected with a code a person approves ([ADR-0036](../adr/0036-a
|
|
|
296
298
|
|
|
297
299
|
### `GET /api/v1/projects/<key>/rules`
|
|
298
300
|
|
|
299
|
-
`{ "workspace": rules, "project": rules }`: the rules that hold in the project ([ADR-0023](../adr/0023-the-rules-of-a-board-are-pages-the-workspace-and-its-projects-keep-read-first-by-every-agent.md)), for whoever may see it, each half shaped as `GET /api/v1/rules` answers: the workspace's, and the project's own, whose `source` is `written`, with its `body` and its `page`, or `none`, with `body` and `page` `null`, when the project adds nothing to the workspace's. A project's rules are the page `rules` of its documents, written and put away through the routes below.
|
|
301
|
+
`{ "workspace": rules, "project": rules, "plugins": [...] }`: the rules that hold in the project ([ADR-0023](../adr/0023-the-rules-of-a-board-are-pages-the-workspace-and-its-projects-keep-read-first-by-every-agent.md)), for whoever may see it, each half shaped as `GET /api/v1/rules` answers: the workspace's, and the project's own, whose `source` is `written`, with its `body` and its `page`, or `none`, with `body` and `page` `null`, when the project adds nothing to the workspace's. A project's rules are the page `rules` of its documents, written and put away through the routes below. `plugins` names the enabled plugins bound to the project, as their board project or on it, that the asker holds a role in, shaped as `GET /api/v1/rules` names them ([plugins.md](plugins.md), "The command").
|
|
300
302
|
|
|
301
303
|
### The documents
|
|
302
304
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skillcdn/console",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
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"
|
|
@@ -59,19 +77,19 @@
|
|
|
59
77
|
"access": "public"
|
|
60
78
|
},
|
|
61
79
|
"devDependencies": {
|
|
62
|
-
"@types/node": "^24.19.
|
|
80
|
+
"@types/node": "^24.19.2",
|
|
63
81
|
"@types/react": "^19.3.0",
|
|
64
82
|
"@types/react-dom": "^19.3.0",
|
|
65
|
-
"react": "^19.3.
|
|
66
|
-
"react-dom": "^19.3.
|
|
83
|
+
"react": "^19.3.1",
|
|
84
|
+
"react-dom": "^19.3.1",
|
|
67
85
|
"typescript": "^7.0.2",
|
|
68
|
-
"vitest": "^5.0
|
|
86
|
+
"vitest": "^5.1.0"
|
|
69
87
|
},
|
|
70
88
|
"dependencies": {
|
|
71
|
-
"@skillcdn/core": "^0.4.
|
|
89
|
+
"@skillcdn/core": "^0.4.2",
|
|
72
90
|
"react-markdown": "^10.1.0",
|
|
73
91
|
"remark-gfm": "^4.0.1",
|
|
74
|
-
"zod": "^4.6.
|
|
92
|
+
"zod": "^4.6.7"
|
|
75
93
|
},
|
|
76
94
|
"peerDependencies": {
|
|
77
95
|
"react": "^19.0.0",
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: building-a-console
|
|
3
|
-
description: "Builds a console from the @skillcdn/console package: a
|
|
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.
|
|
8
|
+
version: "1.9"
|
|
9
9
|
skillcdn:
|
|
10
10
|
translations:
|
|
11
11
|
ko:
|
|
12
12
|
title: 패키지로 콘솔 만들기
|
|
13
|
-
description: "@skillcdn/console 패키지로 콘솔을 만듭니다. console serve로 내 PC에서 내 토큰으로 돌리는 개인 콘솔,
|
|
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.
|
|
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
|
|
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),
|
|
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:
|
|
54
|
-
| The
|
|
55
|
-
| The
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|