@crvouga/atlas 0.10.0 → 0.10.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.
Files changed (51) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/dist/reports/src/layer-merge.d.ts +5 -1
  3. package/dist/reports/src/layer-merge.js +17 -2
  4. package/dist/schema/src/common.d.ts +2 -2
  5. package/dist/schema/src/manifest.d.ts +4 -4
  6. package/dist/schema/src/spec.d.ts +6 -6
  7. package/docs/agents.md +25 -0
  8. package/docs/reference/reports.md +2 -0
  9. package/docs/report-contract.md +3 -0
  10. package/llms-full.txt +28 -0
  11. package/package.json +3 -3
  12. package/packages/schema/schemas/check-detail.schema.json +15 -15
  13. package/packages/schema/schemas/checks-result.schema.json +2 -2
  14. package/packages/schema/schemas/command-error.schema.json +4 -4
  15. package/packages/schema/schemas/doctor-result.schema.json +4 -4
  16. package/packages/schema/schemas/effective-delta.schema.json +69 -95
  17. package/packages/schema/schemas/effective-evidence.schema.json +63 -89
  18. package/packages/schema/schemas/evidence-page.schema.json +41 -59
  19. package/packages/schema/schemas/init-plan.schema.json +58 -90
  20. package/packages/schema/schemas/layer-rows.schema.json +17 -29
  21. package/packages/schema/schemas/layer.schema.json +54 -70
  22. package/packages/schema/schemas/live-run-start.schema.json +1 -1
  23. package/packages/schema/schemas/live-run.schema.json +1 -1
  24. package/packages/schema/schemas/merge-result.schema.json +6 -6
  25. package/packages/schema/schemas/outline.schema.json +7 -11
  26. package/packages/schema/schemas/path-record.schema.json +12 -28
  27. package/packages/schema/schemas/problem.schema.json +9 -9
  28. package/packages/schema/schemas/publish-checks.schema.json +27 -43
  29. package/packages/schema/schemas/publish-result.schema.json +16 -24
  30. package/packages/schema/schemas/ready.schema.json +12 -12
  31. package/packages/schema/schemas/report-event.schema.json +22 -28
  32. package/packages/schema/schemas/report-run.schema.json +33 -59
  33. package/packages/schema/schemas/report-runs.schema.json +24 -38
  34. package/packages/schema/schemas/report-status.schema.json +30 -54
  35. package/packages/schema/schemas/run-info.schema.json +9 -21
  36. package/packages/schema/schemas/run-summary.schema.json +6 -14
  37. package/packages/schema/schemas/server-config.schema.json +21 -21
  38. package/packages/schema/schemas/server-editable-settings.schema.json +14 -14
  39. package/packages/schema/schemas/server-info.schema.json +15 -19
  40. package/packages/schema/schemas/server-settings-snapshot.schema.json +28 -28
  41. package/packages/schema/schemas/spec-set.schema.json +16 -24
  42. package/packages/schema/schemas/state-node.schema.json +16 -16
  43. package/packages/schema/schemas/state-record.schema.json +5 -9
  44. package/packages/schema/schemas/store-listing.schema.json +3 -7
  45. package/packages/schema/schemas/store-write-result.schema.json +2 -2
  46. package/packages/schema/schemas/stream-result.schema.json +13 -17
  47. package/packages/schema/schemas/test-catalog.schema.json +109 -151
  48. package/packages/schema/schemas/test-history.schema.json +72 -136
  49. package/packages/schema/schemas/timeline-entry.schema.json +2 -2
  50. package/packages/schema/schemas/transition-record.schema.json +9 -21
  51. package/packages/server/openapi.json +620 -910
package/CHANGELOG.md CHANGED
@@ -1,6 +1,18 @@
1
1
  # Changelog: @crvouga/atlas
2
2
 
3
- ## 0.10.0 (2026-10-21)
3
+ ## 0.10.2 (2026-10-24)
4
+
5
+ ### Fixes and improvements
6
+
7
+ - stabilize report identity and add issue resolution skill (#19) ([1772e03](https://github.com/crvouga/atlas/commit/1772e03b6376854aecc1da692a1da87d21ebf370))
8
+
9
+ ## 0.10.1 (2026-10-24)
10
+
11
+ ### Fixes and improvements
12
+
13
+ - patch Vite and Zod vulnerabilities (#17) ([4d8e389](https://github.com/crvouga/atlas/commit/4d8e389acb31eccfc34736cb83c6b10fdd6e292e))
14
+
15
+ ## 0.10.0 (2026-10-20)
4
16
 
5
17
  ### Features
6
18
 
@@ -128,5 +128,9 @@ export declare function distinctHeaders<T extends {
128
128
  export declare function distinctEvidence(layers: readonly LayerEvidence[]): LayerEvidence[];
129
129
  /** Drops each mutable layer whose execution is already archived as an immutable one, and keeps one summary per id. */
130
130
  export declare function distinctLayers(layers: readonly LayerSummary[]): LayerSummary[];
131
- /** A string equal for the mutable and the archived address of one execution: its producer, sha, time and parts. */
131
+ /**
132
+ * A string equal for the mutable and the archived address of one execution: its producer, sha, time and parts.
133
+ * Object key order is ignored at every depth, including check evidence and extensions; array order is preserved.
134
+ * This is an advisory execution identity, not the content digest that addresses an immutable layer in storage.
135
+ */
132
136
  export declare function layerExecutionKey(layer: LayerSummary): string;
@@ -269,7 +269,22 @@ export function distinctLayers(layers) {
269
269
  const kept = new Set(layers.filter(layer => archived(layer.id)).map(layerExecutionKey));
270
270
  return [...new Map(layers.filter(layer => archived(layer.id) || !kept.has(layerExecutionKey(layer))).map(layer => [layer.id, layer])).values()];
271
271
  }
272
- /** A string equal for the mutable and the archived address of one execution: its producer, sha, time and parts. */
272
+ /**
273
+ * A string equal for the mutable and the archived address of one execution: its producer, sha, time and parts.
274
+ * Object key order is ignored at every depth, including check evidence and extensions; array order is preserved.
275
+ * This is an advisory execution identity, not the content digest that addresses an immutable layer in storage.
276
+ */
273
277
  export function layerExecutionKey(layer) {
274
- return JSON.stringify([layer.producer, layer.sha, layer.recordedAtMs, layer.parts]);
278
+ return JSON.stringify([layer.producer, layer.sha, layer.recordedAtMs, orderedValue(layer.parts)]);
279
+ }
280
+ /** Sort JSON objects recursively without changing array order or interpreting extension keys as prototypes. */
281
+ function orderedValue(value) {
282
+ if (Array.isArray(value))
283
+ return value.map(orderedValue);
284
+ if (value === null || typeof value !== 'object')
285
+ return value;
286
+ const ordered = Object.create(null);
287
+ for (const key of Object.keys(value).sort())
288
+ ordered[key] = orderedValue(value[key]);
289
+ return ordered;
275
290
  }
@@ -33,12 +33,12 @@ export declare const EVENT_KINDS: readonly ["user", "system", "time", "hand-off"
33
33
  * Zod schema for an `EVENT_KINDS` value that first rewrites the legacy value `member` to `user`, so specs written
34
34
  * before the kinds were renamed still parse.
35
35
  */
36
- export declare const EventKindSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
36
+ export declare const EventKindSchema: z.ZodPreprocess<z.ZodEnum<{
37
37
  time: "time";
38
38
  user: "user";
39
39
  system: "system";
40
40
  "hand-off": "hand-off";
41
- }>>;
41
+ }>, unknown>;
42
42
  /** One of `EVENT_KINDS`. */
43
43
  export type EventKind = z.infer<typeof EventKindSchema>;
44
44
  /**
@@ -258,12 +258,12 @@ export declare const MapEdgeSchema: z.ZodObject<{
258
258
  source: z.ZodString;
259
259
  target: z.ZodString;
260
260
  event: z.ZodString;
261
- kind: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
261
+ kind: z.ZodPreprocess<z.ZodEnum<{
262
262
  time: "time";
263
263
  user: "user";
264
264
  system: "system";
265
265
  "hand-off": "hand-off";
266
- }>>;
266
+ }>, unknown>;
267
267
  inScope: z.ZodOptional<z.ZodBoolean>;
268
268
  }, z.core.$strip>;
269
269
  /**
@@ -380,12 +380,12 @@ export declare const TransitionRecordSchema: z.ZodObject<{
380
380
  source: z.ZodString;
381
381
  target: z.ZodOptional<z.ZodNullable<z.ZodString>>;
382
382
  event: z.ZodString;
383
- kind: z.ZodOptional<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
383
+ kind: z.ZodOptional<z.ZodPreprocess<z.ZodEnum<{
384
384
  time: "time";
385
385
  user: "user";
386
386
  system: "system";
387
387
  "hand-off": "hand-off";
388
- }>>>;
388
+ }>, unknown>>;
389
389
  how: z.ZodOptional<z.ZodNullable<z.ZodString>>;
390
390
  client: z.ZodOptional<z.ZodString>;
391
391
  status: z.ZodEnum<{
@@ -90,12 +90,12 @@ export declare const StateMetaShape: {
90
90
  label: z.ZodOptional<z.ZodString>;
91
91
  }, z.core.$strip>;
92
92
  readonly hints: z.ZodArray<z.ZodString>;
93
- readonly eventKinds: z.ZodRecord<z.ZodString, z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
93
+ readonly eventKinds: z.ZodRecord<z.ZodString, z.ZodPreprocess<z.ZodEnum<{
94
94
  time: "time";
95
95
  user: "user";
96
96
  system: "system";
97
97
  "hand-off": "hand-off";
98
- }>>>;
98
+ }>, unknown>>;
99
99
  readonly timeEvents: z.ZodRecord<z.ZodString, z.ZodString>;
100
100
  };
101
101
  /** `StateMetaShape` with every field optional: the `meta` of a state or of a whole chart. */
@@ -134,12 +134,12 @@ export declare const StateMetaSchema: z.ZodObject<{
134
134
  label: z.ZodOptional<z.ZodString>;
135
135
  }, z.core.$strip>>;
136
136
  hints: z.ZodOptional<z.ZodArray<z.ZodString>>;
137
- eventKinds: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
137
+ eventKinds: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodPreprocess<z.ZodEnum<{
138
138
  time: "time";
139
139
  user: "user";
140
140
  system: "system";
141
141
  "hand-off": "hand-off";
142
- }>>>>;
142
+ }>, unknown>>>;
143
143
  timeEvents: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
144
144
  }, z.core.$strip>;
145
145
  /** A parsed `StateMetaSchema` value. */
@@ -216,12 +216,12 @@ export declare const MachineSchema: z.ZodObject<{
216
216
  label: z.ZodOptional<z.ZodString>;
217
217
  }, z.core.$strip>>;
218
218
  hints: z.ZodOptional<z.ZodArray<z.ZodString>>;
219
- eventKinds: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
219
+ eventKinds: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodPreprocess<z.ZodEnum<{
220
220
  time: "time";
221
221
  user: "user";
222
222
  system: "system";
223
223
  "hand-off": "hand-off";
224
- }>>>>;
224
+ }>, unknown>>>;
225
225
  timeEvents: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
226
226
  }, z.core.$strip>>;
227
227
  states: z.ZodRecord<z.ZodString, z.ZodUnknown>;
package/docs/agents.md CHANGED
@@ -13,6 +13,7 @@ commands provide JSON results with published schemas; the HTTP API is described
13
13
  - [Standards used](#standards-used)
14
14
  - [Where the documentation comes from](#where-the-documentation-comes-from)
15
15
  - [An integration brief you can give an agent](#an-integration-brief-you-can-give-an-agent)
16
+ - [Resolve this repository's open issues](#resolve-this-repositorys-open-issues)
16
17
 
17
18
  ## Given only this repository link
18
19
 
@@ -287,3 +288,27 @@ docs/reporting-issues.md; do not edit node_modules or vendor Atlas into this pro
287
288
  If server access or CI secrets are unavailable, finish the local integration and report exactly which shared
288
289
  server/CI checks remain unverified. A synthetic pass, a generated plan, or an unavailable backend is not proof
289
290
  that the product's real suites are integrated.
291
+
292
+ ## Resolve this repository's open issues
293
+
294
+ For contributors working in this Atlas checkout, the
295
+ [resolve-open-issues skill](https://github.com/crvouga/atlas/blob/main/.agents/skills/resolve-open-issues/SKILL.md)
296
+ handles the entire open GitHub issue inventory in one PR, branch and worktree. It uses the
297
+ [Agent Skills format](https://agentskills.io/specification) in the
298
+ [shared `.agents/skills/` location](https://agentskills.io/integrate-skills#where-to-scan).
299
+ Discovery varies by agent; any coding agent with repository file access and GitHub access can use
300
+ the same instructions by reading the file directly:
301
+
302
+ ```text
303
+ Read .agents/skills/resolve-open-issues/SKILL.md and follow it to resolve all open GitHub issues
304
+ in this repository in a single PR, using one branch and the current worktree. Continue through
305
+ implementation, validation and PR checks. Track evidence for every issue, handle attestations
306
+ autonomously, and report precise blockers without claiming unresolved issues are fixed.
307
+ ```
308
+
309
+ Use the agent's native skill invocation when it discovers `resolve-open-issues`; the file-reading
310
+ prompt is the portable fallback. The skill can also be copied as a whole directory into another
311
+ repository's skill location; it reads that repository's instructions and validation requirements.
312
+ Keep this workflow in the repository being fixed. Atlas consumer integrations still follow the
313
+ playbook above and report Atlas defects as issues. The contributor skill lives in the Git checkout;
314
+ it is not part of the npm package.
@@ -3340,6 +3340,8 @@ export function layerExecutionKey(layer: LayerSummary): string
3340
3340
  ```
3341
3341
 
3342
3342
  A string equal for the mutable and the archived address of one execution: its producer, sha, time and parts.
3343
+ Object key order is ignored at every depth, including check evidence and extensions; array order is preserved.
3344
+ This is an advisory execution identity, not the content digest that addresses an immutable layer in storage.
3343
3345
 
3344
3346
  ### Archiving a recorded run as a layer
3345
3347
 
@@ -178,6 +178,9 @@ Consequences you can rely on:
178
178
  was removed keeps its evidence, outside the outline.
179
179
  - An immutable layer held by several backends is **one** layer, reported by the backend whose id sorts
180
180
  first.
181
+ - The mutable address of an execution already held as an immutable layer is suppressed by the
182
+ de-duplication helpers and static export. Execution identity compares producer, commit, time and
183
+ parts; object key order at any depth does not matter, while array order does.
181
184
 
182
185
  Leaving a layer, backend, environment, branch or version out of the input is how earlier outcomes are
183
186
  inspected.
package/llms-full.txt CHANGED
@@ -22,6 +22,7 @@ commands provide JSON results with published schemas; the HTTP API is described
22
22
  - [Standards used](#standards-used)
23
23
  - [Where the documentation comes from](#where-the-documentation-comes-from)
24
24
  - [An integration brief you can give an agent](#an-integration-brief-you-can-give-an-agent)
25
+ - [Resolve this repository's open issues](#resolve-this-repositorys-open-issues)
25
26
 
26
27
  ## Given only this repository link
27
28
 
@@ -296,6 +297,30 @@ docs/reporting-issues.md; do not edit node_modules or vendor Atlas into this pro
296
297
  If server access or CI secrets are unavailable, finish the local integration and report exactly which shared
297
298
  server/CI checks remain unverified. A synthetic pass, a generated plan, or an unavailable backend is not proof
298
299
  that the product's real suites are integrated.
300
+
301
+ ## Resolve this repository's open issues
302
+
303
+ For contributors working in this Atlas checkout, the
304
+ [resolve-open-issues skill](https://github.com/crvouga/atlas/blob/main/.agents/skills/resolve-open-issues/SKILL.md)
305
+ handles the entire open GitHub issue inventory in one PR, branch and worktree. It uses the
306
+ [Agent Skills format](https://agentskills.io/specification) in the
307
+ [shared `.agents/skills/` location](https://agentskills.io/integrate-skills#where-to-scan).
308
+ Discovery varies by agent; any coding agent with repository file access and GitHub access can use
309
+ the same instructions by reading the file directly:
310
+
311
+ ```text
312
+ Read .agents/skills/resolve-open-issues/SKILL.md and follow it to resolve all open GitHub issues
313
+ in this repository in a single PR, using one branch and the current worktree. Continue through
314
+ implementation, validation and PR checks. Track evidence for every issue, handle attestations
315
+ autonomously, and report precise blockers without claiming unresolved issues are fixed.
316
+ ```
317
+
318
+ Use the agent's native skill invocation when it discovers `resolve-open-issues`; the file-reading
319
+ prompt is the portable fallback. The skill can also be copied as a whole directory into another
320
+ repository's skill location; it reads that repository's instructions and validation requirements.
321
+ Keep this workflow in the repository being fixed. Atlas consumer integrations still follow the
322
+ playbook above and report Atlas defects as issues. The contributor skill lives in the Git checkout;
323
+ it is not part of the npm package.
299
324
  </doc>
300
325
 
301
326
  <doc path="docs/quickstart.md">
@@ -2235,6 +2260,9 @@ Consequences you can rely on:
2235
2260
  was removed keeps its evidence, outside the outline.
2236
2261
  - An immutable layer held by several backends is **one** layer, reported by the backend whose id sorts
2237
2262
  first.
2263
+ - The mutable address of an execution already held as an immutable layer is suppressed by the
2264
+ de-duplication helpers and static export. Execution identity compares producer, commit, time and
2265
+ parts; object key order at any depth does not matter, while array order does.
2238
2266
 
2239
2267
  Leaving a layer, backend, environment, branch or version out of the input is how earlier outcomes are
2240
2268
  inspected.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crvouga/atlas",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
4
4
  "description": "Atlas: specs of any kind, reported as layered evidence. Publish checks from any runner (JUnit, CTRF, a script), combine them across nodes, branches, environments and backends, gate CI on the result, and run statecharts against the real app.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -207,10 +207,10 @@
207
207
  "react-dom": "^19.3.0",
208
208
  "solid-js": "^1.9.15",
209
209
  "tsx": "4.23.13",
210
- "vite": "7.3.6",
210
+ "vite": "7.3.7",
211
211
  "xstate": "5.33.2",
212
212
  "yaml": "^2.9.0",
213
- "zod": "^3.25.76",
213
+ "zod": "^4.6.7",
214
214
  "zustand": "^5.0.15"
215
215
  },
216
216
  "peerDependencies": {
@@ -13,9 +13,9 @@
13
13
  "type": "object",
14
14
  "properties": {
15
15
  "id": {
16
- "description": "The check's stable identity within its producer. The same check must keep the same id in every layer, or layers cannot replace one another",
17
16
  "type": "string",
18
- "minLength": 1
17
+ "minLength": 1,
18
+ "description": "The check's stable identity within its producer. The same check must keep the same id in every layer, or layers cannot replace one another"
19
19
  },
20
20
  "title": {
21
21
  "type": "string"
@@ -30,8 +30,8 @@
30
30
  ]
31
31
  },
32
32
  "detail": {
33
- "description": "Why it failed, or what was measured",
34
33
  "default": "",
34
+ "description": "Why it failed, or what was measured",
35
35
  "type": "string"
36
36
  },
37
37
  "specPath": {
@@ -49,8 +49,8 @@
49
49
  "minLength": 1
50
50
  },
51
51
  "value": {
52
- "description": "A finite number",
53
- "type": "number"
52
+ "type": "number",
53
+ "description": "A finite number"
54
54
  },
55
55
  "unit": {
56
56
  "type": "string"
@@ -215,9 +215,9 @@
215
215
  "type": "object",
216
216
  "properties": {
217
217
  "type": {
218
- "description": "An open vocabulary: note, warning, deprecation, issue, accessibility, coverage…",
219
218
  "type": "string",
220
- "minLength": 1
219
+ "minLength": 1,
220
+ "description": "An open vocabulary: note, warning, deprecation, issue, accessibility, coverage…"
221
221
  },
222
222
  "message": {
223
223
  "type": "string"
@@ -443,9 +443,9 @@
443
443
  "type": "object",
444
444
  "properties": {
445
445
  "type": {
446
- "description": "An open vocabulary: note, warning, deprecation, issue, accessibility, coverage…",
447
446
  "type": "string",
448
- "minLength": 1
447
+ "minLength": 1,
448
+ "description": "An open vocabulary: note, warning, deprecation, issue, accessibility, coverage…"
449
449
  },
450
450
  "message": {
451
451
  "type": "string"
@@ -708,9 +708,9 @@
708
708
  "type": "object",
709
709
  "properties": {
710
710
  "type": {
711
- "description": "An open vocabulary: note, warning, deprecation, issue, accessibility, coverage…",
712
711
  "type": "string",
713
- "minLength": 1
712
+ "minLength": 1,
713
+ "description": "An open vocabulary: note, warning, deprecation, issue, accessibility, coverage…"
714
714
  },
715
715
  "message": {
716
716
  "type": "string"
@@ -908,9 +908,9 @@
908
908
  "type": "object",
909
909
  "properties": {
910
910
  "type": {
911
- "description": "An open vocabulary: note, warning, deprecation, issue, accessibility, coverage…",
912
911
  "type": "string",
913
- "minLength": 1
912
+ "minLength": 1,
913
+ "description": "An open vocabulary: note, warning, deprecation, issue, accessibility, coverage…"
914
914
  },
915
915
  "message": {
916
916
  "type": "string"
@@ -1016,10 +1016,10 @@
1016
1016
  "additionalProperties": {}
1017
1017
  },
1018
1018
  "run": {
1019
- "description": "What the run as a whole carries: its logs, links, labels, annotations and extensions",
1020
1019
  "type": "object",
1021
1020
  "properties": {},
1022
- "additionalProperties": {}
1021
+ "additionalProperties": {},
1022
+ "description": "What the run as a whole carries: its logs, links, labels, annotations and extensions"
1023
1023
  }
1024
1024
  },
1025
1025
  "required": [
@@ -8,8 +8,8 @@
8
8
  "const": true
9
9
  },
10
10
  "id": {
11
- "description": "The layer id",
12
- "type": "string"
11
+ "type": "string",
12
+ "description": "The layer id"
13
13
  },
14
14
  "checks": {
15
15
  "type": "integer",
@@ -11,13 +11,13 @@
11
11
  "type": "object",
12
12
  "properties": {
13
13
  "message": {
14
- "description": "What is wrong, and usually what to do about it",
15
- "type": "string"
14
+ "type": "string",
15
+ "description": "What is wrong, and usually what to do about it"
16
16
  },
17
17
  "code": {
18
- "description": "`usage`: the command or its inputs were wrong. Nothing was written",
19
18
  "type": "string",
20
- "const": "usage"
19
+ "const": "usage",
20
+ "description": "`usage`: the command or its inputs were wrong. Nothing was written"
21
21
  }
22
22
  },
23
23
  "required": [
@@ -4,8 +4,8 @@
4
4
  "type": "object",
5
5
  "properties": {
6
6
  "ok": {
7
- "description": "True when every check of every store passed (otherwise the exit code is 1)",
8
- "type": "boolean"
7
+ "type": "boolean",
8
+ "description": "True when every check of every store passed (otherwise the exit code is 1)"
9
9
  },
10
10
  "stores": {
11
11
  "type": "array",
@@ -21,8 +21,8 @@
21
21
  "type": "object",
22
22
  "properties": {
23
23
  "name": {
24
- "description": "`store`, `list`, `contents`, `write`, …",
25
- "type": "string"
24
+ "type": "string",
25
+ "description": "`store`, `list`, `contents`, `write`, …"
26
26
  },
27
27
  "ok": {
28
28
  "type": "boolean"