@skillcdn/console 0.4.2 → 0.4.3

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 (100) hide show
  1. package/dist/api.d.ts +2 -2
  2. package/dist/api.d.ts.map +1 -1
  3. package/dist/api.js +2 -2
  4. package/dist/api.js.map +1 -1
  5. package/dist/cli/cli.d.ts.map +1 -1
  6. package/dist/cli/cli.js +26 -14
  7. package/dist/cli/cli.js.map +1 -1
  8. package/dist/cli/format.d.ts.map +1 -1
  9. package/dist/cli/format.js +6 -1
  10. package/dist/cli/format.js.map +1 -1
  11. package/dist/cli/help.d.ts.map +1 -1
  12. package/dist/cli/help.js +9 -5
  13. package/dist/cli/help.js.map +1 -1
  14. package/dist/cli/plugin-check.d.ts +5 -0
  15. package/dist/cli/plugin-check.d.ts.map +1 -1
  16. package/dist/cli/plugin-check.js +22 -0
  17. package/dist/cli/plugin-check.js.map +1 -1
  18. package/dist/cli/plugin-cli.d.ts +1 -1
  19. package/dist/cli/plugin-cli.d.ts.map +1 -1
  20. package/dist/cli/plugin-cli.js +70 -4
  21. package/dist/cli/plugin-cli.js.map +1 -1
  22. package/dist/cli/plugin-init.d.ts +17 -0
  23. package/dist/cli/plugin-init.d.ts.map +1 -1
  24. package/dist/cli/plugin-init.js +135 -3
  25. package/dist/cli/plugin-init.js.map +1 -1
  26. package/dist/client.d.ts +3 -2
  27. package/dist/client.d.ts.map +1 -1
  28. package/dist/client.js +16 -5
  29. package/dist/client.js.map +1 -1
  30. package/dist/components/comments.d.ts.map +1 -1
  31. package/dist/components/comments.js +1 -1
  32. package/dist/components/comments.js.map +1 -1
  33. package/dist/components/decision-form.d.ts +2 -1
  34. package/dist/components/decision-form.d.ts.map +1 -1
  35. package/dist/components/decision-form.js +36 -4
  36. package/dist/components/decision-form.js.map +1 -1
  37. package/dist/components/decision-list.d.ts +4 -0
  38. package/dist/components/decision-list.d.ts.map +1 -1
  39. package/dist/components/decision-list.js +29 -3
  40. package/dist/components/decision-list.js.map +1 -1
  41. package/dist/components/my-decisions.d.ts +2 -0
  42. package/dist/components/my-decisions.d.ts.map +1 -1
  43. package/dist/components/my-decisions.js +2 -2
  44. package/dist/components/my-decisions.js.map +1 -1
  45. package/dist/components/task-view.d.ts +2 -1
  46. package/dist/components/task-view.d.ts.map +1 -1
  47. package/dist/components/task-view.js.map +1 -1
  48. package/dist/console.css +3 -1
  49. package/dist/console.d.ts.map +1 -1
  50. package/dist/console.js +16 -15
  51. package/dist/console.js.map +1 -1
  52. package/dist/data.d.ts +2 -1
  53. package/dist/data.d.ts.map +1 -1
  54. package/dist/data.js +26 -7
  55. package/dist/data.js.map +1 -1
  56. package/dist/i18n/en.d.ts +6 -0
  57. package/dist/i18n/en.d.ts.map +1 -1
  58. package/dist/i18n/en.js +6 -0
  59. package/dist/i18n/en.js.map +1 -1
  60. package/dist/i18n/ko.d.ts.map +1 -1
  61. package/dist/i18n/ko.js +6 -0
  62. package/dist/i18n/ko.js.map +1 -1
  63. package/dist/limits.d.ts +2 -0
  64. package/dist/limits.d.ts.map +1 -1
  65. package/dist/limits.js +2 -0
  66. package/dist/limits.js.map +1 -1
  67. package/dist/plugin/context.d.ts +6 -0
  68. package/dist/plugin/context.d.ts.map +1 -1
  69. package/dist/schemas.d.ts +77 -9
  70. package/dist/schemas.d.ts.map +1 -1
  71. package/dist/schemas.js +58 -16
  72. package/dist/schemas.js.map +1 -1
  73. package/docs/specs/cli.md +1 -1
  74. package/docs/specs/plugins.md +7 -6
  75. package/docs/specs/rest.md +8 -7
  76. package/package.json +7 -7
  77. package/skills/building-a-plugin/SKILL.md +4 -4
  78. package/skills/working-the-board/SKILL.md +1 -1
  79. package/src/api.ts +4 -0
  80. package/src/cli/cli.ts +40 -22
  81. package/src/cli/format.ts +12 -1
  82. package/src/cli/help.ts +9 -4
  83. package/src/cli/plugin-check.ts +27 -0
  84. package/src/cli/plugin-cli.ts +94 -5
  85. package/src/cli/plugin-init.ts +170 -3
  86. package/src/client.ts +28 -9
  87. package/src/components/comments.tsx +1 -0
  88. package/src/components/decision-form.tsx +92 -11
  89. package/src/components/decision-list.tsx +71 -2
  90. package/src/components/my-decisions.tsx +4 -1
  91. package/src/components/task-view.tsx +2 -1
  92. package/src/console.tsx +18 -12
  93. package/src/data.ts +32 -9
  94. package/src/i18n/en.ts +7 -0
  95. package/src/i18n/ko.ts +7 -0
  96. package/src/limits.ts +2 -0
  97. package/src/plugin/context.ts +6 -1
  98. package/src/schemas.ts +72 -18
  99. package/src/styles/console.css +3 -1
  100. package/template/plugin/package.json +3 -3
package/src/schemas.ts CHANGED
@@ -284,6 +284,13 @@ export const restMeSchema = z.object({
284
284
  * built on this package still reads an older console's answer, and says it is older.
285
285
  */
286
286
  console: z.optional(z.object({ version: z.string(), clientRange: z.string() })),
287
+ /**
288
+ * How many decisions wait for the person's answer across the projects they may see
289
+ * (ADR-0042), for the pages to say beside My decisions; `null` for nobody. Answered from
290
+ * 0.4.3 and read as optional, so that a console built on this package still reads an older
291
+ * console's answer.
292
+ */
293
+ decisions: z.optional(z.nullable(z.object({ waiting: count }))),
287
294
  });
288
295
  export type RestMe = z.infer<typeof restMeSchema>;
289
296
 
@@ -643,10 +650,50 @@ export const restGoalPatchSchema = z.object({
643
650
  });
644
651
  export type RestGoalPatch = z.infer<typeof restGoalPatchSchema>;
645
652
 
653
+ /** A file a run handed in, as the console keeps it; its bytes are at `projectPath(key, "files", <artifact id>)`. */
654
+ export const restFileSchema = z.object({
655
+ /** What the agent called it: one line, without a path. */
656
+ name: z.string(),
657
+ /** In bytes. */
658
+ size: count,
659
+ /** The media type the agent said, or `application/octet-stream`. */
660
+ contentType: z.string(),
661
+ /** The SHA-256 of the bytes, in hex: what the console keeps them under. */
662
+ sha256: z.string(),
663
+ });
664
+ export type RestFile = z.infer<typeof restFileSchema>;
665
+
666
+ /** A file put on a decision when it was raised (ADR-0055), kept as a run's file is; its bytes are at `projectPath(key, "files", <id>)`. */
667
+ export const restDecisionFileSchema = z.object({
668
+ id: uuid,
669
+ file: restFileSchema,
670
+ });
671
+ export type RestDecisionFile = z.infer<typeof restDecisionFileSchema>;
672
+
673
+ /**
674
+ * The key a raiser may give an option, for a program to read the answer by instead of
675
+ * comparing labels: spelled as a plugin's key is.
676
+ */
677
+ export const OPTION_KEY_PATTERN = /^[a-z][a-z0-9-]{1,31}$/;
678
+ const optionKey = z
679
+ .string()
680
+ .check(
681
+ z.regex(
682
+ OPTION_KEY_PATTERN,
683
+ "must be a key: a lowercase letter, then lowercase letters, digits and hyphens, 2 to 32 long",
684
+ ),
685
+ );
686
+
646
687
  export const restDecisionOptionSchema = z.object({
647
688
  /** What an answer names: stable once given. */
648
689
  id: z.string(),
649
690
  label: z.string(),
691
+ /**
692
+ * The key the raiser gave the option, for a program to read the answer by (`optionKey` on the
693
+ * `decision.answered` event) without comparing labels; none on an option given without one,
694
+ * and none on the person's own answer.
695
+ */
696
+ key: z.optional(z.string()),
650
697
  /**
651
698
  * On the one option a person's own answer became, when they answered in their own words
652
699
  * instead of choosing (`POST .../answer` with `own`): added then, after the options given,
@@ -686,6 +733,13 @@ export const restDecisionSchema = z.object({
686
733
  ),
687
734
  /** What followed the decision, in Markdown, written afterwards; `null` until someone does. */
688
735
  outcome: z.nullable(z.string()),
736
+ /**
737
+ * The files put on it when it was raised (ADR-0055), in the order they came; a picture among
738
+ * them is shown where the context names it as `![words](its name)`, else after it. Answered
739
+ * from 0.4.3 and read as optional, so that a console built on this package still reads an
740
+ * older console's decisions.
741
+ */
742
+ files: z.optional(z.array(restDecisionFileSchema)),
689
743
  createdAt: instant,
690
744
  updatedAt: instant,
691
745
  });
@@ -742,13 +796,25 @@ export const restPersonWorkSchema = z.object({
742
796
  });
743
797
  export type RestPersonWork = z.infer<typeof restPersonWorkSchema>;
744
798
 
745
- /** What `POST /api/v1/projects/<key>/decisions` is sent: the question, its context, and the options. */
799
+ /**
800
+ * What `POST /api/v1/projects/<key>/decisions` is sent: the question, its context, and the
801
+ * options. As JSON; or, with files put on the decision (ADR-0055), as the part `decision` of a
802
+ * form, with a part `file` for each file.
803
+ */
746
804
  export const restDecisionInputSchema = z.object({
747
805
  question: line(MAX_QUESTION_LENGTH),
748
806
  body: z.optional(body),
807
+ /** Each a label, and optionally a key a program reads the answer by, each key once. */
749
808
  options: z
750
- .array(z.object({ label: line(MAX_OPTION_LABEL_LENGTH) }))
751
- .check(z.minLength(MIN_OPTIONS), z.maxLength(MAX_OPTIONS)),
809
+ .array(z.object({ label: line(MAX_OPTION_LABEL_LENGTH), key: z.optional(optionKey) }))
810
+ .check(
811
+ z.minLength(MIN_OPTIONS),
812
+ z.maxLength(MAX_OPTIONS),
813
+ z.refine((options) => {
814
+ const keys = options.flatMap((option) => (option.key === undefined ? [] : [option.key]));
815
+ return new Set(keys).size === keys.length;
816
+ }, "each key once"),
817
+ ),
752
818
  taskId: z.optional(z.nullable(uuid)),
753
819
  /** The run that asks, when an agent does: the decision is about its task, and it waits for the answer. */
754
820
  runId: z.optional(z.nullable(uuid)),
@@ -801,8 +867,9 @@ export const restEventDataSchema = z.object({
801
867
  from: z.optional(z.enum(TASK_STATES)),
802
868
  to: z.optional(z.enum(TASK_STATES)),
803
869
  question: z.optional(z.string()),
804
- /** For `decision.answered`: the label of the chosen option. */
870
+ /** For `decision.answered`: the label of the chosen option, and its key where the raiser gave one. */
805
871
  option: z.optional(z.string()),
872
+ optionKey: z.optional(z.string()),
806
873
  /** For `person.role_changed` and the events about a project's members: whose role, and what it became. */
807
874
  login: z.optional(z.string()),
808
875
  role: z.optional(z.string()),
@@ -818,7 +885,7 @@ export const restEventDataSchema = z.object({
818
885
  label: z.optional(z.string()),
819
886
  /** For `run.reported` and `task.commented`: the first words of what was written. */
820
887
  excerpt: z.optional(z.string()),
821
- /** For `task.commented`: how many files came with it. */
888
+ /** For `task.commented`, and for `decision.raised` when any came: how many files came with it. */
822
889
  files: z.optional(z.int()),
823
890
  /** For `plugin.command`: the command, how it ended, the refusal's code where it was refused, how long it ran, and the arguments, a secret one as `[hidden]`. */
824
891
  command: z.optional(z.string()),
@@ -867,19 +934,6 @@ export const restReportSchema = z.object({
867
934
  });
868
935
  export type RestReport = z.infer<typeof restReportSchema>;
869
936
 
870
- /** A file a run handed in, as the console keeps it; its bytes are at `projectPath(key, "files", <artifact id>)`. */
871
- export const restFileSchema = z.object({
872
- /** What the agent called it: one line, without a path. */
873
- name: z.string(),
874
- /** In bytes. */
875
- size: count,
876
- /** The media type the agent said, or `application/octet-stream`. */
877
- contentType: z.string(),
878
- /** The SHA-256 of the bytes, in hex: what the console keeps them under. */
879
- sha256: z.string(),
880
- });
881
- export type RestFile = z.infer<typeof restFileSchema>;
882
-
883
937
  /** What a run handed in: a link to a branch, a pull request, a page; or a file the console keeps. */
884
938
  export const restArtifactSchema = z.object({
885
939
  id: uuid,
@@ -2980,7 +2980,8 @@ select.sc-input {
2980
2980
  }
2981
2981
  }
2982
2982
 
2983
- .sc-comment-files {
2983
+ .sc-comment-files,
2984
+ .sc-decision-files {
2984
2985
  display: grid;
2985
2986
  gap: var(--sc-space-2);
2986
2987
  margin: 0;
@@ -2990,6 +2991,7 @@ select.sc-input {
2990
2991
  }
2991
2992
 
2992
2993
  .sc-comment-picture,
2994
+ .sc-decision-picture,
2993
2995
  .sc-artifact-picture {
2994
2996
  display: grid;
2995
2997
  gap: var(--sc-space-1);
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "console-plugin-__key__",
2
+ "name": "__package__",
3
3
  "version": "0.1.0",
4
4
  "description": "__name__, a plugin of the SkillCDN Console.",
5
5
  "license": "MIT",
@@ -19,9 +19,9 @@
19
19
  },
20
20
  "devDependencies": {
21
21
  "@skillcdn/console": "__console__",
22
- "@types/node": "^24.19.1",
22
+ "@types/node": "^24.19.2",
23
23
  "esbuild": "^0.28.2",
24
24
  "typescript": "^7.0.2",
25
- "vitest": "^5.0.3"
25
+ "vitest": "^5.1.0"
26
26
  }
27
27
  }