@skillcdn/console 0.1.24 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +8 -7
  2. package/dist/api.d.ts +2 -2
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +2 -2
  5. package/dist/api.js.map +1 -1
  6. package/dist/cli/cli.d.ts +1 -1
  7. package/dist/cli/cli.d.ts.map +1 -1
  8. package/dist/cli/cli.js +248 -92
  9. package/dist/cli/cli.js.map +1 -1
  10. package/dist/cli/credentials.d.ts +5 -0
  11. package/dist/cli/credentials.d.ts.map +1 -1
  12. package/dist/cli/credentials.js +2 -0
  13. package/dist/cli/credentials.js.map +1 -1
  14. package/dist/cli/directory.d.ts +7 -0
  15. package/dist/cli/directory.d.ts.map +1 -1
  16. package/dist/cli/directory.js +7 -0
  17. package/dist/cli/directory.js.map +1 -1
  18. package/dist/cli/format.d.ts +13 -28
  19. package/dist/cli/format.d.ts.map +1 -1
  20. package/dist/cli/format.js +74 -274
  21. package/dist/cli/format.js.map +1 -1
  22. package/dist/cli/help.d.ts.map +1 -1
  23. package/dist/cli/help.js +36 -19
  24. package/dist/cli/help.js.map +1 -1
  25. package/dist/cli/pack.d.ts +46 -0
  26. package/dist/cli/pack.d.ts.map +1 -0
  27. package/dist/cli/pack.js +250 -0
  28. package/dist/cli/pack.js.map +1 -0
  29. package/dist/client.d.ts +26 -1
  30. package/dist/client.d.ts.map +1 -1
  31. package/dist/client.js +14 -1
  32. package/dist/client.js.map +1 -1
  33. package/dist/compat.d.ts +1 -1
  34. package/dist/compat.js +1 -1
  35. package/dist/components/calendar.d.ts +5 -1
  36. package/dist/components/calendar.d.ts.map +1 -1
  37. package/dist/components/calendar.js +3 -3
  38. package/dist/components/calendar.js.map +1 -1
  39. package/dist/components/decision-list.d.ts +13 -1
  40. package/dist/components/decision-list.d.ts.map +1 -1
  41. package/dist/components/decision-list.js +74 -29
  42. package/dist/components/decision-list.js.map +1 -1
  43. package/dist/components/event-feed.d.ts.map +1 -1
  44. package/dist/components/event-feed.js +2 -0
  45. package/dist/components/event-feed.js.map +1 -1
  46. package/dist/components/pack-connect.d.ts +23 -0
  47. package/dist/components/pack-connect.d.ts.map +1 -0
  48. package/dist/components/pack-connect.js +86 -0
  49. package/dist/components/pack-connect.js.map +1 -0
  50. package/dist/components/pack-token.d.ts +27 -0
  51. package/dist/components/pack-token.d.ts.map +1 -0
  52. package/dist/components/pack-token.js +11 -0
  53. package/dist/components/pack-token.js.map +1 -0
  54. package/dist/components/paged.d.ts +24 -0
  55. package/dist/components/paged.d.ts.map +1 -1
  56. package/dist/components/paged.js +40 -4
  57. package/dist/components/paged.js.map +1 -1
  58. package/dist/components/projects.d.ts +13 -0
  59. package/dist/components/projects.d.ts.map +1 -1
  60. package/dist/components/projects.js +37 -5
  61. package/dist/components/projects.js.map +1 -1
  62. package/dist/components/skills.d.ts.map +1 -1
  63. package/dist/components/skills.js +8 -4
  64. package/dist/components/skills.js.map +1 -1
  65. package/dist/components/ui.d.ts +2 -0
  66. package/dist/components/ui.d.ts.map +1 -1
  67. package/dist/components/ui.js +7 -2
  68. package/dist/components/ui.js.map +1 -1
  69. package/dist/components/work.d.ts +3 -1
  70. package/dist/components/work.d.ts.map +1 -1
  71. package/dist/components/work.js +1 -1
  72. package/dist/components/work.js.map +1 -1
  73. package/dist/components/workspace.d.ts +46 -0
  74. package/dist/components/workspace.d.ts.map +1 -0
  75. package/dist/components/workspace.js +124 -0
  76. package/dist/components/workspace.js.map +1 -0
  77. package/dist/console.css +268 -5
  78. package/dist/console.d.ts.map +1 -1
  79. package/dist/console.js +62 -23
  80. package/dist/console.js.map +1 -1
  81. package/dist/data.d.ts +16 -1
  82. package/dist/data.d.ts.map +1 -1
  83. package/dist/data.js +64 -2
  84. package/dist/data.js.map +1 -1
  85. package/dist/dates.d.ts +12 -2
  86. package/dist/dates.d.ts.map +1 -1
  87. package/dist/dates.js +20 -2
  88. package/dist/dates.js.map +1 -1
  89. package/dist/i18n/en.d.ts +66 -0
  90. package/dist/i18n/en.d.ts.map +1 -1
  91. package/dist/i18n/en.js +80 -8
  92. package/dist/i18n/en.js.map +1 -1
  93. package/dist/i18n/ko.d.ts.map +1 -1
  94. package/dist/i18n/ko.js +75 -7
  95. package/dist/i18n/ko.js.map +1 -1
  96. package/dist/index.d.ts +5 -2
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +5 -2
  99. package/dist/index.js.map +1 -1
  100. package/dist/router.d.ts +10 -5
  101. package/dist/router.d.ts.map +1 -1
  102. package/dist/router.js +24 -9
  103. package/dist/router.js.map +1 -1
  104. package/dist/routes.d.ts +4 -0
  105. package/dist/routes.d.ts.map +1 -1
  106. package/dist/routes.js +4 -0
  107. package/dist/routes.js.map +1 -1
  108. package/dist/schemas.d.ts +500 -158
  109. package/dist/schemas.d.ts.map +1 -1
  110. package/dist/schemas.js +169 -165
  111. package/dist/schemas.js.map +1 -1
  112. package/dist/vocabulary.d.ts +19 -1
  113. package/dist/vocabulary.d.ts.map +1 -1
  114. package/dist/vocabulary.js +16 -0
  115. package/dist/vocabulary.js.map +1 -1
  116. package/docs/specs/cli.md +19 -14
  117. package/docs/specs/rest.md +34 -19
  118. package/package.json +2 -1
  119. package/skills/building-a-console/SKILL.md +5 -5
  120. package/skills/building-a-console/references/the-look-from-a-website.md +39 -0
  121. package/skills/deploying-a-console/SKILL.md +9 -8
  122. package/skills/working-the-board/SKILL.md +5 -5
  123. package/skills/working-the-board/references/setting-up.md +1 -1
  124. package/skills/working-the-board/references/terms.md +2 -0
  125. package/skills/working-the-board/references/the-sentence.md +1 -1
  126. package/src/api.ts +18 -7
  127. package/src/cli/cli.ts +345 -109
  128. package/src/cli/credentials.ts +7 -0
  129. package/src/cli/directory.ts +9 -0
  130. package/src/cli/format.ts +82 -341
  131. package/src/cli/help.ts +43 -19
  132. package/src/cli/pack.ts +356 -0
  133. package/src/client.ts +84 -0
  134. package/src/compat.ts +1 -1
  135. package/src/components/calendar.tsx +8 -2
  136. package/src/components/decision-list.tsx +227 -94
  137. package/src/components/event-feed.tsx +2 -0
  138. package/src/components/pack-connect.tsx +179 -0
  139. package/src/components/pack-token.tsx +74 -0
  140. package/src/components/paged.tsx +72 -3
  141. package/src/components/projects.tsx +108 -9
  142. package/src/components/skills.tsx +51 -33
  143. package/src/components/ui.tsx +16 -3
  144. package/src/components/work.tsx +4 -1
  145. package/src/components/workspace.tsx +298 -0
  146. package/src/console.tsx +176 -29
  147. package/src/data.ts +89 -2
  148. package/src/dates.ts +23 -2
  149. package/src/i18n/en.ts +94 -8
  150. package/src/i18n/ko.ts +84 -7
  151. package/src/index.ts +25 -1
  152. package/src/router.ts +37 -14
  153. package/src/routes.ts +4 -0
  154. package/src/schemas.ts +202 -189
  155. package/src/styles/console.css +268 -5
  156. package/src/vocabulary.ts +25 -0
@@ -23,6 +23,8 @@ The API is the board as its members see it: the people, the projects, and in eac
23
23
  | 400 | `project.invalid_address` | The skills address is not one, as the standard spells them. |
24
24
  | 400 | `project.pack_token_refused` | The deployment does not serve the project's pack to the pack token given, or the project names no pack ([ADR-0028](../adr/0028-the-console-reads-a-projects-pack-through-the-deployments-rest-api-with-a-pack-token-for-a-private-one.md)). |
25
25
  | 400 | `project.invalid_icon` | The image for the mark is not a PNG, a JPEG, a GIF or a WebP, by its first bytes. |
26
+ | 400 | `project.pack_connect_refused` | The project names no pack to connect, the pack is on the console's machine, or the deployment refused to begin connecting it, in its own words ([ADR-0036](../adr/0036-a-private-pack-is-connected-with-a-code-a-person-approves-from-the-projects-settings.md)). |
27
+ | 409 | `project.pack_connect_unsupported` | The console reaches no deployment it could connect a pack at, or keeps no secret to seal a token with. |
26
28
  | 404 | `project.no_icon` | The project has no image for its mark. |
27
29
  | 400 | `member.invalid_person` | The person to list is not one of the workspace, or is deactivated. |
28
30
  | 400 | `listing.unknown_host` | The login to let in names a provider nobody signs in through here. |
@@ -55,6 +57,7 @@ The API is the board as its members see it: the people, the projects, and in eac
55
57
  | 404 | `not_found` | Nothing at this path. |
56
58
  | 409 | `project.key_taken` | A project of the workspace has that key already. |
57
59
  | 409 | `member.exists` | The person is listed in the project already. |
60
+ | 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)). |
58
61
  | 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`). |
59
62
  | 409 | `decision.answered` | The decision has an answer already. |
60
63
  | 409 | `document.conflict` | The page has moved on since the version the write started from (`baseVersion`), or was written at that path by someone else first. |
@@ -62,8 +65,12 @@ The API is the board as its members see it: the people, the projects, and in eac
62
65
  | 409 | `document.too_many_versions`, `document.too_many_files` | The page carries as many versions, or files, as one may (`MAX_VERSIONS_PER_DOCUMENT`, `MAX_FILES_PER_DOCUMENT`). |
63
66
  | 409 | `token.too_many` | The person holds as many live tokens as one may (`MAX_TOKENS_PER_PERSON`). |
64
67
  | 409 | `connect.approved` | The connection was approved already; the command claims its token. |
68
+ | 400 | `workspace.pack_token_refused` | The deployment does not serve the organization's pack to the SkillCDN token given, or the console names no address for the organization's skills. |
69
+ | 400 | `workspace.pack_connect_refused` | The console names no address for the organization's skills, the pack is on the console's machine, or the deployment refused to begin connecting, in its words. |
65
70
  | 409 | `project.pack_token_unsupported` | The console keeps no secret to seal a pack token with: nobody signs in here (`AUTH_SECRET`). |
66
71
  | 429 | `connect.too_many` | As many agents ask to connect as the console holds at once; try again in a few minutes. |
72
+ | 409 | `workspace.pack_token_unsupported` | The console keeps no secret to seal a SkillCDN token with: nobody signs in here (`AUTH_SECRET`). |
73
+ | 409 | `workspace.pack_connect_unsupported` | The console reaches no deployment it could connect the organization's pack at, or keeps no secret to seal with. |
67
74
  | 503 | `skills.unavailable` | The SkillCDN deployment could not be reached to try a pack token against; try again later. |
68
75
  | 409 | `person.last_admin` | The change would leave the board without an administrator in. |
69
76
  | 409 | `person.of_organization` | The organization let the person in, and says whether they are in; an administrator lists their login to keep one who left ([ADR-0022](../adr/0022-who-is-in-is-the-consoles-own-record-and-an-administrator-keeps-it.md)). |
@@ -77,11 +84,11 @@ The API is the board as its members see it: the people, the projects, and in eac
77
84
 
78
85
  ### `GET /api/v1/me`
79
86
 
80
- `{ "workspace": { "name", "tokenDaysAtMost", "skills": { "source", "address" } }, "person": ... | null, "agent": "..." | null, "language": "..." | null, "signIn": [{ "key", "label" }, ...], "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`), 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), 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.
87
+ `{ "workspace": { "name", "tokenDaysAtMost", "skills": { "source", "address", "packToken" }, "peopleVisibility" }, "person": ... | null, "agent": "..." | null, "language": "..." | null, "signIn": [{ "key", "label" }, ...], "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 (`weekStart`: `auto`, as the language of the pages has it, or `monday`, `sunday`) 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), 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.
81
88
 
82
- ### `GET /api/v1/people`
89
+ ### `GET /api/v1/people?login=`
83
90
 
84
- `{ "items": [person, ...], "listed": [listing, ...] }`: everyone who has signed in, those in first and by login, and the logins an administrator let in that nobody has signed in with yet ([ADR-0022](../adr/0022-who-is-in-is-the-consoles-own-record-and-an-administrator-keeps-it.md)). A person carries their `role` in the workspace (`admin`, who configures it, or `member`, who works in the projects they are in), their `status` (`active`, or `deactivated`: kept with everything they did, refused on every request, and offered to no picker), their `source` (what let them in at their last sign-in: `organization`, the git host's organization the deployment names; `domain`, the Workspace domain it names; or `listed`, an administrator's listing) and `deactivatedAt` (or `null`). A listing carries its `id`, the `host` (`gh`, `google`), the `login` as the administrator spelled it, and `createdAt`. `organization` is the organization at the git host whose members are in, where the deployment names one (`host`, `name`, and `syncedAt`, when the worker last read it whole, or `null` until it has), or `null`. What a picker of assignees and of members is made of, the active people. A token reads it as its person does: what the command's `--assignee`, `member` and `person` take a login from.
91
+ `{ "items": [person, ...], "listed": [listing, ...] }`: the people the asker may see, those in first and by login, and the logins an administrator let in that nobody has signed in with yet ([ADR-0022](../adr/0022-who-is-in-is-the-consoles-own-record-and-an-administrator-keeps-it.md)). Who sees whom is the workspace's setting, decided by the one policy of the server on every request ([ADR-0035](../adr/0035-who-may-see-whom-is-decided-by-one-policy-and-the-workspace-keeps-its-settings.md)): with `everyone`, everyone who has signed in; with `shared_projects`, a member sees the active people who are in a project they are in, themselves, and the administrators, while an administrator sees everyone whatever the setting; a project open to the workspace has everyone in it, so a member of one sees everyone. The logins let in (`listed`) and the organization's reading (`organization`) go only to whom the policy shows everyone, `[]` and `null` otherwise. With `login`, one person by their exact login, compared without regard to case, or none: whom the asker sees, and, for an owner of a project, anyone active of the workspace, so that an owner lists someone the list does not show, learning that the login is one of the workspace and nothing more; `listed` is `[]` and `organization` `null` then; an empty or overlong login is `request.invalid`. A person carries their `role` in the workspace (`admin`, who configures it, or `member`, who works in the projects they are in), their `status` (`active`, or `deactivated`: kept with everything they did, refused on every request, and offered to no picker), their `source` (what let them in at their last sign-in: `organization`, the git host's organization the deployment names; `domain`, the Workspace domain it names; or `listed`, an administrator's listing) and `deactivatedAt` (or `null`). A listing carries its `id`, the `host` (`gh`, `google`), the `login` as the administrator spelled it, and `createdAt`. `organization` is the organization at the git host whose members are in, where the deployment names one (`host`, `name`, and `syncedAt`, when the worker last read it whole, or `null` until it has), or `null`. What a picker of assignees and of members is made of, the active people. A token reads it as its person does: what the command's `--assignee`, `member` and `person` take a login from, through `login`.
85
92
 
86
93
  ### `PATCH /api/v1/people/<id>`
87
94
 
@@ -101,12 +108,24 @@ Takes `key` and `name`, and optionally `description`, `visibility` (default `pri
101
108
 
102
109
  ### `GET /api/v1/events?after=&limit=`
103
110
 
104
- The workspace's own events, the ones about no project: who joined (`person.joined`), who was made what (`person.role_changed`), who was let in, taken off the list, taken out and taken back in (`person.listed`, `person.unlisted`, `person.deactivated`, `person.reactivated`, each with the `login`), and what became of the categories (`category.created`, `category.updated`, `category.removed`, each with the `key` and the `name`). The same shape and parameters as a project's feed below, without the filters.
111
+ The workspace's own events, the ones about no project: who joined (`person.joined`), who was made what (`person.role_changed`), who was let in, taken off the list, taken out and taken back in (`person.listed`, `person.unlisted`, `person.deactivated`, `person.reactivated`, each with the `login`), what became of the categories (`category.created`, `category.updated`, `category.removed`, each with the `key` and the `name`), and which of the workspace's settings an administrator changed (`workspace.updated`, with `fields`). The same shape and parameters as a project's feed below, without the filters. They say who is in, so they go to whom the policy shows everyone ([ADR-0035](../adr/0035-who-may-see-whom-is-decided-by-one-policy-and-the-workspace-keeps-its-settings.md)): `auth.forbidden` for a member while the people are narrowed to those they share a project with.
105
112
 
106
113
  ### `PATCH /api/v1/me`
107
114
 
108
115
  Keeps the person's own choice of language for the pages ([ADR-0012](../adr/0012-the-pages-speak-the-persons-language-from-packs-that-ship-with-the-package.md)): `{ "language": "ko" }`, a language tag as a browser sends one, or `null` to choose none and let the browser's languages decide; answers what `GET` answers. From the console's own pages, or with a token: a console of a person's own keeps the choice on the person too.
109
116
 
117
+ ### `PATCH /api/v1/workspace`
118
+
119
+ The workspace's settings, which an administrator keeps on the Settings page ([ADR-0035](../adr/0035-who-may-see-whom-is-decided-by-one-policy-and-the-workspace-keeps-its-settings.md)), from the console's own pages or through their agent's token ([ADR-0021](../adr/0021-a-token-configures-as-its-person-does.md)): `{ "peopleVisibility": "everyone" | "shared_projects", "weekStart": "auto" | "monday" | "sunday", "timeZone": "Asia/Seoul" | null }`, which of the settings to change, at least one, a time zone being a name the console knows (`request.invalid` otherwise, as for a patch that names nothing); answers the `workspace` as `GET /api/v1/me` describes it, and writes `workspace.updated` with the `fields` that changed; what is already so writes nothing. `auth.forbidden` for a member. The setting holds from the next request on, for everyone: nothing of it is kept in memory.
120
+
121
+ ### `PUT /api/v1/workspace/pack-token` and `DELETE .../pack-token`
122
+
123
+ The SkillCDN token the organization's pack is read with ([ADR-0036](../adr/0036-a-private-pack-is-connected-with-a-code-a-person-approves-from-the-projects-settings.md)), for an administrator, signed in from the console's own pages or through their agent's token: every project that names no address of its own and holds no token of its own reads the organization's pack (`SKILLS_ADDRESS`) with it. `PUT` takes `{ "token" }` as the project's route does, tries it against the organization's pack once (`workspace.pack_token_refused` when the pack is not served to it or the console names no address for the organization's skills; `skills.unavailable` when the deployment could not be reached), seals it with the console's secret (`workspace.pack_token_unsupported` where the console has none) and keeps it on the workspace, answering the workspace as `me` carries it, with `skills.packToken: { setAt }`, and writing a `workspace.updated` event naming the field `packToken`. The token is answered nowhere and logged nowhere. `DELETE` takes it away the same way; taking away what is not there writes nothing.
124
+
125
+ ### `POST /api/v1/workspace/pack-token/connect`, `GET .../pack-token/connect` and `DELETE .../pack-token/connect`
126
+
127
+ The workspace's token connected with a code a person approves ([ADR-0036](../adr/0036-a-private-pack-is-connected-with-a-code-a-person-approves-from-the-projects-settings.md)), for an administrator, as a project's is: `POST` asks the deployment to connect the organization's address and answers `201` with `{ "code", "url", "expiresAt", "intervalSeconds" }`, with `workspace.pack_connect_unsupported`, `workspace.pack_connect_refused` and `skills.unavailable` where a project's route has its own, the refusal naming a console with no address for the organization's skills; `GET` answers `{ "status": "none" }`, `pending` with what the person is shown, `connected` with `workspace` as `me` carries it once the token is kept, or `ended` with `reason`; `DELETE` gives the request up. One request for the workspace at a time.
128
+
110
129
  ### `GET /api/v1/categories`
111
130
 
112
131
  `{ "items": [category, ...] }`: the kinds of work tasks are sorted into ([ADR-0019](../adr/0019-a-task-is-planned-in-days-the-board-keeps-its-moments-and-goals-and-categories-give-the-work-its-shape.md)), by name, for whoever is signed in or presents a token. A category carries its `key` (what the command and the filters say; lowercase letters, digits and hyphens; immutable), `name`, `color` (one of `CATEGORY_COLORS`, a name the pages paint and never a value typed), `createdAt` and `updatedAt`. Every workspace starts with `engineering`, `product`, `design`, `marketing` and `operations`.
@@ -167,11 +186,11 @@ The project's own image for its mark, in place of the symbol on the colour. `POS
167
186
 
168
187
  ### `GET /api/v1/projects/<key>/members` and `POST /api/v1/projects/<key>/members`
169
188
 
170
- `{ "items": [member, ...] }`: those listed in the project, by login, each a `person`, their `role` in it (`owner`, `member`) and `addedAt`. A project open to the workspace has everyone of it as a member besides; an administrator is an owner of every project, listed or not. `POST`, for an owner, takes `personId` (a person of the workspace; `member.invalid_person`) and optionally `role` (default `member`), answers `201` with the member and writes `project.member_added` with `login` and `role`. A person listed already is `member.exists`.
189
+ `{ "items": [member, ...] }`: the members of the project, by login, each a `person`, their `role` in it (`owner`, `member`), `addedAt` and `listed` ([ADR-0035](../adr/0035-who-may-see-whom-is-decided-by-one-policy-and-the-workspace-keeps-its-settings.md)). In a private project, those listed. In a project open to the workspace everyone active of it is a member, so the list is everyone: an owner where a listing says so or the person is an administrator, a member otherwise; `listed` says whether a listing holds them, and `addedAt` is the listing's day or, for a member without one, the later of the project's making and their joining. An administrator is an owner of every project, listed or not. `POST`, for an owner, takes `personId` (a person of the workspace; `member.invalid_person`) and optionally `role` (default `member`), answers `201` with the member and writes `project.member_added` with `login` and `role`. A person listed already is `member.exists`; in a project open to the workspace everyone is a member already, so a `role` of `member` is `member.open_project` and only an owner is listed.
171
190
 
172
191
  ### `PATCH /api/v1/projects/<key>/members/<person id>` and `DELETE .../members/<person id>`
173
192
 
174
- For an owner, signed in or with a token. The patch takes `role` and writes `project.member_changed`; the removal answers `204` and writes `project.member_removed`. A person not listed is `member.not_found`. A project may be left without an owner listed; the administrators own it then.
193
+ For an owner, signed in or with a token. The patch takes `role` and writes `project.member_changed`; in a private project the person must be listed (`member.not_found`). In a project open to the workspace anyone active of it may be made an `owner`, which lists them, and an owner made a `member` again loses the listing and stays the member everyone is, answered with `listed: false`; an administrator owns every project whatever is asked, and nothing is written for them. The removal takes a listing away, answers `204` and writes `project.member_removed`; a person not listed is `member.not_found`, and in a project open to the workspace the person stays a member. A project may be left without an owner listed; the administrators own it then.
175
194
 
176
195
  ### `GET /api/v1/projects/<key>/tasks?state=&open=&archived=&category=&goal=&assignee=&unassigned=&dueBy=&limit=&offset=`
177
196
 
@@ -197,7 +216,7 @@ Writing one, for whoever may work in the project, with a session or a token, is
197
216
 
198
217
  ### `GET /api/v1/projects/<key>/decisions?open=&task=&limit=&offset=`
199
218
 
200
- `{ "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`), `taskId` and `taskNumber` (or `null`), `raisedBy`, `run` (the `id` and `agent` of the run that raised it, when an agent asked, or `null`), `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.
219
+ `{ "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`; 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`, `run` (the `id` and `agent` of the run that raised it, when an agent asked, or `null`), `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.
201
220
 
202
221
  ### `POST /api/v1/projects/<key>/decisions`
203
222
 
@@ -207,7 +226,7 @@ Takes `question`, `options` (two to `MAX_OPTIONS` labels), and optionally `body`
207
226
 
208
227
  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.
209
228
 
210
- The answer takes `option` (the id of one of its options) and optionally a `note`. 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.
229
+ 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.
211
230
 
212
231
  ### `PATCH /api/v1/projects/<key>/decisions/<id>`
213
232
 
@@ -245,24 +264,20 @@ Takes `status` (`finished`, `failed` or `abandoned`) and optionally a `summary`
245
264
 
246
265
  ### `GET /api/v1/projects/<key>/skills`
247
266
 
248
- The project's pack, as the SkillCDN deployment serves it at the project's address, or at the organization's (`SKILLS_ADDRESS`) when the project names none, read through `SKILLCDN_URL` ([ADR-0028](../adr/0028-the-console-reads-a-projects-pack-through-the-deployments-rest-api-with-a-pack-token-for-a-private-one.md)): `{ "address", "source", "page", "status", "items" }`. `address` is canonical, or `null` with `status: "none"` when neither names one; `source` is the deployment's origin and `page` where a person browses the address. When `ready`, `pack` names the pack as its manifest does, else its README, else the host (`name`, `description` and `language`, each or `null`), and `counts` says how many `skills` and `documents` the deployment indexed at the address; neither is there otherwise. `status` is `ready`, or why `items` is empty: `indexing` and `failed` as the deployment says of the repository, `not_found` when it does not serve the address to the console (a private pack is read with the project's pack token; without one the console asks as nobody, so a private repository is not read), `token_invalid` when the deployment refuses the pack token the project holds (expired, removed, or its maker lost the repository), `unavailable` when it could not be reached or read. An item is one skill: `name`, `description`, `directory` and `path` (of its `SKILL.md`, from the repository's root, which the routes below take), `page` (the skill at the deployment, for a person), `uri` (what an agent loads it by through its own SkillCDN connection, `skill://gh/<owner>/<repo>/<path>`, or `null`), and `translations` (the title and the description by language tag, as the repository gives them). The console keeps nothing of the skills: a public answer per address stands for a minute, then the deployment is asked again; what is read with a pack token is asked every time, and held for nobody.
267
+ The project's pack, read by address ([ADR-0028](../adr/0028-the-console-reads-a-projects-pack-through-the-deployments-rest-api-with-a-pack-token-for-a-private-one.md), [ADR-0031](../adr/0031-the-console-reads-a-pack-as-the-skillcdn-command-does-and-a-local-one-from-a-directory.md)): at the project's address, or at the organization's (`SKILLS_ADDRESS`) when the project names none; at the SkillCDN deployment of `SKILLCDN_URL` for the address of a git host, with the SkillCDN token the pack is read with where it is private, the project's own or, for a project that names no address and holds none, the workspace's ([below](#put-apiv1workspacepack-token-and-delete-pack-token)), and from the directory of `SKILLS_DIR` for a `local` address (`/local/<owner>/<name>`), read on the console's machine with the reading rules a deployment applies. `{ "address", "source", "page", "status", "refusal", "pack", "counts", "items", "mount" }`. `address` is canonical, or `null` with `status: "none"` when neither names one; `source` is the deployment's origin and `page` where a person browses the address there, both `null` for a pack read from a directory. When `ready`, `pack` names the pack as its manifest does, else its README, else the host (`name`, `description` and `language`, each or `null`), `counts` says how many `skills` and `documents` the index found, and `items` are the skills: `name`, `description`, `directory` and `path` (of its `SKILL.md`, from the repository's root, which the routes below take), `page` (the skill at the deployment, for a person, or `null`), `uri` (what an agent loads it by through its own SkillCDN connection, `skill://<host>/<owner>/<name>/<path>`, or `null`; one of a `local` pack means something on the console's machine and nowhere else), and `translations` (the title and the description by language tag, as the repository gives them). `mount` is what the address serves as the main repository's REST API answers it (`RestMount` of `@skillcdn/core`), for a program that renders what a model is given, or `null` when nothing was answered. `status` is `ready`, or why `items` is empty: `indexing` and `failed` as the pack says of itself, `not_found` when nothing is served to the console at the address (a private pack is read with the project's pack token; without one the console asks as nobody, so a private repository is not read; a `local` pack is not in the directory), `token_invalid` when the deployment refuses the pack token the project holds (expired, removed, or its maker lost the repository), `unavailable` when the pack could not be reached or read; `refusal` carries the pack's own `code` and `message` then, with `sourceUrl` and `directories` where it gave them (`null` and empty otherwise), and is `null` when the read went well. The console keeps nothing of the skills: a public answer per address stands for a minute, then the pack is asked again; what is read with a pack token is asked every time, and held for nobody.
249
268
 
250
- ### `GET /api/v1/projects/<key>/skills/one?path=&cursor=` and `GET .../skills/file?path=&offset=&limit=`
269
+ ### `GET /api/v1/projects/<key>/skills/one?path=&cursor=`, `.../skills/file?path=&offset=&limit=`, `.../skills/browse?path=&cursor=&limit=` and `.../skills/find?query=&path=&cursor=&limit=`
251
270
 
252
- One skill of the pack, and a file of it, read by the console from the deployment for whoever may see the project, with the pack token where the project holds one ([ADR-0028](../adr/0028-the-console-reads-a-projects-pack-through-the-deployments-rest-api-with-a-pack-token-for-a-private-one.md)); each read is logged with who read what, never with what was read. `path` is the path from the repository's root, up to 500 characters; a query that is not one is `request.invalid`.
253
-
254
- `skills/one` is the deployment's `load_skill`, in the console's shape: `{ "address", "source", "page", "status", "skill" }`, `skill` being `null` unless `status` is `ready`, else `path`, `directory`, `name`, `description`, `rules` (the manifests that hold for the skill, from the repository's root to the nearest, each `path`, `body` and `truncated`), `body`, `included` (the files the skill includes, the same way), `files` (the paths of the skill's own files), `references` (each `path` and `status`: `available`, `blocked`, `missing` or `outside_mount`), `complete` and `nextCursor` (a page may end inside a rule or a file; the next page continues it, and the skill is whole only when `complete`), `serving` (`full`, whether the skill is served whole or described only under its license; `license`; `sourceUrl`, where it is read at its host) and `warnings`. `skills/file` is `read_repo_file`: `{ "address", "source", "status", "file", "folder" }`, `file` being the page (`path`, `content`, `offset`, `nextOffset` or `null` at the end, `totalLength`, in characters; `limit` 1 to 100,000) or `folder` what a folder holds (`path`, `entries` of `path`, `kind` and `size`, `truncated`), both `null` unless `ready`; `failed` here is a file the deployment will not carry, too large or not text.
255
-
256
- ### `GET /api/v1/projects/<key>/skills/browse?path=&cursor=&limit=` and `GET .../skills/find?query=&path=&cursor=&limit=`
257
-
258
- What a folder of the pack holds, and what words find in it, read the same way: the deployment's `browse_repo` and `search_repo` in the console's shape, for whoever may see the project, with the pack token where the project holds one ([ADR-0028](../adr/0028-the-console-reads-a-projects-pack-through-the-deployments-rest-api-with-a-pack-token-for-a-private-one.md)); each read is logged with who read which folder, never with the words searched for. `path` is a folder's path from the repository's root, up to 500 characters, the mounted folder when left out; `cursor` continues one listing; a query out of bounds is `request.invalid`.
259
-
260
- `skills/browse` answers `{ "address", "source", "page", "status", "folder" }`, `folder` being `null` unless `ready`, else the folder's `path`, its `overview` (the README that introduces it: `path`, `title` and `description`, or `null`), its `entries`, each with `kind` (`skill`, `directory` or `file`), `path` (of the `SKILL.md` for a skill), `name` and `description` (or `null`), `skillCount` and `documentCount` (what a folder holds), `size` (a file's, in bytes, or `null`), `overviewPath` (a folder's README, or `null`), `license` and `describedOnly` (a skill's: whether the address only describes it under its license), and `nextCursor` (or `null` at the end; `limit` 1 to 200, 50 unless given). `skills/find` answers `{ "address", "source", "page", "status", "found" }`, `found` being `null` unless `ready`, else the `query` (1 to 500 characters, required), the `path` the search was kept to (or `null`), `items` in relevance order, a `skill` as the listing's item with the `files` of it that matched (each `path`, `title` and `summary`), `moreFiles`, `license` and `describedOnly`, or a `document` with its `path`, `title`, `summary` and `skillDirectory` (or `null`), and `nextCursor` (`limit` 1 to 25, 10 unless given). Words are matched, not meaning, in the language the pack is written in; the deployment's listing of a mount is bounded, and these two are how the rest of a large pack is reached.
271
+ One skill of the pack, a file of it, what a folder holds and what words find, read by the console from the pack for whoever may see the project, with the SkillCDN token the pack is read with, the project's own or the workspace's ([ADR-0028](../adr/0028-the-console-reads-a-projects-pack-through-the-deployments-rest-api-with-a-pack-token-for-a-private-one.md)), and answered as the pack answered them ([ADR-0031](../adr/0031-the-console-reads-a-pack-as-the-skillcdn-command-does-and-a-local-one-from-a-directory.md)): `{ "address", "source", "page", "status", "refusal", "read" }`, the envelope as above, and `read` the body of the matching route of the main repository's REST API, as `@skillcdn/core` spells it, or `null` unless `ready`. `skills/one` is `load_skill`: `read` is a `RestSkill`, a page of the skill's context, the rules from the repository's root to the nearest manifest, the body and the included files, which `complete` and `nextCursor` say to continue, and `commit`, the commit it was read from. `skills/file` is `read_repo_file`: `read` is a `RestFile`, a page of the file in characters (`offset`, `nextOffset`, `totalLength`; `limit` 1 to 100,000) or, when the path names a folder, its entries. `skills/browse` is `browse_repo`: `read` is a `RestBrowse`, a page of what the folder holds (`limit` 1 to 200, 50 unless given; `cursor` continues). `skills/find` is `search_repo`: `read` is a `RestFind`, a page of what the words find in relevance order (`query` 1 to 500 characters, required; `limit` 1 to 25, 10 unless given). `path` is a path from the repository's root, up to 500 characters, the mounted folder when `browse` and `find` leave it out; a query out of bounds is `request.invalid`. Each read is logged with who read what of which pack, never with what was read or the words searched for. What the pack refuses is the status with the pack's own `refusal`: a skill or a file that is not there is `not_found`, a file the pack will not carry, too large or not text, is `failed` with where it is at its source. `@skillcdn/core` reads every `read` back as the result it was made from (`skillResultOf`, `fileResultOf`, `directoryResultOf`, `browseResultOf`, `findResultOf`, at the `mountSummaryOf` of the listing's `mount`) and renders what a model is given; the command does exactly that.
261
272
 
262
273
  ### `PUT /api/v1/projects/<key>/pack-token` and `DELETE .../pack-token`
263
274
 
264
275
  The pack token ([ADR-0028](../adr/0028-the-console-reads-a-projects-pack-through-the-deployments-rest-api-with-a-pack-token-for-a-private-one.md)), for an owner, signed in from the console's own pages or through their agent's token. `PUT` takes `{ "token" }`, a token a person made at the deployment for the pack's repository (8 to 1024 characters, no whitespace), tries it against the deployment once (`project.pack_token_refused` when the pack is not served to it or the project names no pack; `skills.unavailable` when the deployment could not be reached), seals it with the console's secret (`project.pack_token_unsupported` where the console has none) and keeps it, answering the project with `packToken: { setAt }` and writing a `project.updated` event naming the field `packToken`. The token is answered nowhere and logged nowhere. `DELETE` takes it away the same way; taking away what is not there writes nothing.
265
276
 
277
+ ### `POST /api/v1/projects/<key>/pack-token/connect`, `GET .../pack-token/connect` and `DELETE .../pack-token/connect`
278
+
279
+ A private pack connected with a code a person approves ([ADR-0036](../adr/0036-a-private-pack-is-connected-with-a-code-a-person-approves-from-the-projects-settings.md)), for an owner. `POST` asks the deployment to connect the project's address (the project's own, or the organization's), as nobody, the console calling itself `<the workspace's name> console`, and answers `201` with what the person is shown: `{ "code", "url", "expiresAt", "intervalSeconds" }`, the code, the page at the deployment to approve it on, until when, and how often to ask again; the secret the console claims with is kept sealed on a row of the project's and answered never. One request per project at a time: a new one replaces the one under way. `project.pack_connect_unsupported` (`409`) where the console reaches no deployment or keeps no secret to seal with; `project.pack_connect_refused` (`400`) when the project names no pack, the pack is on the console's machine, or the deployment refused to begin, in its words (an address with a ref or a path, a public pack); `skills.unavailable` (`503`) when the deployment could not be reached. `GET` asks how it stands and answers one of `{ "status": "none" }`, nothing asked; `{ "status": "pending", "code", "url", "expiresAt", "intervalSeconds" }`, while the person has not approved; `{ "status": "connected", "project" }`, once, when the token was claimed, sealed and kept as `PUT .../pack-token` keeps one, writing `project.updated` with `packToken`, the project answered as it stands; or `{ "status": "ended", "reason": "expired" | "declined" | "refused" }`, when the code's time ran out, the person declined or the code was spent, or the deployment refused (a repository the person may not open, as many tokens as one may hold), the request gone each time. A deployment that could not be reached is `skills.unavailable`, and the request stands. `DELETE` gives the request up and answers `204`.
280
+
266
281
  ### `GET /api/v1/projects/<key>/rules`
267
282
 
268
283
  `{ "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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillcdn/console",
3
- "version": "0.1.24",
3
+ "version": "0.3.1",
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",
@@ -68,6 +68,7 @@
68
68
  "vitest": "^5.0.3"
69
69
  },
70
70
  "dependencies": {
71
+ "@skillcdn/core": "^0.3.1",
71
72
  "react-markdown": "^10.1.0",
72
73
  "remark-gfm": "^4.0.1",
73
74
  "zod": "^4.6.5"
@@ -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; 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 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 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 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."
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.3"
8
+ version: "1.4"
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에서 내 토큰으로 돌리는 개인 콘솔, 이미지에서 기본 UI 자리를 대신하며 조직의 웹사이트가 있으면 그 디자인(마크, 색, 글꼴)을 기본으로 삼는 조직 콘솔, 또는 콘솔 REST API를 쓰는 스크립트. 패키지의 세 계층(API 클라이언트와 스키마, 컴포넌트, 구성)이 어디 있는지, 기본 콘솔이 어떻게 조립되는지, 무엇을 설정하고 무엇을 바꾸는지(컴포넌트, 언어 팩, 브랜드, 스타일 토큰), 웹사이트에서 디자인을 읽어 페이지에 입히는 법, 빌드를 보드에 붙여 돌리고 확인하는 법, 신뢰할 수 없는 내용을 안전하게 다루는 규칙을 말합니다. SkillCDN 콘솔 UI나 API 클라이언트를 만들거나 바꾸거나 디자인을 바꾸라고 할 때 쓰세요. 보드의 작업을 할 때는 working-the-board를, 조직의 콘솔을 배포할 때는 deploying-a-console을 쓰세요."
14
14
  ---
15
15
  # Building a console from the package
16
16
 
@@ -50,8 +50,8 @@ Nothing here restates them: they are the contract, current at the version instal
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
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
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 | 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 dark, so it should be a light 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 dark colour vanishes on the dark pages: ask for a light version, or, with the person's word, recolour it when it is one colour. Default: the board's name alone and no marks, which is the honest console. |
54
- | The colour | 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 light colour becomes the accent (`--sc-color-accent` and its family); a dark one tints the field and its light (`--sc-color-field`, `--sc-color-light-*`), with a lighter shade of it as the accent, since an accent must read on the dark field. The mapping is shown at the plan. |
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 light 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 dark, so it should be a light 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 dark colour vanishes on the dark pages: ask for a light 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 light colour becomes the accent (`--sc-color-accent` and its family); a dark one tints the field and its light (`--sc-color-field`, `--sc-color-light-*`), with a lighter shade of it as the accent, since an accent must read on the dark field. The mapping is shown at the plan, with the contrast checked. |
55
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
56
  | The name | Not asked: the server names the board (`WORKSPACE_NAME`), and `title` is only what the page says until the server answers. `index.html` gets the organization's `<title>` and `lang`. |
57
57
  | 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. |
@@ -0,0 +1,39 @@
1
+ # The look from a website
2
+
3
+ An organization with a website has a look already: its marks, its colours, its type. A console built for it takes that look by default, so that the board reads as the organization's and not as a second product; deploying-a-console asks for the website and hands it here, and a request for a console that names a site does the same. This page says how the look is read from the site, how it maps onto the pages, and what is left alone.
4
+
5
+ ## Reading the site
6
+
7
+ Fetch the homepage as HTML, with the agent's own tools, and read, in this order:
8
+
9
+ | What | Where it is | What to take |
10
+ |---|---|---|
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
+ | 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. |
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
+ | The mood | The site itself: dark or light, flat or glassy, round or square corners | Whether the field stays dark (the pages are dark, and stay so), and whether the radii follow the site (`--sc-radius-*`). |
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.
18
+
19
+ ## Mapping onto the pages
20
+
21
+ The pages are dark: a field with a light in it, and panes of glass over it. The mapping is shown at the plan as a table, value by value, before a file is written.
22
+
23
+ - **A mark drawn in a dark colour vanishes** on the dark pages. Look for the site's light or white variant first (a footer, a dark-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 dark fill: keep its fill as a rounded square behind it.
24
+ - **A light primary colour** becomes the accent: `--sc-color-accent` and its family (`-hover`, `-subtle`, the point), as the package's README lists them.
25
+ - **A dark primary colour** tints the field and its light: `--sc-color-field` and `--sc-color-light-*`, with a lighter shade of it as the accent, since an accent must read on the dark field.
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
+ - **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.
28
+ - **The name** stays the server's (`WORKSPACE_NAME`): the look is the marks, the colours and the type, never the words.
29
+
30
+ ## What is left alone
31
+
32
+ - Photographs, illustrations and copy from the site: the pages have their own content, the board.
33
+ - Marks of third parties shown on the site (partners, stores, badges).
34
+ - The structure of the site: the console's pages keep their layout; the look is skinned through the tokens of `console.css` and `brand`, and a component is replaced only when the tokens cannot do it.
35
+ - The marks of SkillCDN: a console with the organization's look shows none of them.
36
+
37
+ ## Where it goes
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.
@@ -1,20 +1,20 @@
1
1
  ---
2
2
  name: deploying-a-console
3
- description: "Deploys a SkillCDN Console for an organization on AWS behind Cloudflare, with an agent on the person's own machine and no developer needed: asks a few plain questions (how many people, the web address, how people sign in and who is in, where the organization's skills are), shows the monthly cost of the size that fits and of the next one before anything is made, creates the database, the bucket, the secrets, the tunnel and the containers, leaves a private repository that redeploys on every push, signs the first administrator in, makes the first project, connects an agent and proves it all with a file handed in and read back. Also grows a deployment to the next size, updates it to a new version of the console, adds a member or rotates a secret. Use when an agent is asked to deploy, set up, host, upgrade or resize a console for an organization. To build a console's pages, use building-a-console; to work tasks on a board, use working-the-board."
3
+ description: "Deploys a SkillCDN Console for an organization on AWS behind Cloudflare, by an agent on the person's machine, no developer needed: asks a few plain questions (how many people, the web address, how people sign in and who is in, where the organization's skills are, and its website, whose look the console takes by default), shows the monthly cost of the fitting size and the next before anything is made, creates the database, bucket, secrets, tunnel and containers, builds the organization's own look into the image, leaves a private repository that redeploys on every push, signs the first administrator in, makes the first project, connects an agent and proves it with a file handed in and read back. Also grows it to the next size, updates it to a new version of the console, adds a member or rotates a secret. Use when an agent is asked to deploy, set up, host, upgrade or resize a console for an organization. To build a console's pages, use building-a-console; to work tasks on a board, use working-the-board."
4
4
  license: MIT
5
5
  compatibility: Needs a shell with Node.js 24 or newer, git, curl, jq and the AWS CLI v2, the gh command signed in or an empty repository the person made, network access to AWS, Cloudflare, GitHub and npm, an AWS account and a domain on Cloudflare the person can create a key and a token for, and a browser on any device for the few steps only a signed-in person can take. Works in any agent that can run a shell and write files; on Windows, in Git Bash with path conversion off.
6
6
  metadata:
7
7
  author: skillcdn
8
- version: "1.1"
8
+ version: "1.3"
9
9
  skillcdn:
10
10
  translations:
11
11
  ko:
12
12
  title: 조직의 콘솔 배포하기
13
- description: "조직의 SkillCDN 콘솔을 AWS와 Cloudflare에 배포합니다. 개발자가 아니어도 됩니다: 에이전트가 쉬운 질문 몇 개(몇 명이 쓰는지, 주소, 로그인 방식과 구성원, 조직 스킬의 위치)를 묻고, 맞는 크기와 그 다음 크기의 월 비용을 먼저 보여준 뒤, 데이터베이스·버킷·비밀·터널·컨테이너를 만들고, 푸시할 때마다 다시 배포되는 비공개 저장소를 남기고, 첫 관리자를 로그인시키고 첫 프로젝트를 만들고 에이전트를 연결해 파일 제출과 되읽기로 증명합니다. 규모 키우기, 콘솔 새 버전으로 올리기, 구성원 추가, 비밀 교체도 합니다. 조직의 콘솔을 배포·설치·호스팅·업그레이드·확장하라고 할 때 쓰세요. 콘솔 페이지를 만들 때는 building-a-console, 보드의 작업을 할 때는 working-the-board를 쓰세요."
13
+ description: "조직의 SkillCDN 콘솔을 AWS와 Cloudflare에 배포합니다. 개발자가 아니어도 됩니다: 에이전트가 쉬운 질문 몇 개(몇 명이 쓰는지, 주소, 로그인 방식과 구성원, 조직 스킬의 위치, 그리고 조직의 웹사이트. 웹사이트가 있으면 그 디자인이 콘솔의 기본이 됩니다)를 묻고, 맞는 크기와 그 다음 크기의 월 비용을 먼저 보여준 뒤, 데이터베이스·버킷·비밀·터널·컨테이너를 만들고, 조직의 디자인을 이미지에 담고, 푸시할 때마다 다시 배포되는 비공개 저장소를 남기고, 첫 관리자를 로그인시키고 첫 프로젝트를 만들고 에이전트를 연결해 파일 제출과 되읽기로 증명합니다. 규모 키우기, 콘솔 새 버전으로 올리기, 구성원 추가, 비밀 교체도 합니다. 조직의 콘솔을 배포·설치·호스팅·업그레이드·확장하라고 할 때 쓰세요. 콘솔 페이지를 만들 때는 building-a-console, 보드의 작업을 할 때는 working-the-board를 쓰세요."
14
14
  ---
15
15
  # Deploying a console for an organization
16
16
 
17
- What goes in: an AWS account, a domain on Cloudflare or one to buy, and the answers to a few plain questions. What comes out: the console at `https://<hostname>`, signed in by its first administrator, with a first project and an agent connected; running as containers on AWS next to a managed PostgreSQL and a bucket, reached only through Cloudflare, every secret in a parameter store; a private deployment repository whose every push rebuilds and redeploys; a budget alert; and a record, `DEPLOY.md`, of what exists and how it is run. The person never needs to know the cloud: every choice is derived from their answers, shown with its cost, and changed when they ask. The shape and why it was chosen are [ADR-0017](/docs/adr/0017-the-reference-deployment-is-the-image-on-aws-behind-cloudflare-written-as-a-skill.md); what the console asks of any platform is [deploy/README.md](/deploy/README.md).
17
+ What goes in: an AWS account, a domain on Cloudflare or one to buy, and the answers to a few plain questions. What comes out: the console at `https://<hostname>`, signed in by its first administrator, with a first project and an agent connected; running as containers on AWS next to a managed PostgreSQL and a bucket, reached only through Cloudflare, every secret in a parameter store; a private deployment repository whose every push rebuilds and redeploys; a budget alert; and a record, `DEPLOY.md`, of what exists and how it is run. The person never needs to know the cloud: every choice is derived from their answers, shown with its cost, and changed when they ask. The shape and why it was chosen are [ADR-0017](/docs/adr/0017-the-reference-deployment-is-the-image-on-aws-behind-cloudflare-written-as-a-skill.md); what the console asks of any platform is [deploy/README.md](/deploy/README.md). For one machine, a trial, or a closed network that reaches no cloud, the smallest install of [deploy/README.md](/deploy/README.md#the-smallest-install-and-a-closed-network) is the shape, not this skill: the image next to PostgreSQL with the packs in a directory, carried in where nothing is reachable.
18
18
 
19
19
  ## How the person is involved
20
20
 
@@ -46,7 +46,8 @@ Check these before the first message. Without the AWS CLI, offer to install it (
46
46
  | The board's name | Asked, with the organization's name as the suggestion when the request gives one: "What should the board be called? Usually the organization's name." |
47
47
  | The web address | Asked: "Which web address should the console have? A domain you already own, and where it is registered (I set it up on Cloudflare; you change its nameservers there once, and I give you the steps), or should I find one to buy (I show the price before buying)? I suggest `console.<domain>`." A domain is needed: the tunnel has no free hostname. A domain that already serves the organization's site is fine: only the console's hostname is added to its zone, and nothing of the site is touched (resources.md "A zone that serves other hosts"). |
48
48
  | How people sign in, and who | Asked: "How should people sign in: with GitHub, with Google (Workspace), or both? Who configures the console (you, at least): their GitHub login or Google address. With GitHub, everyone of your organization can be in, as the organization has them: say which organization. With a Google Workspace, everyone of the domain is in. Anyone else, an administrator lets in on the People page once the console runs." |
49
- | The organization's skills | Asked: "Where are your organization's skills on SkillCDN, if anywhere yet? An address like `/gh/<owner>/<repo>`." Default: none; a project names one later on its Settings page. |
49
+ | The organization's skills | Asked: "Where are your organization's skills on SkillCDN, if anywhere yet? An address like `/gh/<owner>/<repo>`. Is that repository private?" Default: none; a project names one later on its Settings page. A private one is connected in phase 6, with a code the person approves at SkillCDN ([ADR-0036](/docs/adr/0036-a-private-pack-is-connected-with-a-code-a-person-approves-from-the-projects-settings.md)); nothing of it is needed before. |
50
+ | The organization's website, and the look | Asked: "Does your organization have a website? Its address." With one, the console takes the organization's look by default: the marks, the colours and the type read from the site as building-a-console's [the-look-from-a-website.md](/skills/building-a-console/references/the-look-from-a-website.md) says, mapped onto the pages and shown at the plan, and built into the image as the organization's own console, `console-ui/` of the deployment repository, so that the first deploy already carries it. Without a site, or when the person says the default pages are fine, the image's default pages serve: the board's name alone, and no marks. A look that is wanted later is the same skill, building-a-console, in `console-ui/`, and a push. |
50
51
  | The AWS account | Asked: "Do you have an AWS account for this, or should the console get an account of its own (the simplest to run and to read the bill of)?" A new account is made by the person, on the paid plan, with the order of cost already in front of them (the second message). |
51
52
  | The region | Asked when the organization's country does not say: "Which AWS region: the one nearest your people?" Default: the nearest to where the organization is (`ap-northeast-2`, Seoul, for Korea; `ap-northeast-1` for Japan; `eu-central-1` for central Europe; `us-east-1` for the eastern United States). |
52
53
  | The run's folder | Asked with a suggestion: "Which folder should the deployment live in on this machine? I suggest `console-deploy` under your home folder." It is made at once and becomes the deployment repository. |
@@ -65,7 +66,7 @@ Produces the **access record**: the account id, the region, the default VPC and
65
66
 
66
67
  ### Phase 2: Plan and estimate
67
68
 
68
- Produces the **plan**, shown at the checkpoint. From the answers: the size and what it is made of (sizing.md "The sizes"); today's prices, read as sizing.md "Reading today's prices" says, and the estimate of this size and the next one, each line saying whether it is today's price or the snapshot; the resources to create under which names; the domain's path (owned, with the registrar's steps already sent; bought at the price shown); the secrets, which are generated, which are derived, and which the person holds and will be asked for at phase 3 with the exact steps; the budget alert; the few steps only the person takes, and when. Then stop, with the estimate message of sizing.md and: "I will create <the resources>, set <n> secrets, connect <hostname> through Cloudflare, and make a repository at <owner>/<name> that deploys on every push. You do once: <the steps>. OK?"
69
+ Produces the **plan**, shown at the checkpoint. From the answers: the size and what it is made of (sizing.md "The sizes"); today's prices, read as sizing.md "Reading today's prices" says, and the estimate of this size and the next one, each line saying whether it is today's price or the snapshot; the resources to create under which names; the domain's path (owned, with the registrar's steps already sent; bought at the price shown); the secrets, which are generated, which are derived, and which the person holds and will be asked for at phase 3 with the exact steps; the look, with a website: the marks found on it, the colours and how they map onto the pages, the type and whether it can be taken, as a table, with a mock or a screenshot where a browser can be driven; the budget alert; the few steps only the person takes, and when. Then stop, with the estimate message of sizing.md and: "I will create <the resources>, set <n> secrets, connect <hostname> through Cloudflare, build the console in your look (<the marks and the colours>), and make a repository at <owner>/<name> that deploys on every push. You do once: <the steps>. OK?"
69
70
 
70
71
  ### Phase 3: Foundation
71
72
 
@@ -73,7 +74,7 @@ Produces the **resource record**: each resource with its name and id. In this or
73
74
 
74
75
  ### Phase 4: The deployment repository
75
76
 
76
- Produces the **repository**: `deploy/console.env`, the task definitions `deploy/migrate.task.json`, `deploy/api.task.json` and, at the large size, `deploy/worker.task.json`, the workflow `.github/workflows/deploy.yml`, `README.md` and a draft `DEPLOY.md`, as resources.md gives them, every value filled from the record; and on AWS the role the workflow assumes, trusted for this repository's `main` alone. Show the files, each with the lines that matter pointed out for a person who is not a developer; commit; create the empty private repository. Checkpoint: "Pushing starts the first build (about ten minutes), runs the migrations, and starts the console at <hostname>. OK?" On the word, push, and watch the run to its end.
77
+ Produces the **repository**: `deploy/console.env`, the task definitions `deploy/migrate.task.json`, `deploy/api.task.json` and, at the large size, `deploy/worker.task.json`, the workflow `.github/workflows/deploy.yml`, `README.md` and a draft `DEPLOY.md`, as resources.md gives them, every value filled from the record; with the organization's look, `console-ui/`, the organization's own console made here with building-a-console at the console's pinned version, from the look approved at the plan, which the workflow builds into the image on every push (resources.md "The organization's own console"); and on AWS the role the workflow assumes, trusted for this repository's `main` alone. Show the files, each with the lines that matter pointed out for a person who is not a developer, and the look's pages where a browser can be driven; commit; create the empty private repository. Checkpoint: "Pushing starts the first build (about ten minutes), runs the migrations, and starts the console at <hostname>. OK?" On the word, push, and watch the run to its end.
77
78
 
78
79
  ### Phase 5: Live
79
80
 
@@ -81,7 +82,7 @@ Produces the **live address**. The zone is active (else the wait of "How the per
81
82
 
82
83
  ### Phase 6: The first people
83
84
 
84
- Produces the **first administrator and the first project**. Tell the person: "Open <address> and sign in with <provider>; you are an administrator. Make the first project: Projects, New project, a key such as `general`, its name, and the skills address <address or none>. Tell me the key." Then connect this agent: `console login --url <address> --agent deploying-a-console`, which shows an address and a code; relay them, and the person approves on the console's own pages. `console use <key>` in the run's folder.
85
+ Produces the **first administrator and the first project**. Tell the person: "Open <address> and sign in with <provider>; you are an administrator. Make the first project: Projects, New project, a key such as `general`, its name, and the skills address <address or none>. Tell me the key." Then connect this agent: `console login --url <address> --agent deploying-a-console`, which shows an address and a code; relay them, and the person approves on the console's own pages. `console use <key>` in the run's folder. A private pack: `console project pack-token <key> --connect`, which prints a page at SkillCDN and a code; relay them, and the person, signed in at SkillCDN as someone who may open the repository, checks the code and approves there; the command says when the pack is connected, and `console skills` then lists it. Nothing is pasted.
85
86
 
86
87
  ### Phase 7: Proof
87
88
 
@@ -5,7 +5,7 @@ license: MIT
5
5
  compatibility: Needs a shell with the console command on the PATH (npm install -g @skillcdn/console, Node.js 24 or newer), signed in by a person. Nothing else; the command needs no key of its own and the agent never sees a token.
6
6
  metadata:
7
7
  author: skillcdn
8
- version: "1.17"
8
+ version: "1.19"
9
9
  skillcdn:
10
10
  translations:
11
11
  ko:
@@ -23,7 +23,7 @@ A task of the board goes in, named by its number; a run comes out: the task take
23
23
  - **Go-ahead:** the task's body is the go-ahead. A task that says what the agent may decide alone is followed within that; everything else that would change scope, cost or a trade-off is a decision.
24
24
  - **Changes mid-run:** a person changes the task or answers a decision on the board; the run takes it from there and says so in its next report. A report is never rewritten.
25
25
  - **The discussion:** what people say about the task is in its comments, which `console task <number>` and `console take` print with the task; a picture they put in is saved with `console file <id>` and looked at with the agent's own tools. An answer to what they asked there, a question that is not a decision, a remark on what was handed in, is a comment of the agent's own: `console comment <number> "<markdown>" [--attach <file>]`, which needs no run. A report is the run's record; a comment is a word to people.
26
- - **Work given in chat:** when a person gives work in chat, in a directory that works in a project, the agent writes it on the board first (`console task new`), tells the person the number, takes it and works it as below, so that the board holds the work and its record, and the person decides on the board.
26
+ - **Work given in chat:** when a person gives work in chat, in a directory that works in a project, the agent writes it on the board first (`console task new`), tells the person the number the command printed, never one assumed, since other agents write on the same board and the next number is nobody's to guess, takes it by that number and works it as below, so that the board holds the work and its record, and the person decides on the board.
27
27
  - **Language:** what people read, the reports, the questions, the pages and the summaries, is in the language the rules name for the person (`console take` prints them with the task), else the task's, so that the people of the board read as they wrote.
28
28
 
29
29
  ## Requirements
@@ -41,7 +41,7 @@ The full contract is the [specification of the command line](/docs/specs/cli.md)
41
41
  | Input | Source |
42
42
  |---|---|
43
43
  | The task | Its number (`#7`) or its id, from what the person said. Told to pick one, `console work` lists what is on the person's plate across their projects, the sooner due first (`--person <login>` another person's, for an administrator or an owner of a project they are in), and `console tasks --state ready --mine` what is ready and theirs in this one (`--due overdue`, `--due week`, `--category <key>` and `--goal <id>` narrow it further); a task is never taken without being told which, or that any ready one may be. |
44
- | The work | The task's body, read with `console task <number>`: what to make, where, the milestones, what to ask; the comments on it, which are the discussion so far, printed with the task, their pictures saved with `console file <id>`; with its plan, the category, the goal it works towards (`console goal <id>` says what reaching it means, its category and the days it starts and is meant to be reached by) and the days it starts and is due, which the reports and the summary keep to. The pages it links to (`console doc <path>`) and the project's pack (`console skills` lists its skills and says how many skills and documents it has; `console skills <folder>` shows what a folder of it holds, `console skills --search <words>` what the words find in it; `console skill <path>` reads one whole through the console, its rules first, a private pack through the pack token the project holds, [ADR-0028](/docs/adr/0028-the-console-reads-a-projects-pack-through-the-deployments-rest-api-with-a-pack-token-for-a-private-one.md); `console skill --file <file>` a file of it; a host that lists skills through a connection of its own loads them by their URI) say the rest. |
44
+ | The work | The task's body, read with `console task <number>`: what to make, where, the milestones, what to ask; the comments on it, which are the discussion so far, printed with the task, their pictures saved with `console file <id>`; with its plan, the category, the goal it works towards (`console goal <id>` says what reaching it means, its category and the days it starts and is meant to be reached by) and the days it starts and is due, which the reports and the summary keep to. The pages it links to (`console doc <path>`) and the project's pack (`console skills` says where the pack is, what a client is told of it on connect, and every skill and document; `console skills <folder>` shows what a folder of it holds, `console skills --search <words>` what the words find in it; `console skill <path>` reads one whole through the console, its rules first, as an MCP client's model is given it, a private pack through the pack token the project holds, [ADR-0028](/docs/adr/0028-the-console-reads-a-projects-pack-through-the-deployments-rest-api-with-a-pack-token-for-a-private-one.md), and a pack on the console's own machine from its directory, [ADR-0031](/docs/adr/0031-the-console-reads-a-pack-as-the-skillcdn-command-does-and-a-local-one-from-a-directory.md); `console skill --file <file>` a file of it; a host that lists skills through a connection of its own loads them by their URI, which means nothing elsewhere for a pack on the console's machine) say the rest. |
45
45
  | The rules | The workspace's, the console's own until an administrator writes the organization's, and this project's own when it has them: which skills to load first, where the work lives, the pages, what may be decided alone, how to report ([ADR-0023](/docs/adr/0023-the-rules-of-a-board-are-pages-the-workspace-and-its-projects-keep-read-first-by-every-agent.md)). `console take` prints them with the task, so they are read once, there; `console rules` reads them without taking, as when a task is still to be chosen. They hold over this skill's defaults where they differ. |
46
46
 
47
47
  ## Workflow
@@ -54,7 +54,7 @@ Told which task, go to phase 2: `console take` prints the rules of the board wit
54
54
 
55
55
  ### Phase 2: Take
56
56
 
57
- `console take <number>`. A run begins, and the command says its id: the task is in progress and the person's, and every report, hand-in, question and ending from here acts on this run. With another run of the person's open in the project, which `console take` says, each of those commands names the run: `--run <id>`. Taken by mistake, `console abandon` leaves it and the task stays as it was.
57
+ `console take <number>`. A run begins, and the command says its id and the task's on a line of their own (`run id:`, `task id:`; a task has a number for people and an id for the API, a run, a decision and a goal have ids alone, and every command that makes one prints it so, `--json` the whole answer; an id is read from there, never assumed): the task is in progress and the person's, and every report, hand-in, question and ending from here acts on this run. With another run of the person's open in the project, which `console take` says, each of those commands names the run: `--run <id>`. Taken by mistake, `console abandon` leaves it and the task stays as it was.
58
58
 
59
59
  ### Phase 3: Work, and report at the milestones
60
60
 
@@ -62,7 +62,7 @@ The work happens where it happens: in the repository, the document, the tool. At
62
62
 
63
63
  ### Phase 4: Ask when a person must decide
64
64
 
65
- A choice the body does not settle, a trade-off, a cost, a change of scope: `console ask "<question>" --option "<one>" --option "<another>" --body "<what they need to know>"`. The run waits for the answer; the command waits a minute and exits with `3` while it is still to come. Keep waiting with `console decision <id> --wait 100`, as often as needed, and meanwhile do only what does not depend on the answer. Act on the answer as given; what was answered is not asked again. Once acted on, `console decision <id> --outcome "<what followed>"` makes the decision read as a record.
65
+ A choice the body does not settle, a trade-off, a cost, a change of scope: `console ask "<question>" --option "<one>" --option "<another>" --body "<what they need to know>"`. The run waits for the answer; the command waits a minute and exits with `3` while it is still to come. Keep waiting with `console decision <id> --wait 100`, as often as needed, and meanwhile do only what does not depend on the answer. Act on the answer as given, which may be the person's own words rather than one of the options, marked as theirs; what was answered is not asked again. Once acted on, `console decision <id> --outcome "<what followed>"` makes the decision read as a record.
66
66
 
67
67
  ### Phase 5: Hand in
68
68
 
@@ -1,3 +1,3 @@
1
1
  # Setting up, when told to
2
2
 
3
- A task or a person may ask for the project itself rather than work in it: a project made or changed (`console project new <key> "<name>"`, `console project edit <key>`), its mark (`console project icon <key> <file>`), its members (`console member add <login>`, `console member role`, `console member remove`), the workspace's categories (`console category new <key> "<name>"`, `console category edit`, `console category remove`), what a person is (`console person role <login> <admin|member>`), its goals (`console goal new`), and its rules (`console rules write --file <path>`, from [the example](project-rules.md); the workspace's with `--workspace`, for an administrator). The agent does these as its person may, an owner of the project or an administrator of the workspace ([ADR-0021](/docs/adr/0021-a-token-configures-as-its-person-does.md)); the feed names the agent beside the person on each. What the person may not, the console refuses (`auth.forbidden`): that step goes back to the person in the report, never worked around. `console people` and `console members` say who is who, by login.
3
+ A task or a person may ask for the project itself rather than work in it: a project made or changed (`console project new <key> "<name>"`, `console project edit <key>`), its mark (`console project icon <key> <file>`), its members (`console member add <login>`, `console member role`, `console member remove`), the workspace's categories (`console category new <key> "<name>"`, `console category edit`, `console category remove`), what a person is (`console person role <login> <admin|member>`), its goals (`console goal new`), and its rules (`console rules write --file <path>`, from [the example](project-rules.md); the workspace's with `--workspace`, for an administrator). The agent does these as its person may, an owner of the project or an administrator of the workspace ([ADR-0021](/docs/adr/0021-a-token-configures-as-its-person-does.md)); the feed names the agent beside the person on each. What the person may not, the console refuses (`auth.forbidden`): that step goes back to the person in the report, never worked around. `console people` and `console members` say who is who, by login; `console workspace` says the workspace's settings, and `console workspace edit` changes them for an administrator: `--people-visibility <everyone|shared-projects>`, who sees whom on the People page; `--week-start <auto|monday|sunday>`, the day the calendars begin a week on; `--time-zone <zone|none>`, the workspace's time zone, an IANA name such as `Asia/Seoul`, in which the command prints moments ([ADR-0035](/docs/adr/0035-who-may-see-whom-is-decided-by-one-policy-and-the-workspace-keeps-its-settings.md)). In a project open to the workspace everyone is a member already: `console member add <login> --role owner` lists an owner, and `member role <login> member` takes one back; a plain `member add` is refused there (`member.open_project`). A login is found exactly, so an owner lists someone `console people` does not show them. A private pack is connected by an owner with `console project pack-token <key> --connect`, or, for the organization's pack, which projects read when they name no address of their own, by an administrator with `console workspace pack-token --connect` ([ADR-0036](/docs/adr/0036-a-private-pack-is-connected-with-a-code-a-person-approves-from-the-projects-settings.md)): the command prints a page at SkillCDN and a code, which the agent relays; the person approves there, signed in as someone who may open the repository, and the console keeps the SkillCDN token, shown to nobody. Until then `console skills` says the pack is not served to the console.
@@ -7,3 +7,5 @@
7
7
  - **Decision**: a question with options, which a person answers on the board.
8
8
  - **Page**: a document of the project, Markdown at a path that does not change.
9
9
  - **Project**: a board of its own, with its members and its skills address.
10
+ - **SkillCDN token**: what the console reads a private pack with, `pack-token` in the API and the command: a project's own, or the workspace's for the organization's pack, which a project reads when it names no address of its own; connected with a code a person approves at SkillCDN, or made there by hand, and shown to nobody.
11
+ - **Number and id**: a task has a number (`#7`), what people say and the commands take, and an id, what the API takes and `--parent` and `--goal` may; a run, a decision, a goal and a comment have ids alone. Every command that makes one prints it on a line of its own, named (`task id:`, `run id:`, `decision id:`, `goal id:`, `comment <id>:`), and `--json` prints the whole answer: an id or a number is read from there, never assumed, since several agents write on one board.
@@ -1,5 +1,5 @@
1
1
  # The sentence a repository carries
2
2
 
3
- A repository whose checkouts are worked through a console says so in its agreement (AGENTS.md, or CLAUDE.md where that is the file agents read), in one sentence copied as it is and placed at the head of its workflow; a pack says it in the rules of its `SKILLCDN.md`, with `the checkout` for `this checkout`. The sentence binds the checkout to the console and says nothing of how: the command's help and the skill working-the-board say how, and the repository's own agreement keeps saying how a change is committed and pushed.
3
+ A repository whose checkouts are worked through a console says so in its agreement (AGENTS.md, or CLAUDE.md where that is the file agents read), in one sentence copied as it is and placed at the head of its workflow; a pack says it in the rules of its `SKILLCDN.md`, with `the checkout` for `this checkout`. The sentence binds the checkout to the console and says nothing of how: the command's help and the skill working-the-board say how, and the repository's own agreement keeps saying how a change is committed and pushed. `console use` prints the sentence after binding a directory, so that whoever sets a checkout up, a person or an agent, copies it from there.
4
4
 
5
5
  > **Bound to a console?** When `.skillcdn-console.json` is in this checkout, or `console whoami` names a project, work the task through that SkillCDN console (`console help` says how).
package/src/api.ts CHANGED
@@ -188,6 +188,9 @@ export {
188
188
  type RestMembers,
189
189
  type RestMePatch,
190
190
  type RestOrganization,
191
+ type RestPackConnect,
192
+ type RestPackConnectStarted,
193
+ type RestPackRefusal,
191
194
  type RestPackTokenInput,
192
195
  type RestPeople,
193
196
  type RestPerson,
@@ -210,12 +213,9 @@ export {
210
213
  type RestRuns,
211
214
  type RestSkill,
212
215
  type RestSkillBrowse,
213
- type RestSkillBrowseEntry,
214
216
  type RestSkillFile,
215
217
  type RestSkillFind,
216
- type RestSkillFindItem,
217
218
  type RestSkillLoad,
218
- type RestSkillPage,
219
219
  type RestSkills,
220
220
  type RestTask,
221
221
  type RestTaskCounts,
@@ -231,6 +231,9 @@ export {
231
231
  type RestVersionSummary,
232
232
  type RestVersions,
233
233
  type RestWork,
234
+ type RestWorkspace,
235
+ type RestWorkspacePackConnect,
236
+ type RestWorkspacePatch,
234
237
  restAnswerInputSchema,
235
238
  restArchivedTasksSchema,
236
239
  restArchiveTasksInputSchema,
@@ -280,6 +283,9 @@ export {
280
283
  restMePatchSchema,
281
284
  restMeSchema,
282
285
  restOrganizationSchema,
286
+ restPackConnectSchema,
287
+ restPackConnectStartedSchema,
288
+ restPackRefusalSchema,
283
289
  restPackTokenInputSchema,
284
290
  restPeopleSchema,
285
291
  restPersonPatchSchema,
@@ -300,16 +306,12 @@ export {
300
306
  restRunInputSchema,
301
307
  restRunSchema,
302
308
  restRunsSchema,
303
- restSkillBrowseEntrySchema,
304
309
  restSkillBrowseSchema,
305
310
  restSkillFileSchema,
306
- restSkillFindItemSchema,
307
311
  restSkillFindSchema,
308
312
  restSkillLoadSchema,
309
- restSkillPageSchema,
310
313
  restSkillSchema,
311
314
  restSkillsSchema,
312
- restSkillTextSchema,
313
315
  restTaskCountsSchema,
314
316
  restTaskInputSchema,
315
317
  restTaskLinkSchema,
@@ -324,6 +326,9 @@ export {
324
326
  restVersionSummarySchema,
325
327
  restVersionsSchema,
326
328
  restWorkSchema,
329
+ restWorkspacePackConnectSchema,
330
+ restWorkspacePatchSchema,
331
+ restWorkspaceSchema,
327
332
  } from "./schemas.js";
328
333
  export { hasForbiddenCodePoint } from "./text.js";
329
334
  export {
@@ -343,8 +348,12 @@ export {
343
348
  MEMBERSHIP_SOURCES,
344
349
  type MembershipSource,
345
350
  OPEN_TASK_STATES,
351
+ PACK_CONNECT_ENDINGS,
352
+ type PackConnectEnding,
353
+ PEOPLE_VISIBILITIES,
346
354
  PERSON_ROLES,
347
355
  PERSON_STATUSES,
356
+ type PeopleVisibility,
348
357
  type PersonRole,
349
358
  type PersonStatus,
350
359
  PROJECT_ICON_TYPES,
@@ -367,4 +376,6 @@ export {
367
376
  TASK_STATES,
368
377
  type TaskPriority,
369
378
  type TaskState,
379
+ WEEK_STARTS,
380
+ type WeekStart,
370
381
  } from "./vocabulary.js";