@kb-labs/site-tools 2.119.0-canary.e120bc0ee → 2.119.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/page.ts"],"names":[],"mappings":"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","file":"page.js","sourcesContent":["import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { join, resolve, normalize } from 'node:path';\nimport { defineCommand, type PluginContextV3, type CLIInput, type CommandResult } from '@kb-labs/sdk';\n\ninterface PageFlags {\n badge?: string;\n 'dry-run'?: boolean;\n}\n\ntype PageResult = Record<string, never>;\n\ntype JsonObj = { [key: string]: JsonVal };\ntype JsonVal = string | number | boolean | null | JsonVal[] | JsonObj;\n\nfunction dotSet(obj: JsonObj, path: string, value: string): void {\n const parts = path.split('.');\n let cur: JsonObj = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n const key = parts[i] as string;\n if (cur[key] == null || typeof cur[key] !== 'object' || Array.isArray(cur[key])) {\n cur[key] = {};\n }\n cur = cur[key] as JsonObj;\n }\n const last = parts[parts.length - 1] as string;\n cur[last] = value;\n}\n\nfunction pageTemplate(segment: string, namespace: string): string {\n const routePath = `/${segment}`;\n const words = segment.split(/[-/]/);\n const componentName =\n words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join('') + 'Page';\n\n return `import type { Metadata } from 'next';\nimport { getTranslations, setRequestLocale } from 'next-intl/server';\nimport { routing } from '@/i18n/routing';\nimport { buildPageMetadata } from '@/lib/page-metadata';\n\ntype Props = { params: Promise<{ locale: string }> };\n\nexport function generateStaticParams() {\n return routing.locales.map((locale) => ({ locale }));\n}\n\nexport async function generateMetadata({ params }: Props): Promise<Metadata> {\n const { locale } = await params;\n const t = await getTranslations({ locale, namespace: '${namespace}' });\n return buildPageMetadata({\n locale,\n title: t('meta.title'),\n description: t('meta.description'),\n path: '${routePath}',\n imageSegment: '${segment}',\n });\n}\n\nexport default async function ${componentName}({ params }: Props) {\n const { locale } = await params;\n setRequestLocale(locale);\n\n return (\n <main>\n {/* TODO: add page content */}\n </main>\n );\n}\n`;\n}\n\nfunction ogTemplate(segment: string, namespace: string, badge: string): string {\n const displayName = segment.split('/').pop() ?? segment;\n const altText =\n 'KB Labs — ' + displayName.charAt(0).toUpperCase() + displayName.slice(1);\n const badgeLine = badge ? `\\n badge: '${badge}',` : '';\n\n return `import { getTranslations } from 'next-intl/server';\nimport { renderOgImage, OG_SIZE, OG_CONTENT_TYPE } from '@kb-labs/web-og';\n\nexport const alt = '${altText}';\nexport const size = OG_SIZE;\nexport const contentType = OG_CONTENT_TYPE;\n\nexport default async function OpengraphImage({\n params,\n}: {\n params: Promise<{ locale: string }>;\n}) {\n const { locale } = await params;\n const t = await getTranslations({ locale, namespace: '${namespace}' });\n return renderOgImage({\n title: t('meta.title'),\n description: t('meta.description'),${badgeLine}\n });\n}\n`;\n}\n\nasync function runPage(\n ctx: PluginContextV3,\n input: CLIInput<PageFlags>,\n): Promise<CommandResult<PageResult>> {\n const argv = input.argv ?? [];\n const segment = argv.find((a) => !a.startsWith('-'));\n\n if (!segment) {\n ctx.ui.error('Usage: kb site page <segment> [--badge <text>] [--dry-run]');\n ctx.ui.write(\n 'Examples:\\n kb site page pricing\\n kb site page solutions/my-solution --badge Solutions\\n',\n );\n return { ok: false, error: 'A page segment is required' };\n }\n\n // Reject path traversal — only forward slashes and alphanumeric/hyphen segments allowed\n if (!/^[a-z0-9][a-z0-9/-]*$/.test(segment) || segment.includes('..') || normalize(segment) !== segment) {\n ctx.ui.error(`Invalid segment '${segment}' — use only lowercase letters, digits, hyphens, and forward slashes`);\n return { ok: false, error: `Invalid segment '${segment}'` };\n }\n\n const badge = input.flags?.badge ?? '';\n const dryRun = input.flags?.['dry-run'] ?? false;\n\n const workspaceRoot = ctx.cwd ?? process.cwd();\n const siteRoot = join(workspaceRoot, 'sites', 'web', 'apps', 'web');\n const localeDir = join(siteRoot, 'app', '[locale]');\n const segmentDir = resolve(join(localeDir, segment));\n\n // Double-check the resolved path is still inside localeDir (defense in depth)\n if (!segmentDir.startsWith(resolve(localeDir) + '/') && segmentDir !== resolve(localeDir)) {\n ctx.ui.error(`Segment '${segment}' resolves outside app/[locale]/ — aborting`);\n return { ok: false, error: `Segment '${segment}' resolves outside app/[locale]/` };\n }\n\n const namespace = segment\n .split(/[-/]/)\n .map((part, i) =>\n i === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1),\n )\n .join('');\n\n const pagePath = join(segmentDir, 'page.tsx');\n const ogPath = join(segmentDir, 'opengraph-image.tsx');\n const enJsonPath = join(siteRoot, 'messages', 'en.json');\n const ruJsonPath = join(siteRoot, 'messages', 'ru.json');\n\n if (existsSync(pagePath)) {\n ctx.ui.error(`page.tsx already exists at app/[locale]/${segment}/`);\n return { ok: false, error: `page.tsx already exists at app/[locale]/${segment}/` };\n }\n\n if (existsSync(ogPath)) {\n ctx.ui.error(`opengraph-image.tsx already exists at app/[locale]/${segment}/ — remove it first or use a different segment`);\n return { ok: false, error: `opengraph-image.tsx already exists at app/[locale]/${segment}/` };\n }\n\n const pageContent = pageTemplate(segment, namespace);\n const ogContent = ogTemplate(segment, namespace, badge);\n const titleStub = 'TODO: 15–65 chars — Page Title — KB Labs';\n const descStub = 'TODO: 70–165 chars — Describe what this page is about and why it matters.';\n\n if (!dryRun) {\n mkdirSync(segmentDir, { recursive: true });\n writeFileSync(pagePath, pageContent, 'utf8');\n writeFileSync(ogPath, ogContent, 'utf8');\n\n for (const jsonPath of [enJsonPath, ruJsonPath]) {\n const messages = JSON.parse(readFileSync(jsonPath, 'utf8')) as JsonObj;\n dotSet(messages, `${namespace}.meta.title`, titleStub);\n dotSet(messages, `${namespace}.meta.description`, descStub);\n writeFileSync(jsonPath, JSON.stringify(messages, null, 2) + '\\n', 'utf8');\n }\n }\n\n const prefix = dryRun ? '[dry-run] would create' : 'Created';\n\n ctx.ui.success(`${prefix} page '${segment}'`, {\n title: 'site page',\n sections: [\n {\n header: 'Files',\n items: [\n `app/[locale]/${segment}/page.tsx`,\n `app/[locale]/${segment}/opengraph-image.tsx`,\n `messages/en.json (key: ${namespace}.meta.{title,description})`,\n `messages/ru.json (key: ${namespace}.meta.{title,description})`,\n ],\n },\n {\n header: 'Next steps',\n items: [\n `Fill in ${namespace}.meta.title and .description in messages/en.json + ru.json`,\n `Add page content to app/[locale]/${segment}/page.tsx`,\n `Add to sitemap.ts: { path: '/${segment}', priority: 0.7, changeFrequency: 'monthly' }`,\n ],\n },\n ],\n });\n\n return { ok: true };\n}\n\nexport default defineCommand({\n id: 'site-tools:page',\n description: 'Scaffold a new marketing site page with SEO defaults',\n handler: { execute: runPage },\n});\n"]}
1
+ {"version":3,"sources":["../../../home/runner/work/kb-labs/kb-labs/plugins/site-tools/entry/src/commands/page.ts"],"names":[],"mappings":"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","file":"page.js","sourcesContent":["import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { join, resolve, normalize } from 'node:path';\nimport { defineCommand, type PluginContextV3, type CLIInput, type CommandResult } from '@kb-labs/sdk';\n\ninterface PageFlags {\n badge?: string;\n 'dry-run'?: boolean;\n}\n\ntype PageResult = Record<string, never>;\n\ntype JsonObj = { [key: string]: JsonVal };\ntype JsonVal = string | number | boolean | null | JsonVal[] | JsonObj;\n\nfunction dotSet(obj: JsonObj, path: string, value: string): void {\n const parts = path.split('.');\n let cur: JsonObj = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n const key = parts[i] as string;\n if (cur[key] == null || typeof cur[key] !== 'object' || Array.isArray(cur[key])) {\n cur[key] = {};\n }\n cur = cur[key] as JsonObj;\n }\n const last = parts[parts.length - 1] as string;\n cur[last] = value;\n}\n\nfunction pageTemplate(segment: string, namespace: string): string {\n const routePath = `/${segment}`;\n const words = segment.split(/[-/]/);\n const componentName =\n words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join('') + 'Page';\n\n return `import type { Metadata } from 'next';\nimport { getTranslations, setRequestLocale } from 'next-intl/server';\nimport { routing } from '@/i18n/routing';\nimport { buildPageMetadata } from '@/lib/page-metadata';\n\ntype Props = { params: Promise<{ locale: string }> };\n\nexport function generateStaticParams() {\n return routing.locales.map((locale) => ({ locale }));\n}\n\nexport async function generateMetadata({ params }: Props): Promise<Metadata> {\n const { locale } = await params;\n const t = await getTranslations({ locale, namespace: '${namespace}' });\n return buildPageMetadata({\n locale,\n title: t('meta.title'),\n description: t('meta.description'),\n path: '${routePath}',\n imageSegment: '${segment}',\n });\n}\n\nexport default async function ${componentName}({ params }: Props) {\n const { locale } = await params;\n setRequestLocale(locale);\n\n return (\n <main>\n {/* TODO: add page content */}\n </main>\n );\n}\n`;\n}\n\nfunction ogTemplate(segment: string, namespace: string, badge: string): string {\n const displayName = segment.split('/').pop() ?? segment;\n const altText =\n 'KB Labs — ' + displayName.charAt(0).toUpperCase() + displayName.slice(1);\n const badgeLine = badge ? `\\n badge: '${badge}',` : '';\n\n return `import { getTranslations } from 'next-intl/server';\nimport { renderOgImage, OG_SIZE, OG_CONTENT_TYPE } from '@kb-labs/web-og';\n\nexport const alt = '${altText}';\nexport const size = OG_SIZE;\nexport const contentType = OG_CONTENT_TYPE;\n\nexport default async function OpengraphImage({\n params,\n}: {\n params: Promise<{ locale: string }>;\n}) {\n const { locale } = await params;\n const t = await getTranslations({ locale, namespace: '${namespace}' });\n return renderOgImage({\n title: t('meta.title'),\n description: t('meta.description'),${badgeLine}\n });\n}\n`;\n}\n\nasync function runPage(\n ctx: PluginContextV3,\n input: CLIInput<PageFlags>,\n): Promise<CommandResult<PageResult>> {\n const argv = input.argv ?? [];\n const segment = argv.find((a) => !a.startsWith('-'));\n\n if (!segment) {\n ctx.ui.error('Usage: kb site page <segment> [--badge <text>] [--dry-run]');\n ctx.ui.write(\n 'Examples:\\n kb site page pricing\\n kb site page solutions/my-solution --badge Solutions\\n',\n );\n return { ok: false, error: 'A page segment is required' };\n }\n\n // Reject path traversal — only forward slashes and alphanumeric/hyphen segments allowed\n if (!/^[a-z0-9][a-z0-9/-]*$/.test(segment) || segment.includes('..') || normalize(segment) !== segment) {\n ctx.ui.error(`Invalid segment '${segment}' — use only lowercase letters, digits, hyphens, and forward slashes`);\n return { ok: false, error: `Invalid segment '${segment}'` };\n }\n\n const badge = input.flags?.badge ?? '';\n const dryRun = input.flags?.['dry-run'] ?? false;\n\n const workspaceRoot = ctx.cwd ?? process.cwd();\n const siteRoot = join(workspaceRoot, 'sites', 'web', 'apps', 'web');\n const localeDir = join(siteRoot, 'app', '[locale]');\n const segmentDir = resolve(join(localeDir, segment));\n\n // Double-check the resolved path is still inside localeDir (defense in depth)\n if (!segmentDir.startsWith(resolve(localeDir) + '/') && segmentDir !== resolve(localeDir)) {\n ctx.ui.error(`Segment '${segment}' resolves outside app/[locale]/ — aborting`);\n return { ok: false, error: `Segment '${segment}' resolves outside app/[locale]/` };\n }\n\n const namespace = segment\n .split(/[-/]/)\n .map((part, i) =>\n i === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1),\n )\n .join('');\n\n const pagePath = join(segmentDir, 'page.tsx');\n const ogPath = join(segmentDir, 'opengraph-image.tsx');\n const enJsonPath = join(siteRoot, 'messages', 'en.json');\n const ruJsonPath = join(siteRoot, 'messages', 'ru.json');\n\n if (existsSync(pagePath)) {\n ctx.ui.error(`page.tsx already exists at app/[locale]/${segment}/`);\n return { ok: false, error: `page.tsx already exists at app/[locale]/${segment}/` };\n }\n\n if (existsSync(ogPath)) {\n ctx.ui.error(`opengraph-image.tsx already exists at app/[locale]/${segment}/ — remove it first or use a different segment`);\n return { ok: false, error: `opengraph-image.tsx already exists at app/[locale]/${segment}/` };\n }\n\n const pageContent = pageTemplate(segment, namespace);\n const ogContent = ogTemplate(segment, namespace, badge);\n const titleStub = 'TODO: 15–65 chars — Page Title — KB Labs';\n const descStub = 'TODO: 70–165 chars — Describe what this page is about and why it matters.';\n\n if (!dryRun) {\n mkdirSync(segmentDir, { recursive: true });\n writeFileSync(pagePath, pageContent, 'utf8');\n writeFileSync(ogPath, ogContent, 'utf8');\n\n for (const jsonPath of [enJsonPath, ruJsonPath]) {\n const messages = JSON.parse(readFileSync(jsonPath, 'utf8')) as JsonObj;\n dotSet(messages, `${namespace}.meta.title`, titleStub);\n dotSet(messages, `${namespace}.meta.description`, descStub);\n writeFileSync(jsonPath, JSON.stringify(messages, null, 2) + '\\n', 'utf8');\n }\n }\n\n const prefix = dryRun ? '[dry-run] would create' : 'Created';\n\n ctx.ui.success(`${prefix} page '${segment}'`, {\n title: 'site page',\n sections: [\n {\n header: 'Files',\n items: [\n `app/[locale]/${segment}/page.tsx`,\n `app/[locale]/${segment}/opengraph-image.tsx`,\n `messages/en.json (key: ${namespace}.meta.{title,description})`,\n `messages/ru.json (key: ${namespace}.meta.{title,description})`,\n ],\n },\n {\n header: 'Next steps',\n items: [\n `Fill in ${namespace}.meta.title and .description in messages/en.json + ru.json`,\n `Add page content to app/[locale]/${segment}/page.tsx`,\n `Add to sitemap.ts: { path: '/${segment}', priority: 0.7, changeFrequency: 'monthly' }`,\n ],\n },\n ],\n });\n\n return { ok: true };\n}\n\nexport default defineCommand({\n id: 'site-tools:page',\n description: 'Scaffold a new marketing site page with SEO defaults',\n handler: { execute: runPage },\n});\n"]}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/manifest.ts"],"names":[],"mappings":";;;AAEA,IAAM,cAAc,kBAAA,EAAmB,CACpC,IAAA,CAAK,gBAAgB,EACrB,MAAA,CAAO;AAAA,EACN,IAAA,EAAM,WAAA;AAAA,EACN,KAAA,EAAO;AAAA,IACL,oCAAA;AAAA,IACA;AAAA;AAEJ,CAAC,CAAA,CACA,WAAW,EAAE,SAAA,EAAW,KAAO,QAAA,EAAU,GAAA,EAAK,CAAA,CAC9C,KAAA,EAAM;AAET,IAAM,QAAA,GAAW;AAAA,EACf,MAAA,EAAQ,aAAA;AAAA,EACR,EAAA,EAAI,qBAAA;AAAA,EACJ,OAAA,EAAS,OAAA;AAAA,EACT,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,YAAA;AAAA,IACN,WAAA,EAAa,gDAAA;AAAA,IACb,IAAA,EAAM,CAAC,MAAA,EAAQ,UAAA,EAAY,OAAO,IAAI;AAAA,GACxC;AAAA,EACA,GAAA,EAAK;AAAA,IACH,SAAA,EAAW;AAAA,MACT,EAAE,IAAA,EAAM,MAAA,EAAQ,QAAA,EAAU,gCAAA;AAAiC,KAC7D;AAAA,IACA,QAAA,EAAU;AAAA,MACR;AAAA,QACE,IAAA,EAAM,WAAA;AAAA,QACN,QAAA,EAAU,0FAAA;AAAA,QACV,OAAA,EAAS,4BAAA;AAAA,QACT,KAAA,EAAO;AAAA,UACL;AAAA,YACE,IAAA,EAAM,OAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,SAAA;AAAA,YACN,IAAA,EAAM,SAAA;AAAA,YACN,WAAA,EAAa;AAAA;AACf,SACF;AAAA,QACA,QAAA,EAAU;AAAA,UACR,EAAE,OAAA,EAAS,sBAAA,EAAwB,WAAA,EAAa,sBAAA,EAAuB;AAAA,UACvE,EAAE,OAAA,EAAS,sDAAA,EAAwD,WAAA,EAAa,6BAAA,EAA8B;AAAA,UAC9G,EAAE,OAAA,EAAS,oCAAA,EAAsC,WAAA,EAAa,yBAAA;AAA0B;AAC1F;AACF;AACF,GACF;AAAA,EACA;AACF,CAAA;AAEA,IAAO,gBAAA,GAAQ","file":"index.js","sourcesContent":["import { combinePermissions, kbPlatformPreset } from '@kb-labs/sdk';\n\nconst permissions = combinePermissions()\n .with(kbPlatformPreset)\n .withFs({\n mode: 'readWrite',\n allow: [\n 'sites/web/apps/web/app/[locale]/**',\n 'sites/web/apps/web/messages/*.json',\n ],\n })\n .withQuotas({ timeoutMs: 30000, memoryMb: 128 })\n .build();\n\nconst manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/site-tools',\n version: '0.1.0',\n display: {\n name: 'Site Tools',\n description: 'Developer tools for the KB Labs marketing site',\n tags: ['site', 'scaffold', 'seo', 'dx'],\n },\n cli: {\n groupMeta: [\n { path: 'site', describe: 'Marketing site developer tools' },\n ],\n commands: [\n {\n path: 'site page',\n describe: 'Scaffold a new site page with SEO defaults (page.tsx + opengraph-image.tsx + i18n stubs)',\n handler: './commands/page.js#default',\n flags: [\n {\n name: 'badge',\n type: 'string',\n description: 'Badge text shown on the OG image (e.g. \"Product\", \"Solutions\")',\n },\n {\n name: 'dry-run',\n type: 'boolean',\n description: 'Preview what would be created without writing files',\n },\n ],\n examples: [\n { command: 'kb site page pricing', description: 'Create /pricing page' },\n { command: 'kb site page solutions/my-solution --badge Solutions', description: 'Create a solutions sub-page' },\n { command: 'kb site page new-feature --dry-run', description: 'Preview without writing' },\n ],\n },\n ],\n },\n permissions,\n};\n\nexport default manifest;\n"]}
1
+ {"version":3,"sources":["../../home/runner/work/kb-labs/kb-labs/plugins/site-tools/entry/src/manifest.ts"],"names":[],"mappings":";;;AAEA,IAAM,cAAc,kBAAA,EAAmB,CACpC,IAAA,CAAK,gBAAgB,EACrB,MAAA,CAAO;AAAA,EACN,IAAA,EAAM,WAAA;AAAA,EACN,KAAA,EAAO;AAAA,IACL,oCAAA;AAAA,IACA;AAAA;AAEJ,CAAC,CAAA,CACA,WAAW,EAAE,SAAA,EAAW,KAAO,QAAA,EAAU,GAAA,EAAK,CAAA,CAC9C,KAAA,EAAM;AAET,IAAM,QAAA,GAAW;AAAA,EACf,MAAA,EAAQ,aAAA;AAAA,EACR,EAAA,EAAI,qBAAA;AAAA,EACJ,OAAA,EAAS,OAAA;AAAA,EACT,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,YAAA;AAAA,IACN,WAAA,EAAa,gDAAA;AAAA,IACb,IAAA,EAAM,CAAC,MAAA,EAAQ,UAAA,EAAY,OAAO,IAAI;AAAA,GACxC;AAAA,EACA,GAAA,EAAK;AAAA,IACH,SAAA,EAAW;AAAA,MACT,EAAE,IAAA,EAAM,MAAA,EAAQ,QAAA,EAAU,gCAAA;AAAiC,KAC7D;AAAA,IACA,QAAA,EAAU;AAAA,MACR;AAAA,QACE,IAAA,EAAM,WAAA;AAAA,QACN,QAAA,EAAU,0FAAA;AAAA,QACV,OAAA,EAAS,4BAAA;AAAA,QACT,KAAA,EAAO;AAAA,UACL;AAAA,YACE,IAAA,EAAM,OAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,SAAA;AAAA,YACN,IAAA,EAAM,SAAA;AAAA,YACN,WAAA,EAAa;AAAA;AACf,SACF;AAAA,QACA,QAAA,EAAU;AAAA,UACR,EAAE,OAAA,EAAS,sBAAA,EAAwB,WAAA,EAAa,sBAAA,EAAuB;AAAA,UACvE,EAAE,OAAA,EAAS,sDAAA,EAAwD,WAAA,EAAa,6BAAA,EAA8B;AAAA,UAC9G,EAAE,OAAA,EAAS,oCAAA,EAAsC,WAAA,EAAa,yBAAA;AAA0B;AAC1F;AACF;AACF,GACF;AAAA,EACA;AACF,CAAA;AAEA,IAAO,gBAAA,GAAQ","file":"index.js","sourcesContent":["import { combinePermissions, kbPlatformPreset } from '@kb-labs/sdk';\n\nconst permissions = combinePermissions()\n .with(kbPlatformPreset)\n .withFs({\n mode: 'readWrite',\n allow: [\n 'sites/web/apps/web/app/[locale]/**',\n 'sites/web/apps/web/messages/*.json',\n ],\n })\n .withQuotas({ timeoutMs: 30000, memoryMb: 128 })\n .build();\n\nconst manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/site-tools',\n version: '0.1.0',\n display: {\n name: 'Site Tools',\n description: 'Developer tools for the KB Labs marketing site',\n tags: ['site', 'scaffold', 'seo', 'dx'],\n },\n cli: {\n groupMeta: [\n { path: 'site', describe: 'Marketing site developer tools' },\n ],\n commands: [\n {\n path: 'site page',\n describe: 'Scaffold a new site page with SEO defaults (page.tsx + opengraph-image.tsx + i18n stubs)',\n handler: './commands/page.js#default',\n flags: [\n {\n name: 'badge',\n type: 'string',\n description: 'Badge text shown on the OG image (e.g. \"Product\", \"Solutions\")',\n },\n {\n name: 'dry-run',\n type: 'boolean',\n description: 'Preview what would be created without writing files',\n },\n ],\n examples: [\n { command: 'kb site page pricing', description: 'Create /pricing page' },\n { command: 'kb site page solutions/my-solution --badge Solutions', description: 'Create a solutions sub-page' },\n { command: 'kb site page new-feature --dry-run', description: 'Preview without writing' },\n ],\n },\n ],\n },\n permissions,\n};\n\nexport default manifest;\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/manifest.ts"],"names":[],"mappings":";;;AAEA,IAAM,cAAc,kBAAA,EAAmB,CACpC,IAAA,CAAK,gBAAgB,EACrB,MAAA,CAAO;AAAA,EACN,IAAA,EAAM,WAAA;AAAA,EACN,KAAA,EAAO;AAAA,IACL,oCAAA;AAAA,IACA;AAAA;AAEJ,CAAC,CAAA,CACA,WAAW,EAAE,SAAA,EAAW,KAAO,QAAA,EAAU,GAAA,EAAK,CAAA,CAC9C,KAAA,EAAM;AAET,IAAM,QAAA,GAAW;AAAA,EACf,MAAA,EAAQ,aAAA;AAAA,EACR,EAAA,EAAI,qBAAA;AAAA,EACJ,OAAA,EAAS,OAAA;AAAA,EACT,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,YAAA;AAAA,IACN,WAAA,EAAa,gDAAA;AAAA,IACb,IAAA,EAAM,CAAC,MAAA,EAAQ,UAAA,EAAY,OAAO,IAAI;AAAA,GACxC;AAAA,EACA,GAAA,EAAK;AAAA,IACH,SAAA,EAAW;AAAA,MACT,EAAE,IAAA,EAAM,MAAA,EAAQ,QAAA,EAAU,gCAAA;AAAiC,KAC7D;AAAA,IACA,QAAA,EAAU;AAAA,MACR;AAAA,QACE,IAAA,EAAM,WAAA;AAAA,QACN,QAAA,EAAU,0FAAA;AAAA,QACV,OAAA,EAAS,4BAAA;AAAA,QACT,KAAA,EAAO;AAAA,UACL;AAAA,YACE,IAAA,EAAM,OAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,SAAA;AAAA,YACN,IAAA,EAAM,SAAA;AAAA,YACN,WAAA,EAAa;AAAA;AACf,SACF;AAAA,QACA,QAAA,EAAU;AAAA,UACR,EAAE,OAAA,EAAS,sBAAA,EAAwB,WAAA,EAAa,sBAAA,EAAuB;AAAA,UACvE,EAAE,OAAA,EAAS,sDAAA,EAAwD,WAAA,EAAa,6BAAA,EAA8B;AAAA,UAC9G,EAAE,OAAA,EAAS,oCAAA,EAAsC,WAAA,EAAa,yBAAA;AAA0B;AAC1F;AACF;AACF,GACF;AAAA,EACA;AACF,CAAA;AAEA,IAAO,gBAAA,GAAQ","file":"manifest.js","sourcesContent":["import { combinePermissions, kbPlatformPreset } from '@kb-labs/sdk';\n\nconst permissions = combinePermissions()\n .with(kbPlatformPreset)\n .withFs({\n mode: 'readWrite',\n allow: [\n 'sites/web/apps/web/app/[locale]/**',\n 'sites/web/apps/web/messages/*.json',\n ],\n })\n .withQuotas({ timeoutMs: 30000, memoryMb: 128 })\n .build();\n\nconst manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/site-tools',\n version: '0.1.0',\n display: {\n name: 'Site Tools',\n description: 'Developer tools for the KB Labs marketing site',\n tags: ['site', 'scaffold', 'seo', 'dx'],\n },\n cli: {\n groupMeta: [\n { path: 'site', describe: 'Marketing site developer tools' },\n ],\n commands: [\n {\n path: 'site page',\n describe: 'Scaffold a new site page with SEO defaults (page.tsx + opengraph-image.tsx + i18n stubs)',\n handler: './commands/page.js#default',\n flags: [\n {\n name: 'badge',\n type: 'string',\n description: 'Badge text shown on the OG image (e.g. \"Product\", \"Solutions\")',\n },\n {\n name: 'dry-run',\n type: 'boolean',\n description: 'Preview what would be created without writing files',\n },\n ],\n examples: [\n { command: 'kb site page pricing', description: 'Create /pricing page' },\n { command: 'kb site page solutions/my-solution --badge Solutions', description: 'Create a solutions sub-page' },\n { command: 'kb site page new-feature --dry-run', description: 'Preview without writing' },\n ],\n },\n ],\n },\n permissions,\n};\n\nexport default manifest;\n"]}
1
+ {"version":3,"sources":["../../home/runner/work/kb-labs/kb-labs/plugins/site-tools/entry/src/manifest.ts"],"names":[],"mappings":";;;AAEA,IAAM,cAAc,kBAAA,EAAmB,CACpC,IAAA,CAAK,gBAAgB,EACrB,MAAA,CAAO;AAAA,EACN,IAAA,EAAM,WAAA;AAAA,EACN,KAAA,EAAO;AAAA,IACL,oCAAA;AAAA,IACA;AAAA;AAEJ,CAAC,CAAA,CACA,WAAW,EAAE,SAAA,EAAW,KAAO,QAAA,EAAU,GAAA,EAAK,CAAA,CAC9C,KAAA,EAAM;AAET,IAAM,QAAA,GAAW;AAAA,EACf,MAAA,EAAQ,aAAA;AAAA,EACR,EAAA,EAAI,qBAAA;AAAA,EACJ,OAAA,EAAS,OAAA;AAAA,EACT,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,YAAA;AAAA,IACN,WAAA,EAAa,gDAAA;AAAA,IACb,IAAA,EAAM,CAAC,MAAA,EAAQ,UAAA,EAAY,OAAO,IAAI;AAAA,GACxC;AAAA,EACA,GAAA,EAAK;AAAA,IACH,SAAA,EAAW;AAAA,MACT,EAAE,IAAA,EAAM,MAAA,EAAQ,QAAA,EAAU,gCAAA;AAAiC,KAC7D;AAAA,IACA,QAAA,EAAU;AAAA,MACR;AAAA,QACE,IAAA,EAAM,WAAA;AAAA,QACN,QAAA,EAAU,0FAAA;AAAA,QACV,OAAA,EAAS,4BAAA;AAAA,QACT,KAAA,EAAO;AAAA,UACL;AAAA,YACE,IAAA,EAAM,OAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN,WAAA,EAAa;AAAA,WACf;AAAA,UACA;AAAA,YACE,IAAA,EAAM,SAAA;AAAA,YACN,IAAA,EAAM,SAAA;AAAA,YACN,WAAA,EAAa;AAAA;AACf,SACF;AAAA,QACA,QAAA,EAAU;AAAA,UACR,EAAE,OAAA,EAAS,sBAAA,EAAwB,WAAA,EAAa,sBAAA,EAAuB;AAAA,UACvE,EAAE,OAAA,EAAS,sDAAA,EAAwD,WAAA,EAAa,6BAAA,EAA8B;AAAA,UAC9G,EAAE,OAAA,EAAS,oCAAA,EAAsC,WAAA,EAAa,yBAAA;AAA0B;AAC1F;AACF;AACF,GACF;AAAA,EACA;AACF,CAAA;AAEA,IAAO,gBAAA,GAAQ","file":"manifest.js","sourcesContent":["import { combinePermissions, kbPlatformPreset } from '@kb-labs/sdk';\n\nconst permissions = combinePermissions()\n .with(kbPlatformPreset)\n .withFs({\n mode: 'readWrite',\n allow: [\n 'sites/web/apps/web/app/[locale]/**',\n 'sites/web/apps/web/messages/*.json',\n ],\n })\n .withQuotas({ timeoutMs: 30000, memoryMb: 128 })\n .build();\n\nconst manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/site-tools',\n version: '0.1.0',\n display: {\n name: 'Site Tools',\n description: 'Developer tools for the KB Labs marketing site',\n tags: ['site', 'scaffold', 'seo', 'dx'],\n },\n cli: {\n groupMeta: [\n { path: 'site', describe: 'Marketing site developer tools' },\n ],\n commands: [\n {\n path: 'site page',\n describe: 'Scaffold a new site page with SEO defaults (page.tsx + opengraph-image.tsx + i18n stubs)',\n handler: './commands/page.js#default',\n flags: [\n {\n name: 'badge',\n type: 'string',\n description: 'Badge text shown on the OG image (e.g. \"Product\", \"Solutions\")',\n },\n {\n name: 'dry-run',\n type: 'boolean',\n description: 'Preview what would be created without writing files',\n },\n ],\n examples: [\n { command: 'kb site page pricing', description: 'Create /pricing page' },\n { command: 'kb site page solutions/my-solution --badge Solutions', description: 'Create a solutions sub-page' },\n { command: 'kb site page new-feature --dry-run', description: 'Preview without writing' },\n ],\n },\n ],\n },\n permissions,\n};\n\nexport default manifest;\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kb-labs/site-tools",
3
3
  "description": "Developer tools for the KB Labs marketing site (scaffold pages, SEO checks).",
4
- "version": "2.119.0-canary.e120bc0ee",
4
+ "version": "2.119.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -27,11 +27,11 @@
27
27
  "tsup": "^8.5.0",
28
28
  "typescript": "^5.6.3",
29
29
  "vitest": "^3.2.6",
30
- "@kb-labs/plugin-contracts": "2.119.0-canary.e120bc0ee",
31
- "@kb-labs/devkit": "2.119.0-canary.e120bc0ee"
30
+ "@kb-labs/plugin-contracts": "2.119.0",
31
+ "@kb-labs/devkit": "2.119.0"
32
32
  },
33
33
  "engines": {
34
- "node": ">=22.0.0",
34
+ "node": ">=24.0.0",
35
35
  "pnpm": ">=9.0.0"
36
36
  },
37
37
  "kb": {
@@ -1,84 +0,0 @@
1
- {
2
- "schema": "kb.plugin/3",
3
- "id": "@kb-labs/site-tools",
4
- "version": "0.1.0",
5
- "display": {
6
- "name": "Site Tools",
7
- "description": "Developer tools for the KB Labs marketing site",
8
- "tags": [
9
- "site",
10
- "scaffold",
11
- "seo",
12
- "dx"
13
- ]
14
- },
15
- "cli": {
16
- "groupMeta": [
17
- {
18
- "path": "site",
19
- "describe": "Marketing site developer tools"
20
- }
21
- ],
22
- "commands": [
23
- {
24
- "path": "site page",
25
- "describe": "Scaffold a new site page with SEO defaults (page.tsx + opengraph-image.tsx + i18n stubs)",
26
- "handler": "./commands/page.js#default",
27
- "flags": [
28
- {
29
- "name": "badge",
30
- "type": "string",
31
- "description": "Badge text shown on the OG image (e.g. \"Product\", \"Solutions\")"
32
- },
33
- {
34
- "name": "dry-run",
35
- "type": "boolean",
36
- "description": "Preview what would be created without writing files"
37
- }
38
- ],
39
- "examples": [
40
- {
41
- "command": "kb site page pricing",
42
- "description": "Create /pricing page"
43
- },
44
- {
45
- "command": "kb site page solutions/my-solution --badge Solutions",
46
- "description": "Create a solutions sub-page"
47
- },
48
- {
49
- "command": "kb site page new-feature --dry-run",
50
- "description": "Preview without writing"
51
- }
52
- ]
53
- }
54
- ]
55
- },
56
- "permissions": {
57
- "fs": {
58
- "read": [
59
- ".kb/**",
60
- "sites/web/apps/web/app/[locale]/**",
61
- "sites/web/apps/web/messages/*.json"
62
- ],
63
- "write": [
64
- ".kb/**",
65
- "sites/web/apps/web/app/[locale]/**",
66
- "sites/web/apps/web/messages/*.json"
67
- ]
68
- },
69
- "env": {
70
- "read": [
71
- "HOME",
72
- "USER",
73
- "PATH",
74
- "TMPDIR",
75
- "NODE_ENV",
76
- "KB_*"
77
- ]
78
- },
79
- "quotas": {
80
- "timeoutMs": 30000,
81
- "memoryMb": 128
82
- }
83
- }
84
- }