@danypops/papyrus 0.47.0 → 0.47.1
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/package.json +1 -1
- package/src/handlers/shared.ts +8 -0
- package/src/handlers/tasks.ts +33 -17
package/package.json
CHANGED
package/src/handlers/shared.ts
CHANGED
|
@@ -29,6 +29,8 @@ interface OperationSchemaNode {
|
|
|
29
29
|
readonly properties?: Readonly<Record<string, OperationSchemaNode>>;
|
|
30
30
|
readonly required?: readonly string[];
|
|
31
31
|
readonly additionalProperties?: boolean | OperationSchemaNode;
|
|
32
|
+
/** A key not in `properties` is validated against the first pattern here whose RegExp matches it, instead of falling through to `additionalProperties` -- e.g. a free-form string-keyed map (tasks.create's checklist) uses `{"^.*$": entrySchema}` so a client-side JSON-Schema validator that reports `additionalProperties`-as-schema violations only as a generic top-level "must not have additional properties" (TypeBox's own real, confirmed behavior -- see vehicle-shell.ts's formatSchemaChildren for the matching tools_man rendering) instead descends into the real nested violation, matching an array's `items` precision. */
|
|
33
|
+
readonly patternProperties?: Readonly<Record<string, OperationSchemaNode>>;
|
|
32
34
|
readonly items?: OperationSchemaNode;
|
|
33
35
|
readonly minLength?: number;
|
|
34
36
|
readonly maxLength?: number;
|
|
@@ -80,6 +82,12 @@ function validateSchemaValue(value: unknown, schema: OperationSchemaNode, path:
|
|
|
80
82
|
}
|
|
81
83
|
for (const key of Object.keys(record)) {
|
|
82
84
|
if (key in (schema.properties ?? {})) continue;
|
|
85
|
+
const patternMatch = Object.entries(schema.patternProperties ?? {}).find(([pattern]) => new RegExp(pattern).test(key));
|
|
86
|
+
if (patternMatch) {
|
|
87
|
+
const issues = validateSchemaValue(record[key], patternMatch[1], [...path, key]);
|
|
88
|
+
if (issues.length > 0) return issues;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
83
91
|
if (schema.additionalProperties === false) return schemaIssue([...path, key], `${key} is not allowed`);
|
|
84
92
|
if (typeof schema.additionalProperties === "object") {
|
|
85
93
|
const issues = validateSchemaValue(record[key], schema.additionalProperties, [...path, key]);
|
package/src/handlers/tasks.ts
CHANGED
|
@@ -114,31 +114,47 @@ const gateProp = {
|
|
|
114
114
|
],
|
|
115
115
|
} as const;
|
|
116
116
|
|
|
117
|
+
/**
|
|
118
|
+
* `patternProperties: {"^.*$": entrySchema}` rather than `additionalProperties: entrySchema`,
|
|
119
|
+
* despite both meaning "every key maps to entrySchema" for a free-form string-keyed map:
|
|
120
|
+
* confirmed live (2026-08-09) that TypeBox's own Value.Errors -- the schema validator Pi's tool-
|
|
121
|
+
* calling harness runs client-side, before a call ever reaches this daemon -- reports an
|
|
122
|
+
* additionalProperties-as-schema violation only as a generic top-level "must not have additional
|
|
123
|
+
* properties", with zero descent into which nested field actually broke, while the structurally
|
|
124
|
+
* identical items-as-schema case (gates, proof arrays below) descends and reports the exact
|
|
125
|
+
* broken field. patternProperties does not have that limitation and gives the same precision as
|
|
126
|
+
* items. See handlers/shared.ts's OperationSchemaNode.patternProperties for the matching
|
|
127
|
+
* server-side runtime check, and vehicle-shell.ts's formatSchemaChildren for the matching
|
|
128
|
+
* tools_man rendering.
|
|
129
|
+
*/
|
|
117
130
|
const checklistProp = {
|
|
118
131
|
type: "object",
|
|
119
132
|
description: "Map from completion criterion text to one or more typed proof references. An empty map clears the checklist.",
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
+
patternProperties: {
|
|
134
|
+
"^.*$": {
|
|
135
|
+
type: "object",
|
|
136
|
+
properties: {
|
|
137
|
+
proof: {
|
|
138
|
+
type: "array",
|
|
139
|
+
minItems: 1,
|
|
140
|
+
items: {
|
|
141
|
+
type: "object",
|
|
142
|
+
description: "Accepted proof shape: {type, target, expect?}.",
|
|
143
|
+
properties: {
|
|
144
|
+
type: { type: "string", enum: PROOF_TYPES },
|
|
145
|
+
target: { type: "string", minLength: 1 },
|
|
146
|
+
expect: { type: "string" },
|
|
147
|
+
},
|
|
148
|
+
required: ["type", "target"],
|
|
149
|
+
additionalProperties: false,
|
|
133
150
|
},
|
|
134
|
-
required: ["type", "target"],
|
|
135
|
-
additionalProperties: false,
|
|
136
151
|
},
|
|
137
152
|
},
|
|
153
|
+
required: ["proof"],
|
|
154
|
+
additionalProperties: false,
|
|
138
155
|
},
|
|
139
|
-
required: ["proof"],
|
|
140
|
-
additionalProperties: false,
|
|
141
156
|
},
|
|
157
|
+
additionalProperties: false,
|
|
142
158
|
examples: [
|
|
143
159
|
{
|
|
144
160
|
"tests pass": { proof: [{ type: "test", target: "bun test", expect: "0 failures" }] },
|