@skillcdn/console 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -10
- package/dist/api.d.ts +5 -5
- 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 +5 -0
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +100 -43
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/directory.d.ts +14 -0
- package/dist/cli/directory.d.ts.map +1 -0
- package/dist/cli/directory.js +46 -0
- package/dist/cli/directory.js.map +1 -0
- package/dist/cli/format.d.ts +6 -3
- package/dist/cli/format.d.ts.map +1 -1
- package/dist/cli/format.js +17 -6
- package/dist/cli/format.js.map +1 -1
- package/dist/cli/help.d.ts +2 -2
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +25 -11
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/main.js +9 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/client.d.ts +39 -10
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +54 -33
- package/dist/client.js.map +1 -1
- package/dist/components/event-feed.d.ts.map +1 -1
- package/dist/components/event-feed.js +34 -14
- package/dist/components/event-feed.js.map +1 -1
- package/dist/components/projects.d.ts +41 -0
- package/dist/components/projects.d.ts.map +1 -0
- package/dist/components/projects.js +81 -0
- package/dist/components/projects.js.map +1 -0
- package/dist/components/runs.d.ts +2 -2
- package/dist/components/runs.d.ts.map +1 -1
- package/dist/components/runs.js +2 -2
- package/dist/components/runs.js.map +1 -1
- package/dist/components/shell.d.ts +5 -0
- package/dist/components/shell.d.ts.map +1 -1
- package/dist/components/shell.js +1 -1
- package/dist/components/shell.js.map +1 -1
- package/dist/components/task-view.d.ts +5 -1
- package/dist/components/task-view.d.ts.map +1 -1
- package/dist/components/task-view.js +2 -1
- package/dist/components/task-view.js.map +1 -1
- package/dist/console.css +91 -1
- package/dist/console.d.ts +3 -0
- package/dist/console.d.ts.map +1 -1
- package/dist/console.js +148 -39
- package/dist/console.js.map +1 -1
- package/dist/data.d.ts +33 -10
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +202 -81
- package/dist/data.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/limits.d.ts +7 -0
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +7 -0
- package/dist/limits.js.map +1 -1
- package/dist/router.d.ts +22 -7
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +36 -22
- package/dist/router.js.map +1 -1
- package/dist/routes.d.ts +14 -12
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +28 -11
- package/dist/routes.js.map +1 -1
- package/dist/schemas.d.ts +163 -28
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +99 -27
- package/dist/schemas.js.map +1 -1
- package/dist/vocabulary.d.ts +7 -1
- package/dist/vocabulary.d.ts.map +1 -1
- package/dist/vocabulary.js +9 -0
- package/dist/vocabulary.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,25 +30,27 @@ const { items } = await client.tasks({ state: "ready" });
|
|
|
30
30
|
|
|
31
31
|
- **The vocabulary:** `TASK_STATES`, `TASK_PRIORITIES`, `RUN_STATUSES`, `EVENT_KINDS`, with their types. One source for the database's constraints, the schemas and the board.
|
|
32
32
|
- **The bounds** every input is held to (`MAX_TITLE_LENGTH`, `MAX_BODY_LENGTH`, `MAX_OPTIONS`, ...), so that a page can say so before a request is made.
|
|
33
|
-
- **The routes:** `REST_ROUTES
|
|
34
|
-
- **The schemas,** in the mini build of zod, which runs in a browser: what the server answers (`restTaskSchema`, `restDecisionSchema`, `restEventSchema`, `restMeSchema`, ...) and what it is sent (`restTaskInputSchema`, `restTaskPatchSchema`, `restDecisionInputSchema`, `restAnswerInputSchema
|
|
35
|
-
- **The client:** `createClient({ baseUrl, fetch })` answers typed values parsed with those schemas, and throws an `ApiError` with the server's stable `code` (or `network`, `invalid_response`) for anything else. It takes a `fetch` and reads nothing else. With `token`, a token a person made on their Tokens page, every request carries `Authorization: Bearer` and no cookie: how a script or a console of a person's own acts as that person. An `EventSource` cannot carry a header, so a stream read with a token is a `fetch` of `eventStreamUrl(after)`. `handInFile` sends a file as a form, and `fileUrl` says where its bytes are read back. `
|
|
33
|
+
- **The routes:** `REST_ROUTES` (the workspace's resources), `AUTH_ROUTES`, and the helpers that build a path (`projectPath(key, collection, id)` for everything under a project, `restPath`, `loginPath`, `signInPath`). The API itself is described in [docs/specs/rest.md](https://github.com/skillcdn/console/blob/main/docs/specs/rest.md).
|
|
34
|
+
- **The schemas,** in the mini build of zod, which runs in a browser: what the server answers (`restProjectSchema`, `restMemberSchema`, `restTaskSchema`, `restDecisionSchema`, `restEventSchema`, `restMeSchema`, ...) and what it is sent (`restProjectInputSchema`, `restTaskInputSchema`, `restTaskPatchSchema`, `restDecisionInputSchema`, `restAnswerInputSchema`, ...). Absent values are `null` on the wire, never missing keys. The server validates with the input schemas and is tested against the others.
|
|
35
|
+
- **The client:** `createClient({ baseUrl, fetch })` answers typed values parsed with those schemas, and throws an `ApiError` with the server's stable `code` (or `network`, `invalid_response`) for anything else. It takes a `fetch` and reads nothing else. With `token`, a token a person made on their Tokens page, every request carries `Authorization: Bearer` and no cookie: how a script or a console of a person's own acts as that person. The board is a project's: `client.projects()` lists those the person may see, and `client.project(key)` is the client of one, with its tasks, decisions, runs, files, events, skills, settings and members. An `EventSource` cannot carry a header, so a stream read with a token is a `fetch` of `eventStreamUrl(after)`. `handInFile` sends a file as a form, and `fileUrl` says where its bytes are read back. `events(after, { task })` is everything that happened to one task.
|
|
36
36
|
|
|
37
37
|
### The command line
|
|
38
38
|
|
|
39
39
|
```sh
|
|
40
|
-
npm install -g @skillcdn/console # where the agent runs
|
|
40
|
+
npm install -g @skillcdn/console # where the agent runs
|
|
41
41
|
console login --url https://console.example # asks for a token made on the Tokens page, and keeps it
|
|
42
|
-
console
|
|
42
|
+
console use web # the project this directory works in; .skillcdn-console.json, committed
|
|
43
|
+
console take 7 # a run begins on task #7 of the project, for the person the token is
|
|
43
44
|
console report "Found the cause: the parser trusts its input."
|
|
44
45
|
console hand-in ./report.md --label "the report" # a file the console keeps, or an https link
|
|
45
|
-
console skills # the
|
|
46
|
+
console skills # the project's skills, with the URI to load each by
|
|
46
47
|
console ask "Keep the old behaviour?" --option "Keep it" --option "Change it"
|
|
47
48
|
console finish --summary "Done: the parser refuses empty input."
|
|
48
49
|
```
|
|
49
50
|
|
|
50
|
-
- **`console`** is the agent's side of the console ([docs/specs/cli.md](https://github.com/skillcdn/console/blob/main/docs/specs/cli.md)): a thin client of the REST API with no logic of its own, no dependencies beyond the package's, and no cost to an agent until it is used. `console help` says everything an agent needs; `--json` answers with the console's own JSON; the exit code says whether the console did it (`0`), refused or could not be reached (`1`), did not understand (`2`), or a decision still waits (`3`).
|
|
51
|
+
- **`console`** is the agent's side of the console ([docs/specs/cli.md](https://github.com/skillcdn/console/blob/main/docs/specs/cli.md)): a thin client of the REST API with no logic of its own, no dependencies beyond the package's, and no cost to an agent until it is used. `console help` says everything an agent needs and `console --version` which version this is; `--json` answers with the console's own JSON; the exit code says whether the console did it (`0`), refused or could not be reached (`1`), did not understand (`2`), or a decision still waits (`3`).
|
|
51
52
|
- **A person signs it in once:** `login` checks the token against the console and keeps it, with the console's address, in `$XDG_CONFIG_HOME/skillcdn-console/credentials.json` (`~/.config` when unset). `CONSOLE_URL` and `CONSOLE_TOKEN` in the environment win over the file, for a hook or a job. A token is never taken on the command line.
|
|
53
|
+
- **Every command on the board works in one project:** `--project <key>`, else `CONSOLE_PROJECT`, else what `console use <key>` wrote to `.skillcdn-console.json` in the working directory or one above it, a file meant to be committed. `console projects` lists the projects the person may work in.
|
|
52
54
|
- **`@skillcdn/console/cli`** exports `runCli(argv, io)`, the command as a function that takes its environment, its streams, its `fetch` and its credential store: what the integration tests run against the app with no socket, and what a console of a person's own could embed.
|
|
53
55
|
|
|
54
56
|
### The components and the composition
|
|
@@ -59,12 +61,12 @@ import "@skillcdn/console/console.css";
|
|
|
59
61
|
|
|
60
62
|
createConsole({
|
|
61
63
|
title: "Acme", // until the server says what the board is called
|
|
62
|
-
components: { SignIn: MySignIn }, // any of Shell, Board, TaskView, DecisionList, EventFeed, SignIn, TokenList, PeopleList, SkillList
|
|
64
|
+
components: { SignIn: MySignIn }, // any of Shell, Board, TaskView, DecisionList, EventFeed, SignIn, TokenList, PeopleList, SkillList, ProjectList, MemberList
|
|
63
65
|
}).mount(document.getElementById("root"));
|
|
64
66
|
```
|
|
65
67
|
|
|
66
|
-
- **The components** take their data as props and nothing from the network: `Board` (one column per state), `TaskCard`, `TaskView` (one task with its decisions and its parts), `TaskForm`, `DecisionList` and `DecisionCard` (the waiting first, each with the way to answer), `DecisionForm`, `EventFeed` (a sentence per event, newest first; `describeEvent` makes the sentence), `Shell` (the header with the pages and the person), `SignIn` (one button per provider the deployment offers), `TokenList`, `TokenForm` and `NewToken` (the tokens a person holds, the way to make one, and the one just made with its secret shown once), `PeopleList` (everyone, with what each is, and the way for an administrator to change it), `
|
|
67
|
-
- **The composition:** `createConsole(config)` returns `{ App, mount }`. `App` is the whole console as one component; `mount(container)` renders it and returns the way to take it down. `config.baseUrl` is the origin of the API (the page's own when left out), `config.components` the pieces to replace (`ConsoleComponents` names them with the props each takes), `config.client` a client of your own, for tests. The pages route in the browser (`matchRoute`, `PATHS`, `taskHref`); the
|
|
68
|
+
- **The components** take their data as props and nothing from the network: `Board` (one column per state), `TaskCard`, `TaskView` (one task with its decisions and its parts), `TaskForm`, `DecisionList` and `DecisionCard` (the waiting first, each with the way to answer), `DecisionForm`, `EventFeed` (a sentence per event, newest first; `describeEvent` makes the sentence), `Shell` (the header with the pages and the person), `SignIn` (one button per provider the deployment offers), `TokenList`, `TokenForm` and `NewToken` (the tokens a person holds, the way to make one, and the one just made with its secret shown once), `PeopleList` (everyone, with what each is, and the way for an administrator to change it), `ProjectList`, `ProjectForm` and `MemberList` (the projects a person may see with what they are in each, the way to make or change one, and those listed in a project with the way for an owner to add, change and remove them; `ProjectRoleBadge`, `PROJECT_ROLE_LABELS`, `VISIBILITY_LABELS` and `keyOf` with them), `SkillList` (a project's skills as SkillCDN serves them at its address, each with where a person reads it and what an agent loads it by), `RunList` and `RunCard` (an agent at work on a task: what it reported, what it handed in, links and files alike, what it waits for; `RunStatusBadge` and `RUN_STATUS_LABELS` with them, and `fileHref` for where a file is read), and `Markdown`, which renders what people and agents wrote as elements, never as HTML, with links to the web only and pictures over https only. The small blocks (`Button`, `Badge`, `Avatar`, `PersonChip`, `Callout`, `EmptyState`, `Spinner`, `Time`) and the words of the vocabulary (`STATE_LABELS`, `PRIORITY_LABELS`, `ROLE_LABELS`, with `RoleBadge`) are exported too.
|
|
69
|
+
- **The composition:** `createConsole(config)` returns `{ App, mount }`. `App` is the whole console as one component; `mount(container)` renders it and returns the way to take it down. `config.baseUrl` is the origin of the API (the page's own when left out), `config.components` the pieces to replace (`ConsoleComponents` names them with the props each takes), `config.client` a client of your own, for tests. The pages route in the browser: the projects at `/`, a project's pages under `/p/<key>` (`matchRoute`, `PATHS`, `projectHref`, `taskHref`); the workspace is loaded once and the project the page is on whole, kept current by the project's stream (`useConsoleData(client, projectKey)`, for a composition of your own).
|
|
68
70
|
- **The styles** are one file, `@skillcdn/console/console.css`: the tokens (`--sc-*`), a small reset, and one class per block, all prefixed `sc-`. Re-skinning starts and mostly ends with the tokens.
|
|
69
71
|
- React 19 is a peer dependency; `react-markdown` and `remark-gfm` are the package's own.
|
|
70
72
|
|
package/dist/api.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { ApiError, type ClientOptions, type ConsoleClient, createClient, type FetchLike, type FileUpload, } from "./client.js";
|
|
2
|
-
export { DEFAULT_TOKEN_DAYS, EVENTS_PAGE_LIMIT, LIST_LIMIT, MAX_AGENT_LENGTH, MAX_ARTIFACTS_PER_RUN, MAX_BODY_LENGTH, MAX_FILE_BYTES, MAX_FILE_NAME_LENGTH, MAX_LINK_LABEL_LENGTH, MAX_LINKS, MAX_NOTE_LENGTH, MAX_OPTION_LABEL_LENGTH, MAX_OPTIONS, MAX_QUESTION_LENGTH, MAX_REPORTS_PER_RUN, MAX_SUMMARY_LENGTH, MAX_TITLE_LENGTH, MAX_TOKEN_DAYS, MAX_TOKEN_NAME_LENGTH, MAX_TOKENS_PER_PERSON, MAX_URL_LENGTH, MIN_OPTIONS, } from "./limits.js";
|
|
3
|
-
export { AUTH_ROUTES, isSignInFailure, loginPath, REST_ROUTES, RETURN_TO_PARAM, restPath, SIGN_IN_FAILURES, SIGN_IN_PARAM, type SignInFailure, signInPath, } from "./routes.js";
|
|
4
|
-
export { type RestAnswerInput, type RestArtifact, type RestArtifactInput, type RestDecision, type RestDecisionInput, type RestDecisionOption, type RestDecisions, type RestError, type RestEvent, type RestEventData, type RestEvents, type RestFile, type RestFileInput, type RestMe, type RestPeople, type RestPerson, type RestPersonPatch, type RestProvider, type RestReport, type RestReportInput, type RestRun, type RestRunEndInput, type RestRunInput, type RestRuns, type RestSkill, type RestSkills, type RestTask, type RestTaskInput, type RestTaskLink, type RestTaskPatch, type RestTasks, type RestToken, type RestTokenCreated, type RestTokenInput, type RestTokens, restAnswerInputSchema, restArtifactInputSchema, restArtifactSchema, restDecisionInputSchema, restDecisionOptionSchema, restDecisionSchema, restDecisionsSchema, restErrorSchema, restEventDataSchema, restEventSchema, restEventsSchema, restFileInputSchema, restFileSchema, restMeSchema, restPeopleSchema, restPersonPatchSchema, restPersonSchema, restProviderSchema, restReportInputSchema, restReportSchema, restRunEndInputSchema, restRunInputSchema, restRunSchema, restRunsSchema, restSkillSchema, restSkillsSchema, restTaskInputSchema, restTaskLinkSchema, restTaskPatchSchema, restTaskSchema, restTasksSchema, restTokenCreatedSchema, restTokenInputSchema, restTokenSchema, restTokensSchema, } from "./schemas.js";
|
|
1
|
+
export { ApiError, type ClientOptions, type ConsoleClient, createClient, type EventFilter, type FetchLike, type FileUpload, type ProjectClient, } from "./client.js";
|
|
2
|
+
export { DEFAULT_TOKEN_DAYS, EVENTS_PAGE_LIMIT, LIST_LIMIT, MAX_AGENT_LENGTH, MAX_ARTIFACTS_PER_RUN, MAX_BODY_LENGTH, MAX_FILE_BYTES, MAX_FILE_NAME_LENGTH, MAX_LINK_LABEL_LENGTH, MAX_LINKS, MAX_NOTE_LENGTH, MAX_OPTION_LABEL_LENGTH, MAX_OPTIONS, MAX_PROJECT_DESCRIPTION_LENGTH, MAX_PROJECT_KEY_LENGTH, MAX_PROJECT_NAME_LENGTH, MAX_QUESTION_LENGTH, MAX_REPORTS_PER_RUN, MAX_SKILLS_ADDRESS_LENGTH, MAX_SUMMARY_LENGTH, MAX_TITLE_LENGTH, MAX_TOKEN_DAYS, MAX_TOKEN_NAME_LENGTH, MAX_TOKENS_PER_PERSON, MAX_URL_LENGTH, MIN_OPTIONS, } from "./limits.js";
|
|
3
|
+
export { AUTH_ROUTES, isSignInFailure, loginPath, PROJECT_COLLECTIONS, type ProjectCollection, projectPath, REST_ROUTES, RETURN_TO_PARAM, restPath, SIGN_IN_FAILURES, SIGN_IN_PARAM, type SignInFailure, signInPath, } from "./routes.js";
|
|
4
|
+
export { type RestAnswerInput, type RestArtifact, type RestArtifactInput, type RestDecision, type RestDecisionInput, type RestDecisionOption, type RestDecisions, type RestError, type RestEvent, type RestEventData, type RestEvents, type RestFile, type RestFileInput, type RestMe, type RestMember, type RestMemberInput, type RestMemberPatch, type RestMembers, type RestPeople, type RestPerson, type RestPersonPatch, type RestProject, type RestProjectInput, type RestProjectPatch, type RestProjects, type RestProvider, type RestReport, type RestReportInput, type RestRun, type RestRunEndInput, type RestRunInput, type RestRuns, type RestSkill, type RestSkills, type RestTask, type RestTaskInput, type RestTaskLink, type RestTaskPatch, type RestTasks, type RestToken, type RestTokenCreated, type RestTokenInput, type RestTokens, restAnswerInputSchema, restArtifactInputSchema, restArtifactSchema, restDecisionInputSchema, restDecisionOptionSchema, restDecisionSchema, restDecisionsSchema, restErrorSchema, restEventDataSchema, restEventSchema, restEventsSchema, restFileInputSchema, restFileSchema, restMemberInputSchema, restMemberPatchSchema, restMemberSchema, restMembersSchema, restMeSchema, restPeopleSchema, restPersonPatchSchema, restPersonSchema, restProjectInputSchema, restProjectPatchSchema, restProjectSchema, restProjectsSchema, restProviderSchema, restReportInputSchema, restReportSchema, restRunEndInputSchema, restRunInputSchema, restRunSchema, restRunsSchema, restSkillSchema, restSkillsSchema, restTaskInputSchema, restTaskLinkSchema, restTaskPatchSchema, restTaskSchema, restTasksSchema, restTokenCreatedSchema, restTokenInputSchema, restTokenSchema, restTokensSchema, } from "./schemas.js";
|
|
5
5
|
export { hasForbiddenCodePoint } from "./text.js";
|
|
6
|
-
export { ARTIFACT_KINDS, type ArtifactKind, EVENT_KINDS, type EventKind, isProviderKey, PERSON_ROLES, type PersonRole, PROVIDER_KEYS, type ProviderKey, RUN_ENDINGS, RUN_STATUSES, type RunEnding, type RunStatus, SKILLS_STATUSES, type SkillsStatus, TASK_PRIORITIES, TASK_STATES, type TaskPriority, type TaskState, } from "./vocabulary.js";
|
|
6
|
+
export { ARTIFACT_KINDS, type ArtifactKind, EVENT_KINDS, type EventKind, isProviderKey, PERSON_ROLES, type PersonRole, PROJECT_ROLES, PROJECT_VISIBILITIES, PROVIDER_KEYS, type ProjectRole, type ProjectVisibility, type ProviderKey, RUN_ENDINGS, RUN_STATUSES, type RunEnding, type RunStatus, SKILLS_STATUSES, type SkillsStatus, TASK_PRIORITIES, TASK_STATES, type TaskPriority, type TaskState, } from "./vocabulary.js";
|
|
7
7
|
//# sourceMappingURL=api.d.ts.map
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,QAAQ,EACR,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,YAAY,EACZ,KAAK,SAAS,EACd,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
// custom UI talks to any console with types, and so that the contract has one source. No React
|
|
4
4
|
// here: the server and the command line import this entry point, and nothing of the pages.
|
|
5
5
|
export { ApiError, createClient, } from "./client.js";
|
|
6
|
-
export { DEFAULT_TOKEN_DAYS, EVENTS_PAGE_LIMIT, LIST_LIMIT, MAX_AGENT_LENGTH, MAX_ARTIFACTS_PER_RUN, MAX_BODY_LENGTH, MAX_FILE_BYTES, MAX_FILE_NAME_LENGTH, MAX_LINK_LABEL_LENGTH, MAX_LINKS, MAX_NOTE_LENGTH, MAX_OPTION_LABEL_LENGTH, MAX_OPTIONS, MAX_QUESTION_LENGTH, MAX_REPORTS_PER_RUN, MAX_SUMMARY_LENGTH, MAX_TITLE_LENGTH, MAX_TOKEN_DAYS, MAX_TOKEN_NAME_LENGTH, MAX_TOKENS_PER_PERSON, MAX_URL_LENGTH, MIN_OPTIONS, } from "./limits.js";
|
|
7
|
-
export { AUTH_ROUTES, isSignInFailure, loginPath, REST_ROUTES, RETURN_TO_PARAM, restPath, SIGN_IN_FAILURES, SIGN_IN_PARAM, signInPath, } from "./routes.js";
|
|
8
|
-
export { restAnswerInputSchema, restArtifactInputSchema, restArtifactSchema, restDecisionInputSchema, restDecisionOptionSchema, restDecisionSchema, restDecisionsSchema, restErrorSchema, restEventDataSchema, restEventSchema, restEventsSchema, restFileInputSchema, restFileSchema, restMeSchema, restPeopleSchema, restPersonPatchSchema, restPersonSchema, restProviderSchema, restReportInputSchema, restReportSchema, restRunEndInputSchema, restRunInputSchema, restRunSchema, restRunsSchema, restSkillSchema, restSkillsSchema, restTaskInputSchema, restTaskLinkSchema, restTaskPatchSchema, restTaskSchema, restTasksSchema, restTokenCreatedSchema, restTokenInputSchema, restTokenSchema, restTokensSchema, } from "./schemas.js";
|
|
6
|
+
export { DEFAULT_TOKEN_DAYS, EVENTS_PAGE_LIMIT, LIST_LIMIT, MAX_AGENT_LENGTH, MAX_ARTIFACTS_PER_RUN, MAX_BODY_LENGTH, MAX_FILE_BYTES, MAX_FILE_NAME_LENGTH, MAX_LINK_LABEL_LENGTH, MAX_LINKS, MAX_NOTE_LENGTH, MAX_OPTION_LABEL_LENGTH, MAX_OPTIONS, MAX_PROJECT_DESCRIPTION_LENGTH, MAX_PROJECT_KEY_LENGTH, MAX_PROJECT_NAME_LENGTH, MAX_QUESTION_LENGTH, MAX_REPORTS_PER_RUN, MAX_SKILLS_ADDRESS_LENGTH, MAX_SUMMARY_LENGTH, MAX_TITLE_LENGTH, MAX_TOKEN_DAYS, MAX_TOKEN_NAME_LENGTH, MAX_TOKENS_PER_PERSON, MAX_URL_LENGTH, MIN_OPTIONS, } from "./limits.js";
|
|
7
|
+
export { AUTH_ROUTES, isSignInFailure, loginPath, PROJECT_COLLECTIONS, projectPath, REST_ROUTES, RETURN_TO_PARAM, restPath, SIGN_IN_FAILURES, SIGN_IN_PARAM, signInPath, } from "./routes.js";
|
|
8
|
+
export { restAnswerInputSchema, restArtifactInputSchema, restArtifactSchema, restDecisionInputSchema, restDecisionOptionSchema, restDecisionSchema, restDecisionsSchema, restErrorSchema, restEventDataSchema, restEventSchema, restEventsSchema, restFileInputSchema, restFileSchema, restMemberInputSchema, restMemberPatchSchema, restMemberSchema, restMembersSchema, restMeSchema, restPeopleSchema, restPersonPatchSchema, restPersonSchema, restProjectInputSchema, restProjectPatchSchema, restProjectSchema, restProjectsSchema, restProviderSchema, restReportInputSchema, restReportSchema, restRunEndInputSchema, restRunInputSchema, restRunSchema, restRunsSchema, restSkillSchema, restSkillsSchema, restTaskInputSchema, restTaskLinkSchema, restTaskPatchSchema, restTaskSchema, restTasksSchema, restTokenCreatedSchema, restTokenInputSchema, restTokenSchema, restTokensSchema, } from "./schemas.js";
|
|
9
9
|
export { hasForbiddenCodePoint } from "./text.js";
|
|
10
|
-
export { ARTIFACT_KINDS, EVENT_KINDS, isProviderKey, PERSON_ROLES, PROVIDER_KEYS, RUN_ENDINGS, RUN_STATUSES, SKILLS_STATUSES, TASK_PRIORITIES, TASK_STATES, } from "./vocabulary.js";
|
|
10
|
+
export { ARTIFACT_KINDS, EVENT_KINDS, isProviderKey, PERSON_ROLES, PROJECT_ROLES, PROJECT_VISIBILITIES, PROVIDER_KEYS, RUN_ENDINGS, RUN_STATUSES, SKILLS_STATUSES, TASK_PRIORITIES, TASK_STATES, } from "./vocabulary.js";
|
|
11
11
|
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,8FAA8F;AAC9F,+FAA+F;AAC/F,2FAA2F;AAE3F,OAAO,EACL,QAAQ,EAGR,YAAY,
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,8FAA8F;AAC9F,+FAA+F;AAC/F,2FAA2F;AAE3F,OAAO,EACL,QAAQ,EAGR,YAAY,GAKb,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,qBAAqB,EACrB,SAAS,EACT,eAAe,EACf,uBAAuB,EACvB,WAAW,EACX,8BAA8B,EAC9B,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,yBAAyB,EACzB,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACd,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,WAAW,EACX,eAAe,EACf,SAAS,EACT,mBAAmB,EAEnB,WAAW,EACX,WAAW,EACX,eAAe,EACf,QAAQ,EACR,gBAAgB,EAChB,aAAa,EAEb,UAAU,GACX,MAAM,aAAa,CAAC;AACrB,OAAO,EA4CL,qBAAqB,EACrB,uBAAuB,EACvB,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,EAChB,sBAAsB,EACtB,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EACL,cAAc,EAEd,WAAW,EAEX,aAAa,EACb,YAAY,EAEZ,aAAa,EACb,oBAAoB,EACpB,aAAa,EAIb,WAAW,EACX,YAAY,EAGZ,eAAe,EAEf,eAAe,EACf,WAAW,GAGZ,MAAM,iBAAiB,CAAC"}
|
package/dist/cli/cli.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type FetchLike } from "../client.js";
|
|
2
2
|
import type { CredentialStore } from "./credentials.js";
|
|
3
|
+
import type { DirectoryStore } from "./directory.js";
|
|
3
4
|
/** The exit codes of the command, for whoever runs it: a shell, a hook, an agent. */
|
|
4
5
|
export declare const EXIT: {
|
|
5
6
|
readonly ok: 0;
|
|
@@ -24,8 +25,12 @@ export interface CliIo {
|
|
|
24
25
|
/** A file handed in, as bytes. */
|
|
25
26
|
readonly readBytes: (path: string) => Promise<Uint8Array>;
|
|
26
27
|
readonly store: CredentialStore;
|
|
28
|
+
/** What the working directory says of the project, and the way to write it. */
|
|
29
|
+
readonly directory: DirectoryStore;
|
|
27
30
|
readonly sleep: (ms: number) => Promise<void>;
|
|
28
31
|
readonly now: () => number;
|
|
32
|
+
/** The version of the package the command runs from, when the entry point knows it. */
|
|
33
|
+
readonly version?: string | undefined;
|
|
29
34
|
}
|
|
30
35
|
/** Runs the command and answers with its exit code. What it prints goes through `io`. */
|
|
31
36
|
export declare function runCli(argv: readonly string[], io: CliIo): Promise<number>;
|
package/dist/cli/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli/cli.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli/cli.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,cAAc,CAAC;AAItB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAqBrD,qFAAqF;AACrF,eAAO,MAAM,IAAI;aACf,EAAE,EAAE,CAAC;IACL,6EAA6E;aAC7E,MAAM,EAAE,CAAC;IACT,sCAAsC;aACtC,KAAK,EAAE,CAAC;IACR,6CAA6C;aAC7C,OAAO,EAAE,CAAC;CACF,CAAC;AAWX,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC3D,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,sDAAsD;IACtD,QAAQ,CAAC,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,gFAAgF;IAChF,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACzD,2CAA2C;IAC3C,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,kCAAkC;IAClC,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1D,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,+EAA+E;IAC/E,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;IAC3B,uFAAuF;IACvF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAqsBD,yFAAyF;AACzF,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CA6BhF"}
|
package/dist/cli/cli.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { basename, extname } from "node:path";
|
|
2
2
|
import { parseArgs } from "node:util";
|
|
3
|
-
import { ApiError, createClient } from "../client.js";
|
|
3
|
+
import { ApiError, createClient, } from "../client.js";
|
|
4
4
|
import { MAX_OPTIONS, MIN_OPTIONS } from "../limits.js";
|
|
5
5
|
import { TASK_PRIORITIES, TASK_STATES } from "../vocabulary.js";
|
|
6
|
-
import { formatAnswer, formatDecision, formatDecisionLine, formatOptions, formatRun, formatRunLine, formatSkills, formatTask, formatTaskLine, } from "./format.js";
|
|
6
|
+
import { formatAnswer, formatDecision, formatDecisionLine, formatOptions, formatProjectLine, formatRun, formatRunLine, formatSkills, formatTask, formatTaskLine, } from "./format.js";
|
|
7
7
|
import { COMMAND_HELP, helpFor, usage } from "./help.js";
|
|
8
8
|
// The `console` command (docs/specs/cli.md): the agent's side of the console. A thin client of
|
|
9
9
|
// the REST API with no logic of its own: every command is one or two requests and the words to
|
|
10
10
|
// say what came back. It takes what it needs from `CliIo`, so that tests run it whole, against
|
|
11
|
-
// the app and no socket, with a store and readers of their own.
|
|
11
|
+
// the app and no socket, with a store and readers of their own. The board is a project's: every
|
|
12
|
+
// command on it works in the project the flag, the environment or the working directory names.
|
|
12
13
|
/** The exit codes of the command, for whoever runs it: a shell, a hook, an agent. */
|
|
13
14
|
export const EXIT = {
|
|
14
15
|
ok: 0,
|
|
@@ -38,7 +39,11 @@ class CliExit extends Error {
|
|
|
38
39
|
}
|
|
39
40
|
const failed = (message) => new CliExit(EXIT.failed, message);
|
|
40
41
|
const misuse = (message) => new CliExit(EXIT.usage, message);
|
|
41
|
-
const GLOBAL_OPTIONS = {
|
|
42
|
+
const GLOBAL_OPTIONS = {
|
|
43
|
+
json: { type: "boolean" },
|
|
44
|
+
url: { type: "string" },
|
|
45
|
+
project: { type: "string" },
|
|
46
|
+
};
|
|
42
47
|
function parse(args, options, allowPositionals = true) {
|
|
43
48
|
try {
|
|
44
49
|
return parseArgs({
|
|
@@ -64,6 +69,7 @@ const texts = (values, name) => {
|
|
|
64
69
|
}
|
|
65
70
|
return typeof value === "string" ? [value] : [];
|
|
66
71
|
};
|
|
72
|
+
const NO_PROJECT = "Say which project: --project <key>, CONSOLE_PROJECT in the environment, or console use <key> once in this directory. console projects lists the projects you may work in.";
|
|
67
73
|
/** The console and the token to talk to it with: the flags, the environment, then what login kept. */
|
|
68
74
|
async function open(io, values) {
|
|
69
75
|
const stored = await io.store.load();
|
|
@@ -72,29 +78,39 @@ async function open(io, values) {
|
|
|
72
78
|
if (url === undefined || token === undefined) {
|
|
73
79
|
throw failed("Not signed in. A person signs the command in: console login --url <the console's origin>");
|
|
74
80
|
}
|
|
81
|
+
const client = createClient({ baseUrl: url, token, fetch: io.fetch });
|
|
82
|
+
const projectKey = async () => text(values, "project") ?? io.env.CONSOLE_PROJECT ?? (await io.directory.load())?.project;
|
|
75
83
|
return {
|
|
76
|
-
client
|
|
84
|
+
client,
|
|
77
85
|
url,
|
|
78
86
|
json: on(values, "json"),
|
|
87
|
+
projectKey,
|
|
88
|
+
async project() {
|
|
89
|
+
const key = await projectKey();
|
|
90
|
+
if (key === undefined) {
|
|
91
|
+
throw failed(NO_PROJECT);
|
|
92
|
+
}
|
|
93
|
+
return client.project(key);
|
|
94
|
+
},
|
|
79
95
|
};
|
|
80
96
|
}
|
|
81
97
|
/** Prints what came back: the console's JSON on `--json`, the words otherwise. */
|
|
82
98
|
function answer(io, session, value, words) {
|
|
83
99
|
io.stdout(session.json ? `${JSON.stringify(value, null, 2)}\n` : `${words()}\n`);
|
|
84
100
|
}
|
|
85
|
-
/** The run a command on a run means: the one named, else the one open run of this token. */
|
|
86
|
-
async function currentRun(
|
|
101
|
+
/** The run a command on a run means: the one named, else the one open run of this token in the project. */
|
|
102
|
+
async function currentRun(project, values) {
|
|
87
103
|
const given = text(values, "run");
|
|
88
104
|
if (given !== undefined) {
|
|
89
105
|
return given;
|
|
90
106
|
}
|
|
91
|
-
const { items } = await
|
|
107
|
+
const { items } = await project.runs({ open: true, mine: true });
|
|
92
108
|
const [only] = items;
|
|
93
109
|
if (only !== undefined && items.length === 1) {
|
|
94
110
|
return only.id;
|
|
95
111
|
}
|
|
96
112
|
if (items.length === 0) {
|
|
97
|
-
throw failed("No run of yours is open. Take a task first: console take <number>");
|
|
113
|
+
throw failed("No run of yours is open in this project. Take a task first: console take <number>");
|
|
98
114
|
}
|
|
99
115
|
throw failed(`Several runs of yours are open; say which with --run <id>:\n${items.map((run) => ` ${formatRunLine(run)}`).join("\n")}`);
|
|
100
116
|
}
|
|
@@ -159,7 +175,7 @@ function theOne(positionals, ask) {
|
|
|
159
175
|
* The decision once answered, or as it stands when the wait is over. Each request asks the
|
|
160
176
|
* console to hold it for a while, so the answer arrives as soon as a person gives it.
|
|
161
177
|
*/
|
|
162
|
-
async function waitForAnswer(io,
|
|
178
|
+
async function waitForAnswer(io, project, decision, seconds) {
|
|
163
179
|
const deadline = io.now() + seconds * 1000;
|
|
164
180
|
let current = decision;
|
|
165
181
|
for (;;) {
|
|
@@ -167,7 +183,7 @@ async function waitForAnswer(io, client, decision, seconds) {
|
|
|
167
183
|
if (current.answer !== null || left <= 0) {
|
|
168
184
|
return current;
|
|
169
185
|
}
|
|
170
|
-
current = await
|
|
186
|
+
current = await project.awaitDecision(current.id, Math.max(1, Math.min(Math.ceil(left / 1000), WAIT_STEP_SECONDS)));
|
|
171
187
|
if (current.answer === null) {
|
|
172
188
|
await io.sleep(WAIT_PAUSE_MS);
|
|
173
189
|
}
|
|
@@ -178,9 +194,9 @@ const stillWaiting = (id) => `Decision ${id} still waits for a person; the run w
|
|
|
178
194
|
* Waits for the answer and says what it is, or that it is still to come. On `--json`, a decision
|
|
179
195
|
* printed already as it was raised (`shown`) is printed again only with its answer.
|
|
180
196
|
*/
|
|
181
|
-
async function settle(io, session, decision, seconds, shown = false) {
|
|
197
|
+
async function settle(io, session, project, decision, seconds, shown = false) {
|
|
182
198
|
const outcome = decision.answer === null && seconds > 0
|
|
183
|
-
? await waitForAnswer(io,
|
|
199
|
+
? await waitForAnswer(io, project, decision, seconds)
|
|
184
200
|
: decision;
|
|
185
201
|
if (session.json) {
|
|
186
202
|
if (!shown || outcome.answer !== null) {
|
|
@@ -212,7 +228,7 @@ const login = async (args, io) => {
|
|
|
212
228
|
throw failed("The console does not know this token. Make one on your Tokens page and try again.");
|
|
213
229
|
}
|
|
214
230
|
const kept = await io.store.save({ url, token });
|
|
215
|
-
io.stdout(`Signed in to ${me.workspace.name} at ${url} as ${person.login} (${person.role}). The token is kept in ${kept}.\n`);
|
|
231
|
+
io.stdout(`Signed in to ${me.workspace.name} at ${url} as ${person.login} (${person.role}). The token is kept in ${kept}.\nNext, say which project this directory works in: console use <key> (console projects lists them).\n`);
|
|
216
232
|
return EXIT.ok;
|
|
217
233
|
};
|
|
218
234
|
const logout = async (args, io) => {
|
|
@@ -229,21 +245,42 @@ const whoami = async (args, io) => {
|
|
|
229
245
|
if (person === null) {
|
|
230
246
|
throw failed("The console does not know this token. Sign in again: console login");
|
|
231
247
|
}
|
|
232
|
-
|
|
248
|
+
const key = await session.projectKey();
|
|
249
|
+
answer(io, session, { ...me, project: key ?? null }, () => `${person.login} (${person.role}) at ${me.workspace.name}, ${session.url}${key === undefined ? "; no project named here" : `; project ${key}`}`);
|
|
250
|
+
return EXIT.ok;
|
|
251
|
+
};
|
|
252
|
+
const projects = async (args, io) => {
|
|
253
|
+
const { values } = parse(args, {}, false);
|
|
254
|
+
const session = await open(io, values);
|
|
255
|
+
const found = await session.client.projects();
|
|
256
|
+
answer(io, session, found, () => found.items.length === 0
|
|
257
|
+
? "No projects you may work in. A person makes one on the console's Projects page."
|
|
258
|
+
: found.items.map(formatProjectLine).join("\n"));
|
|
259
|
+
return EXIT.ok;
|
|
260
|
+
};
|
|
261
|
+
const use = async (args, io) => {
|
|
262
|
+
const { values, positionals } = parse(args, {});
|
|
263
|
+
const key = theOne(positionals, "Say which project: console use <key>");
|
|
264
|
+
const session = await open(io, values);
|
|
265
|
+
const project = await session.client.project(key).get();
|
|
266
|
+
const kept = await io.directory.save({ project: project.key });
|
|
267
|
+
answer(io, session, project, () => `Working in ${project.name} (${project.key}) from this directory on: kept in ${kept}, which is meant to be committed.`);
|
|
233
268
|
return EXIT.ok;
|
|
234
269
|
};
|
|
235
270
|
const tasks = async (args, io) => {
|
|
236
271
|
const { values } = parse(args, { state: { type: "string" } }, false);
|
|
237
272
|
const state = stateOf(text(values, "state"));
|
|
238
273
|
const session = await open(io, values);
|
|
239
|
-
const
|
|
274
|
+
const project = await session.project();
|
|
275
|
+
const found = await project.tasks(state === undefined ? {} : { state });
|
|
240
276
|
answer(io, session, found, () => found.items.length === 0 ? "No tasks." : found.items.map(formatTaskLine).join("\n"));
|
|
241
277
|
return EXIT.ok;
|
|
242
278
|
};
|
|
243
279
|
const skills = async (args, io) => {
|
|
244
280
|
const { values } = parse(args, {}, false);
|
|
245
281
|
const session = await open(io, values);
|
|
246
|
-
const
|
|
282
|
+
const project = await session.project();
|
|
283
|
+
const found = await project.skills();
|
|
247
284
|
answer(io, session, found, () => formatSkills(found));
|
|
248
285
|
return EXIT.ok;
|
|
249
286
|
};
|
|
@@ -259,7 +296,8 @@ const newTask = async (args, io) => {
|
|
|
259
296
|
const priority = priorityOf(text(values, "priority"));
|
|
260
297
|
const body = await bodyOf(io, values, text(values, "body"));
|
|
261
298
|
const session = await open(io, values);
|
|
262
|
-
const
|
|
299
|
+
const project = await session.project();
|
|
300
|
+
const made = await project.createTask({
|
|
263
301
|
title,
|
|
264
302
|
...(body === undefined ? {} : { body }),
|
|
265
303
|
...(state === undefined ? {} : { state }),
|
|
@@ -275,10 +313,11 @@ const task = async (args, io) => {
|
|
|
275
313
|
const { values, positionals } = parse(args, {});
|
|
276
314
|
const ref = theOne(positionals, "Say which task: console task <number|id>");
|
|
277
315
|
const session = await open(io, values);
|
|
278
|
-
const
|
|
316
|
+
const project = await session.project();
|
|
317
|
+
const found = await project.task(ref);
|
|
279
318
|
const [decisions, runs] = await Promise.all([
|
|
280
|
-
|
|
281
|
-
|
|
319
|
+
project.decisions({ task: found.id }),
|
|
320
|
+
project.runs({ task: found.id }),
|
|
282
321
|
]);
|
|
283
322
|
answer(io, session, { task: found, decisions: decisions.items, runs: runs.items }, () => formatTask(found, decisions.items, runs.items));
|
|
284
323
|
return EXIT.ok;
|
|
@@ -287,9 +326,10 @@ const take = async (args, io) => {
|
|
|
287
326
|
const { values, positionals } = parse(args, { agent: { type: "string" } });
|
|
288
327
|
const ref = theOne(positionals, "Say which task: console take <number|id>");
|
|
289
328
|
const session = await open(io, values);
|
|
290
|
-
const
|
|
329
|
+
const project = await session.project();
|
|
330
|
+
const found = await project.task(ref);
|
|
291
331
|
const agent = text(values, "agent");
|
|
292
|
-
const run = await
|
|
332
|
+
const run = await project.startRun({
|
|
293
333
|
taskId: found.id,
|
|
294
334
|
...(agent === undefined ? {} : { agent }),
|
|
295
335
|
});
|
|
@@ -316,8 +356,9 @@ const report = async (args, io) => {
|
|
|
316
356
|
throw misuse('Say what to report: console report "<markdown>", or --file <path>, or - to read standard input.');
|
|
317
357
|
}
|
|
318
358
|
const session = await open(io, values);
|
|
319
|
-
const
|
|
320
|
-
const
|
|
359
|
+
const project = await session.project();
|
|
360
|
+
const runId = await currentRun(project, values);
|
|
361
|
+
const run = await project.report(runId, { body });
|
|
321
362
|
answer(io, session, run, () => `Reported on run ${run.id}: ${run.reports.length} report${run.reports.length === 1 ? "" : "s"} so far.`);
|
|
322
363
|
return EXIT.ok;
|
|
323
364
|
};
|
|
@@ -349,11 +390,12 @@ const handIn = async (args, io) => {
|
|
|
349
390
|
const what = theOne(positionals, "Say what to hand in: console hand-in <https url | file path> [--label <words>]");
|
|
350
391
|
const label = text(values, "label");
|
|
351
392
|
const session = await open(io, values);
|
|
352
|
-
const
|
|
393
|
+
const project = await session.project();
|
|
394
|
+
const runId = await currentRun(project, values);
|
|
353
395
|
// A URL is handed in as a link, and the console says whether it takes it; anything else
|
|
354
396
|
// names a file on this machine.
|
|
355
397
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(what)) {
|
|
356
|
-
const run = await
|
|
398
|
+
const run = await project.handIn(runId, {
|
|
357
399
|
url: what,
|
|
358
400
|
...(label === undefined ? {} : { label }),
|
|
359
401
|
});
|
|
@@ -369,7 +411,7 @@ const handIn = async (args, io) => {
|
|
|
369
411
|
}
|
|
370
412
|
const name = basename(what);
|
|
371
413
|
const contentType = CONTENT_TYPES[extname(name).toLowerCase()];
|
|
372
|
-
const run = await
|
|
414
|
+
const run = await project.handInFile(runId, {
|
|
373
415
|
name,
|
|
374
416
|
bytes,
|
|
375
417
|
...(contentType === undefined ? {} : { contentType }),
|
|
@@ -394,8 +436,9 @@ const ask = async (args, io) => {
|
|
|
394
436
|
const seconds = secondsOf(text(values, "wait"), DEFAULT_ASK_WAIT_SECONDS);
|
|
395
437
|
const body = await bodyOf(io, values, text(values, "body"));
|
|
396
438
|
const session = await open(io, values);
|
|
397
|
-
const
|
|
398
|
-
const
|
|
439
|
+
const project = await session.project();
|
|
440
|
+
const runId = await currentRun(project, values);
|
|
441
|
+
const raised = await project.raiseDecision({
|
|
399
442
|
question,
|
|
400
443
|
options: options.map((label) => ({ label })),
|
|
401
444
|
runId,
|
|
@@ -405,24 +448,26 @@ const ask = async (args, io) => {
|
|
|
405
448
|
io.stdout(session.json
|
|
406
449
|
? `${JSON.stringify(raised, null, 2)}\n`
|
|
407
450
|
: `Decision ${raised.id} raised on run ${runId}; the run waits for a person.\n${formatOptions(raised)}\n`);
|
|
408
|
-
return settle(io, session, raised, seconds, true);
|
|
451
|
+
return settle(io, session, project, raised, seconds, true);
|
|
409
452
|
};
|
|
410
453
|
const decision = async (args, io) => {
|
|
411
454
|
const { values, positionals } = parse(args, { wait: { type: "string" } });
|
|
412
455
|
const id = theOne(positionals, "Say which decision: console decision <id> [--wait <seconds>]");
|
|
413
456
|
const seconds = secondsOf(text(values, "wait"), 0);
|
|
414
457
|
const session = await open(io, values);
|
|
415
|
-
const
|
|
458
|
+
const project = await session.project();
|
|
459
|
+
const found = await project.decision(id);
|
|
416
460
|
if (seconds === 0) {
|
|
417
461
|
answer(io, session, found, () => formatDecision(found));
|
|
418
462
|
return EXIT.ok;
|
|
419
463
|
}
|
|
420
|
-
return settle(io, session, found, seconds);
|
|
464
|
+
return settle(io, session, project, found, seconds);
|
|
421
465
|
};
|
|
422
466
|
const decisions = async (args, io) => {
|
|
423
467
|
const { values } = parse(args, { open: { type: "boolean" } }, false);
|
|
424
468
|
const session = await open(io, values);
|
|
425
|
-
const
|
|
469
|
+
const project = await session.project();
|
|
470
|
+
const found = await project.decisions(on(values, "open") ? { open: true } : {});
|
|
426
471
|
answer(io, session, found, () => found.items.length === 0 ? "No decisions." : found.items.map(formatDecisionLine).join("\n"));
|
|
427
472
|
return EXIT.ok;
|
|
428
473
|
};
|
|
@@ -430,8 +475,9 @@ const ending = (status) => async (args, io) => {
|
|
|
430
475
|
const { values } = parse(args, { summary: { type: "string" }, file: { type: "string" }, run: { type: "string" } }, false);
|
|
431
476
|
const summary = await bodyOf(io, values, text(values, "summary"));
|
|
432
477
|
const session = await open(io, values);
|
|
433
|
-
const
|
|
434
|
-
const
|
|
478
|
+
const project = await session.project();
|
|
479
|
+
const runId = await currentRun(project, values);
|
|
480
|
+
const run = await project.endRun(runId, {
|
|
435
481
|
status,
|
|
436
482
|
...(summary === undefined ? {} : { summary }),
|
|
437
483
|
});
|
|
@@ -451,8 +497,9 @@ const abandon = async (args, io) => {
|
|
|
451
497
|
}
|
|
452
498
|
const summary = await bodyOf(io, values, text(values, "summary"));
|
|
453
499
|
const session = await open(io, values);
|
|
454
|
-
const
|
|
455
|
-
const
|
|
500
|
+
const project = await session.project();
|
|
501
|
+
const runId = positionals[0] ?? (await currentRun(project, values));
|
|
502
|
+
const run = await project.endRun(runId, {
|
|
456
503
|
status: "abandoned",
|
|
457
504
|
...(summary === undefined ? {} : { summary }),
|
|
458
505
|
});
|
|
@@ -462,9 +509,10 @@ const abandon = async (args, io) => {
|
|
|
462
509
|
const runs = async (args, io) => {
|
|
463
510
|
const { values } = parse(args, { task: { type: "string" }, open: { type: "boolean" }, mine: { type: "boolean" } }, false);
|
|
464
511
|
const session = await open(io, values);
|
|
512
|
+
const project = await session.project();
|
|
465
513
|
const ref = text(values, "task");
|
|
466
|
-
const taskId = ref === undefined ? undefined : (await
|
|
467
|
-
const found = await
|
|
514
|
+
const taskId = ref === undefined ? undefined : (await project.task(ref)).id;
|
|
515
|
+
const found = await project.runs({
|
|
468
516
|
...(taskId === undefined ? {} : { task: taskId }),
|
|
469
517
|
...(on(values, "open") ? { open: true } : {}),
|
|
470
518
|
...(on(values, "mine") ? { mine: true } : {}),
|
|
@@ -476,14 +524,17 @@ const run = async (args, io) => {
|
|
|
476
524
|
const { values, positionals } = parse(args, {});
|
|
477
525
|
const id = theOne(positionals, "Say which run: console run <id>");
|
|
478
526
|
const session = await open(io, values);
|
|
479
|
-
const
|
|
480
|
-
|
|
527
|
+
const project = await session.project();
|
|
528
|
+
const found = await project.run(id);
|
|
529
|
+
answer(io, session, found, () => formatRun(found, (artifactId) => project.fileUrl(artifactId)));
|
|
481
530
|
return EXIT.ok;
|
|
482
531
|
};
|
|
483
532
|
const COMMANDS = {
|
|
484
533
|
login,
|
|
485
534
|
logout,
|
|
486
535
|
whoami,
|
|
536
|
+
projects,
|
|
537
|
+
use,
|
|
487
538
|
tasks,
|
|
488
539
|
task,
|
|
489
540
|
skills,
|
|
@@ -501,7 +552,7 @@ const COMMANDS = {
|
|
|
501
552
|
};
|
|
502
553
|
function help(io, name) {
|
|
503
554
|
if (name === undefined) {
|
|
504
|
-
io.stdout(usage());
|
|
555
|
+
io.stdout(usage(io.version));
|
|
505
556
|
return EXIT.ok;
|
|
506
557
|
}
|
|
507
558
|
const found = helpFor(name);
|
|
@@ -516,6 +567,8 @@ function hintFor(error) {
|
|
|
516
567
|
switch (error.code) {
|
|
517
568
|
case "auth.required":
|
|
518
569
|
return "The token is not one the console knows, any more or at all. A person signs the command in again: console login\n";
|
|
570
|
+
case "project.not_found":
|
|
571
|
+
return "No project has this key, or it is not yours to see. console projects lists the projects you may work in.\n";
|
|
519
572
|
case "network":
|
|
520
573
|
return "Is the console's address right? console whoami --url <origin> says what the command uses.\n";
|
|
521
574
|
default:
|
|
@@ -526,6 +579,10 @@ function hintFor(error) {
|
|
|
526
579
|
export async function runCli(argv, io) {
|
|
527
580
|
const [name, ...rest] = argv;
|
|
528
581
|
try {
|
|
582
|
+
if (name === "--version" || name === "-v" || name === "version") {
|
|
583
|
+
io.stdout(`console ${io.version ?? "(version unknown)"} (@skillcdn/console)\n`);
|
|
584
|
+
return EXIT.ok;
|
|
585
|
+
}
|
|
529
586
|
if (name === undefined || name === "help" || name === "--help" || name === "-h") {
|
|
530
587
|
return help(io, rest[0]);
|
|
531
588
|
}
|