fix: emit #/$defs/ refs in set_tasks schema
TypeBox Type.Cyclic generates bare local refs ("AddTask") which strict
moonshot-flavored JSON Schema gateways (Console Go upstream) reject with
HTTP 400. Rewrite all local $ref values to the #/$defs/ form after
building the schema, and add a regression test asserting the ref format.
Bump version to 0.2.2.
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pi-todo-herdr",
|
"name": "pi-todo-herdr",
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"description": "Hierarchical task tools for Pi with a live widget and Herdr sidebar integration.",
|
"description": "Hierarchical task tools for Pi with a live widget and Herdr sidebar integration.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./index.ts",
|
"main": "./index.ts",
|
||||||
|
|||||||
+26
-1
@@ -15,6 +15,29 @@ const TaskStatusSchema = StringEnum(["pending", "in-progress", "blocked", "done"
|
|||||||
const SetTaskModeSchema = StringEnum(["append", "replace"] as const);
|
const SetTaskModeSchema = StringEnum(["append", "replace"] as const);
|
||||||
const RemovalReasonSchema = StringEnum(["mistaken", "duplicate", "canceled"] as const);
|
const RemovalReasonSchema = StringEnum(["mistaken", "duplicate", "canceled"] as const);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TypeBox's Type.Cyclic emits bare local refs ("AddTask") instead of URI
|
||||||
|
* references ("#/$defs/AddTask"). Strict JSON Schema gateways (e.g. the
|
||||||
|
* moonshot-flavored validator behind Console Go) reject those with a 400.
|
||||||
|
* Rewrite every local $ref in place to the #/$defs/ form.
|
||||||
|
*/
|
||||||
|
function normalizeLocalRefs<T>(schema: T): T {
|
||||||
|
if (Array.isArray(schema)) {
|
||||||
|
for (const item of schema) normalizeLocalRefs(item);
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
if (schema && typeof schema === "object") {
|
||||||
|
for (const [key, value] of Object.entries(schema)) {
|
||||||
|
if (key === "$ref" && typeof value === "string" && !value.startsWith("#") && !value.includes("://")) {
|
||||||
|
(schema as Record<string, unknown>)[key] = `#/$defs/${value}`;
|
||||||
|
} else {
|
||||||
|
normalizeLocalRefs(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
const AddTaskSchema = Type.Cyclic(
|
const AddTaskSchema = Type.Cyclic(
|
||||||
{
|
{
|
||||||
AddTask: Type.Object(
|
AddTask: Type.Object(
|
||||||
@@ -38,7 +61,8 @@ const AddTaskSchema = Type.Cyclic(
|
|||||||
"AddTask",
|
"AddTask",
|
||||||
);
|
);
|
||||||
|
|
||||||
export const SetTaskParams = Type.Object(
|
export const SetTaskParams = normalizeLocalRefs(
|
||||||
|
Type.Object(
|
||||||
{
|
{
|
||||||
mode: SetTaskModeSchema,
|
mode: SetTaskModeSchema,
|
||||||
tasks: Type.Array(AddTaskSchema, {
|
tasks: Type.Array(AddTaskSchema, {
|
||||||
@@ -49,6 +73,7 @@ export const SetTaskParams = Type.Object(
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{ additionalProperties: false },
|
{ additionalProperties: false },
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
const TaskPatchSchema = Type.Object(
|
const TaskPatchSchema = Type.Object(
|
||||||
|
|||||||
@@ -31,6 +31,17 @@ test("registers five focused tools without the old add_task alias", () => {
|
|||||||
assert.deepEqual(Object.keys(tools.get("get_task").parameters.properties), ["ids"]);
|
assert.deepEqual(Object.keys(tools.get("get_task").parameters.properties), ["ids"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("set_tasks schema uses #/$defs/ refs accepted by strict providers", () => {
|
||||||
|
const { tools } = registeredTools();
|
||||||
|
const itemSchema = tools.get("set_tasks").parameters.properties.tasks.items;
|
||||||
|
// Every local $ref must be a URI reference; bare names ("AddTask") are
|
||||||
|
// rejected by moonshot-flavored schema validators (Console Go upstream).
|
||||||
|
assert.equal(itemSchema.$ref, "#/$defs/AddTask");
|
||||||
|
assert.equal(itemSchema.$defs.AddTask.properties.children.items.$ref, "#/$defs/AddTask");
|
||||||
|
const serialized = JSON.stringify(tools.get("set_tasks").parameters);
|
||||||
|
assert.ok(!/"\$ref":"(?!\#)/.test(serialized), "no bare $ref values remain");
|
||||||
|
});
|
||||||
|
|
||||||
test("set_tasks appends optional-description tasks and persists a complete snapshot", async () => {
|
test("set_tasks appends optional-description tasks and persists a complete snapshot", async () => {
|
||||||
const harness = registeredTools();
|
const harness = registeredTools();
|
||||||
const result = await execute(harness.tools.get("set_tasks"), {
|
const result = await execute(harness.tools.get("set_tasks"), {
|
||||||
|
|||||||
Reference in New Issue
Block a user