@tanqory/dev-mcp 0.0.0-stage → 0.1.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 (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +94 -2
  3. package/bin/tanqory-dev-mcp.mjs +16 -0
  4. package/bundled/examples/blank/config/settings.json +3 -0
  5. package/bundled/examples/blank/locales/en.json +22 -0
  6. package/bundled/examples/blank/locales/th.json +22 -0
  7. package/bundled/examples/blank/regions/footer.json +35 -0
  8. package/bundled/examples/blank/regions/header.json +13 -0
  9. package/bundled/examples/blank/src/bundle.ts +15 -0
  10. package/bundled/examples/blank/src/components/parts.tsx +32 -0
  11. package/bundled/examples/blank/src/entry.client.tsx +6 -0
  12. package/bundled/examples/blank/src/entry.server.tsx +13 -0
  13. package/bundled/examples/blank/src/sections/chrome.tsx +132 -0
  14. package/bundled/examples/blank/src/sections/commerce.tsx +242 -0
  15. package/bundled/examples/blank/src/sections/content.tsx +111 -0
  16. package/bundled/examples/blank/src/sections/editorial.tsx +107 -0
  17. package/bundled/examples/blank/src/settings.ts +15 -0
  18. package/bundled/examples/blank/src/styles/theme.css +195 -0
  19. package/bundled/examples/blank/src/templates.ts +14 -0
  20. package/bundled/examples/blank/src/theme.tsx +76 -0
  21. package/bundled/examples/blank/template.json +24 -0
  22. package/bundled/examples/blank/templates/404.json +14 -0
  23. package/bundled/examples/blank/templates/account.json +14 -0
  24. package/bundled/examples/blank/templates/article.json +14 -0
  25. package/bundled/examples/blank/templates/blog.json +14 -0
  26. package/bundled/examples/blank/templates/cart.json +14 -0
  27. package/bundled/examples/blank/templates/collection.json +14 -0
  28. package/bundled/examples/blank/templates/index.json +36 -0
  29. package/bundled/examples/blank/templates/page.contact.json +18 -0
  30. package/bundled/examples/blank/templates/page.json +14 -0
  31. package/bundled/examples/blank/templates/product.json +18 -0
  32. package/bundled/examples/blank/templates/search.json +14 -0
  33. package/bundled/examples/blank/tests/theme.test.ts +49 -0
  34. package/bundled/theme-abi/contracts/render-context.v2.d.ts +849 -0
  35. package/bundled/theme-abi/contracts/theme-abi-v2.md +1833 -0
  36. package/bundled/theme-abi/generated/capabilities.json +80 -0
  37. package/bundled/theme-abi/generated/field-types.json +869 -0
  38. package/bundled/theme-abi/generated/limits.json +173 -0
  39. package/bundled/theme-abi/schemas/conformance-report.v2.schema.json +482 -0
  40. package/bundled/theme-abi/schemas/theme-artifact.v1.schema.json +230 -0
  41. package/bundled/theme-abi/schemas/theme-manifest.v2.schema.json +254 -0
  42. package/bundled/theme-conformance/docs/storefront-tier.md +250 -0
  43. package/bundled/theme-conformance/schema/conformance-report.v2.schema.json +482 -0
  44. package/bundled/theme-conformance/schema/storefront-report.v1.schema.json +110 -0
  45. package/bundled/theme-conformance/schema/x-tanqory-ai.v0.schema.json +70 -0
  46. package/bundled/theme-kit/docs/headless-api.md +220 -0
  47. package/bundled/theme-kit/generated/kit-strings.json +180 -0
  48. package/bundled/theme-kit/types/headless/index.d.ts +36 -0
  49. package/bundled/theme-kit/types/headless/theme.d.ts +99 -0
  50. package/bundled/theme-kit/types/sdk/schema.d.ts +197 -0
  51. package/bundled/versions.json +8 -0
  52. package/package.json +53 -3
  53. package/src/bm25.mjs +69 -0
  54. package/src/browser.mjs +123 -0
  55. package/src/cli.mjs +127 -0
  56. package/src/devserver.mjs +82 -0
  57. package/src/docs.mjs +329 -0
  58. package/src/index.mjs +33 -0
  59. package/src/kit.mjs +150 -0
  60. package/src/manifest.mjs +82 -0
  61. package/src/prompts.mjs +97 -0
  62. package/src/scaffold.mjs +471 -0
  63. package/src/schemas.mjs +127 -0
  64. package/src/server.mjs +595 -0
  65. package/src/theme.mjs +91 -0
@@ -0,0 +1,127 @@
1
+ /**
2
+ * get_schema: the shapes a theme author writes, from the installed packages (bundled copy as fallback).
3
+ */
4
+ import { DOCS } from './docs.mjs'
5
+
6
+ export const SCHEMA_KINDS = ['manifest', 'section', 'block', 'field-registry', 'theme-settings', 'content-document', 'locale', 'ai-profile', 'storefront-report', 'conformance-report']
7
+
8
+ const doc = (id) => DOCS.find((d) => d.id === id)
9
+
10
+ /** `export interface Name …` / `export declare function name …` up to its closing line at column 0. */
11
+ export function tsBlock(text, name) {
12
+ const lines = text.split('\n')
13
+ const re = new RegExp(`^export\\s+(?:declare\\s+)?(?:interface|type|function|const)\\s+${name}\\b`)
14
+ let at = lines.findIndex((l) => re.test(l))
15
+ if (at < 0) return null
16
+ let start = at
17
+ while (start > 0 && /^\s*(\/\*\*|\*)/.test(lines[start - 1])) start--
18
+ let end = at
19
+ if (/;\s*$/.test(lines[at]) && !/\{\s*$/.test(lines[at])) return lines.slice(start, at + 1).join('\n')
20
+ while (end < lines.length - 1 && !/^\}/.test(lines[end])) end++
21
+ return lines.slice(start, end + 1).join('\n')
22
+ }
23
+
24
+ const LOCALE_SCHEMA = {
25
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
26
+ title: 'Theme locale file (locales/<lang>.json)',
27
+ description:
28
+ "A flat object: dotted key → string. The theme's own keys start with `theme.`; any kit key may be overridden. `{name}` placeholders must be the same set in every language. en.json and th.json must have exactly the same keys.",
29
+ type: 'object',
30
+ propertyNames: { pattern: '^[A-Za-z0-9_]+(\\.[A-Za-z0-9_-]+)+$' },
31
+ additionalProperties: { type: 'string' },
32
+ }
33
+
34
+ const CONTENT_SCHEMA = {
35
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
36
+ title: 'Starter content document (templates/<name>.json, regions/<region>.json)',
37
+ description:
38
+ 'templates/<name>.json: { contentVersion, template: "<name>", regions: { main: { sections: [node…] } } }. regions/header.json and regions/footer.json: { sections: [node…] }. A node is { id, type, settings?, blocks? }; `type` must be a declared section (or, inside blocks, a declared block of that section) and every setting key must be declared with a valid value. `npm run build` refuses anything else.',
39
+ $defs: {
40
+ node: {
41
+ type: 'object',
42
+ required: ['id', 'type'],
43
+ properties: {
44
+ id: { type: 'string', pattern: '^[A-Za-z0-9][A-Za-z0-9._-]*$' },
45
+ type: { type: 'string' },
46
+ settings: { type: 'object' },
47
+ blocks: { type: 'array', items: { $ref: '#/$defs/node' } },
48
+ disabled: { type: 'boolean' },
49
+ },
50
+ additionalProperties: false,
51
+ },
52
+ },
53
+ oneOf: [
54
+ {
55
+ type: 'object',
56
+ required: ['contentVersion', 'template', 'regions'],
57
+ properties: {
58
+ contentVersion: { type: 'integer', minimum: 1 },
59
+ template: { type: 'string' },
60
+ regions: { type: 'object', additionalProperties: { type: 'object', properties: { sections: { type: 'array', items: { $ref: '#/$defs/node' } } } } },
61
+ },
62
+ },
63
+ { type: 'object', required: ['sections'], properties: { sections: { type: 'array', items: { $ref: '#/$defs/node' } } } },
64
+ ],
65
+ }
66
+
67
+ /**
68
+ * @param {import('./docs.mjs').DocCorpus} corpus
69
+ */
70
+ export async function getSchema(corpus, kind) {
71
+ const read = async (id) => corpus.read(doc(id))
72
+ const parse = (r) => (r ? JSON.parse(r.text) : null)
73
+ const meta = (r) => ({ source: r?.source ?? null, version: r?.version ?? null })
74
+
75
+ switch (kind) {
76
+ case 'manifest': {
77
+ const r = await read('abi/manifest-schema')
78
+ return { kind, ...meta(r), schema: parse(r), notes: ['dist/abi/manifest.json is generated by buildManifest (scripts/build.mjs) from your defineSection/defineBlock/defineSettings declarations; do not edit it by hand.', 'The file is the JCS (RFC 8785) bytes plus one trailing newline.'] }
79
+ }
80
+ case 'section':
81
+ case 'block': {
82
+ const m = parse(await read('abi/manifest-schema'))
83
+ const t = await read('kit/section-types')
84
+ const names = kind === 'section' ? ['SectionDefinition', 'SectionPresetDef', 'SectionComponentProps', 'BlockInstance', 'defineSection'] : ['defineBlock', 'BlockSchema', 'BlockInstance']
85
+ return {
86
+ kind,
87
+ ...meta(t),
88
+ types: names.map((n) => tsBlock(t.text, n)).filter(Boolean).join('\n\n'),
89
+ schema: m?.$defs?.component ?? null,
90
+ schemaNote: 'manifest.components.<type> as the build derives it from the declaration (attributes = settings, children = blocks).',
91
+ notes:
92
+ kind === 'section'
93
+ ? ['`type` is persisted: never rename it once stores saved content.', 'presets[0] is the editor\'s "Add section" preview: it must render with height > 0.', 'The kit wraps every section in its data-tq-node element; never render a section outside the kit section tree.', 'Register the section in defineTheme({ sections }) (src/theme.tsx).']
94
+ : ['List the block in the section\'s `blocks`; the component receives blocks in the merchant\'s order as { type, settings } (settings are not resolved for blocks: coerce with String()/Number()).'],
95
+ }
96
+ }
97
+ case 'field-registry': {
98
+ const r = await read('abi/field-types')
99
+ const helpers = await read('kit/field-helpers')
100
+ return { kind, ...meta(r), types: helpers ? tsBlock(helpers.text, 'field') : null, registry: r?.text ?? null, notes: ['Every field takes { label, info, placeholder, group }; every setting needs a default.', "field.resource(kind, default, opts): the stored value is a handle (or an image URL); pass '' for no default."] }
101
+ }
102
+ case 'theme-settings': {
103
+ const m = parse(await read('abi/manifest-schema'))
104
+ return { kind, source: 'installed-or-bundled', version: null, schema: m?.properties?.settingsSchema ?? null, notes: ['Declared in src/settings.ts with defineSettings(); values for the starter in config/settings.json (only declared keys, valid values). Read in components with useSettings().'] }
105
+ }
106
+ case 'content-document':
107
+ return { kind, source: 'dev-mcp', version: null, schema: CONTENT_SCHEMA, notes: ['Node ids must be unique within a document.'] }
108
+ case 'locale': {
109
+ const r = await read('kit/strings')
110
+ return { kind, source: 'dev-mcp', version: null, schema: LOCALE_SCHEMA, kitKeys: r ? [...r.text.matchAll(/^\| `([^`]+)` \|/gm)].map((m) => m[1]) : [], notes: ['Every visible string the theme adds goes in locales/en.json and locales/th.json and is rendered with t(); merchant-editable text belongs in settings.', 'The storefront tier renders th and en and fails visible text that does not change between them.'] }
111
+ }
112
+ case 'ai-profile': {
113
+ const r = await read('conformance/x-tanqory-ai-schema')
114
+ return { kind, ...meta(r), schema: parse(r), notes: ['Declared with ai.* helpers on sections; buildManifest prints manifest["x-tanqory-ai"]. Warn-only today.'] }
115
+ }
116
+ case 'storefront-report': {
117
+ const r = await read('conformance/storefront-report-schema')
118
+ return { kind, ...meta(r), schema: parse(r) }
119
+ }
120
+ case 'conformance-report': {
121
+ const r = await read('abi/conformance-report-schema')
122
+ return { kind, ...meta(r), schema: parse(r) }
123
+ }
124
+ default:
125
+ return null
126
+ }
127
+ }