create-pathfinder 4.2.0 → 4.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 (39) hide show
  1. package/CLAUDE.md +2 -0
  2. package/package.json +1 -1
  3. package/skills/learn-codebase/SKILL.md +188 -17
  4. package/skills/learn-feature/SKILL.md +136 -15
  5. package/skills/map-system/SKILL.md +293 -0
  6. package/skills/render-artifact/SKILL.md +187 -0
  7. package/skills/render-artifact/engine/bin/render.mjs +225 -0
  8. package/skills/render-artifact/engine/deliver.mjs +197 -0
  9. package/skills/render-artifact/engine/doctor.mjs +96 -0
  10. package/skills/render-artifact/engine/examples/diagram.json +223 -0
  11. package/skills/render-artifact/engine/examples/lesson.json +242 -0
  12. package/skills/render-artifact/engine/references/determinism.md +71 -0
  13. package/skills/render-artifact/engine/references/specification.md +149 -0
  14. package/skills/render-artifact/engine/references/validation.md +268 -0
  15. package/skills/render-artifact/engine/render/behavior.mjs +128 -0
  16. package/skills/render-artifact/engine/render/diagram.mjs +342 -0
  17. package/skills/render-artifact/engine/render/escape.mjs +34 -0
  18. package/skills/render-artifact/engine/render/graph/behavior.mjs +394 -0
  19. package/skills/render-artifact/engine/render/graph/draw.mjs +204 -0
  20. package/skills/render-artifact/engine/render/graph/interaction.mjs +174 -0
  21. package/skills/render-artifact/engine/render/graph/layout.mjs +698 -0
  22. package/skills/render-artifact/engine/render/graph/style.mjs +200 -0
  23. package/skills/render-artifact/engine/render/graph/width.mjs +204 -0
  24. package/skills/render-artifact/engine/render/index.mjs +50 -0
  25. package/skills/render-artifact/engine/render/lesson.mjs +294 -0
  26. package/skills/render-artifact/engine/render/shell.mjs +275 -0
  27. package/skills/render-artifact/engine/render/theme.mjs +592 -0
  28. package/skills/render-artifact/engine/schemas/common.schema.json +101 -0
  29. package/skills/render-artifact/engine/schemas/diagram.schema.json +176 -0
  30. package/skills/render-artifact/engine/schemas/lesson.schema.json +210 -0
  31. package/skills/render-artifact/engine/validate/composition.mjs +395 -0
  32. package/skills/render-artifact/engine/validate/diagnostics.mjs +83 -0
  33. package/skills/render-artifact/engine/validate/diagram-parts.mjs +68 -0
  34. package/skills/render-artifact/engine/validate/evidence.mjs +302 -0
  35. package/skills/render-artifact/engine/validate/index.mjs +132 -0
  36. package/skills/render-artifact/engine/validate/jsonschema.mjs +312 -0
  37. package/skills/render-artifact/engine/validate/structural.mjs +241 -0
  38. package/skills/render-artifact/engine/verification.mjs +76 -0
  39. package/skills/render-artifact/engine/version.mjs +24 -0
@@ -0,0 +1,176 @@
1
+ {
2
+ "$id": "diagram.schema.json",
3
+ "title": "Pathfinder artifact specification — diagram",
4
+ "description": "One diagram artifact. The producer describes the system: what exists, what each thing is, what relates to what, which things belong together, and which ordered walks matter. It describes no part of the canvas. Geometry, ranking, axis, size, spacing, routing, label placement, typography, shape, colour and emphasis are the renderer's, and the schema rejects an attempt at any of them rather than ignoring it.",
5
+ "type": "object",
6
+ "required": ["schema_version", "kind", "provenance", "artifact", "diagram"],
7
+ "additionalProperties": false,
8
+ "if": {
9
+ "description": "A derived diagram is the one that must declare where it was derived from. The requirement is conditional because a proposed diagram may legitimately have no repository behind it at all, and it is written as a conditional so the contract lives in the schema rather than only in code.",
10
+ "required": ["provenance"],
11
+ "properties": { "provenance": { "const": "derived" } }
12
+ },
13
+ "then": { "required": ["source"] },
14
+ "properties": {
15
+ "schema_version": { "$ref": "common.schema.json#/$defs/schema_version" },
16
+ "kind": { "const": "diagram" },
17
+ "provenance": {
18
+ "description": "What kind of claim this diagram makes, and the only thing that decides how strictly it is checked. `derived` maps what the repository asserts about itself at the declared commit: it requires a source, every node and edge carries a citation, claim-bearing prose on a group, path or view carries one, and `artifact.summary` is not permitted. `proposed` describes an intended system: citations are optional, and with no source they are refused outright. There is no default — a diagram that did not say would be assigned a trust level by the engine, and the engine has no business guessing which claim a producer meant to make.",
19
+ "enum": ["derived", "proposed"]
20
+ },
21
+ "artifact": { "$ref": "common.schema.json#/$defs/artifact" },
22
+ "source": { "$ref": "common.schema.json#/$defs/source" },
23
+ "diagram": {
24
+ "type": "object",
25
+ "required": ["topology", "nodes", "edges"],
26
+ "additionalProperties": false,
27
+ "properties": {
28
+ "topology": {
29
+ "description": "The structure of the graph, and the only discriminator. It selects the layout the renderer uses. `graph` — a directed graph with semantic roles, optional grouping and authored paths — is the only supported value; anything else is refused rather than approximated.",
30
+ "enum": ["graph"]
31
+ },
32
+ "nodes": {
33
+ "type": "array",
34
+ "minItems": 1,
35
+ "maxItems": 40,
36
+ "items": { "$ref": "diagram.schema.json#/$defs/node" }
37
+ },
38
+ "groups": {
39
+ "description": "Boundaries. Which nodes belong together is meaning; whether a boundary is drawn as a box, a band or a tint is not.",
40
+ "type": "array",
41
+ "maxItems": 8,
42
+ "items": { "$ref": "diagram.schema.json#/$defs/group" }
43
+ },
44
+ "edges": {
45
+ "description": "Relationships. An empty list is legal: a diagram of things that do not yet relate is a diagram.",
46
+ "type": "array",
47
+ "maxItems": 80,
48
+ "items": { "$ref": "diagram.schema.json#/$defs/edge" }
49
+ },
50
+ "paths": {
51
+ "description": "Ordered walks that matter — a request flow, a clean run. A path names the edges it consists of, never the nodes, because two edges may join the same pair and a node sequence could not say which claim the path was making. Emphasis is derived from these: the producer says why something matters, and the renderer decides how much ink it gets.",
52
+ "type": "array",
53
+ "maxItems": 6,
54
+ "items": { "$ref": "diagram.schema.json#/$defs/path" }
55
+ },
56
+ "views": {
57
+ "description": "Authored focus sets — an argument about what matters together.",
58
+ "type": "array",
59
+ "maxItems": 6,
60
+ "items": { "$ref": "diagram.schema.json#/$defs/view" }
61
+ }
62
+ }
63
+ }
64
+ },
65
+ "$defs": {
66
+ "label": {
67
+ "description": "A short label the renderer places. The real cap is 32 columns and is enforced by the structural layer, because a column is not a character: `漢` is one character and two columns, and a combining mark is one character and none. `maxLength` here is only a sanity bound — a label may carry many more characters than columns once combining marks are counted, so it is set well above the column cap rather than duplicating it.",
68
+ "type": "string",
69
+ "minLength": 1,
70
+ "maxLength": 400
71
+ },
72
+ "edge_label": {
73
+ "description": "Capped at 24 columns by the structural layer, on one line. `maxLength` is a sanity bound, as above.",
74
+ "type": "string",
75
+ "minLength": 1,
76
+ "maxLength": 400
77
+ },
78
+ "role": {
79
+ "description": "What a node is, semantically. A closed vocabulary, because the renderer maps role to shape and colour and must never improvise a presentation for a value it does not know. Architecture roles and process roles share one vocabulary on purpose: a codebase map uses `service` and `store`, a migration map uses `step` and `decision`, and nothing in the renderer branches on which.",
80
+ "enum": [
81
+ "actor", "interface", "service", "store", "queue",
82
+ "job", "external", "step", "decision", "terminal"
83
+ ]
84
+ },
85
+ "relation": {
86
+ "description": "What one node does to another. Closed for the same reason as `role`.",
87
+ "enum": [
88
+ "calls", "reads", "writes", "publishes",
89
+ "consumes", "depends_on", "transitions_to", "triggers"
90
+ ]
91
+ },
92
+ "node": {
93
+ "type": "object",
94
+ "required": ["id", "label", "role"],
95
+ "additionalProperties": false,
96
+ "properties": {
97
+ "id": { "$ref": "common.schema.json#/$defs/identifier" },
98
+ "label": { "$ref": "diagram.schema.json#/$defs/label" },
99
+ "role": { "$ref": "diagram.schema.json#/$defs/role" },
100
+ "summary": { "type": "string", "minLength": 1, "maxLength": 1000 },
101
+ "detail": { "$ref": "common.schema.json#/$defs/prose" },
102
+ "group": {
103
+ "description": "The group this node belongs to, or nothing. A node belongs to at most one group: multiple membership is not a rule to detect later, it is a state this field cannot represent.",
104
+ "$ref": "common.schema.json#/$defs/identifier"
105
+ },
106
+ "evidence": { "$ref": "common.schema.json#/$defs/evidence" }
107
+ }
108
+ },
109
+ "group": {
110
+ "type": "object",
111
+ "required": ["id", "label"],
112
+ "additionalProperties": false,
113
+ "properties": {
114
+ "id": { "$ref": "common.schema.json#/$defs/identifier" },
115
+ "label": { "$ref": "diagram.schema.json#/$defs/label" },
116
+ "summary": { "type": "string", "minLength": 1, "maxLength": 1000 },
117
+ "parent": {
118
+ "description": "The group containing this one, or nothing. Nesting is one level: a parent must itself be a root.",
119
+ "$ref": "common.schema.json#/$defs/identifier"
120
+ },
121
+ "evidence": { "$ref": "common.schema.json#/$defs/evidence" }
122
+ }
123
+ },
124
+ "edge": {
125
+ "type": "object",
126
+ "required": ["id", "from", "to", "relation"],
127
+ "additionalProperties": false,
128
+ "properties": {
129
+ "id": {
130
+ "description": "Required, because paths address edges by it and a highlight has to be exact.",
131
+ "$ref": "common.schema.json#/$defs/identifier"
132
+ },
133
+ "from": { "$ref": "common.schema.json#/$defs/identifier" },
134
+ "to": { "$ref": "common.schema.json#/$defs/identifier" },
135
+ "relation": { "$ref": "diagram.schema.json#/$defs/relation" },
136
+ "label": { "$ref": "diagram.schema.json#/$defs/edge_label" },
137
+ "evidence": { "$ref": "common.schema.json#/$defs/evidence" }
138
+ }
139
+ },
140
+ "path": {
141
+ "type": "object",
142
+ "required": ["id", "label", "edges"],
143
+ "additionalProperties": false,
144
+ "properties": {
145
+ "id": { "$ref": "common.schema.json#/$defs/identifier" },
146
+ "label": { "$ref": "diagram.schema.json#/$defs/label" },
147
+ "note": { "type": "string", "minLength": 1, "maxLength": 1000 },
148
+ "edges": {
149
+ "description": "Ordered edge ids. Each edge's target is the next edge's source, which is what makes the walk a walk.",
150
+ "type": "array",
151
+ "minItems": 1,
152
+ "maxItems": 80,
153
+ "items": { "$ref": "common.schema.json#/$defs/identifier" }
154
+ },
155
+ "evidence": { "$ref": "common.schema.json#/$defs/evidence" }
156
+ }
157
+ },
158
+ "view": {
159
+ "type": "object",
160
+ "required": ["id", "label", "focus"],
161
+ "additionalProperties": false,
162
+ "properties": {
163
+ "id": { "$ref": "common.schema.json#/$defs/identifier" },
164
+ "label": { "$ref": "diagram.schema.json#/$defs/label" },
165
+ "note": { "type": "string", "minLength": 1, "maxLength": 1000 },
166
+ "focus": {
167
+ "type": "array",
168
+ "minItems": 1,
169
+ "maxItems": 40,
170
+ "items": { "$ref": "common.schema.json#/$defs/identifier" }
171
+ },
172
+ "evidence": { "$ref": "common.schema.json#/$defs/evidence" }
173
+ }
174
+ }
175
+ }
176
+ }
@@ -0,0 +1,210 @@
1
+ {
2
+ "$id": "lesson.schema.json",
3
+ "title": "Pathfinder artifact specification — lesson",
4
+ "description": "One lesson artifact. `learn-feature` supplies one module; `learn-codebase` supplies many. The same fields serve both: there is no consumer-specific field, branch, or escape hatch.",
5
+ "type": "object",
6
+ "required": ["schema_version", "kind", "artifact", "source", "lesson"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "schema_version": { "$ref": "common.schema.json#/$defs/schema_version" },
10
+ "kind": { "const": "lesson" },
11
+ "artifact": { "$ref": "common.schema.json#/$defs/artifact" },
12
+ "source": { "$ref": "common.schema.json#/$defs/source" },
13
+ "lesson": {
14
+ "type": "object",
15
+ "required": ["modules"],
16
+ "additionalProperties": false,
17
+ "properties": {
18
+ "objectives": {
19
+ "description": "What a reader should be able to do afterwards. Renderer-owned chrome labels it; the producer owns the claims.",
20
+ "type": "array",
21
+ "minItems": 1,
22
+ "maxItems": 20,
23
+ "items": { "type": "string", "minLength": 1, "maxLength": 400 }
24
+ },
25
+ "modules": {
26
+ "type": "array",
27
+ "minItems": 1,
28
+ "maxItems": 60,
29
+ "items": { "$ref": "lesson.schema.json#/$defs/module" }
30
+ }
31
+ }
32
+ }
33
+ },
34
+ "$defs": {
35
+ "module": {
36
+ "description": "One unit of the lesson. A single module and sixty modules render through the same path; nothing branches on the count.",
37
+ "type": "object",
38
+ "required": ["id", "title", "sections"],
39
+ "additionalProperties": false,
40
+ "properties": {
41
+ "id": { "$ref": "common.schema.json#/$defs/identifier" },
42
+ "title": { "type": "string", "minLength": 1, "maxLength": 200 },
43
+ "summary": { "type": "string", "minLength": 1, "maxLength": 1000 },
44
+ "requires": {
45
+ "description": "Module ids this module builds on. Optional: the module graph is allowed to be a flat list. Edges must resolve and must not form a cycle.",
46
+ "type": "array",
47
+ "maxItems": 20,
48
+ "items": { "$ref": "common.schema.json#/$defs/identifier" }
49
+ },
50
+ "sections": {
51
+ "type": "array",
52
+ "minItems": 1,
53
+ "maxItems": 60,
54
+ "items": { "$ref": "lesson.schema.json#/$defs/section" }
55
+ }
56
+ }
57
+ },
58
+ "section": {
59
+ "description": "A section of a module, discriminated by `type`.",
60
+ "oneOf": [
61
+ { "$ref": "lesson.schema.json#/$defs/prose_section" },
62
+ { "$ref": "lesson.schema.json#/$defs/concept_section" },
63
+ { "$ref": "lesson.schema.json#/$defs/code_section" },
64
+ { "$ref": "lesson.schema.json#/$defs/flow_section" },
65
+ { "$ref": "lesson.schema.json#/$defs/quiz_section" },
66
+ { "$ref": "lesson.schema.json#/$defs/exercise_section" }
67
+ ]
68
+ },
69
+ "prose_section": {
70
+ "description": "Explanatory text carrying no claim that needs citing.",
71
+ "type": "object",
72
+ "required": ["type", "id", "body"],
73
+ "additionalProperties": false,
74
+ "properties": {
75
+ "type": { "const": "prose" },
76
+ "id": { "$ref": "common.schema.json#/$defs/identifier" },
77
+ "title": { "type": "string", "minLength": 1, "maxLength": 200 },
78
+ "body": { "$ref": "common.schema.json#/$defs/prose" }
79
+ }
80
+ },
81
+ "concept_section": {
82
+ "description": "A claim about the source. `evidence` is required and the evidence layer rejects it empty: a concept without evidence is an error, not a warning.",
83
+ "type": "object",
84
+ "required": ["type", "id", "title", "body", "evidence"],
85
+ "additionalProperties": false,
86
+ "properties": {
87
+ "type": { "const": "concept" },
88
+ "id": { "$ref": "common.schema.json#/$defs/identifier" },
89
+ "title": { "type": "string", "minLength": 1, "maxLength": 200 },
90
+ "body": { "$ref": "common.schema.json#/$defs/prose" },
91
+ "evidence": { "$ref": "common.schema.json#/$defs/evidence" }
92
+ }
93
+ },
94
+ "code_section": {
95
+ "description": "A literal excerpt. `language` names the code's language for the reader; it selects no highlighter and no styling.",
96
+ "type": "object",
97
+ "required": ["type", "id", "language", "lines"],
98
+ "additionalProperties": false,
99
+ "properties": {
100
+ "type": { "const": "code" },
101
+ "id": { "$ref": "common.schema.json#/$defs/identifier" },
102
+ "title": { "type": "string", "minLength": 1, "maxLength": 200 },
103
+ "language": {
104
+ "type": "string",
105
+ "pattern": "^[a-z0-9][a-z0-9+#.-]{0,20}$"
106
+ },
107
+ "caption": { "type": "string", "minLength": 1, "maxLength": 1000 },
108
+ "first_line": {
109
+ "description": "The source line number the first emitted line had. Renders the gutter; changes nothing else.",
110
+ "type": "integer",
111
+ "minimum": 1
112
+ },
113
+ "lines": {
114
+ "type": "array",
115
+ "minItems": 1,
116
+ "maxItems": 400,
117
+ "items": { "type": "string", "maxLength": 500 }
118
+ },
119
+ "evidence": { "$ref": "common.schema.json#/$defs/evidence" }
120
+ }
121
+ },
122
+ "flow_section": {
123
+ "description": "An ordered process. The first step is the entry; every other step must be reachable from it, and the graph must be acyclic.",
124
+ "type": "object",
125
+ "required": ["type", "id", "title", "steps"],
126
+ "additionalProperties": false,
127
+ "properties": {
128
+ "type": { "const": "flow" },
129
+ "id": { "$ref": "common.schema.json#/$defs/identifier" },
130
+ "title": { "type": "string", "minLength": 1, "maxLength": 200 },
131
+ "steps": {
132
+ "type": "array",
133
+ "minItems": 1,
134
+ "maxItems": 40,
135
+ "items": {
136
+ "type": "object",
137
+ "required": ["id", "title"],
138
+ "additionalProperties": false,
139
+ "properties": {
140
+ "id": { "$ref": "common.schema.json#/$defs/identifier" },
141
+ "title": { "type": "string", "minLength": 1, "maxLength": 200 },
142
+ "detail": { "type": "string", "minLength": 1, "maxLength": 2000 },
143
+ "next": {
144
+ "description": "Step ids this step leads to. Absent means the following step in the array, which is what a linear flow wants.",
145
+ "type": "array",
146
+ "maxItems": 10,
147
+ "items": { "$ref": "common.schema.json#/$defs/identifier" }
148
+ },
149
+ "evidence": { "$ref": "common.schema.json#/$defs/evidence" }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ },
155
+ "quiz_section": {
156
+ "description": "Comprehension questions. Each answer is an index into that question's own options.",
157
+ "type": "object",
158
+ "required": ["type", "id", "questions"],
159
+ "additionalProperties": false,
160
+ "properties": {
161
+ "type": { "const": "quiz" },
162
+ "id": { "$ref": "common.schema.json#/$defs/identifier" },
163
+ "title": { "type": "string", "minLength": 1, "maxLength": 200 },
164
+ "questions": {
165
+ "type": "array",
166
+ "minItems": 1,
167
+ "maxItems": 30,
168
+ "items": {
169
+ "type": "object",
170
+ "required": ["id", "prompt", "options", "answer"],
171
+ "additionalProperties": false,
172
+ "properties": {
173
+ "id": { "$ref": "common.schema.json#/$defs/identifier" },
174
+ "prompt": { "type": "string", "minLength": 1, "maxLength": 1000 },
175
+ "options": {
176
+ "type": "array",
177
+ "minItems": 2,
178
+ "maxItems": 8,
179
+ "uniqueItems": true,
180
+ "items": { "type": "string", "minLength": 1, "maxLength": 500 }
181
+ },
182
+ "answer": { "type": "integer", "minimum": 0 },
183
+ "explanation": { "type": "string", "minLength": 1, "maxLength": 2000 },
184
+ "evidence": { "$ref": "common.schema.json#/$defs/evidence" }
185
+ }
186
+ }
187
+ }
188
+ }
189
+ },
190
+ "exercise_section": {
191
+ "description": "Something for the reader to do. The renderer supplies the disclosure chrome around hints; the producer supplies their text.",
192
+ "type": "object",
193
+ "required": ["type", "id", "title", "body"],
194
+ "additionalProperties": false,
195
+ "properties": {
196
+ "type": { "const": "exercise" },
197
+ "id": { "$ref": "common.schema.json#/$defs/identifier" },
198
+ "title": { "type": "string", "minLength": 1, "maxLength": 200 },
199
+ "body": { "$ref": "common.schema.json#/$defs/prose" },
200
+ "hints": {
201
+ "type": "array",
202
+ "minItems": 1,
203
+ "maxItems": 10,
204
+ "items": { "type": "string", "minLength": 1, "maxLength": 2000 }
205
+ },
206
+ "evidence": { "$ref": "common.schema.json#/$defs/evidence" }
207
+ }
208
+ }
209
+ }
210
+ }