@skillcdn/console 0.1.24 → 0.3.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.
Files changed (85) hide show
  1. package/README.md +6 -5
  2. package/dist/api.d.ts +1 -1
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +1 -1
  5. package/dist/api.js.map +1 -1
  6. package/dist/cli/cli.d.ts.map +1 -1
  7. package/dist/cli/cli.js +64 -65
  8. package/dist/cli/cli.js.map +1 -1
  9. package/dist/cli/format.d.ts +4 -28
  10. package/dist/cli/format.d.ts.map +1 -1
  11. package/dist/cli/format.js +7 -261
  12. package/dist/cli/format.js.map +1 -1
  13. package/dist/cli/help.d.ts.map +1 -1
  14. package/dist/cli/help.js +6 -6
  15. package/dist/cli/help.js.map +1 -1
  16. package/dist/cli/pack.d.ts +46 -0
  17. package/dist/cli/pack.d.ts.map +1 -0
  18. package/dist/cli/pack.js +250 -0
  19. package/dist/cli/pack.js.map +1 -0
  20. package/dist/compat.d.ts +1 -1
  21. package/dist/compat.js +1 -1
  22. package/dist/components/decision-list.d.ts +13 -1
  23. package/dist/components/decision-list.d.ts.map +1 -1
  24. package/dist/components/decision-list.js +74 -29
  25. package/dist/components/decision-list.js.map +1 -1
  26. package/dist/components/paged.d.ts +24 -0
  27. package/dist/components/paged.d.ts.map +1 -1
  28. package/dist/components/paged.js +40 -4
  29. package/dist/components/paged.js.map +1 -1
  30. package/dist/components/skills.d.ts.map +1 -1
  31. package/dist/components/skills.js +8 -4
  32. package/dist/components/skills.js.map +1 -1
  33. package/dist/components/ui.d.ts +2 -0
  34. package/dist/components/ui.d.ts.map +1 -1
  35. package/dist/components/ui.js +7 -2
  36. package/dist/components/ui.js.map +1 -1
  37. package/dist/console.css +112 -5
  38. package/dist/console.d.ts.map +1 -1
  39. package/dist/console.js +2 -2
  40. package/dist/console.js.map +1 -1
  41. package/dist/data.d.ts.map +1 -1
  42. package/dist/data.js +27 -2
  43. package/dist/data.js.map +1 -1
  44. package/dist/i18n/en.d.ts +13 -0
  45. package/dist/i18n/en.d.ts.map +1 -1
  46. package/dist/i18n/en.js +15 -0
  47. package/dist/i18n/en.js.map +1 -1
  48. package/dist/i18n/ko.d.ts.map +1 -1
  49. package/dist/i18n/ko.js +15 -0
  50. package/dist/i18n/ko.js.map +1 -1
  51. package/dist/index.d.ts +2 -2
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +2 -2
  54. package/dist/index.js.map +1 -1
  55. package/dist/router.d.ts +6 -1
  56. package/dist/router.d.ts.map +1 -1
  57. package/dist/router.js +13 -7
  58. package/dist/router.js.map +1 -1
  59. package/dist/schemas.d.ts +321 -159
  60. package/dist/schemas.d.ts.map +1 -1
  61. package/dist/schemas.js +61 -154
  62. package/dist/schemas.js.map +1 -1
  63. package/docs/specs/cli.md +3 -3
  64. package/docs/specs/rest.md +5 -13
  65. package/package.json +2 -1
  66. package/skills/deploying-a-console/SKILL.md +2 -2
  67. package/skills/working-the-board/SKILL.md +3 -3
  68. package/src/api.ts +2 -7
  69. package/src/cli/cli.ts +92 -76
  70. package/src/cli/format.ts +10 -328
  71. package/src/cli/help.ts +7 -6
  72. package/src/cli/pack.ts +356 -0
  73. package/src/compat.ts +1 -1
  74. package/src/components/decision-list.tsx +227 -94
  75. package/src/components/paged.tsx +72 -3
  76. package/src/components/skills.tsx +51 -33
  77. package/src/components/ui.tsx +16 -3
  78. package/src/console.tsx +3 -0
  79. package/src/data.ts +32 -2
  80. package/src/i18n/en.ts +18 -0
  81. package/src/i18n/ko.ts +17 -0
  82. package/src/index.ts +9 -1
  83. package/src/router.ts +20 -9
  84. package/src/schemas.ts +76 -180
  85. package/src/styles/console.css +112 -5
package/src/data.ts CHANGED
@@ -245,6 +245,28 @@ async function readTasks(
245
245
  return { items };
246
246
  }
247
247
 
248
+ /** How many pages of the decisions are read before the record is shown as it stands. */
249
+ const DECISIONS_MAX_PAGES = 20;
250
+
251
+ /**
252
+ * The decisions of a project, whole: page after page while the server says there is more, so
253
+ * that the record is read to its end and the pages turn it without asking again.
254
+ */
255
+ async function readDecisions(
256
+ scope: ProjectClient,
257
+ signal: AbortSignal | undefined,
258
+ ): Promise<{ readonly items: RestDecision[] }> {
259
+ const items: RestDecision[] = [];
260
+ for (let page = 0; page < DECISIONS_MAX_PAGES; page += 1) {
261
+ const result = await scope.decisions({ limit: LIST_LIMIT, offset: page * LIST_LIMIT }, signal);
262
+ items.push(...result.items);
263
+ if (!result.more) {
264
+ break;
265
+ }
266
+ }
267
+ return { items };
268
+ }
269
+
248
270
  const wordsOf = (failure: unknown, fallback: string): string =>
249
271
  failure instanceof ApiError ? failure.message : fallback;
250
272
 
@@ -310,7 +332,7 @@ export function useConsoleData(client: ConsoleClient, projectKey: string | undef
310
332
  await Promise.all([
311
333
  scope.get(signal),
312
334
  readTasks(scope, signal),
313
- scope.decisions(undefined, signal),
335
+ readDecisions(scope, signal),
314
336
  scope.goals({}, signal),
315
337
  scope.runs(undefined, signal),
316
338
  scope.members(signal),
@@ -427,7 +449,15 @@ export function useConsoleData(client: ConsoleClient, projectKey: string | undef
427
449
  // No answer at all is said on the page as the deployment being out of reach,
428
450
  // rather than waited for.
429
451
  if (!signal.aborted) {
430
- setSkills({ address: null, source: "", page: null, status: "unavailable", items: [] });
452
+ setSkills({
453
+ address: null,
454
+ source: "",
455
+ page: null,
456
+ status: "unavailable",
457
+ refusal: null,
458
+ items: [],
459
+ mount: null,
460
+ });
431
461
  }
432
462
  });
433
463
  if (typeof EventSource === "undefined") {
package/src/i18n/en.ts CHANGED
@@ -9,6 +9,7 @@ import type {
9
9
  ProjectVisibility,
10
10
  ProviderKey,
11
11
  RunStatus,
12
+ SkillsStatus,
12
13
  TaskPriority,
13
14
  TaskState,
14
15
  } from "../vocabulary.js";
@@ -102,6 +103,12 @@ export const en = {
102
103
  copy: "Copy",
103
104
  copied: "Copied",
104
105
  showMore: (n: number, of: number) => `Show ${n} more of ${of}`,
106
+ pager: {
107
+ label: "Pages",
108
+ previous: "Previous page",
109
+ next: "Next page",
110
+ range: (from: number, to: number, of: number) => `${from}-${to} of ${of}`,
111
+ },
105
112
  },
106
113
 
107
114
  nav: {
@@ -325,6 +332,9 @@ export const en = {
325
332
  waitingForPerson: "Waiting for a person.",
326
333
  options: "Options",
327
334
  notePlaceholder: "A word about it, if any",
335
+ own: "Something else",
336
+ ownPlaceholder: "Your answer, in a line",
337
+ ownAnswer: "in their own words",
328
338
  answer: "Answer",
329
339
  asked: "asked",
330
340
  askedThrough: (agent: string) => `asked through ${agent}`,
@@ -662,6 +672,14 @@ export const en = {
662
672
  connect:
663
673
  "An agent reads these with the console command (console skill <path>), or through its own MCP connection to this address, which a person makes once:",
664
674
  connectLink: "how, on the address's page at SkillCDN",
675
+ fromMachine: "Read from a directory on the console's machine, at",
676
+ connectLocal:
677
+ "An agent reads these with the console command (console skill <path>); the pack is on the console's machine and nowhere else.",
678
+ localStatus: {
679
+ not_found:
680
+ "No pack is served from the console's machine at this address: whoever runs the console puts it in the packs directory, as <owner>/<name>.",
681
+ unavailable: "The pack could not be read from the console's machine. Look again later.",
682
+ } as Partial<Record<SkillsStatus, string>>,
665
683
  status: {
666
684
  indexing: "SkillCDN is still indexing the repository. Look again in a moment.",
667
685
  failed: "SkillCDN could not index the repository. What it found is on the address's page.",
package/src/i18n/ko.ts CHANGED
@@ -72,6 +72,12 @@ export const ko: Messages = {
72
72
  copy: "복사",
73
73
  copied: "복사됨",
74
74
  showMore: (n, of) => `${of}개 중 ${n}개 더 보기`,
75
+ pager: {
76
+ label: "페이지",
77
+ previous: "이전",
78
+ next: "다음",
79
+ range: (from, to, of) => `${of}건 중 ${from}-${to}`,
80
+ },
75
81
  },
76
82
 
77
83
  nav: {
@@ -294,6 +300,9 @@ export const ko: Messages = {
294
300
  waitingForPerson: "사람을 기다리는 중입니다.",
295
301
  options: "선택지",
296
302
  notePlaceholder: "덧붙일 말이 있다면",
303
+ own: "직접 입력",
304
+ ownPlaceholder: "원하는 답을 한 줄로",
305
+ ownAnswer: "직접 입력",
297
306
  answer: "답변",
298
307
  asked: "질문",
299
308
  askedThrough: (agent) => `${agent}을(를) 통해 질문`,
@@ -626,6 +635,14 @@ export const ko: Messages = {
626
635
  connect:
627
636
  "에이전트는 콘솔 명령(console skill <경로>)으로, 또는 이 주소에 자기 MCP 연결로 스킬을 받습니다. MCP 연결은 사람이 한 번 해 줍니다:",
628
637
  connectLink: "SkillCDN 페이지의 연결 안내",
638
+ fromMachine: "콘솔 기계의 디렉터리에서 읽음, 주소:",
639
+ connectLocal:
640
+ "에이전트는 콘솔 명령(console skill <경로>)으로 읽습니다. 이 팩은 콘솔 기계에만 있습니다.",
641
+ localStatus: {
642
+ not_found:
643
+ "이 주소로 콘솔 기계에서 제공되는 팩이 없습니다. 콘솔 운영자가 팩 디렉터리에 <owner>/<name>으로 넣습니다.",
644
+ unavailable: "콘솔 기계에서 팩을 읽지 못했습니다. 나중에 다시 보세요.",
645
+ },
629
646
  status: {
630
647
  indexing: "SkillCDN이 아직 저장소를 색인하고 있습니다. 잠시 후 다시 보세요.",
631
648
  failed: "SkillCDN이 저장소를 색인하지 못했습니다. 찾은 내용은 주소의 페이지에 있습니다.",
package/src/index.ts CHANGED
@@ -82,7 +82,14 @@ export {
82
82
  goalMonth,
83
83
  } from "./components/goals.js";
84
84
  export { Markdown, type MarkdownProps } from "./components/markdown.js";
85
- export { PAGE_SIZE, ShowMore, usePaged } from "./components/paged.js";
85
+ export {
86
+ PAGE_SIZE,
87
+ Pager,
88
+ pageOf,
89
+ RECORD_PAGE_SIZE,
90
+ ShowMore,
91
+ usePaged,
92
+ } from "./components/paged.js";
86
93
  export {
87
94
  ListingForm,
88
95
  type ListingFormProps,
@@ -246,6 +253,7 @@ export {
246
253
  customPageHref,
247
254
  type DocsView,
248
255
  decisionHref,
256
+ decisionsHref,
249
257
  docHref,
250
258
  GOAL_TASK_VIEWS,
251
259
  type GoalPageOptions,
package/src/router.ts CHANGED
@@ -5,7 +5,7 @@ import { isDay, isMonth } from "./dates.js";
5
5
  // route, and the hrefs below are its inverse. A project's pages live under `/projects/<key>`,
6
6
  // the word the REST API uses; an address names what it shows (a task by its number, a decision
7
7
  // by its id, a document by its path, a goal by its id), every form has one, and the query says
8
- // how a page is shown (`?edit`, `?ask`, `?new`, `?version=`, `?q=`, `?month=`, `?week=`, and the
8
+ // how a page is shown (`?edit`, `?ask`, `?new`, `?version=`, `?q=`, `?month=`, `?week=`, `?page=`, and the
9
9
  // board's filters). The old addresses are taken to the new.
10
10
 
11
11
  /** How a task's page is shown: as it is, or with one of its forms open. */
@@ -49,7 +49,8 @@ export type Route =
49
49
  readonly path: string;
50
50
  readonly view: DocsView;
51
51
  }
52
- | { readonly name: "decisions"; readonly project: string }
52
+ /** The decisions of a project: the waiting ones, and the record on one of its pages, the first when the address names none. */
53
+ | { readonly name: "decisions"; readonly project: string; readonly page: number | undefined }
53
54
  | { readonly name: "new-decision"; readonly project: string }
54
55
  | { readonly name: "decision"; readonly project: string; readonly id: string }
55
56
  /** The calendar of a project: the month shown, or this one when the address names none, narrowed as the board is. */
@@ -155,13 +156,10 @@ const NUMBER = /^[1-9][0-9]{0,8}$/;
155
156
  /** A code as it may be typed into an address: checked for what it is by the page. */
156
157
  const CODE_TEXT = /^[A-Za-z0-9-]{1,16}$/;
157
158
  /** The pages of a project that take nothing after their name. */
158
- const PLAIN_PAGES: readonly Exclude<ProjectPage, "docs" | "calendar" | "roadmap" | "settings">[] = [
159
- "decisions",
160
- "archive",
161
- "feed",
162
- "skills",
163
- "members",
164
- ];
159
+ const PLAIN_PAGES: readonly Exclude<
160
+ ProjectPage,
161
+ "docs" | "decisions" | "calendar" | "roadmap" | "settings"
162
+ >[] = ["archive", "feed", "skills", "members"];
165
163
  const NOT_FOUND: Route = { name: "not-found" };
166
164
 
167
165
  /** Where an address of the 0.1 line before this one leads now, or nothing for a current one. */
@@ -386,6 +384,13 @@ export function matchRoute(pathname: string, search = ""): Route {
386
384
  : undefined,
387
385
  };
388
386
  }
387
+ if (page === "decisions") {
388
+ const turned = params.get("page");
389
+ if (turned !== null && !NUMBER.test(turned)) {
390
+ return NOT_FOUND;
391
+ }
392
+ return { name: "decisions", project, page: turned === null ? undefined : Number(turned) };
393
+ }
389
394
  const found = PLAIN_PAGES.find((candidate) => candidate === page);
390
395
  return found === undefined ? NOT_FOUND : { name: found, project };
391
396
  }
@@ -469,6 +474,12 @@ export function decisionHref(key: string, id: string): string {
469
474
  return `${PATHS.project}/${key}/decisions/${id}`;
470
475
  }
471
476
 
477
+ /** Where a project's decisions are: the waiting ones and the record, on one of its pages, or on the first when none is named. */
478
+ export function decisionsHref(key: string, page?: number): string {
479
+ const base = projectHref(key, "decisions");
480
+ return page === undefined || page <= 1 ? base : `${base}?page=${page}`;
481
+ }
482
+
472
483
  /** Where the person's own work is, with the week of a day at the top, or this week's when none is named. */
473
484
  export function workHref(week?: string): string {
474
485
  return week === undefined ? PATHS.work : `${PATHS.work}?week=${week}`;
package/src/schemas.ts CHANGED
@@ -2,6 +2,13 @@
2
2
  // most of what a page downloads. The server validates what it is sent with the input schemas
3
3
  // and builds the output shapes; the pages and a custom console parse answers with the rest.
4
4
  // Absent values are `null` on the wire, never missing keys. Changes within a version are additive.
5
+ import {
6
+ restBrowseSchema as packBrowseSchema,
7
+ restFileSchema as packFileSchema,
8
+ restFindSchema as packFindSchema,
9
+ restMountSchema as packMountSchema,
10
+ restSkillSchema as packSkillSchema,
11
+ } from "@skillcdn/core";
5
12
  import * as z from "zod/mini";
6
13
  import { isDocumentPath } from "./documents.js";
7
14
  import {
@@ -548,9 +555,15 @@ export const restGoalPatchSchema = z.object({
548
555
  export type RestGoalPatch = z.infer<typeof restGoalPatchSchema>;
549
556
 
550
557
  export const restDecisionOptionSchema = z.object({
551
- /** What an answer names: stable for the life of the decision. */
558
+ /** What an answer names: stable once given. */
552
559
  id: z.string(),
553
560
  label: z.string(),
561
+ /**
562
+ * On the one option a person's own answer became, when they answered in their own words
563
+ * instead of choosing (`POST .../answer` with `own`): added then, after the options given,
564
+ * which carry no `own`.
565
+ */
566
+ own: z.optional(z.literal(true)),
554
567
  });
555
568
  export type RestDecisionOption = z.infer<typeof restDecisionOptionSchema>;
556
569
 
@@ -646,11 +659,24 @@ export const restDecisionPatchSchema = z.object({
646
659
  });
647
660
  export type RestDecisionPatch = z.infer<typeof restDecisionPatchSchema>;
648
661
 
649
- /** What `POST .../decisions/<id>/answer` is sent: an option, and a word about it. */
650
- export const restAnswerInputSchema = z.object({
651
- option: z.string().check(z.minLength(1), z.maxLength(64)),
652
- note: z.optional(paragraphs(MAX_NOTE_LENGTH)),
653
- });
662
+ /**
663
+ * What `POST .../decisions/<id>/answer` is sent: one of the options by its id, or the person's
664
+ * own answer in a line, one of the two; and a word about either.
665
+ */
666
+ export const restAnswerInputSchema = z
667
+ .object({
668
+ /** The id of the chosen option. */
669
+ option: z.optional(z.string().check(z.minLength(1), z.maxLength(64))),
670
+ /** The person's own answer, when none of the options is it: one line, worded as an option is. */
671
+ own: z.optional(line(MAX_OPTION_LABEL_LENGTH)),
672
+ note: z.optional(paragraphs(MAX_NOTE_LENGTH)),
673
+ })
674
+ .check(
675
+ z.refine(
676
+ (input) => (input.option === undefined) !== (input.own === undefined),
677
+ "must name an option or give an answer of its own, one of the two",
678
+ ),
679
+ );
654
680
  export type RestAnswerInput = z.infer<typeof restAnswerInputSchema>;
655
681
 
656
682
  /**
@@ -894,15 +920,39 @@ export const restClaimSchema = z.union([
894
920
  ]);
895
921
  export type RestClaim = z.infer<typeof restClaimSchema>;
896
922
 
897
- /** One of the project's skills, as the SkillCDN deployment lists it at the project's address. */
923
+ /** Why a pack did not answer a read: the code and the words the deployment, or the console reading a directory, gave, as the main repository's API spells them. */
924
+ export const restPackRefusalSchema = z.object({
925
+ code: z.string(),
926
+ message: z.string(),
927
+ /** With a file the pack will not carry: where it is at its source, or `null`. */
928
+ sourceUrl: z.nullable(z.string()),
929
+ /** With `skill.ambiguous`: the directories to choose from. */
930
+ directories: z.array(z.string()),
931
+ });
932
+ export type RestPackRefusal = z.infer<typeof restPackRefusalSchema>;
933
+
934
+ /** What every answer about a pack says first: its address, where it is read, and how the read went. */
935
+ const packEnvelope = {
936
+ /** The address, canonical, or `null` when neither the project nor the console names one. */
937
+ address: z.nullable(z.string()),
938
+ /** The origin of the SkillCDN deployment the pack is read at; `null` for a pack read from a directory on the console's machine (ADR-0031). */
939
+ source: z.nullable(z.string()),
940
+ /** Where a person browses the address at the deployment, or `null` without one. */
941
+ page: z.nullable(z.string()),
942
+ status: z.enum(SKILLS_STATUSES),
943
+ /** Why the read did not happen, in the pack's own words, when `status` says it did not; `null` otherwise. */
944
+ refusal: z.nullable(restPackRefusalSchema),
945
+ };
946
+
947
+ /** One of the project's skills, as the pack lists it: what the repository says of it, where a person reads it, what an agent loads it by. */
898
948
  export const restSkillSchema = z.object({
899
949
  name: z.string(),
900
950
  description: z.string(),
901
951
  /** The skill's folder in the repository (`""` for the root), and the path of its `SKILL.md`. */
902
952
  directory: z.string(),
903
953
  path: z.string(),
904
- /** Where a person reads the skill: its page at the deployment. */
905
- page: z.string(),
954
+ /** Where a person reads the skill: its page at the deployment, or `null` for a pack read from a directory. */
955
+ page: z.nullable(z.string()),
906
956
  /** What an agent loads the skill by, through its own SkillCDN connection; `null` when the path is not one. */
907
957
  uri: z.nullable(z.string()),
908
958
  /** The title and the description in other languages, by language tag, as the repository gives them. */
@@ -913,15 +963,9 @@ export const restSkillSchema = z.object({
913
963
  });
914
964
  export type RestSkill = z.infer<typeof restSkillSchema>;
915
965
 
916
- /** `GET /api/v1/projects/<key>/skills`: the project's skills, read by address through SkillCDN. */
966
+ /** `GET /api/v1/projects/<key>/skills`: the project's pack, read by address (ADR-0028, ADR-0031). */
917
967
  export const restSkillsSchema = z.object({
918
- /** The address, canonical, or `null` when neither the project nor the deployment names one. */
919
- address: z.nullable(z.string()),
920
- /** The origin of the SkillCDN deployment the skills are read through. */
921
- source: z.string(),
922
- /** Where a person browses the address, or `null` without one. */
923
- page: z.nullable(z.string()),
924
- status: z.enum(SKILLS_STATUSES),
968
+ ...packEnvelope,
925
969
  /** The pack as its manifest or its README names it, when `ready`: what it is called, what it is for, the language it is written in. */
926
970
  pack: z.optional(
927
971
  z.object({
@@ -930,10 +974,12 @@ export const restSkillsSchema = z.object({
930
974
  language: z.nullable(z.string()),
931
975
  }),
932
976
  ),
933
- /** How many skills and documents the deployment indexed at the address, when `ready`. */
977
+ /** How many skills and documents the index found at the address, when `ready`. */
934
978
  counts: z.optional(z.object({ skills: count, documents: count })),
935
979
  /** The skills, when `ready`; empty otherwise. */
936
980
  items: z.array(restSkillSchema),
981
+ /** What the address serves, as the main repository's REST API answers it (`RestMount` of `@skillcdn/core`), for a program that renders what a model is given; `null` when nothing was answered. */
982
+ mount: z.nullable(packMountSchema),
937
983
  });
938
984
  export type RestSkills = z.infer<typeof restSkillsSchema>;
939
985
 
@@ -945,181 +991,31 @@ export const restPackTokenInputSchema = z.object({
945
991
  });
946
992
  export type RestPackTokenInput = z.infer<typeof restPackTokenInputSchema>;
947
993
 
948
- /** A rule, the body or an included file of a skill: its path from the repository's root and its text, cut where a page ends. */
949
- export const restSkillTextSchema = z.object({
950
- path: z.string(),
951
- body: z.string(),
952
- truncated: z.boolean(),
953
- });
954
- /** A skill as the deployment serves it, on one page of its context: what `load_skill` gives a model, in the console's shape. */
955
- export const restSkillPageSchema = z.object({
956
- path: z.string(),
957
- directory: z.string(),
958
- name: z.string(),
959
- description: z.string(),
960
- /** The rules that hold for the skill, from the repository's root to the nearest manifest. */
961
- rules: z.array(restSkillTextSchema),
962
- body: z.string(),
963
- /** The files the skill includes with its body. */
964
- included: z.array(restSkillTextSchema),
965
- /** The paths of the skill's own files, read with the file route. */
966
- files: z.array(z.string()),
967
- references: z.array(
968
- z.object({
969
- path: z.string(),
970
- status: z.enum(["available", "blocked", "missing", "outside_mount"]),
971
- }),
972
- ),
973
- /** Whether this page completes the skill; else the cursor of the next. */
974
- complete: z.boolean(),
975
- nextCursor: z.nullable(z.string()),
976
- /** How the skill is served: whole, or described only, with its license and where it is read at its host. */
977
- serving: z.object({
978
- full: z.boolean(),
979
- license: z.nullable(z.string()),
980
- sourceUrl: z.nullable(z.string()),
981
- }),
982
- warnings: z.array(z.string()),
983
- });
984
- export type RestSkillPage = z.infer<typeof restSkillPageSchema>;
985
-
986
- /** `GET .../skills/one?path=&cursor=`: one skill of the pack, a page of it; `skill` is `null` unless `ready`. */
994
+ /** `GET .../skills/one?path=&cursor=`: a page of a skill's context, as the pack answers `load_skill` (`RestSkill` of `@skillcdn/core`); `read` is `null` unless `ready`. */
987
995
  export const restSkillLoadSchema = z.object({
988
- address: z.nullable(z.string()),
989
- source: z.string(),
990
- page: z.nullable(z.string()),
991
- status: z.enum(SKILLS_STATUSES),
992
- skill: z.nullable(restSkillPageSchema),
996
+ ...packEnvelope,
997
+ read: z.nullable(packSkillSchema),
993
998
  });
994
999
  export type RestSkillLoad = z.infer<typeof restSkillLoadSchema>;
995
1000
 
996
- /** `GET .../skills/file?path=&offset=&limit=`: a page of a file of the pack, or what a folder holds; both `null` unless `ready`. */
1001
+ /** `GET .../skills/file?path=&offset=&limit=`: a page of a file, or what a folder holds, as the pack answers `read_repo_file` (`RestFile` of `@skillcdn/core`); `read` is `null` unless `ready`. */
997
1002
  export const restSkillFileSchema = z.object({
998
- address: z.nullable(z.string()),
999
- source: z.string(),
1000
- status: z.enum(SKILLS_STATUSES),
1001
- file: z.nullable(
1002
- z.object({
1003
- path: z.string(),
1004
- content: z.string(),
1005
- offset: count,
1006
- nextOffset: z.nullable(count),
1007
- totalLength: count,
1008
- }),
1009
- ),
1010
- folder: z.nullable(
1011
- z.object({
1012
- path: z.string(),
1013
- entries: z.array(
1014
- z.object({
1015
- path: z.string(),
1016
- kind: z.enum(["directory", "file"]),
1017
- size: z.nullable(count),
1018
- }),
1019
- ),
1020
- truncated: z.boolean(),
1021
- }),
1022
- ),
1003
+ ...packEnvelope,
1004
+ read: z.nullable(packFileSchema),
1023
1005
  });
1024
1006
  export type RestSkillFile = z.infer<typeof restSkillFileSchema>;
1025
1007
 
1026
- /** An entry of a folder of the pack, as the deployment browses it: a skill, a folder with what it holds, or a file. */
1027
- export const restSkillBrowseEntrySchema = z.object({
1028
- kind: z.enum(["skill", "directory", "file"]),
1029
- /** The path from the repository's root: of the `SKILL.md` for a skill, of the folder, of the file. */
1030
- path: z.string(),
1031
- name: z.nullable(z.string()),
1032
- description: z.nullable(z.string()),
1033
- /** For a folder: the skills and the documents under it. */
1034
- skillCount: count,
1035
- documentCount: count,
1036
- /** For a file: its size in bytes. */
1037
- size: z.nullable(count),
1038
- /** For a folder: the README that introduces it, read with the file route. */
1039
- overviewPath: z.nullable(z.string()),
1040
- /** For a skill: its license, and whether the address only describes it. */
1041
- license: z.nullable(z.string()),
1042
- describedOnly: z.boolean(),
1043
- });
1044
- export type RestSkillBrowseEntry = z.infer<typeof restSkillBrowseEntrySchema>;
1045
-
1046
- /** `GET .../skills/browse?path=&cursor=&limit=`: what a folder of the pack holds, a page of it (`browse_repo`); `folder` is `null` unless `ready`. */
1008
+ /** `GET .../skills/browse?path=&cursor=&limit=`: what a folder holds, a page of it, as the pack answers `browse_repo` (`RestBrowse` of `@skillcdn/core`); `read` is `null` unless `ready`. */
1047
1009
  export const restSkillBrowseSchema = z.object({
1048
- address: z.nullable(z.string()),
1049
- source: z.string(),
1050
- page: z.nullable(z.string()),
1051
- status: z.enum(SKILLS_STATUSES),
1052
- folder: z.nullable(
1053
- z.object({
1054
- path: z.string(),
1055
- /** The README that introduces the folder, or `null`. */
1056
- overview: z.nullable(
1057
- z.object({
1058
- path: z.string(),
1059
- title: z.nullable(z.string()),
1060
- description: z.nullable(z.string()),
1061
- }),
1062
- ),
1063
- entries: z.array(restSkillBrowseEntrySchema),
1064
- /** Where the listing goes on, or `null` at its end. */
1065
- nextCursor: z.nullable(z.string()),
1066
- }),
1067
- ),
1010
+ ...packEnvelope,
1011
+ read: z.nullable(packBrowseSchema),
1068
1012
  });
1069
1013
  export type RestSkillBrowse = z.infer<typeof restSkillBrowseSchema>;
1070
1014
 
1071
- /** What a search of the pack found: a skill, as the listing has it, with the files of it that matched; or a document on its own. */
1072
- export const restSkillFindItemSchema = z.discriminatedUnion("kind", [
1073
- z.object({
1074
- kind: z.literal("skill"),
1075
- name: z.string(),
1076
- description: z.string(),
1077
- directory: z.string(),
1078
- path: z.string(),
1079
- page: z.string(),
1080
- uri: z.nullable(z.string()),
1081
- translations: z.record(
1082
- z.string(),
1083
- z.object({ title: z.nullable(z.string()), description: z.nullable(z.string()) }),
1084
- ),
1085
- /** The files of the skill that matched, a few, and how many more did. */
1086
- files: z.array(
1087
- z.object({
1088
- path: z.string(),
1089
- title: z.nullable(z.string()),
1090
- summary: z.nullable(z.string()),
1091
- }),
1092
- ),
1093
- moreFiles: count,
1094
- license: z.nullable(z.string()),
1095
- describedOnly: z.boolean(),
1096
- }),
1097
- z.object({
1098
- kind: z.literal("document"),
1099
- path: z.string(),
1100
- title: z.nullable(z.string()),
1101
- summary: z.nullable(z.string()),
1102
- /** The folder of the skill the document belongs to, or `null` for one on its own. */
1103
- skillDirectory: z.nullable(z.string()),
1104
- }),
1105
- ]);
1106
- export type RestSkillFindItem = z.infer<typeof restSkillFindItemSchema>;
1107
-
1108
- /** `GET .../skills/find?query=&path=&cursor=&limit=`: what words find in the pack, a page of it in relevance order (`search_repo`); `found` is `null` unless `ready`. */
1015
+ /** `GET .../skills/find?query=&path=&cursor=&limit=`: what words find, a page of it in relevance order, as the pack answers `search_repo` (`RestFind` of `@skillcdn/core`); `read` is `null` unless `ready`. */
1109
1016
  export const restSkillFindSchema = z.object({
1110
- address: z.nullable(z.string()),
1111
- source: z.string(),
1112
- page: z.nullable(z.string()),
1113
- status: z.enum(SKILLS_STATUSES),
1114
- found: z.nullable(
1115
- z.object({
1116
- query: z.string(),
1117
- /** The folder the search was kept to, or `null` for the whole pack. */
1118
- path: z.nullable(z.string()),
1119
- items: z.array(restSkillFindItemSchema),
1120
- nextCursor: z.nullable(z.string()),
1121
- }),
1122
- ),
1017
+ ...packEnvelope,
1018
+ read: z.nullable(packFindSchema),
1123
1019
  });
1124
1020
  export type RestSkillFind = z.infer<typeof restSkillFindSchema>;
1125
1021