@agentshouse/mdmodel 0.1.0-alpha.6 → 0.1.0-alpha.8

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/dist/project.js CHANGED
@@ -49,7 +49,7 @@ export function project(document, file, context = {
49
49
  const body = document.content.slice(bodyStart);
50
50
  const edits = internalEdits(body, file, new Set(context.documentTargets));
51
51
  const declared = document.type;
52
- if (declared === undefined) {
52
+ if (declared === undefined || declared === 'any') {
53
53
  return {
54
54
  ok: true,
55
55
  text: projected(body, [
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdmodel/src/project.ts"],"sourcesContent":["import { readDefinition } from './definition.js';\nimport { parse } from './document.js';\nimport { linkInventory } from './links.js';\nimport { classifyHref } from './paths.js';\nimport { refusal } from './refuse.js';\nimport { headingSpans } from './sections.js';\nimport type { Document, Projection, ProjectionContext } from './types.js';\nimport { bodyStartOf } from './yaml.js';\n\ntype Span = readonly [number, number];\n\ntype Edit = {\n readonly start: number;\n readonly end: number;\n readonly text: string;\n};\n\nfunction internalEdits(body: string, file: string, documentTargets: ReadonlySet<string>): Edit[] {\n const inventory = linkInventory(body);\n const internal = new Set<number>();\n const edits: Edit[] = [];\n for (const use of inventory.uses) {\n const resolved = classifyHref(file, use.destination.href);\n if (resolved.kind !== 'path' || !documentTargets.has(resolved.path)) continue;\n internal.add(use.destination.start);\n edits.push({\n start: use.start,\n end: use.end,\n text: body.slice(use.labelStart, use.labelEnd),\n });\n }\n for (const block of inventory.blocks) {\n if (!internal.has(block.destination.start)) continue;\n edits.push({ start: block.start, end: block.end, text: '' });\n }\n return edits.sort((left, right) => left.start - right.start);\n}\n\nfunction projected(body: string, spans: readonly Span[], edits: readonly Edit[]): string {\n let text = '';\n for (const [from, to] of spans) {\n let cursor = from;\n for (const edit of edits) {\n if (edit.start < cursor || edit.end > to) continue;\n text += body.slice(cursor, edit.start) + edit.text;\n cursor = edit.end;\n }\n text += body.slice(cursor, to);\n }\n return text;\n}\n\nexport function project(\n document: Document,\n file: string,\n context: ProjectionContext = { documentTargets: [] },\n): Projection {\n const bodyStart = bodyStartOf(document.content);\n const body = document.content.slice(bodyStart);\n const edits = internalEdits(body, file, new Set(context.documentTargets));\n const declared = document.type;\n if (declared === undefined) {\n return { ok: true, text: projected(body, [[0, body.length]], edits) };\n }\n const source = context.definition;\n if (source === undefined) {\n return { ok: false, refusal: refusal(file, 'unknown-type', { location: 'type' }) };\n }\n const definitionFile = `types/${declared}.md`;\n const parsed = parse(source, definitionFile);\n if (!parsed.ok) return { ok: false, refusal: parsed.refusal };\n const definition = readDefinition(definitionFile, parsed.document);\n if ('rule' in definition) return { ok: false, refusal: definition };\n const free = new Set(\n Object.entries(definition.sections).flatMap(([name, spec]) =>\n spec.kind === 'text' ? [name] : [],\n ),\n );\n const spans = headingSpans(document.content, bodyStart)\n .filter((span) => free.has(span.name))\n .map((span): Span => [span.headingStart - bodyStart, span.bodyEnd - bodyStart]);\n return { ok: true, text: projected(body, spans, edits) };\n}\n"],"names":["readDefinition","parse","linkInventory","classifyHref","refusal","headingSpans","bodyStartOf","internalEdits","body","file","documentTargets","inventory","internal","Set","edits","use","uses","resolved","destination","href","kind","has","path","add","start","push","end","text","slice","labelStart","labelEnd","block","blocks","sort","left","right","projected","spans","from","to","cursor","edit","project","document","context","bodyStart","content","declared","type","undefined","ok","length","source","definition","location","definitionFile","parsed","free","Object","entries","sections","flatMap","name","spec","filter","span","map","headingStart","bodyEnd"],"mappings":"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"}
1
+ {"version":3,"sources":["/workspace/packages/mdmodel/src/project.ts"],"sourcesContent":["import { readDefinition } from './definition.js';\nimport { parse } from './document.js';\nimport { linkInventory } from './links.js';\nimport { classifyHref } from './paths.js';\nimport { refusal } from './refuse.js';\nimport { headingSpans } from './sections.js';\nimport type { Document, Projection, ProjectionContext } from './types.js';\nimport { bodyStartOf } from './yaml.js';\n\ntype Span = readonly [number, number];\n\ntype Edit = {\n readonly start: number;\n readonly end: number;\n readonly text: string;\n};\n\nfunction internalEdits(body: string, file: string, documentTargets: ReadonlySet<string>): Edit[] {\n const inventory = linkInventory(body);\n const internal = new Set<number>();\n const edits: Edit[] = [];\n for (const use of inventory.uses) {\n const resolved = classifyHref(file, use.destination.href);\n if (resolved.kind !== 'path' || !documentTargets.has(resolved.path)) continue;\n internal.add(use.destination.start);\n edits.push({\n start: use.start,\n end: use.end,\n text: body.slice(use.labelStart, use.labelEnd),\n });\n }\n for (const block of inventory.blocks) {\n if (!internal.has(block.destination.start)) continue;\n edits.push({ start: block.start, end: block.end, text: '' });\n }\n return edits.sort((left, right) => left.start - right.start);\n}\n\nfunction projected(body: string, spans: readonly Span[], edits: readonly Edit[]): string {\n let text = '';\n for (const [from, to] of spans) {\n let cursor = from;\n for (const edit of edits) {\n if (edit.start < cursor || edit.end > to) continue;\n text += body.slice(cursor, edit.start) + edit.text;\n cursor = edit.end;\n }\n text += body.slice(cursor, to);\n }\n return text;\n}\n\nexport function project(\n document: Document,\n file: string,\n context: ProjectionContext = { documentTargets: [] },\n): Projection {\n const bodyStart = bodyStartOf(document.content);\n const body = document.content.slice(bodyStart);\n const edits = internalEdits(body, file, new Set(context.documentTargets));\n const declared = document.type;\n if (declared === undefined || declared === 'any') {\n return { ok: true, text: projected(body, [[0, body.length]], edits) };\n }\n const source = context.definition;\n if (source === undefined) {\n return { ok: false, refusal: refusal(file, 'unknown-type', { location: 'type' }) };\n }\n const definitionFile = `types/${declared}.md`;\n const parsed = parse(source, definitionFile);\n if (!parsed.ok) return { ok: false, refusal: parsed.refusal };\n const definition = readDefinition(definitionFile, parsed.document);\n if ('rule' in definition) return { ok: false, refusal: definition };\n const free = new Set(\n Object.entries(definition.sections).flatMap(([name, spec]) =>\n spec.kind === 'text' ? [name] : [],\n ),\n );\n const spans = headingSpans(document.content, bodyStart)\n .filter((span) => free.has(span.name))\n .map((span): Span => [span.headingStart - bodyStart, span.bodyEnd - bodyStart]);\n return { ok: true, text: projected(body, spans, edits) };\n}\n"],"names":["readDefinition","parse","linkInventory","classifyHref","refusal","headingSpans","bodyStartOf","internalEdits","body","file","documentTargets","inventory","internal","Set","edits","use","uses","resolved","destination","href","kind","has","path","add","start","push","end","text","slice","labelStart","labelEnd","block","blocks","sort","left","right","projected","spans","from","to","cursor","edit","project","document","context","bodyStart","content","declared","type","undefined","ok","length","source","definition","location","definitionFile","parsed","free","Object","entries","sections","flatMap","name","spec","filter","span","map","headingStart","bodyEnd"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,iBAAiB,CAAC;AAgC7D,wBAAgB,cAAc,CAC5B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,EAC3C,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACxC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,gBAAgB,GAAG,YAAY,GAAG,YAAY,CAAA;CAAE,GAAG,SAAS,CAgBrF"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,iBAAiB,CAAC;AAkB7D,wBAAgB,cAAc,CAC5B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,EAC3C,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACxC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,gBAAgB,GAAG,YAAY,GAAG,YAAY,CAAA;CAAE,GAAG,SAAS,CAUrF"}
package/dist/schema.js CHANGED
@@ -1,14 +1,4 @@
1
- import { Ajv } from 'ajv';
2
- import formatsPlugin from 'ajv-formats';
3
- const addFormats = formatsPlugin;
4
- const ajv = new Ajv({
5
- allErrors: true,
6
- strict: false,
7
- validateFormats: true
8
- });
9
- addFormats(ajv, [
10
- 'date'
11
- ]);
1
+ import { Validator } from '@cfworker/json-schema';
12
2
  function scalarSchema(spec) {
13
3
  if (spec.kind === 'string' || spec.kind === 'reference') return {
14
4
  type: 'string'
@@ -35,36 +25,24 @@ function fieldSchema(spec) {
35
25
  return scalarSchema(spec);
36
26
  }
37
27
  function ruleFor(error) {
38
- if (error.keyword === 'required') return 'required-field';
39
- if (error.keyword === 'enum') return 'field-enum';
40
- return 'field-kind';
41
- }
42
- function locationFor(error) {
43
- if (error.keyword === 'required' && typeof error.params.missingProperty === 'string') {
44
- return error.params.missingProperty;
45
- }
46
- const path = error.instancePath.replace(/^\//, '').split('/');
47
- return path[0] ?? '';
28
+ return error.keyword === 'enum' ? 'field-enum' : 'field-kind';
48
29
  }
49
30
  export function validateFields(fields, values) {
50
- const properties = {};
51
- const required = [];
52
31
  for (const [name, spec] of Object.entries(fields)){
53
- properties[name] = fieldSchema(spec);
54
- if (spec.required) required.push(name);
32
+ if (spec.required && values[name] === undefined) return {
33
+ field: name,
34
+ rule: 'required-field'
35
+ };
55
36
  }
56
- const validate = ajv.compile({
57
- type: 'object',
58
- properties,
59
- required,
60
- additionalProperties: true
61
- });
62
- if (validate(values)) return undefined;
63
- const error = validate.errors[0];
64
- return {
65
- field: locationFor(error),
66
- rule: ruleFor(error)
67
- };
37
+ for (const [name, spec] of Object.entries(fields)){
38
+ if (values[name] === undefined) continue;
39
+ const result = new Validator(fieldSchema(spec), '2020-12', false).validate(values[name]);
40
+ if (!result.valid) return {
41
+ field: name,
42
+ rule: ruleFor(result.errors[0])
43
+ };
44
+ }
45
+ return undefined;
68
46
  }
69
47
 
70
48
  //# sourceMappingURL=schema.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdmodel/src/schema.ts"],"sourcesContent":["import { Ajv, type ErrorObject } from 'ajv';\nimport formatsPlugin from 'ajv-formats';\nimport type { FieldSpec, ScalarSpec } from './definition.js';\n\nconst addFormats = formatsPlugin as unknown as (validator: Ajv, names?: string[]) => Ajv;\nconst ajv = new Ajv({ allErrors: true, strict: false, validateFormats: true });\naddFormats(ajv, ['date']);\n\nfunction scalarSchema(spec: ScalarSpec): Record<string, unknown> {\n if (spec.kind === 'string' || spec.kind === 'reference') return { type: 'string' };\n if (spec.kind === 'number') return { type: 'number' };\n if (spec.kind === 'date') return { type: 'string', format: 'date' };\n return { type: 'string', enum: [...spec.values] };\n}\n\nfunction fieldSchema(spec: FieldSpec): Record<string, unknown> {\n if (spec.kind === 'list') return { type: 'array', items: scalarSchema(spec.of) };\n return scalarSchema(spec);\n}\n\nfunction ruleFor(error: ErrorObject): 'required-field' | 'field-enum' | 'field-kind' {\n if (error.keyword === 'required') return 'required-field';\n if (error.keyword === 'enum') return 'field-enum';\n return 'field-kind';\n}\n\nfunction locationFor(error: ErrorObject): string {\n if (error.keyword === 'required' && typeof error.params.missingProperty === 'string') {\n return error.params.missingProperty;\n }\n const path = error.instancePath.replace(/^\\//, '').split('/');\n return path[0] ?? '';\n}\n\nexport function validateFields(\n fields: Readonly<Record<string, FieldSpec>>,\n values: Readonly<Record<string, unknown>>,\n): { field: string; rule: 'required-field' | 'field-enum' | 'field-kind' } | undefined {\n const properties: Record<string, Record<string, unknown>> = {};\n const required: string[] = [];\n for (const [name, spec] of Object.entries(fields)) {\n properties[name] = fieldSchema(spec);\n if (spec.required) required.push(name);\n }\n const validate = ajv.compile({\n type: 'object',\n properties,\n required,\n additionalProperties: true,\n });\n if (validate(values)) return undefined;\n const error = validate.errors![0]!;\n return { field: locationFor(error), rule: ruleFor(error) };\n}\n"],"names":["Ajv","formatsPlugin","addFormats","ajv","allErrors","strict","validateFormats","scalarSchema","spec","kind","type","format","enum","values","fieldSchema","items","of","ruleFor","error","keyword","locationFor","params","missingProperty","path","instancePath","replace","split","validateFields","fields","properties","required","name","Object","entries","push","validate","compile","additionalProperties","undefined","errors","field","rule"],"mappings":"AAAA,SAASA,GAAG,QAA0B,MAAM;AAC5C,OAAOC,mBAAmB,cAAc;AAGxC,MAAMC,aAAaD;AACnB,MAAME,MAAM,IAAIH,IAAI;IAAEI,WAAW;IAAMC,QAAQ;IAAOC,iBAAiB;AAAK;AAC5EJ,WAAWC,KAAK;IAAC;CAAO;AAExB,SAASI,aAAaC,IAAgB;IACpC,IAAIA,KAAKC,IAAI,KAAK,YAAYD,KAAKC,IAAI,KAAK,aAAa,OAAO;QAAEC,MAAM;IAAS;IACjF,IAAIF,KAAKC,IAAI,KAAK,UAAU,OAAO;QAAEC,MAAM;IAAS;IACpD,IAAIF,KAAKC,IAAI,KAAK,QAAQ,OAAO;QAAEC,MAAM;QAAUC,QAAQ;IAAO;IAClE,OAAO;QAAED,MAAM;QAAUE,MAAM;eAAIJ,KAAKK,MAAM;SAAC;IAAC;AAClD;AAEA,SAASC,YAAYN,IAAe;IAClC,IAAIA,KAAKC,IAAI,KAAK,QAAQ,OAAO;QAAEC,MAAM;QAASK,OAAOR,aAAaC,KAAKQ,EAAE;IAAE;IAC/E,OAAOT,aAAaC;AACtB;AAEA,SAASS,QAAQC,KAAkB;IACjC,IAAIA,MAAMC,OAAO,KAAK,YAAY,OAAO;IACzC,IAAID,MAAMC,OAAO,KAAK,QAAQ,OAAO;IACrC,OAAO;AACT;AAEA,SAASC,YAAYF,KAAkB;IACrC,IAAIA,MAAMC,OAAO,KAAK,cAAc,OAAOD,MAAMG,MAAM,CAACC,eAAe,KAAK,UAAU;QACpF,OAAOJ,MAAMG,MAAM,CAACC,eAAe;IACrC;IACA,MAAMC,OAAOL,MAAMM,YAAY,CAACC,OAAO,CAAC,OAAO,IAAIC,KAAK,CAAC;IACzD,OAAOH,IAAI,CAAC,EAAE,IAAI;AACpB;AAEA,OAAO,SAASI,eACdC,MAA2C,EAC3Cf,MAAyC;IAEzC,MAAMgB,aAAsD,CAAC;IAC7D,MAAMC,WAAqB,EAAE;IAC7B,KAAK,MAAM,CAACC,MAAMvB,KAAK,IAAIwB,OAAOC,OAAO,CAACL,QAAS;QACjDC,UAAU,CAACE,KAAK,GAAGjB,YAAYN;QAC/B,IAAIA,KAAKsB,QAAQ,EAAEA,SAASI,IAAI,CAACH;IACnC;IACA,MAAMI,WAAWhC,IAAIiC,OAAO,CAAC;QAC3B1B,MAAM;QACNmB;QACAC;QACAO,sBAAsB;IACxB;IACA,IAAIF,SAAStB,SAAS,OAAOyB;IAC7B,MAAMpB,QAAQiB,SAASI,MAAM,AAAC,CAAC,EAAE;IACjC,OAAO;QAAEC,OAAOpB,YAAYF;QAAQuB,MAAMxB,QAAQC;IAAO;AAC3D"}
1
+ {"version":3,"sources":["/workspace/packages/mdmodel/src/schema.ts"],"sourcesContent":["import { Validator, type OutputUnit } from '@cfworker/json-schema';\nimport type { FieldSpec, ScalarSpec } from './definition.js';\n\nfunction scalarSchema(spec: ScalarSpec): Record<string, unknown> {\n if (spec.kind === 'string' || spec.kind === 'reference') return { type: 'string' };\n if (spec.kind === 'number') return { type: 'number' };\n if (spec.kind === 'date') return { type: 'string', format: 'date' };\n return { type: 'string', enum: [...spec.values] };\n}\n\nfunction fieldSchema(spec: FieldSpec): Record<string, unknown> {\n if (spec.kind === 'list') return { type: 'array', items: scalarSchema(spec.of) };\n return scalarSchema(spec);\n}\n\nfunction ruleFor(error: OutputUnit): 'field-enum' | 'field-kind' {\n return error.keyword === 'enum' ? 'field-enum' : 'field-kind';\n}\n\nexport function validateFields(\n fields: Readonly<Record<string, FieldSpec>>,\n values: Readonly<Record<string, unknown>>,\n): { field: string; rule: 'required-field' | 'field-enum' | 'field-kind' } | undefined {\n for (const [name, spec] of Object.entries(fields)) {\n if (spec.required && values[name] === undefined) return { field: name, rule: 'required-field' };\n }\n for (const [name, spec] of Object.entries(fields)) {\n if (values[name] === undefined) continue;\n const result = new Validator(fieldSchema(spec), '2020-12', false).validate(values[name]);\n if (!result.valid) return { field: name, rule: ruleFor(result.errors[0]!) };\n }\n return undefined;\n}\n"],"names":["Validator","scalarSchema","spec","kind","type","format","enum","values","fieldSchema","items","of","ruleFor","error","keyword","validateFields","fields","name","Object","entries","required","undefined","field","rule","result","validate","valid","errors"],"mappings":"AAAA,SAASA,SAAS,QAAyB,wBAAwB;AAGnE,SAASC,aAAaC,IAAgB;IACpC,IAAIA,KAAKC,IAAI,KAAK,YAAYD,KAAKC,IAAI,KAAK,aAAa,OAAO;QAAEC,MAAM;IAAS;IACjF,IAAIF,KAAKC,IAAI,KAAK,UAAU,OAAO;QAAEC,MAAM;IAAS;IACpD,IAAIF,KAAKC,IAAI,KAAK,QAAQ,OAAO;QAAEC,MAAM;QAAUC,QAAQ;IAAO;IAClE,OAAO;QAAED,MAAM;QAAUE,MAAM;eAAIJ,KAAKK,MAAM;SAAC;IAAC;AAClD;AAEA,SAASC,YAAYN,IAAe;IAClC,IAAIA,KAAKC,IAAI,KAAK,QAAQ,OAAO;QAAEC,MAAM;QAASK,OAAOR,aAAaC,KAAKQ,EAAE;IAAE;IAC/E,OAAOT,aAAaC;AACtB;AAEA,SAASS,QAAQC,KAAiB;IAChC,OAAOA,MAAMC,OAAO,KAAK,SAAS,eAAe;AACnD;AAEA,OAAO,SAASC,eACdC,MAA2C,EAC3CR,MAAyC;IAEzC,KAAK,MAAM,CAACS,MAAMd,KAAK,IAAIe,OAAOC,OAAO,CAACH,QAAS;QACjD,IAAIb,KAAKiB,QAAQ,IAAIZ,MAAM,CAACS,KAAK,KAAKI,WAAW,OAAO;YAAEC,OAAOL;YAAMM,MAAM;QAAiB;IAChG;IACA,KAAK,MAAM,CAACN,MAAMd,KAAK,IAAIe,OAAOC,OAAO,CAACH,QAAS;QACjD,IAAIR,MAAM,CAACS,KAAK,KAAKI,WAAW;QAChC,MAAMG,SAAS,IAAIvB,UAAUQ,YAAYN,OAAO,WAAW,OAAOsB,QAAQ,CAACjB,MAAM,CAACS,KAAK;QACvF,IAAI,CAACO,OAAOE,KAAK,EAAE,OAAO;YAAEJ,OAAOL;YAAMM,MAAMX,QAAQY,OAAOG,MAAM,CAAC,EAAE;QAAG;IAC5E;IACA,OAAON;AACT"}
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.1.0-alpha.6";
1
+ export declare const VERSION = "0.1.0-alpha.8";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
- export const VERSION = '0.1.0-alpha.6';
1
+ export const VERSION = '0.1.0-alpha.8';
2
2
 
3
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdmodel/src/version.ts"],"sourcesContent":["export const VERSION = '0.1.0-alpha.6';\n"],"names":["VERSION"],"mappings":"AAAA,OAAO,MAAMA,UAAU,gBAAgB"}
1
+ {"version":3,"sources":["/workspace/packages/mdmodel/src/version.ts"],"sourcesContent":["export const VERSION = '0.1.0-alpha.8';\n"],"names":["VERSION"],"mappings":"AAAA,OAAO,MAAMA,UAAU,gBAAgB"}
@@ -40,6 +40,24 @@
40
40
  "text": "# Title\n\nSee the plan.\n"
41
41
  }
42
42
  },
43
+ {
44
+ "name": "a Document that declares the built-in any type projects its body like an undeclared one",
45
+ "file": "notes/three.md",
46
+ "source": "---\ntype: any\ntitle: Note\n---\n\n## Notes\n\nRead [the plan](../plans/q3.md#goals \"Plan\") and see the [site](https://example.com/x.md).\n",
47
+ "documentTargets": [
48
+ "plans/q3.md",
49
+ "plans/2026-q3.md"
50
+ ],
51
+ "definition": null,
52
+ "move": {
53
+ "href": "../plans/q3.md#goals",
54
+ "to": "../plans/2026-q3.md"
55
+ },
56
+ "expected": {
57
+ "ok": true,
58
+ "text": "\n## Notes\n\nRead the plan and see the [site](https://example.com/x.md).\n"
59
+ }
60
+ },
43
61
  {
44
62
  "name": "typed Document takes its declared free-text sections alone",
45
63
  "file": "tasks/one.md",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentshouse/mdmodel",
3
- "version": "0.1.0-alpha.6",
3
+ "version": "0.1.0-alpha.8",
4
4
  "description": "MD Type language, parser, validator, structured change application, Markdown syntax profile, and conformance fixtures",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,7 +35,6 @@
35
35
  "url": "https://github.com/agentshouse/mdmodel/issues"
36
36
  },
37
37
  "dependencies": {
38
- "ajv": "8.17.1",
39
- "ajv-formats": "3.0.1"
38
+ "@cfworker/json-schema": "4.1.1"
40
39
  }
41
40
  }