@skillcdn/console 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/api.d.ts +4 -4
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +4 -4
- package/dist/api.js.map +1 -1
- package/dist/cli/cli.d.ts +4 -0
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +201 -25
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/format.d.ts.map +1 -1
- package/dist/cli/format.js +15 -11
- package/dist/cli/format.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +59 -26
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/main.js +1 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/pack.d.ts +7 -2
- package/dist/cli/pack.d.ts.map +1 -1
- package/dist/cli/pack.js +16 -2
- package/dist/cli/pack.js.map +1 -1
- package/dist/client.d.ts +20 -10
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +17 -3
- package/dist/client.js.map +1 -1
- package/dist/compat.d.ts +28 -6
- package/dist/compat.d.ts.map +1 -1
- package/dist/compat.js +55 -14
- package/dist/compat.js.map +1 -1
- package/dist/components/board.d.ts +12 -1
- package/dist/components/board.d.ts.map +1 -1
- package/dist/components/board.js +57 -7
- package/dist/components/board.js.map +1 -1
- package/dist/components/calendar.d.ts +17 -7
- package/dist/components/calendar.d.ts.map +1 -1
- package/dist/components/calendar.js +89 -38
- package/dist/components/calendar.js.map +1 -1
- package/dist/components/decision-form.d.ts +12 -4
- package/dist/components/decision-form.d.ts.map +1 -1
- package/dist/components/decision-form.js +24 -6
- package/dist/components/decision-form.js.map +1 -1
- package/dist/components/decision-list.d.ts +4 -0
- package/dist/components/decision-list.d.ts.map +1 -1
- package/dist/components/decision-list.js +9 -6
- package/dist/components/decision-list.js.map +1 -1
- package/dist/components/documents.d.ts.map +1 -1
- package/dist/components/documents.js +3 -3
- package/dist/components/documents.js.map +1 -1
- package/dist/components/event-feed.d.ts.map +1 -1
- package/dist/components/event-feed.js +63 -8
- package/dist/components/event-feed.js.map +1 -1
- package/dist/components/my-decisions.d.ts +20 -0
- package/dist/components/my-decisions.d.ts.map +1 -0
- package/dist/components/my-decisions.js +36 -0
- package/dist/components/my-decisions.js.map +1 -0
- package/dist/components/people.d.ts.map +1 -1
- package/dist/components/people.js +1 -1
- package/dist/components/people.js.map +1 -1
- package/dist/components/picker.d.ts +39 -0
- package/dist/components/picker.d.ts.map +1 -0
- package/dist/components/picker.js +155 -0
- package/dist/components/picker.js.map +1 -0
- package/dist/components/projects.d.ts.map +1 -1
- package/dist/components/projects.js +3 -3
- package/dist/components/projects.js.map +1 -1
- package/dist/components/roadmap.js +1 -1
- package/dist/components/roadmap.js.map +1 -1
- package/dist/components/runs.d.ts.map +1 -1
- package/dist/components/runs.js +1 -1
- package/dist/components/runs.js.map +1 -1
- package/dist/components/shell.d.ts.map +1 -1
- package/dist/components/shell.js +36 -1
- package/dist/components/shell.js.map +1 -1
- package/dist/components/task-form.d.ts +18 -4
- package/dist/components/task-form.d.ts.map +1 -1
- package/dist/components/task-form.js +56 -13
- package/dist/components/task-form.js.map +1 -1
- package/dist/components/task-list.js +2 -2
- package/dist/components/task-list.js.map +1 -1
- package/dist/components/task-view.d.ts +7 -1
- package/dist/components/task-view.d.ts.map +1 -1
- package/dist/components/task-view.js +7 -6
- package/dist/components/task-view.js.map +1 -1
- package/dist/components/ui.d.ts +17 -0
- package/dist/components/ui.d.ts.map +1 -1
- package/dist/components/ui.js +26 -11
- package/dist/components/ui.js.map +1 -1
- package/dist/components/work.d.ts.map +1 -1
- package/dist/components/work.js +5 -3
- package/dist/components/work.js.map +1 -1
- package/dist/console.css +1794 -433
- package/dist/console.d.ts.map +1 -1
- package/dist/console.js +93 -10
- package/dist/console.js.map +1 -1
- package/dist/data.d.ts +21 -1
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +24 -1
- package/dist/data.js.map +1 -1
- package/dist/i18n/en.d.ts +45 -3
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +52 -10
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/ko.d.ts.map +1 -1
- package/dist/i18n/ko.js +54 -12
- package/dist/i18n/ko.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/limits.d.ts +2 -0
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +2 -0
- package/dist/limits.js.map +1 -1
- package/dist/router.d.ts +9 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +12 -0
- package/dist/router.js.map +1 -1
- package/dist/routes.d.ts +3 -1
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +3 -1
- package/dist/routes.js.map +1 -1
- package/dist/rules.js +1 -1
- package/dist/rules.js.map +1 -1
- package/dist/schemas.d.ts +252 -12
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +27 -10
- package/dist/schemas.js.map +1 -1
- package/dist/vocabulary.d.ts +2 -0
- package/dist/vocabulary.d.ts.map +1 -1
- package/dist/vocabulary.js +2 -0
- package/dist/vocabulary.js.map +1 -1
- package/docs/specs/cli.md +14 -13
- package/docs/specs/rest.md +24 -19
- package/package.json +2 -2
- package/skills/building-a-console/SKILL.md +4 -4
- package/skills/building-a-console/references/the-default-console.md +4 -4
- package/skills/building-a-console/references/the-look-from-a-website.md +5 -5
- package/skills/deploying-a-console/SKILL.md +2 -2
- package/skills/deploying-a-console/references/resources.md +1 -1
- package/skills/working-the-board/SKILL.md +8 -6
- package/skills/working-the-board/references/terms.md +3 -3
- package/src/api.ts +7 -0
- package/src/cli/cli.ts +254 -25
- package/src/cli/format.ts +22 -11
- package/src/cli/help.ts +63 -26
- package/src/cli/main.ts +1 -0
- package/src/cli/pack.ts +17 -1
- package/src/client.ts +44 -11
- package/src/compat.ts +63 -14
- package/src/components/board.tsx +124 -25
- package/src/components/calendar.tsx +258 -117
- package/src/components/decision-form.tsx +71 -23
- package/src/components/decision-list.tsx +30 -3
- package/src/components/documents.tsx +27 -11
- package/src/components/event-feed.tsx +116 -33
- package/src/components/my-decisions.tsx +138 -0
- package/src/components/people.tsx +3 -1
- package/src/components/picker.tsx +297 -0
- package/src/components/projects.tsx +7 -5
- package/src/components/roadmap.tsx +1 -1
- package/src/components/runs.tsx +5 -1
- package/src/components/shell.tsx +36 -1
- package/src/components/task-form.tsx +149 -63
- package/src/components/task-list.tsx +3 -3
- package/src/components/task-view.tsx +71 -56
- package/src/components/ui.tsx +89 -11
- package/src/components/work.tsx +6 -4
- package/src/console.tsx +157 -29
- package/src/data.ts +61 -1
- package/src/i18n/en.ts +54 -10
- package/src/i18n/ko.ts +56 -12
- package/src/index.ts +19 -1
- package/src/limits.ts +2 -0
- package/src/router.ts +18 -1
- package/src/routes.ts +3 -1
- package/src/rules.ts +1 -1
- package/src/schemas.ts +29 -9
- package/src/styles/console.css +1794 -433
- package/src/vocabulary.ts +3 -0
package/docs/specs/rest.md
CHANGED
|
@@ -13,7 +13,7 @@ The API is the board as its members see it: the people, the projects, and in eac
|
|
|
13
13
|
- A token ([`POST /api/v1/tokens`](#get-apiv1tokens-and-post-apiv1tokens)) is presented as `Authorization: Bearer <secret>` on any route, by an agent, a script or a console of a person's own. It is then the credential: a cookie beside it is not looked at, and no origin is needed, since nothing attaches a token but whoever holds it. A token that is nothing is refused, whatever cookie travels with it. What a token does is attributed to its person, and the event names the agent: the token's name, or what the agent called itself on its run.
|
|
14
14
|
- A token configures as its person does ([ADR-0021](../adr/0021-a-token-configures-as-its-person-does.md)): every request a session may make, a token may make, within the same roles, except the tokens themselves and the approval of a connection, which stay a person's own doing, signed in on the console's own pages; the one thing a token does about the tokens is give itself up (`DELETE /api/v1/me/token`).
|
|
15
15
|
- An agent connects without anyone copying a token ([ADR-0011](../adr/0011-an-agent-connects-with-a-short-code-a-person-approves-and-the-token-is-never-shown.md)): [`POST /api/v1/connect`](#connecting-an-agent) is nobody's, the approval is a person's own doing on the console's own pages, and the claim is the command's, with the secret it was given.
|
|
16
|
-
- The command names its version on every request, as the product token of its `user-agent` (`skillcdn-console/0.1.18 (cli; node 24.11.0; linux)`), and every answer under `/api` says the console's version (`console-version`) and the range of command versions it takes (`console-client-range`, as npm spells one: `>=0.1.18 <0.2.0`) ([ADR-0025](../adr/0025-the-command-names-its-version-on-every-request-and-the-console-holds-it-to-the-range-it-takes.md)). Before 1.0 the range is the console's
|
|
16
|
+
- The command names its version on every request, as the product token of its `user-agent` (`skillcdn-console/0.1.18 (cli; node 24.11.0; linux)`), and every answer under `/api` says the console's version (`console-version`) and the range of command versions it takes (`console-client-range`, as npm spells one: `>=0.1.18 <0.2.0`) ([ADR-0025](../adr/0025-the-command-names-its-version-on-every-request-and-the-console-holds-it-to-the-range-it-takes.md)). Before 1.0 the range is the console's line, every patch of its major.minor, from the floor the console names where a release raised one: the oldest command whose requests and answers still fit it, raised only by a release that changed what passes between them ([ADR-0038](../adr/0038-the-command-and-the-console-go-together-within-a-line-and-a-release-that-changes-what-passes-between-them-raises-the-floors.md)); from 1.0, the console's major and a minor within one, either way. A command outside the range is refused with `426` before anything else is asked of its request, `client.outdated` or `client.too_new`, the message naming both versions and the range. The command holds the console to a floor of its own the same way, and refuses a console below it itself, as `console.outdated`, in this same form. A request that names no command, a browser's, a script's, is held to nothing.
|
|
17
17
|
- Request bodies are JSON, at most 256 KiB, and parsed once with the package's input schema. Text is trimmed where it is a line, bounded everywhere (`MAX_TITLE_LENGTH` and the rest of `@skillcdn/console/api`), and refused when it carries control or invisible characters. Links are `https` URLs only.
|
|
18
18
|
- Errors have `{ "error": { "code": "...", "message": "..." } }`. The code is stable; the message is for a person, in English.
|
|
19
19
|
|
|
@@ -28,7 +28,7 @@ The API is the board as its members see it: the people, the projects, and in eac
|
|
|
28
28
|
| 404 | `project.no_icon` | The project has no image for its mark. |
|
|
29
29
|
| 400 | `member.invalid_person` | The person to list is not one of the workspace, or is deactivated. |
|
|
30
30
|
| 400 | `listing.unknown_host` | The login to let in names a provider nobody signs in through here. |
|
|
31
|
-
| 400 | `task.
|
|
31
|
+
| 400 | `task.invalid_worker` | A person named as a worker is not one who may work in the project. |
|
|
32
32
|
| 400 | `task.invalid_parent` | The parent is not a task of the project, is the task itself, or would make a loop. |
|
|
33
33
|
| 400 | `task.invalid_category` | No category of the workspace has that key. |
|
|
34
34
|
| 400 | `task.invalid_goal` | The goal is not one of the project's. |
|
|
@@ -38,6 +38,7 @@ The API is the board as its members see it: the people, the projects, and in eac
|
|
|
38
38
|
| 400 | `decision.invalid_task` | The decision is about a task that is not one of the project's. |
|
|
39
39
|
| 400 | `decision.no_such_option` | The answer names an option the decision does not have. |
|
|
40
40
|
| 400 | `decision.invalid_run` | A decision raised from a run that is not the asker's, or is over. |
|
|
41
|
+
| 400 | `decision.invalid_decider` | The person named to decide may not work in the project ([ADR-0042](../adr/0042-a-decision-is-addressed-to-a-person-its-raiser-unless-another-is-named.md)). |
|
|
41
42
|
| 400 | `token.expiry_at_most` | A token that would not expire, or would outlast `TOKEN_DAYS_AT_MOST`, where the organization requires an expiry. |
|
|
42
43
|
| 400 | `document.invalid_path` | The path a page is written at is not one: segments of lowercase letters, digits and hyphens, separated by slashes. |
|
|
43
44
|
| 400 | `run.too_many_reports`, `run.too_many_artifacts` | The run carries as many as one may (`MAX_REPORTS_PER_RUN`, `MAX_ARTIFACTS_PER_RUN`). |
|
|
@@ -77,18 +78,18 @@ The API is the board as its members see it: the people, the projects, and in eac
|
|
|
77
78
|
| 409 | `listing.exists` | The login is let in already, or is one an active person signs in as. |
|
|
78
79
|
| 409 | `run.over`, `run.task_closed` | The run has ended already; the task is done or dropped. A run open on a task is no refusal: a new run takes it over ([ADR-0020](../adr/0020-the-console-does-not-claim-an-agent-is-at-work-a-run-says-when-it-was-last-heard-from-and-a-new-run-takes-over.md)). |
|
|
79
80
|
| 413 | `request.too_large` | The body is over the limit; for a file handed in or attached, the file is over `MAX_FILE_BYTES`. |
|
|
80
|
-
| 426 | `client.outdated`, `client.too_new` | The command named a version outside the range the console takes ([ADR-0025](../adr/0025-the-command-names-its-version-on-every-request-and-the-console-holds-it-to-the-range-it-takes.md)):
|
|
81
|
+
| 426 | `client.outdated`, `client.too_new` | The command named a version outside the range the console takes ([ADR-0025](../adr/0025-the-command-names-its-version-on-every-request-and-the-console-holds-it-to-the-range-it-takes.md), [ADR-0038](../adr/0038-the-command-and-the-console-go-together-within-a-line-and-a-release-that-changes-what-passes-between-them-raises-the-floors.md)): below the floor the console names, of an older line, or of a line it does not take yet. The message names both versions and the range; `console-version` and `console-client-range` say them too. `console.outdated` is the command's own refusal of a console older than it works with, in this form. |
|
|
81
82
|
| 503 | `file.store_unavailable` | The bytes of files are kept in a bucket, and it did not answer or refused the console; `retry-after` says when to try again. Nothing was written on the run or the page. |
|
|
82
83
|
|
|
83
84
|
## The workspace
|
|
84
85
|
|
|
85
86
|
### `GET /api/v1/me`
|
|
86
87
|
|
|
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
|
|
88
|
+
`{ "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 and this week is counted by (`weekStart`: `auto`, as the language of the pages has it, or `monday`, `sunday`; [ADR-0039](../adr/0039-this-week-is-the-plans-unit-and-the-week-begins-as-the-workspace-says.md)) and the workspace's time zone (`timeZone`: an IANA name, in which the command prints moments, or `null` for none; both optional the same way), who the session cookie or the token says is asking (`id`, `login`, `name` or `null`, `avatar` or `null`, `role`), with what (`agent`: the name of the token when a token asks, as its person called it, so that a console of a person's own knows it holds one and offers nothing a token cannot do; `null` on a session), the language the person chose for the pages (`language`, a tag, or `null` for the browser's), and the identity providers people sign in through (`gh`, `google`, each with the label of its button), 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.
|
|
88
89
|
|
|
89
90
|
### `GET /api/v1/people?login=`
|
|
90
91
|
|
|
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
|
|
92
|
+
`{ "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 workers and of members is made of, the active people. A token reads it as its person does: what the command's `--worker`, `member` and `person` take a login from, through `login`.
|
|
92
93
|
|
|
93
94
|
### `PATCH /api/v1/people/<id>`
|
|
94
95
|
|
|
@@ -140,7 +141,11 @@ The rules of the board ([ADR-0023](../adr/0023-the-rules-of-a-board-are-pages-th
|
|
|
140
141
|
|
|
141
142
|
### `GET /api/v1/work`
|
|
142
143
|
|
|
143
|
-
`{ "tasks": [{ "project": { "key", "name", "color", "symbol", "icon" }, "task" }, ...], "closed": [{ "project", "task" }, ...], "decisions": [{ "project", "decision" }, ...] }`: what is on the asker's plate across the projects they may see ([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)): the open tasks
|
|
144
|
+
`{ "tasks": [{ "project": { "key", "name", "color", "symbol", "icon" }, "task" }, ...], "closed": [{ "project", "task" }, ...], "decisions": [{ "project", "decision" }, ...] }`: what is on the asker's plate across the projects they may see ([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)): the open tasks they are at work on, the sooner due first and those with no day last; `closed`, the tasks they are at work on that are done or dropped and not yet put away, the last closed first, so that the week on the plate's page shows them on their days as a project's calendar does; and the decisions that wait for the asker's answer ([ADR-0042](../adr/0042-a-decision-is-addressed-to-a-person-its-raiser-unless-another-is-named.md)), the longest waiting first; each with the project it belongs to, so that a page says and links it. A task put away is in neither list ([ADR-0030](../adr/0030-a-task-is-put-away-from-any-state.md)). At most `LIST_LIMIT` of each.
|
|
145
|
+
|
|
146
|
+
### `GET /api/v1/decisions?open=&raised=&limit=&offset=`
|
|
147
|
+
|
|
148
|
+
`{ "items": [{ "project": { "key", "name", "color", "symbol", "icon" }, "decision" }, ...], "more": boolean }`: the decisions addressed to the asker ([ADR-0042](../adr/0042-a-decision-is-addressed-to-a-person-its-raiser-unless-another-is-named.md)) across the projects they may see, a page at a time as the tasks are (`limit`, `offset`, `more`): the ones that wait first, the longest waiting first among them, then the answered, newest first, as the record; `open=true` keeps only those that wait, and `raised=true` answers instead the decisions the asker raised, through their agent or themselves, for someone else. Each decision comes with the project it belongs to, as the plate's things do, so that a page says and links it. What a person's own page of decisions reads, in both kinds, and `console decisions --mine` and `--raised`.
|
|
144
149
|
|
|
145
150
|
### `GET /api/v1/tokens` and `POST /api/v1/tokens`
|
|
146
151
|
|
|
@@ -160,7 +165,7 @@ An administrator's sight of everyone's agents ([ADR-0011](../adr/0011-an-agent-c
|
|
|
160
165
|
|
|
161
166
|
### `GET /api/v1/people/<id>/work`
|
|
162
167
|
|
|
163
|
-
`{ "tasks": [{ "project", "task" }, ...], "closed": [{ "project", "task" }, ...] }`: what is on another person's plate, for whoever oversees them: an administrator, or an owner of a project the person is in (everyone of the workspace is in a project open to it; a private one holds those listed), signed in or through their agent. The person
|
|
168
|
+
`{ "tasks": [{ "project", "task" }, ...], "closed": [{ "project", "task" }, ...] }`: what is on another person's plate, for whoever oversees them: an administrator, or an owner of a project the person is in (everyone of the workspace is in a project open to it; a private one holds those listed), signed in or through their agent. The open tasks the person is at work on, the sooner due first and those with no day last, and as `closed` those of them done or dropped and not yet put away, both within the projects the asker may see and no other, each with its project; the decisions are left out, since they wait for anyone. `auth.forbidden` for anyone else; `person.not_found` for an id that is nobody's.
|
|
164
169
|
|
|
165
170
|
### Connecting an agent
|
|
166
171
|
|
|
@@ -192,17 +197,17 @@ The project's own image for its mark, in place of the symbol on the colour. `POS
|
|
|
192
197
|
|
|
193
198
|
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.
|
|
194
199
|
|
|
195
|
-
### `GET /api/v1/projects/<key>/tasks?state=&open=&archived=&category=&goal=&
|
|
200
|
+
### `GET /api/v1/projects/<key>/tasks?state=&open=&archived=&category=&goal=&worker=&unassigned=&dueBy=&q=&limit=&offset=`
|
|
196
201
|
|
|
197
|
-
`{ "items": [task, ...], "more": boolean }`: the project's board, newest first, a page at a time: `limit` (1 to `LIST_LIMIT`, the default) and `offset` (from 0) say which page, and `more` whether there is one after it; a `limit` or an `offset` that is not a number in range is `request.invalid`. `state` keeps one state of it; `open=true` the tasks not done or dropped, `open=false` the rest; `category=<key>` those sorted into a category; `goal=<id>` those that work towards a goal; `
|
|
202
|
+
`{ "items": [task, ...], "more": boolean }`: the project's board, newest first, a page at a time: `limit` (1 to `LIST_LIMIT`, the default) and `offset` (from 0) say which page, and `more` whether there is one after it; a `limit` or an `offset` that is not a number in range is `request.invalid`. `state` keeps one state of it; `open=true` the tasks not done or dropped, `open=false` the rest; `category=<key>` those sorted into a category; `goal=<id>` those that work towards a goal; `worker=<person id>` those one person is at work on, `unassigned=true` those nobody is at work on (with `worker`, nothing); `dueBy=<day>` (`2026-10-24`) those due on that day or before it; `q=<words>` (1 to `MAX_SEARCH_LENGTH` characters) those whose title holds every word, whatever the case and in any order, and the task of that number for a number (`12`, `#12`), which is how a picker or a command finds a task by its title ([ADR-0037](../adr/0037-a-task-has-one-owner-and-any-number-of-workers-and-a-parent-or-a-goal-is-found-by-search.md)). The tasks put away ([ADR-0029](../adr/0029-a-task-done-or-dropped-is-put-away-out-of-the-board-and-open-by-its-number.md)) are left out; `archived=true` answers them alone, newest first: the archive and the board are two listings, never one. A task carries its `number` (the one people say out loud, numbered per project), `title`, `body` (Markdown, to be shown as text or rendered to elements, never as HTML), `state`, `priority`, `owner` (one person, whoever wrote it), `workers` (the people at work on it, in the order they came to it, `[]` while nobody is; [ADR-0037](../adr/0037-a-task-has-one-owner-and-any-number-of-workers-and-a-parent-or-a-goal-is-found-by-search.md)), `parentId`, `category` (its `key`, `name` and `color` as the workspace keeps it, or `null`), `goalId` (or `null`), its plan ([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)): `startsOn` and `dueOn`, each a day (`2026-10-24`) or `null`; its moments, which the board keeps itself: `startedAt`, when it was first moved past `ready`, and `doneAt`, when it was moved to `done`, each an instant or `null`; `archivedAt`, when it was put away, an instant or `null` while it is current; `links` (`url` and `label`), `openDecisions` (how many decisions about it wait for a person), `openRuns` (how many runs on it are open: begun and not ended, which says nothing of whether an agent is still at it, [ADR-0020](../adr/0020-the-console-does-not-claim-an-agent-is-at-work-a-run-says-when-it-was-last-heard-from-and-a-new-run-takes-over.md)), `createdAt` and `updatedAt`.
|
|
198
203
|
|
|
199
204
|
### `POST /api/v1/projects/<key>/tasks`
|
|
200
205
|
|
|
201
|
-
Takes `title`, and optionally `body`, `state` (default `idea`), `priority` (default `normal`), `
|
|
206
|
+
Takes `title`, and optionally `body`, `state` (default `idea`), `priority` (default `normal`), `workerIds` (the people to be at work on it, each one who may work in the project: everyone of the workspace for a project open to it, those listed for a private one, an administrator anywhere; each once however often named, up to `MAX_WORKERS`; `task.invalid_worker`), `parentId` (a task of the project), `category` (the key of a category of the workspace, or `null`; `task.invalid_category`), `goalId` (a goal of the project, or `null`; `task.invalid_goal`), `startsOn` and `dueOn` (days; the due day not before the start, `task.invalid_dates`) and `links`. The owner is whoever writes it. Answers `201` with the task, numbered after the project's last, and writes a `task.created` event. A task written past `ready` has its `startedAt`; one written `done` has its `doneAt` too.
|
|
202
207
|
|
|
203
208
|
### `GET /api/v1/projects/<key>/tasks/<id or number>` and `PATCH .../tasks/<id>`
|
|
204
209
|
|
|
205
|
-
One task, by its id or by its number in the project (`/tasks/7`): the pages hold ids, people and their agents say numbers. A patch takes the id and names only what changes, with the same fields as a creation; a field set to `null` clears it. A change of `state` is a `task.moved` event with `from` and `to`; any other change is one `task.updated` event naming the `fields` (`category`, `goalId`, `startsOn` and `dueOn` among them, as the input names them). A patch that changes nothing writes nothing and answers the task as it is. The moments follow the moves: the first move past `ready` sets `startedAt`, a move to `done` sets `doneAt`, and a move back out of `done` clears it.
|
|
210
|
+
One task, by its id or by its number in the project (`/tasks/7`): the pages hold ids, people and their agents say numbers. A patch takes the id and names only what changes, with the same fields as a creation; a field set to `null` clears it, and `workerIds` names the workers whole, in place of those there were, only the newcomers being checked, `[]` leaving nobody on it. A change of `state` is a `task.moved` event with `from` and `to`; any other change is one `task.updated` event naming the `fields` (`workers`, `category`, `goalId`, `startsOn` and `dueOn` among them, as the input names them). A patch that changes nothing writes nothing and answers the task as it is. The moments follow the moves: the first move past `ready` sets `startedAt`, a move to `done` sets `doneAt`, and a move back out of `done` clears it.
|
|
206
211
|
|
|
207
212
|
### `POST .../tasks/<id>/archive`, `POST .../tasks/<id>/restore` and `POST /api/v1/projects/<key>/tasks/archive`
|
|
208
213
|
|
|
@@ -216,11 +221,11 @@ Writing one, for whoever may work in the project, with a session or a token, is
|
|
|
216
221
|
|
|
217
222
|
### `GET /api/v1/projects/<key>/decisions?open=&task=&limit=&offset=`
|
|
218
223
|
|
|
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.
|
|
224
|
+
`{ "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`, `decider` (whom it is for, [ADR-0042](../adr/0042-a-decision-is-addressed-to-a-person-its-raiser-unless-another-is-named.md): the raiser, unless another person of the project was named), `run` (the `id` and `agent` of the run that raised it, when an agent asked, or `null`), `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.
|
|
220
225
|
|
|
221
226
|
### `POST /api/v1/projects/<key>/decisions`
|
|
222
227
|
|
|
223
|
-
Takes `question`, `options` (two to `MAX_OPTIONS` labels), and optionally `body`, and either `taskId` or `runId`. Options are numbered from `1`. From a run, which must be the asker's and open (`decision.invalid_run`), the decision is about the run's task, `taskId` is not looked at, and the run waits (`status: waiting`) until the answer. Answers `201` with the decision and writes a `decision.raised` event, with the `agent` when a run asked.
|
|
228
|
+
Takes `question`, `options` (two to `MAX_OPTIONS` labels), and optionally `body`, and either `taskId` or `runId`. `deciderId` names whom the decision is for ([ADR-0042](../adr/0042-a-decision-is-addressed-to-a-person-its-raiser-unless-another-is-named.md)): a person who may work in the project, as a worker of a task must (`decision.invalid_decider` otherwise); left out, the asker, which from a run is the person the agent works for. Anyone of the project may still answer. Options are numbered from `1`. From a run, which must be the asker's and open (`decision.invalid_run`), the decision is about the run's task, `taskId` is not looked at, and the run waits (`status: waiting`) until the answer. Answers `201` with the decision and writes a `decision.raised` event, with the `agent` when a run asked.
|
|
224
229
|
|
|
225
230
|
### `GET .../decisions/<id>?wait=` and `POST .../decisions/<id>/answer`
|
|
226
231
|
|
|
@@ -232,9 +237,9 @@ The answer takes `option` (the id of one of its options) or `own` (the person's
|
|
|
232
237
|
|
|
233
238
|
Grows the record: takes any of `body` (the context) and `outcome` (what followed; empty clears it), for anyone who may work in the project, with a session from the console's own pages or a token, answered or not. Writes a `decision.updated` event naming the `fields`; a patch that changes nothing writes nothing.
|
|
234
239
|
|
|
235
|
-
### `GET /api/v1/projects/<key>/goals
|
|
240
|
+
### `GET /api/v1/projects/<key>/goals?state=&open=&category=&q=&limit=&offset=` and `POST /api/v1/projects/<key>/goals`
|
|
236
241
|
|
|
237
|
-
The roadmap ([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), [ADR-0026](../adr/0026-a-goal-is-planned-in-days-and-sorted-into-a-category-and-the-roadmap-is-read-as-months.md)). `GET`, for whoever may see the project, answers `{ "items": [goal, ...] }`: the active goals first, then the planned, the reached and the dropped, the sooner due first within each and the older first among those with no day;
|
|
242
|
+
The roadmap ([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), [ADR-0026](../adr/0026-a-goal-is-planned-in-days-and-sorted-into-a-category-and-the-roadmap-is-read-as-months.md)). `GET`, for whoever may see the project, answers `{ "items": [goal, ...], "more": boolean }`: a page of the roadmap, the active goals first, then the planned, the reached and the dropped, the sooner due first within each and the older first among those with no day; `limit` (1 to `LIST_LIMIT`, the default) and `offset` say which page and `more` whether there is one after it; `?category=<key>` keeps those sorted into a category, `?state=<state>` those in one state, `?open=true` the planned and the active and `?open=false` the reached and the dropped, and `?q=<words>` those whose title holds every word, whatever the case, which is how a picker or a command finds a goal ([ADR-0037](../adr/0037-a-task-has-one-owner-and-any-number-of-workers-and-a-parent-or-a-goal-is-found-by-search.md)). A goal carries its `title`, `body` (Markdown: what reaching it means), `state` (`planned`, `active`, `done`, `dropped`), `category` (its `key`, `name` and `color` as the workspace keeps it, or `null`), its plan, `startsOn` (the day the work towards it is meant to begin, or `null`) and `dueOn` (the day it is meant to be reached by, or `null`), `createdBy`, `taskCounts` (the tasks that work towards it, counted by state: `idea`, `ready`, `in_progress`, `in_review`, `done`, `dropped`; read from the board as it stands, never written down), `createdAt` and `updatedAt`. `POST`, for an owner of the project, from the console's own pages or with a token, takes `title` and optionally `body`, `state` (default `planned`), `category` (the key of a category of the workspace, or `null`; `goal.invalid_category`), `startsOn` and `dueOn` (days; the target not before the start, `goal.invalid_dates`), answers `201` with the goal and writes a `goal.created` event with its `title`; a member is `auth.forbidden`.
|
|
238
243
|
|
|
239
244
|
### `GET .../goals/<id>` and `PATCH .../goals/<id>`
|
|
240
245
|
|
|
@@ -242,7 +247,7 @@ One goal, for whoever may see the project. The patch, for an owner, takes any of
|
|
|
242
247
|
|
|
243
248
|
### `GET /api/v1/projects/<key>/runs?task=&open=&mine=&limit=&offset=` and `GET .../runs/<id>`
|
|
244
249
|
|
|
245
|
-
`{ "items": [run, ...], "more": boolean }`: the project's runs, newest first, a page at a time as the tasks are (`limit`, `offset`, `more`); `task=<id>` keeps those on one task, `open=true` those not over (`running` or `waiting`) and `open=false` those over, `mine=true` the asker's own: with a token, the runs begun with that token, which is one agent's; on a session, the runs for the person. A run is one agent's work on one task for one person: `taskId` and `taskNumber` (the one people say), `person` (whom the agent acts for), `agent` (what it calls itself), `status` (`running`, that is open, `waiting` for a decision, `finished`, `failed`, `abandoned`), `startedAt`, `endedAt` or `null`, `lastHeardAt` (when the agent was last heard from through the run: its start, then its latest report, hand-in or question; the console knows nothing of an agent but what it sends, and claims nothing more, [ADR-0020](../adr/0020-the-console-does-not-claim-an-agent-is-at-work-a-run-says-when-it-was-last-heard-from-and-a-new-run-takes-over.md)), `summary` (Markdown, what the agent said at the end, or `null`), `reports` (each `id`, `body` in Markdown, `createdAt`; oldest first), `artifacts` (each `id`, `kind`, `url` for a link or `null`, `label` or `null`, `file` for a file or `null`, and `createdAt`; a file is its `name`, `size` in bytes, `contentType` and `sha256`), and `waitingFor`, the id of the decision the run waits for, or `null`.
|
|
250
|
+
`{ "items": [run, ...], "more": boolean }`: the project's runs, newest first, a page at a time as the tasks are (`limit`, `offset`, `more`); `task=<id>` keeps those on one task, `open=true` those not over (`running` or `waiting`) and `open=false` those over, `mine=true` the asker's own: with a token, the runs begun with that token, which is one agent's; on a session, the runs for the person. A run is one agent's work on one task for one person: `taskId` and `taskNumber` (the one people say), `person` (whom the agent acts for), `agent` (what it calls itself), `status` (`running`, that is open, `waiting` for a decision, `finished`, `failed`, `abandoned`), `startedAt`, `endedAt` or `null`, `lastHeardAt` (when the agent was last heard from through the run: its start, then its latest report, hand-in or question; the console knows nothing of an agent but what it sends, and claims nothing more, [ADR-0020](../adr/0020-the-console-does-not-claim-an-agent-is-at-work-a-run-says-when-it-was-last-heard-from-and-a-new-run-takes-over.md); a run `running` and not heard from for twelve hours, or the hours the deployment sets, is ended by the console as `abandoned`, its `summary` saying so and `run.ended` naming no actor and `reason: "unheard"`, while a run `waiting` for an answer waits on, [ADR-0041](../adr/0041-a-run-not-heard-from-for-twelve-hours-is-ended-by-the-console.md)), `summary` (Markdown, what the agent said at the end, or `null`), `reports` (each `id`, `body` in Markdown, `createdAt`; oldest first), `artifacts` (each `id`, `kind`, `url` for a link or `null`, `label` or `null`, `file` for a file or `null`, and `createdAt`; a file is its `name`, `size` in bytes, `contentType` and `sha256`), and `waitingFor`, the id of the decision the run waits for, or `null`.
|
|
246
251
|
|
|
247
252
|
### `POST /api/v1/projects/<key>/runs`
|
|
248
253
|
|
|
@@ -260,7 +265,7 @@ The bytes of any file of the project, handed in by a run, put in a comment or at
|
|
|
260
265
|
|
|
261
266
|
### `POST .../runs/<id>/end`
|
|
262
267
|
|
|
263
|
-
Takes `status` (`finished`, `failed` or `abandoned`) and optionally a `summary` (Markdown, `MAX_SUMMARY_LENGTH`: what was done and what is left), ends the run (`run.ended`), and answers it. A finished run puts a task that was `in_progress` up for review (`in_review`); the rest leave the task as it is. The run's person ends it, as `finished` or `failed` from their agent; `abandoned` is a person giving up on a run that will not come back: their own, or anyone's as an owner of the project, signed in or through their agent (`run.not_yours` otherwise). A run that is over is `run.over`.
|
|
268
|
+
Takes `status` (`finished`, `failed` or `abandoned`) and optionally a `summary` (Markdown, `MAX_SUMMARY_LENGTH`: what was done and what is left), ends the run (`run.ended`), and answers it. A finished run puts a task that was `in_progress` up for review (`in_review`); the rest leave the task as it is. The run's person ends it, as `finished` or `failed` from their agent; `abandoned` is a person giving up on a run that will not come back: their own, or anyone's as an owner of the project, signed in or through their agent (`run.not_yours` otherwise); the console gives up on a run itself when it has not heard from it for twelve hours ([ADR-0041](../adr/0041-a-run-not-heard-from-for-twelve-hours-is-ended-by-the-console.md)). A run that is over is `run.over`.
|
|
264
269
|
|
|
265
270
|
### `GET /api/v1/projects/<key>/skills`
|
|
266
271
|
|
|
@@ -268,7 +273,7 @@ The project's pack, read by address ([ADR-0028](../adr/0028-the-console-reads-a-
|
|
|
268
273
|
|
|
269
274
|
### `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=`
|
|
270
275
|
|
|
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.
|
|
276
|
+
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); given a file's path, the file's `outline`, every heading with its level and the `offset` and `length` that read its section through `skills/file`, paged the same way, with `entries` empty (SkillCDN 0.4). `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); a document among the results names the `sections` of it that matched, each with its heading path, the `offset` and `limit` that read it and an excerpt, and `ranking` says how the page was ranked where the deployment searches by meaning as well as by words. `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.
|
|
272
277
|
|
|
273
278
|
### `PUT /api/v1/projects/<key>/pack-token` and `DELETE .../pack-token`
|
|
274
279
|
|
|
@@ -276,7 +281,7 @@ The pack token ([ADR-0028](../adr/0028-the-console-reads-a-projects-pack-through
|
|
|
276
281
|
|
|
277
282
|
### `POST /api/v1/projects/<key>/pack-token/connect`, `GET .../pack-token/connect` and `DELETE .../pack-token/connect`
|
|
278
283
|
|
|
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
|
|
284
|
+
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 by the workspace's name with Console after it, once (`Acme Console`, whether the name ends with it or not), 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
285
|
|
|
281
286
|
### `GET /api/v1/projects/<key>/rules`
|
|
282
287
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skillcdn/console",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
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,7 +68,7 @@
|
|
|
68
68
|
"vitest": "^5.0.3"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"@skillcdn/core": "^0.
|
|
71
|
+
"@skillcdn/core": "^0.4.0",
|
|
72
72
|
"react-markdown": "^10.1.0",
|
|
73
73
|
"remark-gfm": "^4.0.1",
|
|
74
74
|
"zod": "^4.6.5"
|
|
@@ -5,7 +5,7 @@ license: MIT
|
|
|
5
5
|
compatibility: A shell with Node.js 24 or newer and npm or pnpm, and an agent that reads and writes files. For looking at the pages against a board, the console command signed in by a person. A browser the agent can drive is optional. No key of the agent's own is needed, and it never sees a token.
|
|
6
6
|
metadata:
|
|
7
7
|
author: skillcdn
|
|
8
|
-
version: "1.
|
|
8
|
+
version: "1.7"
|
|
9
9
|
skillcdn:
|
|
10
10
|
translations:
|
|
11
11
|
ko:
|
|
@@ -50,10 +50,10 @@ 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 | 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
|
|
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
|
|
53
|
+
| The marks | From the organization's website when the request, or deploying-a-console, names one: its symbol and wordmark read from the site as [the-look-from-a-website.md](references/the-look-from-a-website.md) says, the dark version or, with the person's word, the one-colour mark recoloured, shown at the plan. Else asked for a console that shows marks of its own, for the half the request leaves open: "Which picture should the pages show beside the board's name: a small square mark, the name as lettering, or both? Where is the file? The pages are light, so it should be a dark one." `brand` takes either or both. The symbol's slot is a square of one line's height (`.sc-brand-symbol`, 1rem): a wide mark, a lettermark of three or four times its height, is a wordmark and goes in as one, alone or beside a square symbol. A mark drawn in a light colour vanishes on the light pages: ask for a dark version, or, with the person's word, recolour it when it is one colour. Default without a site: the board's name alone and no marks, which is the honest console. |
|
|
54
|
+
| The colour | From the website's own colours when one is named, as the reference says, its primary colour read from the theme colour, the stylesheet's properties or the primary button. Else asked when the request names none and marks are wanted: "Which colour, or which mood?" A colour comes as words or a value; the value is the mark's own fill when it has one, else chosen and shown. A dark or saturated colour becomes the accent (`--sc-color-accent` and its family); a pale one tints the field (`--sc-field-gradient`), with a darker shade of it as the accent, since an accent must read on the light field. The mapping is shown at the plan, with the contrast checked. |
|
|
55
55
|
| The languages | Asked when the organization's language is not among the packs: "Which languages should the pages speak?" Default: the packs the package ships, chosen by the browser; a Korean organization gets Pretendard loaded, as the default console does. |
|
|
56
|
-
| The name | Not asked: the server names the board (`WORKSPACE_NAME`), and `title` is only what the page says until the server answers. `index.html` gets the organization's `<title>` and `lang`. |
|
|
56
|
+
| The name | Not asked: the server names the board (`WORKSPACE_NAME`, conventionally the organization or the person it is for, then Console: `Acme Console`), and `title` is only what the page says until the server answers. `index.html` gets the organization's `<title>` and `lang`. |
|
|
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. |
|
|
58
58
|
|
|
59
59
|
## Workflow
|
|
@@ -10,7 +10,7 @@ The four files of the default UI, `apps/console/web/` in the console's repositor
|
|
|
10
10
|
<head>
|
|
11
11
|
<meta charset="utf-8" />
|
|
12
12
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
13
|
-
<meta name="color-scheme" content="
|
|
13
|
+
<meta name="color-scheme" content="light" />
|
|
14
14
|
<title>Console</title>
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
@@ -24,9 +24,9 @@ The four files of the default UI, `apps/console/web/` in the console's repositor
|
|
|
24
24
|
|
|
25
25
|
```tsx
|
|
26
26
|
// The marks of the brand come from the main repository's package, never from a copy here
|
|
27
|
-
// (ADR-0013); the build gives back their addresses. The pages are
|
|
27
|
+
// (ADR-0013); the build gives back their addresses. The pages are light, so the wordmark is black.
|
|
28
28
|
import symbol from "@skillcdn/brand/symbol.svg";
|
|
29
|
-
import wordmark from "@skillcdn/brand/wordmark-
|
|
29
|
+
import wordmark from "@skillcdn/brand/wordmark-black.svg";
|
|
30
30
|
import { createConsole } from "@skillcdn/console";
|
|
31
31
|
// The styles ship with the package; the build bundles them next to the script.
|
|
32
32
|
import "@skillcdn/console/console.css";
|
|
@@ -137,4 +137,4 @@ export default defineConfig({
|
|
|
137
137
|
}
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
-
What a console of one's own changes. In the page: its `<title>` and `lang`, and its icons, linked directly in the page or through the plugin, for its own. In the script: the `title` it passes; the two `@skillcdn/brand` imports, for its own symbol and wordmark (a
|
|
140
|
+
What a console of one's own changes. In the page: its `<title>` and `lang`, and its icons, linked directly in the page or through the plugin, for its own. In the script: the `title` it passes; the two `@skillcdn/brand` imports, for its own symbol and wordmark (a dark one, since the pages are light), or none; the face it loads, for its languages (`npm install pretendard` for Korean). In the build: the proxy's target, `http://127.0.0.1:11197` with `changeOrigin: true` for `console serve`; the default console's own proxy points at the `api` role's development port, which a console of one's own does not have, and its plugin reads the icons from the brand package, which a console of one's own replaces with files of its own. In the compiler's settings: `jsx`, `moduleResolution` and the `vite/client` types stay, which make an imported picture a module; `extends` and `references` are the repository's and go, with `"strict": true` of the console's own in their place. One thing to add in the build: `build: { assetsInlineLimit: 0 }`, so that every picture and font stays a file; Vite inlines an asset under 4 KB as a `data:` address, which the policy allows for a picture and refuses for a font (`font-src 'self'`), and the default console gets by only because none of its assets is that small.
|
|
@@ -12,17 +12,17 @@ Fetch the homepage as HTML, with the agent's own tools, and read, in this order:
|
|
|
12
12
|
| The wordmark | The same header: the name as lettering, wide, often an SVG beside or instead of the symbol | `brand.wordmark`, alone or beside the symbol. A mark three or four times wider than high is a wordmark, not a symbol. |
|
|
13
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
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
|
|
15
|
+
| The mood | The site itself: dark or light, flat or glassy, round or square corners | Whether the field stays light (the pages are light by default, ADR-0040; a dark site is said at the plan, and darkening the pages is the person's word, not the default), and whether the radii follow the site (`--sc-radius-*`). |
|
|
16
16
|
|
|
17
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
18
|
|
|
19
19
|
## Mapping onto the pages
|
|
20
20
|
|
|
21
|
-
The pages are
|
|
21
|
+
The pages are light: a pale field, and panes of frosted glass over it. The mapping is shown at the plan as a table, value by value, before a file is written.
|
|
22
22
|
|
|
23
|
-
- **A mark drawn in a
|
|
24
|
-
- **A
|
|
25
|
-
- **A
|
|
23
|
+
- **A mark drawn in a light colour vanishes** on the light pages. Take the site's dark or black variant first (its header on a light page, a light-mode asset, a `prefers-color-scheme` rule). Found none, and the mark is one colour: recolour it to the pages' text colour, with the person's word, since the mark is theirs. A mark of several colours on a light fill: keep its fill as a rounded square behind it.
|
|
24
|
+
- **A dark or saturated primary colour** becomes the accent: `--sc-color-accent` and its family (`-solid`, `-contrast`, `-subtle`, the point), as the package's README lists them.
|
|
25
|
+
- **A pale primary colour** tints the field: `--sc-field-gradient`, with a darker shade of it as the accent, since an accent must read on the light field.
|
|
26
26
|
- **Contrast is checked**, not assumed: the accent on the field, and text on the panes, at the 4.5:1 of WCAG AA for text; a shade is moved until it passes, and the plan says which.
|
|
27
27
|
- **The type follows the rules of the skill**: scripts, styles and fonts are bundled, never loaded from a CDN or written inline. A face the organization owns, or one under a license that allows bundling, is put in the repository and named in `--sc-font-sans`; otherwise the system faces stay, and the plan says that the site's face was not taken and why. Pretendard stays for Korean, as the default console has it.
|
|
28
28
|
- **The name** stays the server's (`WORKSPACE_NAME`): the look is the marks, the colours and the type, never the words.
|
|
@@ -5,7 +5,7 @@ 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.
|
|
8
|
+
version: "1.4"
|
|
9
9
|
skillcdn:
|
|
10
10
|
translations:
|
|
11
11
|
ko:
|
|
@@ -43,7 +43,7 @@ Check these before the first message. Without the AWS CLI, offer to install it (
|
|
|
43
43
|
| Input | Source |
|
|
44
44
|
|---|---|
|
|
45
45
|
| How many people | Asked: "How many people will use the console within a year: just you, up to 10, up to 30, or up to 100?" The answer picks the size ([sizing.md](references/sizing.md)). |
|
|
46
|
-
| The board's name |
|
|
46
|
+
| The board's name | Suggested from the convention and confirmed, never invented: the organization or the person the console is for, then Console, as `SkillCDN Console` is named. With the organization's name in the request or on its website: "The board will be called `Acme Console`, as consoles are named: the organization's name, then Console. Keep it, or say another?" Without one: "Whose console is this, your organization's or yours? Its name, then Console, is what the board is called." It goes to `WORKSPACE_NAME`, one line of up to 100 characters: what the pages say after the SkillCDN mark, and what the console calls itself at SkillCDN when it connects a pack. |
|
|
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
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. |
|
|
@@ -251,7 +251,7 @@ The task definition of the `api` role with the tunnel's connector beside it, in
|
|
|
251
251
|
"portMappings": [{ "containerPort": 11199, "protocol": "tcp" }],
|
|
252
252
|
"environment": [
|
|
253
253
|
{ "name": "PUBLIC_URL", "value": "https://<hostname>" },
|
|
254
|
-
{ "name": "WORKSPACE_NAME", "value": "<the board's name>" },
|
|
254
|
+
{ "name": "WORKSPACE_NAME", "value": "<the board's name, such as Acme Console>" },
|
|
255
255
|
{ "name": "WORKER_IN_PROCESS", "value": "true" },
|
|
256
256
|
{ "name": "TRUSTED_PROXIES", "value": "127.0.0.1,::1" },
|
|
257
257
|
{ "name": "CLIENT_IP_HEADER", "value": "cf-connecting-ip" },
|
|
@@ -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.
|
|
8
|
+
version: "1.25"
|
|
9
9
|
skillcdn:
|
|
10
10
|
translations:
|
|
11
11
|
ko:
|
|
@@ -22,6 +22,8 @@ A task of the board goes in, named by its number; a run comes out: the task take
|
|
|
22
22
|
- **Checkpoints:** on the board, as decisions (phase 4), which a person answers from wherever they are; the reports say what was done at each milestone, and need no answer.
|
|
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
|
+
- **A choice made elsewhere:** a decision is the record of a choice that is the person's to make, not the place it has to be made. An answer they give in chat, in a meeting or by changing the task is written on the decision in their name, `console answer <id> --option <n>|--own "<their words>" --note "<where and when>"`, before the work goes on: the run waits on the record, and the board shows as waiting only what is still open. What was decided is not asked again.
|
|
26
|
+
- **A briefing:** asked what is on their plate, what is next, or for a briefing, the agent starts from `console work`: the decisions waiting for the person's answer come first, each with what waits on it and since when, since a waiting decision holds a run; then the tasks by their days. `console decisions --mine` and `--raised` read the rest of their decisions, the answered ones as the record.
|
|
25
27
|
- **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
28
|
- **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
29
|
- **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.
|
|
@@ -31,7 +33,7 @@ A task of the board goes in, named by its number; a run comes out: the task take
|
|
|
31
33
|
| Need | How | When missing |
|
|
32
34
|
|---|---|---|
|
|
33
35
|
| The `console` command, signed in | `console whoami` says as whom, at which console, and in which project this directory works; and whether the command and the console go together. `console logins` lists the consoles this machine is signed in to; a directory bound to another console (`.skillcdn-console.json`) needs a login there, and a token never goes to a console it was not made at ([ADR-0027](/docs/adr/0027-the-command-keeps-a-login-per-console-and-a-token-goes-only-to-the-console-that-issued-it.md)). | Stop and tell the person what to do: `npm install -g @skillcdn/console`; `console login --url <the console's address>`, which shows an address and a code the person approves on the console's own pages; `console use <key>` once in the directory, to name the project. Never look for a token. |
|
|
34
|
-
| The command at a version the console takes | A command the console refuses as outdated, or as too new, exits with `4` and prints the command that updates it where it is installed ([ADR-0025](/docs/adr/0025-the-command-names-its-version-on-every-request-and-the-console-holds-it-to-the-range-it-takes.md)). | Run the update command it printed, then go on; where the machine refuses the update, stop and tell the person. A line on stderr that a newer command exists, while the console still answers, is read and left for later. |
|
|
36
|
+
| The command at a version the console takes | A command the console refuses as outdated, or as too new, exits with `4` and prints the command that updates it where it is installed; so does a command that refuses the console as older than it works with, printing the command that installs the console's version ([ADR-0025](/docs/adr/0025-the-command-names-its-version-on-every-request-and-the-console-holds-it-to-the-range-it-takes.md), [ADR-0038](/docs/adr/0038-the-command-and-the-console-go-together-within-a-line-and-a-release-that-changes-what-passes-between-them-raises-the-floors.md)). Within a line of SkillCDN the two go together whatever the patch, until a release says otherwise. | Run the update command it printed, then go on; where the machine refuses the update, stop and tell the person. A line on stderr that a newer command exists, while the console still answers, is read and left for later. |
|
|
35
37
|
| The command's own words | `console help` lists every command in a line, read once; `console help <command>` says one in full, every form and flag, the limits the console holds it to, and the refusals it may meet, by code, read when the command is about to be used. | They are the reference at run time. This skill says how the work goes, not what each flag means. |
|
|
36
38
|
|
|
37
39
|
The full contract is the [specification of the command line](/docs/specs/cli.md); the command is a thin client of the [REST API](/docs/specs/rest.md), which a script may use directly.
|
|
@@ -40,8 +42,8 @@ The full contract is the [specification of the command line](/docs/specs/cli.md)
|
|
|
40
42
|
|
|
41
43
|
| Input | Source |
|
|
42
44
|
|---|---|
|
|
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` 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
|
+
| 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; `--search <words>` finds a task by the words of its title, or by its number); a task is never taken without being told which, or that any ready one may be. |
|
|
46
|
+
| 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, `console skills <file>` the outline of a document and `console skill --file <file> --offset <n> --limit <n>` one section of it, as a search or the outline names them; 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
47
|
| 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
48
|
|
|
47
49
|
## Workflow
|
|
@@ -54,7 +56,7 @@ Told which task, go to phase 2: `console take` prints the rules of the board wit
|
|
|
54
56
|
|
|
55
57
|
### Phase 2: Take
|
|
56
58
|
|
|
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.
|
|
59
|
+
`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. A run the board has not heard from for twelve hours (what the deployment sets), and that is not waiting for an answer, is ended by the board itself as abandoned (ADR-0041): report at the milestones, wait for a decision with `--wait` or come back for it, and, refused with `run.over` on a run ended that way, take the task again.
|
|
58
60
|
|
|
59
61
|
### Phase 3: Work, and report at the milestones
|
|
60
62
|
|
|
@@ -62,7 +64,7 @@ The work happens where it happens: in the repository, the document, the tool. At
|
|
|
62
64
|
|
|
63
65
|
### Phase 4: Ask when a person must decide
|
|
64
66
|
|
|
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.
|
|
67
|
+
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 decision is for the person you work for, who finds it among their decisions; `--to <login>` addresses it to another person of the project when the task or the rules name who decides such things (ADR-0042). 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. An answer that reaches you anywhere but the board, in chat, in a comment, in the task changed, is written on the decision in the person's name first, `console answer <id> --option <n>|--own "<their words>" --note "<where and when they said it>"`, and acted on from there; a question the work overtook is answered the same way, with the person's word on it, however short. Once acted on, `console decision <id> --outcome "<what followed>"` makes the decision read as a record.
|
|
66
68
|
|
|
67
69
|
### Phase 5: Hand in
|
|
68
70
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Terms
|
|
2
2
|
|
|
3
|
-
- **Task**: what is to be done, numbered per project, with its plan (a category, a goal, the days it starts and is due) and its moments (when it was started and done, which the board keeps).
|
|
3
|
+
- **Task**: what is to be done, numbered per project, with its plan (a category, a goal, the days it starts and is due) and its moments (when it was started and done, which the board keeps); its owner is the one person who wrote it, and its workers are the people at work on it, any number, among whom taking a task puts the agent's person ([ADR-0037](/docs/adr/0037-a-task-has-one-owner-and-any-number-of-workers-and-a-parent-or-a-goal-is-found-by-search.md)).
|
|
4
4
|
- **Goal**: what the project works towards, on its roadmap, with the day it is meant to be reached by; its progress is its tasks.
|
|
5
5
|
- **Category**: a kind of work, the workspace's word for it, by key.
|
|
6
6
|
- **Run**: one agent at work on one task for one person, with its reports, what it handed in, and what it waits for.
|
|
7
|
-
- **Decision**: a question
|
|
7
|
+
- **Decision**: a choice that is a person's to make, kept as a record on the board: the question, the options, whom it is for ([ADR-0042](/docs/adr/0042-a-decision-is-addressed-to-a-person-its-raiser-unless-another-is-named.md)), the answer with who gave it and when, and what followed. It is answered on the board whoever decided it where: a person who answers in chat, in a meeting or by changing the task has decided, and the agent writes that answer down for them (`console answer`), so that the board shows as waiting only what is still open.
|
|
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
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.
|
|
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. A task whose number is not known is found by the words of its title, `console tasks --search <words>`, and a goal's id by `console goals --search <words>`. 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.
|
package/src/api.ts
CHANGED
|
@@ -27,14 +27,17 @@ export {
|
|
|
27
27
|
type ClientJudgement,
|
|
28
28
|
type ClientPolicy,
|
|
29
29
|
type ClientVerdict,
|
|
30
|
+
CONSOLE_AT_LEAST,
|
|
30
31
|
clientRange,
|
|
31
32
|
clientVersionOf,
|
|
32
33
|
commonRange,
|
|
33
34
|
compareVersions,
|
|
35
|
+
consoleRange,
|
|
34
36
|
formatRange,
|
|
35
37
|
formatVersion,
|
|
36
38
|
inRange,
|
|
37
39
|
judgeClient,
|
|
40
|
+
judgeConsole,
|
|
38
41
|
parseRange,
|
|
39
42
|
parseVersion,
|
|
40
43
|
userAgentOf,
|
|
@@ -101,6 +104,7 @@ export {
|
|
|
101
104
|
MAX_TOKENS_PER_PERSON,
|
|
102
105
|
MAX_URL_LENGTH,
|
|
103
106
|
MAX_VERSIONS_PER_DOCUMENT,
|
|
107
|
+
MAX_WORKERS,
|
|
104
108
|
MIN_OPTIONS,
|
|
105
109
|
} from "./limits.js";
|
|
106
110
|
export { projectColorOf, projectSymbolOf } from "./marks.js";
|
|
@@ -187,6 +191,7 @@ export {
|
|
|
187
191
|
type RestMemberPatch,
|
|
188
192
|
type RestMembers,
|
|
189
193
|
type RestMePatch,
|
|
194
|
+
type RestMyDecisions,
|
|
190
195
|
type RestOrganization,
|
|
191
196
|
type RestPackConnect,
|
|
192
197
|
type RestPackConnectStarted,
|
|
@@ -282,6 +287,7 @@ export {
|
|
|
282
287
|
restMembersSchema,
|
|
283
288
|
restMePatchSchema,
|
|
284
289
|
restMeSchema,
|
|
290
|
+
restMyDecisionsSchema,
|
|
285
291
|
restOrganizationSchema,
|
|
286
292
|
restPackConnectSchema,
|
|
287
293
|
restPackConnectStartedSchema,
|
|
@@ -347,6 +353,7 @@ export {
|
|
|
347
353
|
type LinkSource,
|
|
348
354
|
MEMBERSHIP_SOURCES,
|
|
349
355
|
type MembershipSource,
|
|
356
|
+
OPEN_GOAL_STATES,
|
|
350
357
|
OPEN_TASK_STATES,
|
|
351
358
|
PACK_CONNECT_ENDINGS,
|
|
352
359
|
type PackConnectEnding,
|