@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/src/cli/help.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
MAX_FILES_PER_COMMENT,
|
|
14
14
|
MAX_FILES_PER_DOCUMENT,
|
|
15
15
|
MAX_LINK_LABEL_LENGTH,
|
|
16
|
+
MAX_NOTE_LENGTH,
|
|
16
17
|
MAX_OPTION_LABEL_LENGTH,
|
|
17
18
|
MAX_OPTIONS,
|
|
18
19
|
MAX_PROJECT_DESCRIPTION_LENGTH,
|
|
@@ -23,9 +24,11 @@ import {
|
|
|
23
24
|
MAX_QUESTION_LENGTH,
|
|
24
25
|
MAX_REPORTS_PER_RUN,
|
|
25
26
|
MAX_RULES_LENGTH,
|
|
27
|
+
MAX_SEARCH_LENGTH,
|
|
26
28
|
MAX_SUMMARY_LENGTH,
|
|
27
29
|
MAX_TITLE_LENGTH,
|
|
28
30
|
MAX_VERSIONS_PER_DOCUMENT,
|
|
31
|
+
MAX_WORKERS,
|
|
29
32
|
MIN_OPTIONS,
|
|
30
33
|
} from "../limits.js";
|
|
31
34
|
import { COLOR_NAMES } from "../vocabulary.js";
|
|
@@ -84,17 +87,17 @@ const DAY = "a day as 2026-10-24, today, tomorrow, or +7 for seven days from tod
|
|
|
84
87
|
const COLORS = `one of ${COLOR_NAMES.join(", ")}`;
|
|
85
88
|
const KEY = "lowercase letters, digits and hyphens";
|
|
86
89
|
const TASK_FIELD_FLAGS =
|
|
87
|
-
"[--state <state>] [--priority <priority>] [--category <key>] [--goal <id>] [--starts <day>] [--due <day>] [--
|
|
90
|
+
"[--state <state>] [--priority <priority>] [--category <key>] [--goal <id>] [--starts <day>] [--due <day>] [--worker <login|me|none>]... [--parent <number|id>]";
|
|
88
91
|
const TASK_FIELD_LIMITS = [
|
|
89
92
|
`starts, due: ${DAY}; the due day is not before the start`,
|
|
90
93
|
"category: the key of one of the workspace's categories (console categories); goal: the id of one of the project's goals (console goals)",
|
|
91
|
-
|
|
94
|
+
`worker: a login of the workspace, or me; given again, or with commas between, for several, up to ${MAX_WORKERS}, in place of the workers there were; none alone for nobody. parent: a task of the project, by its number or its id; console tasks --search <words> finds one by its title`,
|
|
92
95
|
];
|
|
93
96
|
const TASK_FIELD_REFUSALS = [
|
|
94
97
|
"task.invalid_category: no category has that key",
|
|
95
98
|
"task.invalid_goal: the goal is not one of this project",
|
|
96
99
|
"task.invalid_dates: the due day is before the start",
|
|
97
|
-
"task.
|
|
100
|
+
"task.invalid_worker: a person named as a worker may not work in the project",
|
|
98
101
|
"task.invalid_parent: the parent is not a task of the project, or would make a loop",
|
|
99
102
|
];
|
|
100
103
|
|
|
@@ -145,16 +148,17 @@ export const COMMAND_HELP: Readonly<Record<string, CommandHelp>> = {
|
|
|
145
148
|
work: {
|
|
146
149
|
usage: "work [--person <login>]",
|
|
147
150
|
synopsis:
|
|
148
|
-
"What is on your plate across your projects: your open tasks, and the decisions waiting.",
|
|
151
|
+
"What is on your plate across your projects: your open tasks, and the decisions waiting for you.",
|
|
149
152
|
about:
|
|
150
|
-
"What is on your plate across the projects you may see: the open tasks
|
|
153
|
+
"What is on your plate across the projects you may see: the open tasks you work on, the sooner due first, each with its project; and the decisions waiting for your answer (ADR-0042). Needs no project. --person <login> shows another person's plate, for an administrator or for an owner of a project they are in: the open tasks they work on within the projects you may see, without the decisions.",
|
|
151
154
|
},
|
|
152
155
|
tasks: {
|
|
153
156
|
usage:
|
|
154
|
-
"tasks [--state <state>] [--open] [--mine] [--category <key>] [--goal <id>] [--due <day|today|week|overdue>] [--unassigned] [--archived] [--limit <n>] [--offset <n>]",
|
|
157
|
+
"tasks [--state <state>] [--open] [--mine] [--category <key>] [--goal <id>] [--due <day|today|week|overdue>] [--unassigned] [--search <words>] [--archived] [--limit <n>] [--offset <n>]",
|
|
155
158
|
synopsis:
|
|
156
|
-
"The tasks on the board, newest first, narrowed by state,
|
|
157
|
-
about: `The tasks on the board, newest first: number, state, priority, title, who owns and works on each, its category and its due day, and what waits on it. --open keeps the ones not done or dropped, --mine those
|
|
159
|
+
"The tasks on the board, newest first, narrowed by state, worker, category, goal, due day or words of the title.",
|
|
160
|
+
about: `The tasks on the board, newest first: number, state, priority, title, who owns and who works on each, its category and its due day, and what waits on it. --open keeps the ones not done or dropped, --mine those you work on, --unassigned those nobody works on (not with --mine), --category and --goal those sorted into one, --due those due by a day: today, this week (through its last day, the week beginning as the workspace says, console workspace, or as your language has it), or overdue (the open ones past their day), --search those whose title has every word given, whatever the case, and the task of that number for a number (12 or #12): how a task is found by its title, as a parent or otherwise. The tasks put away (ADR-0029) are left out unless --archived asks for them alone. A page at a time: ${DEFAULT_PAGE_LIMIT} unless --limit says otherwise, from --offset on; a last line says when there is more. States: idea, ready, in_progress, in_review, done, dropped.`,
|
|
161
|
+
limits: [`search: 1 to ${MAX_SEARCH_LENGTH} characters`],
|
|
158
162
|
},
|
|
159
163
|
task: {
|
|
160
164
|
usage: `task <number|id> | task new <title> [--body <markdown>|--file <path>] ${TASK_FIELD_FLAGS} | task edit <number|id> [--title <title>] [--body <markdown>|--file <path>] ${TASK_FIELD_FLAGS} | task archive <number|id> | task archive --goal <id> | task restore <number|id>`,
|
|
@@ -171,10 +175,11 @@ export const COMMAND_HELP: Readonly<Record<string, CommandHelp>> = {
|
|
|
171
175
|
refusals: ["task.not_found: no task has that number or id", ...TASK_FIELD_REFUSALS],
|
|
172
176
|
},
|
|
173
177
|
goals: {
|
|
174
|
-
usage:
|
|
178
|
+
usage:
|
|
179
|
+
"goals [--category <key>] [--state <state>] [--search <words>] [--limit <n>] [--offset <n>]",
|
|
175
180
|
synopsis: "The roadmap: the project's goals, with their state, their days and how far each is.",
|
|
176
|
-
about:
|
|
177
|
-
|
|
181
|
+
about: `The roadmap of the project: its goals, the active first, each with its id, its state (planned, active, done, dropped), its category, the days it starts and is meant to be reached by, and how far it is, counted from the tasks that work towards it. --category keeps those sorted into one, --state those in one state, --search those whose title has every word given, whatever the case: how a goal's id is found for --goal. A page at a time: ${DEFAULT_PAGE_LIMIT} unless --limit says otherwise, from --offset on; a last line says when there is more.`,
|
|
182
|
+
limits: [`search: 1 to ${MAX_SEARCH_LENGTH} characters`],
|
|
178
183
|
},
|
|
179
184
|
goal: {
|
|
180
185
|
usage:
|
|
@@ -206,7 +211,7 @@ export const COMMAND_HELP: Readonly<Record<string, CommandHelp>> = {
|
|
|
206
211
|
usage: "people",
|
|
207
212
|
synopsis: "The people you see, by login, with what each is in the workspace.",
|
|
208
213
|
about:
|
|
209
|
-
"The people of the workspace you see, by login, with their name where the host gives one and what they are in it: admin, who configures the workspace, or member, who works in the projects they are in; a person taken out is marked deactivated. Everyone, unless the workspace shows a member only the people they share a project with (console workspace says which; an administrator sees everyone). Then, where you see everyone, the logins an administrator let in that nobody has signed in with yet. The logins are what --
|
|
214
|
+
"The people of the workspace you see, by login, with their name where the host gives one and what they are in it: admin, who configures the workspace, or member, who works in the projects they are in; a person taken out is marked deactivated. Everyone, unless the workspace shows a member only the people they share a project with (console workspace says which; an administrator sees everyone). Then, where you see everyone, the logins an administrator let in that nobody has signed in with yet. The logins are what --worker, member and person take; a login is found exactly, so an owner lists someone the list does not show.",
|
|
210
215
|
},
|
|
211
216
|
workspace: {
|
|
212
217
|
usage:
|
|
@@ -309,11 +314,11 @@ export const COMMAND_HELP: Readonly<Record<string, CommandHelp>> = {
|
|
|
309
314
|
},
|
|
310
315
|
skills: {
|
|
311
316
|
usage:
|
|
312
|
-
"skills | skills <folder> | skills --search <words> [<folder>] [--limit <n>] [--cursor <cursor>]",
|
|
317
|
+
"skills | skills <folder|file> | skills --search <words> [<folder>] [--limit <n>] [--cursor <cursor>]",
|
|
313
318
|
synopsis:
|
|
314
|
-
"The project's pack: its skills; what a folder of it holds; or what words find in it.",
|
|
319
|
+
"The project's pack: its skills; what a folder of it holds, or a document's outline; or what words find in it.",
|
|
315
320
|
about:
|
|
316
|
-
"The project's pack, read by the console at the project's address, or the organization's: at a SkillCDN deployment, with the pack token the project holds where the pack is private (ADR-0028), or from a directory on the console's machine for a local address (ADR-0031). Alone: where the pack is and what a client is told of it on connect, then every skill with the path of its SKILL.md and every document, as a connection of your own would list them, and where the console's own skills are on this machine. With a folder (. for the root): what it holds, whole, as browse_repo lays it out for a model: its skills, its folders with what each holds and the README that introduces it, its files. With --search: what the words find, as search_repo does: skills first, with the files of theirs that matched, then documents, in relevance order; words
|
|
321
|
+
"The project's pack, read by the console at the project's address, or the organization's: at a SkillCDN deployment, with the pack token the project holds where the pack is private (ADR-0028), or from a directory on the console's machine for a local address (ADR-0031). Alone: where the pack is and what a client is told of it on connect, then every skill with the path of its SKILL.md and every document, as a connection of your own would list them, and where the console's own skills are on this machine. With a folder (. for the root): what it holds, whole, as browse_repo lays it out for a model: its skills, its folders with what each holds and the README that introduces it, its files. With a file's path: the file's outline, every heading with its level and the offset and limit that read its section with console skill --file, whole; a file that is not Markdown has none. With --search: what the words find, as search_repo does: skills first, with the files of theirs that matched, then documents, each with the sections of it that matched and what reads each, in relevance order; words in the language the pack is written in, and meaning too where the deployment searches by it, which the result then says; within the folder when one is named; 10 unless --limit says otherwise, up to 25, and a nextCursor line says when more matched, which --cursor continues. The text is the one an MCP client's model is given, with the reads named as these commands. --json answers with the console's own JSON: what the pack answered, in the shapes of the main repository's REST API, the pages of a folder or an outline joined.",
|
|
317
322
|
limits: ["search: 1 to 500 characters; limit: 1 to 25"],
|
|
318
323
|
refusals: [
|
|
319
324
|
"status not_found: the pack is not served to the console; private, with no pack token on the project",
|
|
@@ -321,11 +326,12 @@ export const COMMAND_HELP: Readonly<Record<string, CommandHelp>> = {
|
|
|
321
326
|
],
|
|
322
327
|
},
|
|
323
328
|
skill: {
|
|
324
|
-
usage: "skill <path> | skill --file <path>",
|
|
329
|
+
usage: "skill <path> | skill --file <path> [--offset <n>] [--limit <n>]",
|
|
325
330
|
synopsis:
|
|
326
|
-
"One skill of the pack whole, its rules first; or with --file a file of the pack, or what a folder holds.",
|
|
331
|
+
"One skill of the pack whole, its rules first; or with --file a file of the pack, one section of it, or what a folder holds.",
|
|
327
332
|
about:
|
|
328
|
-
"One skill of the project's pack, whole, as load_skill lays it out for a model: the rules of the repository from its root to the nearest manifest, the skill's instructions, the files it includes, then its supporting files and what it refers to; the pages it came in are joined. Read by the console from the pack, with the pack token the project holds where the pack is private, so you need no connection of your own. <path> is the path of the SKILL.md from the repository's root, as console skills lists it, or the URI the pack names it by (skill://<host>/<owner>/<name>/<path>). --file <path> reads a file of the pack instead, whole, as read_repo_file does, or what a folder holds, and takes no skill's path beside it; console skills <folder> shows a folder with more. --json answers with what the pack answered, in the shapes of the main repository's REST API, the pages joined.",
|
|
333
|
+
"One skill of the project's pack, whole, as load_skill lays it out for a model: the rules of the repository from its root to the nearest manifest, the skill's instructions, the files it includes, then its supporting files and what it refers to; the pages it came in are joined. Read by the console from the pack, with the pack token the project holds where the pack is private, so you need no connection of your own. <path> is the path of the SKILL.md from the repository's root, as console skills lists it, or the URI the pack names it by (skill://<host>/<owner>/<name>/<path>). --file <path> reads a file of the pack instead, whole, as read_repo_file does, or what a folder holds, and takes no skill's path beside it; console skills <folder> shows a folder with more. --offset <n> and --limit <n>, with --file, read one page of the file as asked, from that character on and at most that many characters, as a search or an outline (console skills <file>) names a section, instead of the file whole; the result says where the file continues. --json answers with what the pack answered, in the shapes of the main repository's REST API, the pages joined.",
|
|
334
|
+
limits: ["offset: 0 or more; limit: 1 to 100000 characters; both with --file"],
|
|
329
335
|
refusals: [
|
|
330
336
|
"status not_found: the pack is not served to the console; private, with no pack token on the project",
|
|
331
337
|
"status token_invalid: the pack token the project holds no longer works; an owner sets a new one",
|
|
@@ -389,18 +395,38 @@ export const COMMAND_HELP: Readonly<Record<string, CommandHelp>> = {
|
|
|
389
395
|
},
|
|
390
396
|
ask: {
|
|
391
397
|
usage:
|
|
392
|
-
'ask "<question>" --option "<label>" --option "<label>" [...] [--body <markdown>|--file <path>] [--wait <seconds>] [--run <id>]',
|
|
398
|
+
'ask "<question>" --option "<label>" --option "<label>" [...] [--body <markdown>|--file <path>] [--to <login|me>] [--wait <seconds>] [--run <id>]',
|
|
393
399
|
overview:
|
|
394
|
-
'ask "<question>" --option "<label>" --option "<label>" [...] [--body <markdown>|--file <path>] [--wait <seconds>]',
|
|
400
|
+
'ask "<question>" --option "<label>" --option "<label>" [...] [--body <markdown>|--file <path>] [--to <login|me>] [--wait <seconds>]',
|
|
395
401
|
synopsis:
|
|
396
402
|
"Raises a decision a person must make, with options, and waits a while for the answer.",
|
|
397
|
-
about: `Raises a decision a person must make: the question, the options to choose from, and what they need to know. The run waits for the answer. The command waits 60 seconds for it unless --wait says otherwise, and exits with 3 if it is still to come: keep waiting with \`console decision <id> --wait 100\`, within what your shell gives one command. The decision's id is printed as soon as it is raised. The person chooses one of the options, or answers in their own words: the answer then names one more option, their words, marked own; act on it as given. ${ON_THE_RUN}`,
|
|
403
|
+
about: `Raises a decision a person must make: the question, the options to choose from, and what they need to know. It is for the person you work for unless --to names another of the project, who then finds it among their decisions (ADR-0042); anyone of the project may still answer. The run waits for the answer. The command waits 60 seconds for it unless --wait says otherwise, and exits with 3 if it is still to come: keep waiting with \`console decision <id> --wait 100\`, within what your shell gives one command. The decision's id is printed as soon as it is raised. The person chooses one of the options, or answers in their own words: the answer then names one more option, their words, marked own; act on it as given. ${ON_THE_RUN}`,
|
|
398
404
|
limits: [
|
|
399
405
|
`question: one line, up to ${MAX_QUESTION_LENGTH} characters`,
|
|
400
406
|
`options: ${MIN_OPTIONS} to ${MAX_OPTIONS}, each one line up to ${MAX_OPTION_LABEL_LENGTH} characters`,
|
|
401
407
|
`body: ${MARKDOWN}`,
|
|
408
|
+
"to: a login of the project, or me",
|
|
409
|
+
],
|
|
410
|
+
refusals: [
|
|
411
|
+
...RUN_CHOICE,
|
|
412
|
+
"decision.invalid_run: the run is not yours, or is over",
|
|
413
|
+
"decision.invalid_decider: the person named may not work in the project",
|
|
414
|
+
],
|
|
415
|
+
},
|
|
416
|
+
answer: {
|
|
417
|
+
usage: 'answer <id> --option <n>|--own "<answer>" [--note <markdown>|--file <path>]',
|
|
418
|
+
synopsis: "Writes a person's answer on a decision: the option they chose, or their own words.",
|
|
419
|
+
about:
|
|
420
|
+
"Writes on the board the answer a person gave: one of the decision's options by its number, or their own words, which become one more option of the decision marked as theirs; and a note about it. The answer is the person's, written in their name through you (ADR-0021): a choice they made in chat, in a meeting or by changing the task is written here, with where and when they made it in the note, so that the record is whole and a run that waited goes on. A decision is answered once; what followed is written with console decision <id> --outcome.",
|
|
421
|
+
limits: [
|
|
422
|
+
`own: one line, up to ${MAX_OPTION_LABEL_LENGTH} characters`,
|
|
423
|
+
`note: Markdown, up to ${MAX_NOTE_LENGTH} characters`,
|
|
424
|
+
],
|
|
425
|
+
refusals: [
|
|
426
|
+
"decision.not_found: no decision has that id",
|
|
427
|
+
"decision.answered: the decision has an answer already",
|
|
428
|
+
"decision.no_such_option: the option is not one of the decision's",
|
|
402
429
|
],
|
|
403
|
-
refusals: [...RUN_CHOICE, "decision.invalid_run: the run is not yours, or is over"],
|
|
404
430
|
},
|
|
405
431
|
decision: {
|
|
406
432
|
usage: "decision <id> [--wait <seconds>] | decision <id> --outcome <markdown>|--file <path>",
|
|
@@ -412,9 +438,9 @@ export const COMMAND_HELP: Readonly<Record<string, CommandHelp>> = {
|
|
|
412
438
|
refusals: ["decision.not_found: no decision has that id"],
|
|
413
439
|
},
|
|
414
440
|
decisions: {
|
|
415
|
-
usage: "decisions [--open] [--limit <n>] [--offset <n>]",
|
|
416
|
-
synopsis: "The decisions on the board, the waiting first.",
|
|
417
|
-
about: `The decisions on the board, the waiting first; --open keeps only those. A page at a time: ${DEFAULT_PAGE_LIMIT} unless --limit says otherwise, from --offset on.`,
|
|
441
|
+
usage: "decisions [--open] [--mine|--raised] [--limit <n>] [--offset <n>]",
|
|
442
|
+
synopsis: "The decisions on the board, the waiting first; or your own across the projects.",
|
|
443
|
+
about: `The decisions on the board, the waiting first; --open keeps only those. --mine lists the decisions addressed to you instead (ADR-0042), and --raised those you asked of someone else, through your agent or yourself, each across the projects you may see with its project's key; neither needs a project. A page at a time: ${DEFAULT_PAGE_LIMIT} unless --limit says otherwise, from --offset on.`,
|
|
418
444
|
},
|
|
419
445
|
finish: {
|
|
420
446
|
usage: 'finish [--summary "<markdown>"|--file <path>] [--run <id>]',
|
|
@@ -618,7 +644,18 @@ const SECTIONS: readonly { readonly title: string; readonly commands: readonly s
|
|
|
618
644
|
},
|
|
619
645
|
{
|
|
620
646
|
title: "Working",
|
|
621
|
-
commands: [
|
|
647
|
+
commands: [
|
|
648
|
+
"take",
|
|
649
|
+
"report",
|
|
650
|
+
"hand-in",
|
|
651
|
+
"comment",
|
|
652
|
+
"file",
|
|
653
|
+
"ask",
|
|
654
|
+
"answer",
|
|
655
|
+
"finish",
|
|
656
|
+
"fail",
|
|
657
|
+
"abandon",
|
|
658
|
+
],
|
|
622
659
|
},
|
|
623
660
|
{
|
|
624
661
|
title: "The documents: the project's pages of Markdown, in folders, by path",
|
package/src/cli/main.ts
CHANGED
|
@@ -60,6 +60,7 @@ process.exitCode = await runCli(process.argv.slice(2), {
|
|
|
60
60
|
exists: existsSync,
|
|
61
61
|
}),
|
|
62
62
|
notices: createNoticeStore(configDir),
|
|
63
|
+
locale: Intl.DateTimeFormat().resolvedOptions().locale,
|
|
63
64
|
skillsDir: existsSync(skillsDir) ? skillsDir : undefined,
|
|
64
65
|
listen: listenOn,
|
|
65
66
|
});
|
package/src/cli/pack.ts
CHANGED
|
@@ -264,11 +264,20 @@ export function joinFolder(
|
|
|
264
264
|
if (first === undefined || last === undefined) {
|
|
265
265
|
return undefined;
|
|
266
266
|
}
|
|
267
|
+
// A file's path answers its outline (SkillCDN 0.4), its headings paged as a folder's entries are.
|
|
268
|
+
const outline =
|
|
269
|
+
first.outline === undefined
|
|
270
|
+
? undefined
|
|
271
|
+
: {
|
|
272
|
+
...first.outline,
|
|
273
|
+
headings: results.flatMap((result) => result.outline?.headings ?? []),
|
|
274
|
+
};
|
|
267
275
|
return {
|
|
268
276
|
...first,
|
|
269
277
|
mount: last.mount,
|
|
270
278
|
entries: results.flatMap((result) => result.entries),
|
|
271
279
|
nextCursor: last.nextCursor,
|
|
280
|
+
...(outline === undefined ? {} : { outline }),
|
|
272
281
|
};
|
|
273
282
|
}
|
|
274
283
|
|
|
@@ -304,10 +313,16 @@ export function formatSkillFind(found: RestSkillFind, summary: PackSummary | und
|
|
|
304
313
|
return renderFindResult(findResultOf(found.read, summary), CONSOLE_WORDS);
|
|
305
314
|
}
|
|
306
315
|
|
|
307
|
-
/**
|
|
316
|
+
/**
|
|
317
|
+
* The pages of a file, as the console answered them, as the file whole; or the folder the path
|
|
318
|
+
* named. With `requested`, the one page is a section read as asked (`--offset`, `--limit`): the
|
|
319
|
+
* result carries the length asked for, so that the renderer says where the file continues rather
|
|
320
|
+
* than asking for the rest.
|
|
321
|
+
*/
|
|
308
322
|
export function joinFile(
|
|
309
323
|
pages: readonly RestSkillFile[],
|
|
310
324
|
summary: PackSummary,
|
|
325
|
+
requested?: number,
|
|
311
326
|
): FileResult | DirectoryResult | undefined {
|
|
312
327
|
const reads = pages.flatMap((page) => (page.read === null ? [] : [page.read]));
|
|
313
328
|
const first = reads[0];
|
|
@@ -331,6 +346,7 @@ export function joinFile(
|
|
|
331
346
|
content: files.map((file) => file.content).join(""),
|
|
332
347
|
nextOffset: closing.nextOffset,
|
|
333
348
|
totalLength: closing.totalLength,
|
|
349
|
+
...(requested === undefined ? {} : { requestedLength: requested }),
|
|
334
350
|
};
|
|
335
351
|
}
|
|
336
352
|
|
package/src/client.ts
CHANGED
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
type RestMemberPatch,
|
|
45
45
|
type RestMembers,
|
|
46
46
|
type RestMePatch,
|
|
47
|
+
type RestMyDecisions,
|
|
47
48
|
type RestPackConnect,
|
|
48
49
|
type RestPackConnectStarted,
|
|
49
50
|
type RestPackTokenInput,
|
|
@@ -101,6 +102,7 @@ import {
|
|
|
101
102
|
restMemberSchema,
|
|
102
103
|
restMembersSchema,
|
|
103
104
|
restMeSchema,
|
|
105
|
+
restMyDecisionsSchema,
|
|
104
106
|
restPackConnectSchema,
|
|
105
107
|
restPackConnectStartedSchema,
|
|
106
108
|
restPeopleSchema,
|
|
@@ -214,14 +216,18 @@ export interface Page {
|
|
|
214
216
|
readonly offset?: number | undefined;
|
|
215
217
|
}
|
|
216
218
|
|
|
217
|
-
/** What the
|
|
218
|
-
|
|
219
|
-
export interface GoalFilter {
|
|
219
|
+
/** What the roadmap is narrowed by: the goals in one state, the open ones, those sorted into one category (ADR-0026), or those whose title has some words; and which page of it. */
|
|
220
|
+
export interface GoalFilter extends Page {
|
|
220
221
|
readonly state?: GoalState | undefined;
|
|
222
|
+
/** True for the goals planned or active; false for the reached and the dropped. */
|
|
223
|
+
readonly open?: boolean | undefined;
|
|
221
224
|
/** The key of a category of the workspace. */
|
|
222
225
|
readonly category?: string | undefined;
|
|
226
|
+
/** Words of the title, each found in it whatever the case. */
|
|
227
|
+
readonly q?: string | undefined;
|
|
223
228
|
}
|
|
224
229
|
|
|
230
|
+
/** What the board is narrowed to: one state, the open ones, a category, a goal, a worker, what is due by a day, or words of the title; and which page of it. */
|
|
225
231
|
export interface TaskFilter extends Page {
|
|
226
232
|
readonly state?: TaskState | undefined;
|
|
227
233
|
/** True for the tasks not done or dropped; false for the rest. */
|
|
@@ -230,10 +236,12 @@ export interface TaskFilter extends Page {
|
|
|
230
236
|
readonly category?: string | undefined;
|
|
231
237
|
/** The id of a goal. */
|
|
232
238
|
readonly goal?: string | undefined;
|
|
233
|
-
/** The id of
|
|
234
|
-
readonly
|
|
235
|
-
/** True for the tasks
|
|
239
|
+
/** The id of a person among the workers of the tasks. */
|
|
240
|
+
readonly worker?: string | undefined;
|
|
241
|
+
/** True for the tasks with no worker. */
|
|
236
242
|
readonly unassigned?: boolean | undefined;
|
|
243
|
+
/** Words of the title, each found in it whatever the case; `#12` or `12` finds the task of that number too. */
|
|
244
|
+
readonly q?: string | undefined;
|
|
237
245
|
/** A day (`2026-10-20`): the tasks due on it or before it. */
|
|
238
246
|
readonly dueBy?: string | undefined;
|
|
239
247
|
/** True for the tasks put away alone (ADR-0029); false, or left out, for the current ones. */
|
|
@@ -380,8 +388,7 @@ export interface ProjectClient {
|
|
|
380
388
|
attachFile(path: string, input: FileUpload): Promise<RestDocument>;
|
|
381
389
|
/** Where the bytes of a file attached to a document are read, by the file's id. */
|
|
382
390
|
documentFileUrl(path: string, fileId: string): string;
|
|
383
|
-
/** The roadmap (ADR-0019)
|
|
384
|
-
/** The roadmap, or what the filter keeps of it: the active goals first. */
|
|
391
|
+
/** The roadmap (ADR-0019), or what the filter keeps of it, a page at a time: the active goals first, each with its tasks counted by state. */
|
|
385
392
|
goals(filter?: GoalFilter, signal?: AbortSignal): Promise<RestGoals>;
|
|
386
393
|
goal(id: string, signal?: AbortSignal): Promise<RestGoal>;
|
|
387
394
|
/** Sets a goal; for an owner, with a session or a token. */
|
|
@@ -444,8 +451,13 @@ export interface ConsoleClient {
|
|
|
444
451
|
updateCategory(key: string, patch: RestCategoryPatch): Promise<RestCategory>;
|
|
445
452
|
/** Removes a category no task uses; for an administrator signed in. */
|
|
446
453
|
removeCategory(key: string): Promise<void>;
|
|
447
|
-
/** What is on the asker's plate across the projects they may see: their open tasks, and the decisions waiting. */
|
|
454
|
+
/** What is on the asker's plate across the projects they may see: their open tasks, and the decisions waiting for them. */
|
|
448
455
|
work(signal?: AbortSignal): Promise<RestWork>;
|
|
456
|
+
/** The decisions addressed to the asker (ADR-0042) across the projects they may see, or with `raised` those they raised for someone else: a page, the waiting first; or only those. */
|
|
457
|
+
myDecisions(
|
|
458
|
+
filter?: { readonly open?: boolean; readonly raised?: boolean } & Page,
|
|
459
|
+
signal?: AbortSignal,
|
|
460
|
+
): Promise<RestMyDecisions>;
|
|
449
461
|
/** Another person's plate, within what the asker may see: for an administrator, or an owner of a project they are in. */
|
|
450
462
|
personWork(personId: string, signal?: AbortSignal): Promise<RestPersonWork>;
|
|
451
463
|
/** The tokens of whoever asks. */
|
|
@@ -642,9 +654,10 @@ export function createClient(options: ClientOptions = {}): ConsoleClient {
|
|
|
642
654
|
open: flag(filter.open),
|
|
643
655
|
category: filter.category,
|
|
644
656
|
goal: filter.goal,
|
|
645
|
-
|
|
657
|
+
worker: filter.worker,
|
|
646
658
|
unassigned: flag(filter.unassigned),
|
|
647
659
|
dueBy: filter.dueBy,
|
|
660
|
+
q: filter.q,
|
|
648
661
|
limit: number(filter.limit),
|
|
649
662
|
offset: number(filter.offset),
|
|
650
663
|
}),
|
|
@@ -862,7 +875,14 @@ export function createClient(options: ClientOptions = {}): ConsoleClient {
|
|
|
862
875
|
goals: (filter = {}, signal) =>
|
|
863
876
|
request(
|
|
864
877
|
"GET",
|
|
865
|
-
withQuery(at("goals"), {
|
|
878
|
+
withQuery(at("goals"), {
|
|
879
|
+
state: filter.state,
|
|
880
|
+
open: flag(filter.open),
|
|
881
|
+
category: filter.category,
|
|
882
|
+
q: filter.q,
|
|
883
|
+
limit: number(filter.limit),
|
|
884
|
+
offset: number(filter.offset),
|
|
885
|
+
}),
|
|
866
886
|
undefined,
|
|
867
887
|
restGoalsSchema,
|
|
868
888
|
signal,
|
|
@@ -948,6 +968,19 @@ export function createClient(options: ClientOptions = {}): ConsoleClient {
|
|
|
948
968
|
removeCategory: (key) => request("DELETE", `${base}${categoryPath(key)}`, undefined, undefined),
|
|
949
969
|
work: (signal) =>
|
|
950
970
|
request("GET", `${base}${REST_ROUTES.work}`, undefined, restWorkSchema, signal),
|
|
971
|
+
myDecisions: (filter = {}, signal) =>
|
|
972
|
+
request(
|
|
973
|
+
"GET",
|
|
974
|
+
withQuery(REST_ROUTES.decisions, {
|
|
975
|
+
open: flag(filter.open),
|
|
976
|
+
raised: filter.raised === true ? "true" : undefined,
|
|
977
|
+
limit: number(filter.limit),
|
|
978
|
+
offset: number(filter.offset),
|
|
979
|
+
}),
|
|
980
|
+
undefined,
|
|
981
|
+
restMyDecisionsSchema,
|
|
982
|
+
signal,
|
|
983
|
+
),
|
|
951
984
|
personWork: (personId, signal) =>
|
|
952
985
|
request("GET", `${base}${personWorkPath(personId)}`, undefined, restPersonWorkSchema, signal),
|
|
953
986
|
tokens: (signal) =>
|
package/src/compat.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
// Whether the command and the console go together (ADR-0025). The command names its version on
|
|
1
|
+
// Whether the command and the console go together (ADR-0025, ADR-0038). The command names its version on
|
|
2
2
|
// every request, in the product token of its user-agent; the console answers every request of
|
|
3
3
|
// the API with its own version and the range of command versions it takes, and refuses a
|
|
4
4
|
// command outside the range with `426` and the words to update. One rule for both sides, kept
|
|
5
5
|
// here so that the command and the console read the same one, and narrowed by the console's
|
|
6
|
-
// policy below only, never widened: what the rule promises stays predictable.
|
|
6
|
+
// policy below only, never widened: what the rule promises stays predictable. The command holds
|
|
7
|
+
// the console to a floor of its own the same way (ADR-0038).
|
|
7
8
|
|
|
8
9
|
/** The product token the command names itself with: `skillcdn-console/<version>`. */
|
|
9
10
|
export const CLIENT_PRODUCT = "skillcdn-console";
|
|
@@ -74,15 +75,19 @@ export function inRange(version: Version, range: VersionRange): boolean {
|
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
/**
|
|
77
|
-
* The common rule. Before 1.0, a command
|
|
78
|
-
*
|
|
79
|
-
* console's own
|
|
80
|
-
*
|
|
81
|
-
* major breaks, as the version
|
|
78
|
+
* The common rule. Before 1.0, the line: a command and a console of one major.minor go
|
|
79
|
+
* together whatever the patch, since the minor is SkillCDN's line and a patch is a release of
|
|
80
|
+
* the console's own (ADR-0034), and a release that changes what passes between them raises the
|
|
81
|
+
* floors below instead (ADR-0038). From 1.0, the console's major and a minor within one of the
|
|
82
|
+
* console's, either way, whatever the patch: a minor adds and a major breaks, as the version
|
|
83
|
+
* promises from then on.
|
|
82
84
|
*/
|
|
83
85
|
export function commonRange(server: Version): VersionRange {
|
|
84
86
|
if (server.major === 0) {
|
|
85
|
-
return {
|
|
87
|
+
return {
|
|
88
|
+
atLeast: { major: 0, minor: server.minor, patch: 0 },
|
|
89
|
+
below: { major: 0, minor: server.minor + 1, patch: 0 },
|
|
90
|
+
};
|
|
86
91
|
}
|
|
87
92
|
return {
|
|
88
93
|
atLeast: { major: server.major, minor: Math.max(0, server.minor - 1), patch: 0 },
|
|
@@ -103,13 +108,25 @@ export interface ClientPolicy {
|
|
|
103
108
|
readonly refused?: readonly string[] | undefined;
|
|
104
109
|
}
|
|
105
110
|
|
|
106
|
-
/**
|
|
107
|
-
|
|
111
|
+
/**
|
|
112
|
+
* The console's policy: the oldest command this console answers, raised by the release that
|
|
113
|
+
* last changed what the command reads or sends (ADR-0038), whose changelog entry begins with
|
|
114
|
+
* `Breaking:`; `pnpm check` holds it to a version the package has, or is about to have.
|
|
115
|
+
*/
|
|
116
|
+
export const CLIENT_POLICY: ClientPolicy = { atLeast: "0.4.0" };
|
|
108
117
|
|
|
109
|
-
/**
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
118
|
+
/**
|
|
119
|
+
* The oldest console this command works with (ADR-0038): raised by the release that last
|
|
120
|
+
* changed what the command asks of the console, whose changelog entry begins with `Breaking:`.
|
|
121
|
+
* The command compares it with the version every answer names and refuses a console below it
|
|
122
|
+
* itself, naming the command to install instead; `pnpm check` holds it as it holds the
|
|
123
|
+
* console's floor.
|
|
124
|
+
*/
|
|
125
|
+
export const CONSOLE_AT_LEAST = "0.4.0";
|
|
126
|
+
|
|
127
|
+
/** `common` from `atLeast` on, where that floor is within it; `common` as it is otherwise. */
|
|
128
|
+
function narrowed(common: VersionRange, atLeast: string | undefined): VersionRange {
|
|
129
|
+
const floor = parseVersion(atLeast);
|
|
113
130
|
return floor !== undefined &&
|
|
114
131
|
compareVersions(floor, common.atLeast) > 0 &&
|
|
115
132
|
compareVersions(floor, common.below) < 0
|
|
@@ -117,6 +134,16 @@ export function clientRange(server: Version, policy: ClientPolicy = CLIENT_POLIC
|
|
|
117
134
|
: common;
|
|
118
135
|
}
|
|
119
136
|
|
|
137
|
+
/** The range of command versions a console of `server` takes: the common rule, narrowed by the policy's floor where that floor is within it. */
|
|
138
|
+
export function clientRange(server: Version, policy: ClientPolicy = CLIENT_POLICY): VersionRange {
|
|
139
|
+
return narrowed(commonRange(server), policy.atLeast);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** The range of console versions a command of `client` works with: the common rule, narrowed by the command's floor where that floor is within it. */
|
|
143
|
+
export function consoleRange(client: Version, atLeast: string = CONSOLE_AT_LEAST): VersionRange {
|
|
144
|
+
return narrowed(commonRange(client), atLeast);
|
|
145
|
+
}
|
|
146
|
+
|
|
120
147
|
/**
|
|
121
148
|
* What a command of one version is to a console of another: within the range and the same
|
|
122
149
|
* (`current`), older (`behind`) or newer (`ahead`), which the console answers; or outside it,
|
|
@@ -152,6 +179,28 @@ export function judgeClient(
|
|
|
152
179
|
return { verdict: order === 0 ? "current" : order < 0 ? "behind" : "ahead", range };
|
|
153
180
|
}
|
|
154
181
|
|
|
182
|
+
/**
|
|
183
|
+
* What a console of one version is to a command of another (ADR-0038): within the range the
|
|
184
|
+
* command works with, the same (`current`), older (`behind`) or newer (`ahead`); below it
|
|
185
|
+
* (`outdated`), which the command refuses itself, naming the command to install; or beyond it
|
|
186
|
+
* (`too_new`), which the console refuses the command for.
|
|
187
|
+
*/
|
|
188
|
+
export function judgeConsole(
|
|
189
|
+
server: Version,
|
|
190
|
+
client: Version,
|
|
191
|
+
atLeast: string = CONSOLE_AT_LEAST,
|
|
192
|
+
): ClientJudgement {
|
|
193
|
+
const range = consoleRange(client, atLeast);
|
|
194
|
+
if (compareVersions(server, range.atLeast) < 0) {
|
|
195
|
+
return { verdict: "outdated", range };
|
|
196
|
+
}
|
|
197
|
+
if (compareVersions(server, range.below) >= 0) {
|
|
198
|
+
return { verdict: "too_new", range };
|
|
199
|
+
}
|
|
200
|
+
const order = compareVersions(server, client);
|
|
201
|
+
return { verdict: order === 0 ? "current" : order < 0 ? "behind" : "ahead", range };
|
|
202
|
+
}
|
|
203
|
+
|
|
155
204
|
/** What the command sends as its user-agent: its product token, and, in a comment, where it runs. */
|
|
156
205
|
export function userAgentOf(version: string, comment?: string): string {
|
|
157
206
|
// A comment holds printable ASCII without parentheses or backslashes; nothing else is said.
|